/* * A fairly generic DMA-API to IOMMU-API glue layer. * * Copyright (C) 2014 ARM Ltd. * * based in part on arch/arm/mm/dma-mapping.c: * Copyright (C) 2000-2004 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include #include int iommu_dma_init(void) { return 0; } struct iommu_dma_domain { struct iommu_domain *domain; unsigned long **bitmaps; /* array of bitmaps */ unsigned int nr_bitmaps; /* nr of elements in array */ unsigned int extensions; size_t bitmap_size; /* size of a single bitmap */ size_t bits; /* per bitmap */ dma_addr_t base; spinlock_t lock; struct kref kref; }; static inline dma_addr_t dev_dma_addr(struct device *dev, dma_addr_t addr) { BUG_ON(addr < dev->dma_pfn_offset); return addr - ((dma_addr_t)dev->dma_pfn_offset << PAGE_SHIFT); } static int __dma_direction_to_prot(enum dma_data_direction dir, bool coherent) { int prot = coherent ? IOMMU_CACHE : 0; switch (dir) { case DMA_BIDIRECTIONAL: return prot | IOMMU_READ | IOMMU_WRITE; case DMA_TO_DEVICE: return prot | IOMMU_READ; case DMA_FROM_DEVICE: return prot | IOMMU_WRITE; default: return 0; } } static int extend_iommu_mapping(struct iommu_dma_domain *mapping); static inline int __reserve_iova(struct iommu_dma_domain *mapping, dma_addr_t iova, size_t size) { unsigned long count, start; unsigned long flags; int i, sbitmap, ebitmap; if (iova < mapping->base) return -EINVAL; start = (iova - mapping->base) >> PAGE_SHIFT; count = PAGE_ALIGN(size) >> PAGE_SHIFT; sbitmap = start / mapping->bits; ebitmap = (start + count) / mapping->bits; start = start % mapping->bits; if (ebitmap > mapping->extensions) return -EINVAL; spin_lock_irqsave(&mapping->lock, flags); for (i = mapping->nr_bitmaps; i <= ebitmap; i++) { if (extend_iommu_mapping(mapping)) { spin_unlock_irqrestore(&mapping->lock, flags); return -ENOMEM; } } for (i = sbitmap; count && i < mapping->nr_bitmaps; i++) { int bits = count; if (bits + start > mapping->bits) bits = mapping->bits - start; bitmap_set(mapping->bitmaps[i], start, bits); start = 0; count -= bits; } spin_unlock_irqrestore(&mapping->lock, flags); return 0; } static inline dma_addr_t __alloc_iova(struct iommu_dma_domain *mapping, size_t size, bool coherent) { unsigned int order = get_order(size); unsigned int align = 0; unsigned int count, start; size_t mapping_size = mapping->bits << PAGE_SHIFT; unsigned long flags; dma_addr_t iova; int i; if (order > 8) order = 8; count = PAGE_ALIGN(size) >> PAGE_SHIFT; align = (1 << order) - 1; spin_lock_irqsave(&mapping->lock, flags); for (i = 0; i < mapping->nr_bitmaps; i++) { start = bitmap_find_next_zero_area(mapping->bitmaps[i], mapping->bits, 0, count, align); if (start > mapping->bits) continue; bitmap_set(mapping->bitmaps[i], start, count); break; } /* * No unused range found. Try to extend the existing mapping * and perform a second attempt to reserve an IO virtual * address range of size bytes. */ if (i == mapping->nr_bitmaps) { if (extend_iommu_mapping(mapping)) { spin_unlock_irqrestore(&mapping->lock, flags); return DMA_ERROR_CODE; } start = bitmap_find_next_zero_area(mapping->bitmaps[i], mapping->bits, 0, count, align); if (start > mapping->bits) { spin_unlock_irqrestore(&mapping->lock, flags); return DMA_ERROR_CODE; } bitmap_set(mapping->bitmaps[i], start, count); } spin_unlock_irqrestore(&mapping->lock, flags); iova = mapping->base + (mapping_size * i); iova += start << PAGE_SHIFT; return iova; } static inline void __free_iova(struct iommu_dma_domain *mapping, dma_addr_t addr, size_t size) { unsigned int start, count; size_t mapping_size = mapping->bits << PAGE_SHIFT; unsigned long flags; dma_addr_t bitmap_base; u32 bitmap_index; if (!size) return; bitmap_index = (u32) (addr - mapping->base) / (u32) mapping_size; BUG_ON(addr < mapping->base || bitmap_index > mapping->extensions); bitmap_base = mapping->base + mapping_size * bitmap_index; start = (addr - bitmap_base) >> PAGE_SHIFT; if (addr + size > bitmap_base + mapping_size) { /* * The address range to be freed reaches into the iova * range of the next bitmap. This should not happen as * we don't allow this in __alloc_iova (at the * moment). */ BUG(); } else count = size >> PAGE_SHIFT; spin_lock_irqsave(&mapping->lock, flags); bitmap_clear(mapping->bitmaps[bitmap_index], start, count); spin_unlock_irqrestore(&mapping->lock, flags); } static inline size_t iova_offset(dma_addr_t iova) { return iova & ~PAGE_MASK; } static inline size_t iova_align(size_t size) { return PAGE_ALIGN(size); } /* * Create a mapping in device IO address space for specified pages */ dma_addr_t iommu_dma_create_iova_mapping(struct device *dev, struct page **pages, size_t size, bool coherent) { struct iommu_dma_domain *dom = get_dma_domain(dev); struct iommu_domain *domain = dom->domain; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; dma_addr_t addr_lo, addr_hi; int i, prot = __dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent); addr_lo = __alloc_iova(dom, size, coherent); if (addr_lo == DMA_ERROR_CODE) return DMA_ERROR_CODE; addr_hi = addr_lo; for (i = 0; i < count; ) { unsigned int next_pfn = page_to_pfn(pages[i]) + 1; phys_addr_t phys = page_to_phys(pages[i]); unsigned int len, j; for (j = i+1; j < count; j++, next_pfn++) if (page_to_pfn(pages[j]) != next_pfn) break; len = (j - i) << PAGE_SHIFT; if (iommu_map(domain, addr_hi, phys, len, prot)) goto fail; addr_hi += len; i = j; } return dev_dma_addr(dev, addr_lo); fail: iommu_unmap(domain, addr_lo, addr_hi - addr_lo); __free_iova(dom, addr_lo, size); return DMA_ERROR_CODE; } int iommu_dma_release_iova_mapping(struct device *dev, dma_addr_t iova, size_t size) { struct iommu_dma_domain *dom = get_dma_domain(dev); size_t offset = iova_offset(iova); size_t len = iova_align(size + offset); iommu_unmap(dom->domain, iova - offset, len); __free_iova(dom, iova, len); return 0; } struct page **iommu_dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp, struct dma_attrs *attrs, void (clear_buffer)(struct page *page, size_t size)) { struct page **pages; int count = size >> PAGE_SHIFT; int array_size = count * sizeof(struct page *); int i = 0; if (array_size <= PAGE_SIZE) pages = kzalloc(array_size, GFP_KERNEL); else pages = vzalloc(array_size); if (!pages) return NULL; if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) { unsigned long order = get_order(size); struct page *page; page = dma_alloc_from_contiguous(dev, count, order); if (!page) goto error; if (clear_buffer) clear_buffer(page, size); for (i = 0; i < count; i++) pages[i] = page + i; return pages; } /* * IOMMU can map any pages, so himem can also be used here */ gfp |= __GFP_NOWARN | __GFP_HIGHMEM; while (count) { int j, order = __fls(count); pages[i] = alloc_pages(gfp, order); while (!pages[i] && order) pages[i] = alloc_pages(gfp, --order); if (!pages[i]) goto error; if (order) { split_page(pages[i], order); j = 1 << order; while (--j) pages[i + j] = pages[i] + j; } if (clear_buffer) clear_buffer(pages[i], PAGE_SIZE << order); i += 1 << order; count -= 1 << order; } return pages; error: while (i--) if (pages[i]) __free_pages(pages[i], 0); if (array_size <= PAGE_SIZE) kfree(pages); else vfree(pages); return NULL; } int iommu_dma_free_buffer(struct device *dev, struct page **pages, size_t size, struct dma_attrs *attrs) { int count = size >> PAGE_SHIFT; int array_size = count * sizeof(struct page *); int i; if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) { dma_release_from_contiguous(dev, pages[0], count); } else { for (i = 0; i < count; i++) if (pages[i]) __free_pages(pages[i], 0); } if (array_size <= PAGE_SIZE) kfree(pages); else vfree(pages); return 0; } static dma_addr_t __iommu_dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, bool coherent) { dma_addr_t dma_addr; struct iommu_dma_domain *dom = get_dma_domain(dev); phys_addr_t phys = page_to_phys(page); int prot = __dma_direction_to_prot(dir, coherent); int len = PAGE_ALIGN(size + offset); dma_addr = __alloc_iova(dom, len, coherent); if (dma_addr == DMA_ERROR_CODE) return dma_addr; if (iommu_map(dom->domain, dma_addr, phys, len, prot)) { __free_iova(dom, dma_addr, len); return DMA_ERROR_CODE; } return dev_dma_addr(dev, dma_addr + offset); } dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { return __iommu_dma_map_page(dev, page, offset, size, dir, false); } dma_addr_t iommu_dma_coherent_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { return __iommu_dma_map_page(dev, page, offset, size, dir, true); } void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { struct iommu_dma_domain *dom = get_dma_domain(dev); dma_addr_t iova = handle & PAGE_MASK; int offset = handle & ~PAGE_MASK; int len = PAGE_ALIGN(size + offset); iommu_unmap(dom->domain, iova, len); __free_iova(dom, iova, len); } static int finalise_sg(struct device *dev, struct scatterlist *sg, int nents, dma_addr_t dma_addr) { struct scatterlist *s, *seg = sg; unsigned long seg_mask = dma_get_seg_boundary(dev); unsigned int max_len = dma_get_max_seg_size(dev); unsigned int seg_len = 0, seg_dma = 0; int i, count = 1; for_each_sg(sg, s, nents, i) { /* Un-swizzling the fields here, hence the naming mismatch */ unsigned int s_offset = sg_dma_address(s); unsigned int s_length = sg_dma_len(s); unsigned int s_dma_len = s->length; s->offset = s_offset; s->length = s_length; sg_dma_address(s) = DMA_ERROR_CODE; sg_dma_len(s) = 0; if (seg_len && (seg_dma + seg_len == dma_addr + s_offset) && (seg_len + s_dma_len <= max_len) && ((seg_dma & seg_mask) <= seg_mask - (seg_len + s_length)) ) { sg_dma_len(seg) += s_dma_len; } else { if (seg_len) { seg = sg_next(seg); count++; } sg_dma_len(seg) = s_dma_len; sg_dma_address(seg) = dma_addr + s_offset; seg_len = s_offset; seg_dma = dma_addr + s_offset; } seg_len += s_length; dma_addr += s_dma_len; } return count; } static void invalidate_sg(struct scatterlist *sg, int nents) { struct scatterlist *s; int i; for_each_sg(sg, s, nents, i) { if (sg_dma_address(s) != DMA_ERROR_CODE) s->offset = sg_dma_address(s); if (sg_dma_len(s)) s->length = sg_dma_len(s); sg_dma_address(s) = DMA_ERROR_CODE; sg_dma_len(s) = 0; } } static int __iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs, bool coherent) { struct iommu_dma_domain *dom = get_dma_domain(dev); dma_addr_t iova; struct scatterlist *s; dma_addr_t dma_addr; size_t iova_len = 0; int i, prot = __dma_direction_to_prot(dir, coherent); /* * Work out how much IOVA space we need, and align the segments to * IOVA granules for the IOMMU driver to handle. With some clever * trickery we can modify the list in a reversible manner. */ for_each_sg(sg, s, nents, i) { size_t s_offset = iova_offset(s->offset); size_t s_length = s->length; sg_dma_address(s) = s->offset; sg_dma_len(s) = s_length; s->offset -= s_offset; s_length = iova_align(s_length + s_offset); s->length = s_length; iova_len += s_length; } iova = __alloc_iova(dom, iova_len, coherent); if (iova == DMA_ERROR_CODE) goto out_restore_sg; /* * We'll leave any physical concatenation to the IOMMU driver's * implementation - it knows better than we do. */ dma_addr = iova; if (iommu_map_sg(dom->domain, dma_addr, sg, nents, prot) < iova_len) goto out_free_iova; return finalise_sg(dev, sg, nents, dev_dma_addr(dev, dma_addr)); out_free_iova: __free_iova(dom, iova, iova_len); out_restore_sg: invalidate_sg(sg, nents); return 0; } int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { return __iommu_dma_map_sg(dev, sg, nents, dir, attrs, false); } int iommu_dma_coherent_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { return __iommu_dma_map_sg(dev, sg, nents, dir, attrs, true); } void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { struct iommu_dma_domain *dom = get_dma_domain(dev); struct scatterlist *s; int i; dma_addr_t iova = sg_dma_address(sg) & PAGE_MASK; size_t len = 0; /* * The scatterlist segments are mapped into contiguous IOVA space, * so just add up the total length and unmap it in one go. */ for_each_sg(sg, s, nents, i) len += sg_dma_len(s); iommu_unmap(dom->domain, iova, len); __free_iova(dom, iova, len); } struct iommu_dma_domain *iommu_dma_create_domain(struct bus_type *bus, dma_addr_t base, size_t size) { struct iommu_dma_domain *dom; struct iommu_domain *domain; struct iommu_domain_geometry *dg; unsigned long order, base_pfn, end_pfn; unsigned int bits = size >> PAGE_SHIFT; unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); int extensions = 1; if (bitmap_size > PAGE_SIZE) { extensions = bitmap_size / PAGE_SIZE; bitmap_size = PAGE_SIZE; } pr_debug("base=%pad\tsize=0x%zx\n", &base, size); dom = kzalloc(sizeof(*dom), GFP_KERNEL); if (!dom) return NULL; dom->bitmap_size = bitmap_size; dom->bitmaps = kcalloc(extensions, sizeof(unsigned long *), GFP_KERNEL); if (!dom->bitmaps) goto out_free_dma_domain; dom->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL); if (!dom->bitmaps[0]) goto out_free_dma_domain; dom->nr_bitmaps = 1; dom->extensions = extensions; dom->base = base; dom->bits = BITS_PER_BYTE * bitmap_size; spin_lock_init(&dom->lock); /* * HACK: We'd like to ask the relevant IOMMU in ops for a suitable * domain, but until that happens, bypass the bus nonsense and create * one directly for this specific device/IOMMU combination... */ domain = iommu_domain_alloc(bus); if (!domain) goto out_free_dma_domain; /* * ...and do the bare minimum to sanity-check that the domain allows * at least some access to the device... */ dg = &domain->geometry; if (!(base <= dg->aperture_end && base + size > dg->aperture_start)) { pr_warn("DMA range outside IOMMU capability; is DT correct?\n"); goto out_free_iommu_domain; } /* ...then finally give it a kicking to make sure it fits */ dg->aperture_start = max(base, dg->aperture_start); dg->aperture_end = min(base + size - 1, dg->aperture_end); /* * Note that this almost certainly breaks the case where multiple * devices with different DMA capabilities need to share a domain, * but we don't have the necessary information to handle that here * anyway - "proper" group and domain allocation needs to involve * the IOMMU driver and a complete view of the bus. */ /* Use the smallest supported page size for IOVA granularity */ order = __ffs(bus->iommu_ops->pgsize_bitmap); base_pfn = max(dg->aperture_start >> order, (dma_addr_t)1); end_pfn = dg->aperture_end >> order; dom->domain = domain; kref_init(&dom->kref); pr_debug("domain %p created\n", dom); return dom; out_free_iommu_domain: kfree(domain); out_free_dma_domain: kfree(dom); return NULL; } static int extend_iommu_mapping(struct iommu_dma_domain *mapping) { int next_bitmap; if (mapping->nr_bitmaps >= mapping->extensions) return -EINVAL; next_bitmap = mapping->nr_bitmaps; mapping->bitmaps[next_bitmap] = kzalloc(mapping->bitmap_size, GFP_ATOMIC); if (!mapping->bitmaps[next_bitmap]) return -ENOMEM; mapping->nr_bitmaps++; return 0; } static void iommu_dma_free_domain(struct kref *kref) { struct iommu_dma_domain *dom; int i; dom = container_of(kref, struct iommu_dma_domain, kref); for (i = 0; i < dom->nr_bitmaps; i++) kfree(dom->bitmaps[i]); kfree(dom->bitmaps); iommu_domain_free(dom->domain); kfree(dom); pr_debug("domain %p freed\n", dom); } void iommu_dma_release_domain(struct iommu_dma_domain *dom) { kref_put(&dom->kref, iommu_dma_free_domain); } struct iommu_domain *iommu_dma_raw_domain(struct iommu_dma_domain *dom) { return dom ? dom->domain : NULL; } int iommu_dma_attach_device(struct device *dev, struct iommu_dma_domain *dom) { int ret; kref_get(&dom->kref); ret = iommu_attach_device(dom->domain, dev); if (ret) iommu_dma_release_domain(dom); else set_dma_domain(dev, dom); pr_debug("%s%s attached to domain %p\n", dev_name(dev), ret?" *not*":"", dom); return ret; } void iommu_dma_detach_device(struct device *dev) { struct iommu_dma_domain *dom = get_dma_domain(dev); if (!dom) { dev_warn(dev, "Not attached\n"); return; } set_dma_domain(dev, NULL); iommu_detach_device(dom->domain, dev); iommu_dma_release_domain(dom); pr_debug("%s detached from domain %p\n", dev_name(dev), dom); } int iommu_dma_supported(struct device *dev, u64 mask) { /* * This looks awful, but really it's reasonable to assume that if an * IOMMU can't address everything that the CPU can, it probably isn't * generic enough to be using this implementation in the first place. */ return 1; } int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return dma_addr == DMA_ERROR_CODE; } int iommu_add_reserved_mapping(struct device *dev, struct iommu_dma_domain *dma_domain, phys_addr_t phys, dma_addr_t dma, size_t size) { int ret; ret = __reserve_iova(dma_domain, dma, size); if (ret != 0) { dev_err(dev, "failed to reserve mapping\n"); return ret; } ret = iommu_map(dma_domain->domain, dma, phys, size, IOMMU_READ); if (ret != 0) { dev_err(dev, "create IOMMU mapping\n"); return ret; } dev_info(dev, "created reserved DMA mapping (%pa -> %pad, %zd bytes)\n", &phys, &dma, size); return 0; } int iommu_dma_init_reserved(struct device *dev, struct iommu_dma_domain *dma_domain) { const char *name = "iommu-reserved-mapping"; const __be32 *prop = NULL; int len, naddr, nsize; struct device_node *node = dev->of_node; phys_addr_t phys; dma_addr_t dma; size_t size; if (!node) return 0; naddr = of_n_addr_cells(node); nsize = of_n_size_cells(node); prop = of_get_property(node, name, &len); if (!prop) return 0; len /= sizeof(u32); if (len < 2 * naddr + nsize) { dev_err(dev, "invalid length (%d cells) of %s property\n", len, name); return -EINVAL; } phys = of_read_number(prop, naddr); dma = of_read_number(prop + naddr, naddr); size = of_read_number(prop + 2*naddr, nsize); return iommu_add_reserved_mapping(dev, dma_domain, phys, dma, size); }