* [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware
@ 2011-11-10 9:32 Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 1/7] iommu/core: stop converting bytes to page order back and forth Ohad Ben-Cohen
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
v3->v4:
- simplify splitter logic (Joerg)
- declare supported page-sizes in the iommu_ops, without extending iommu_register (Joerg)
- iommu_unmap should now return bytes too (Joerg)
- don't cache min_pgsize anymore (Joerg)
- handle cases when ->unmap() actually unmaps more than requested (Joerg)
- unroll iommu_unmap completely in case it fails (KyongHo)
- use size_t for size parameters (KyongHo)
- add a patch to remove the bytes->order->bytes conversion we had
- rabased to master branch of the iommu tree (Joerg)
(and now rebased to 3.2-rc1)
v2->v3:
- s/KB/KiB/ (David W)
v1->v2:
- split to patches (by keeping the old code around until all drivers are converted) (Joerg)
Tested with OMAP4 (with rpmsg/remoteproc) and compile tested for X86-64.
Ohad Ben-Cohen (7):
iommu/core: stop converting bytes to page order back and forth
iommu/core: split mapping to page sizes as supported by the hardware
iommu/omap: announce supported page sizes
iommu/msm: announce supported page sizes
iommu/amd: announce supported page sizes
iommu/intel: announce supported page sizes
iommu/core: remove the temporary pgsize settings
drivers/iommu/amd_iommu.c | 32 +++++++++---
drivers/iommu/intel-iommu.c | 30 ++++++++---
drivers/iommu/iommu.c | 119 ++++++++++++++++++++++++++++++++++++++----
drivers/iommu/msm_iommu.c | 25 ++++-----
drivers/iommu/omap-iommu.c | 18 +++---
drivers/iommu/omap-iovmm.c | 17 ++----
include/linux/iommu.h | 26 +++++++--
virt/kvm/iommu.c | 8 ++--
8 files changed, 205 insertions(+), 70 deletions(-)
--
1.7.5.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 1/7] iommu/core: stop converting bytes to page order back and forth
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 2/7] iommu/core: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Express sizes in bytes rather than in page order, to eliminate the
size->order->size conversions we have whenever the IOMMU API is calling
the low level drivers' map/unmap methods.
Adopt all existing drivers.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
Cc: KyongHo Cho <pullip.cho@samsung.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/iommu/amd_iommu.c | 13 +++++--------
drivers/iommu/intel-iommu.c | 11 ++++-------
drivers/iommu/iommu.c | 8 +++++---
drivers/iommu/msm_iommu.c | 19 +++++++------------
drivers/iommu/omap-iommu.c | 14 +++++---------
include/linux/iommu.h | 6 +++---
6 files changed, 29 insertions(+), 42 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 4ee277a..a3b7072 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2702,9 +2702,8 @@ static int amd_iommu_attach_device(struct iommu_domain *dom,
}
static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int iommu_prot)
+ phys_addr_t paddr, size_t page_size, int iommu_prot)
{
- unsigned long page_size = 0x1000UL << gfp_order;
struct protection_domain *domain = dom->priv;
int prot = 0;
int ret;
@@ -2721,13 +2720,11 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
return ret;
}
-static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
- int gfp_order)
+static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
+ size_t page_size)
{
struct protection_domain *domain = dom->priv;
- unsigned long page_size, unmap_size;
-
- page_size = 0x1000UL << gfp_order;
+ size_t unmap_size;
mutex_lock(&domain->api_lock);
unmap_size = iommu_unmap_page(domain, iova, page_size);
@@ -2735,7 +2732,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
domain_flush_tlb_pde(domain);
- return get_order(unmap_size);
+ return unmap_size;
}
static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c0c7820..2a16501 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3979,12 +3979,11 @@ static void intel_iommu_detach_device(struct iommu_domain *domain,
static int intel_iommu_map(struct iommu_domain *domain,
unsigned long iova, phys_addr_t hpa,
- int gfp_order, int iommu_prot)
+ size_t size, int iommu_prot)
{
struct dmar_domain *dmar_domain = domain->priv;
u64 max_addr;
int prot = 0;
- size_t size;
int ret;
if (iommu_prot & IOMMU_READ)
@@ -3994,7 +3993,6 @@ static int intel_iommu_map(struct iommu_domain *domain,
if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
prot |= DMA_PTE_SNP;
- size = PAGE_SIZE << gfp_order;
max_addr = iova + size;
if (dmar_domain->max_addr < max_addr) {
u64 end;
@@ -4017,11 +4015,10 @@ static int intel_iommu_map(struct iommu_domain *domain,
return ret;
}
-static int intel_iommu_unmap(struct iommu_domain *domain,
- unsigned long iova, int gfp_order)
+static size_t intel_iommu_unmap(struct iommu_domain *domain,
+ unsigned long iova, size_t size)
{
struct dmar_domain *dmar_domain = domain->priv;
- size_t size = PAGE_SIZE << gfp_order;
int order;
order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
@@ -4030,7 +4027,7 @@ static int intel_iommu_unmap(struct iommu_domain *domain,
if (dmar_domain->max_addr == iova + size)
dmar_domain->max_addr = iova;
- return order;
+ return PAGE_SIZE << order;
}
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 2fb2963..7a2953d 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -168,13 +168,13 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
BUG_ON(!IS_ALIGNED(iova | paddr, size));
- return domain->ops->map(domain, iova, paddr, gfp_order, prot);
+ return domain->ops->map(domain, iova, paddr, size, prot);
}
EXPORT_SYMBOL_GPL(iommu_map);
int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
{
- size_t size;
+ size_t size, unmapped;
if (unlikely(domain->ops->unmap == NULL))
return -ENODEV;
@@ -183,6 +183,8 @@ int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
BUG_ON(!IS_ALIGNED(iova, size));
- return domain->ops->unmap(domain, iova, gfp_order);
+ unmapped = domain->ops->unmap(domain, iova, size);
+
+ return get_order(unmapped);
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 5865dd2..13718d9 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -352,7 +352,7 @@ fail:
}
static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
- phys_addr_t pa, int order, int prot)
+ phys_addr_t pa, size_t len, int prot)
{
struct msm_priv *priv;
unsigned long flags;
@@ -363,7 +363,6 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
unsigned long *sl_pte;
unsigned long sl_offset;
unsigned int pgprot;
- size_t len = 0x1000UL << order;
int ret = 0, tex, sh;
spin_lock_irqsave(&msm_iommu_lock, flags);
@@ -463,8 +462,8 @@ fail:
return ret;
}
-static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
- int order)
+static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
+ size_t len)
{
struct msm_priv *priv;
unsigned long flags;
@@ -474,7 +473,6 @@ static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
unsigned long *sl_table;
unsigned long *sl_pte;
unsigned long sl_offset;
- size_t len = 0x1000UL << order;
int i, ret = 0;
spin_lock_irqsave(&msm_iommu_lock, flags);
@@ -544,15 +542,12 @@ static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
ret = __flush_iotlb(domain);
- /*
- * the IOMMU API requires us to return the order of the unmapped
- * page (on success).
- */
- if (!ret)
- ret = order;
fail:
spin_unlock_irqrestore(&msm_iommu_lock, flags);
- return ret;
+
+ /* the IOMMU API requires us to return how many bytes were unmapped */
+ len = ret ? 0 : len;
+ return len;
}
static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 8f32b2b..ad80b1d 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1019,12 +1019,11 @@ static void iopte_cachep_ctor(void *iopte)
}
static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
- phys_addr_t pa, int order, int prot)
+ phys_addr_t pa, size_t bytes, int prot)
{
struct omap_iommu_domain *omap_domain = domain->priv;
struct omap_iommu *oiommu = omap_domain->iommu_dev;
struct device *dev = oiommu->dev;
- size_t bytes = PAGE_SIZE << order;
struct iotlb_entry e;
int omap_pgsz;
u32 ret, flags;
@@ -1049,19 +1048,16 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
return ret;
}
-static int omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
- int order)
+static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
+ size_t size)
{
struct omap_iommu_domain *omap_domain = domain->priv;
struct omap_iommu *oiommu = omap_domain->iommu_dev;
struct device *dev = oiommu->dev;
- size_t unmap_size;
- dev_dbg(dev, "unmapping da 0x%lx order %d\n", da, order);
+ dev_dbg(dev, "unmapping da 0x%lx size %u\n", da, size);
- unmap_size = iopgtable_clear_entry(oiommu, da);
-
- return unmap_size ? get_order(unmap_size) : -EINVAL;
+ return iopgtable_clear_entry(oiommu, da);
}
static int
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 432acc4..d5ebf3f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -54,9 +54,9 @@ struct iommu_ops {
int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
int (*map)(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot);
- int (*unmap)(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ phys_addr_t paddr, size_t size, int prot);
+ size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
+ size_t size);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
unsigned long iova);
int (*domain_has_cap)(struct iommu_domain *domain,
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 2/7] iommu/core: split mapping to page sizes as supported by the hardware
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 1/7] iommu/core: stop converting bytes to page order back and forth Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 3/7] iommu/omap: announce supported page sizes Ohad Ben-Cohen
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
When mapping a memory region, split it to page sizes as supported
by the iommu hardware. Always prefer bigger pages, when possible,
in order to reduce the TLB pressure.
The logic to do that is now added to the IOMMU core, so neither the iommu
drivers themselves nor users of the IOMMU API have to duplicate it.
This allows a more lenient granularity of mappings; traditionally the
IOMMU API took 'order' (of a page) as a mapping size, and directly let
the low level iommu drivers handle the mapping, but now that the IOMMU
core can split arbitrary memory regions into pages, we can remove this
limitation, so users don't have to split those regions by themselves.
Currently the supported page sizes are advertised once and they then
remain static. That works well for OMAP and MSM but it would probably
not fly well with intel's hardware, where the page size capabilities
seem to have the potential to be different between several DMA
remapping devices.
register_iommu() currently sets a default pgsize behavior, so we can convert
the IOMMU drivers in subsequent patches. After all the drivers
are converted, the temporary default settings will be removed.
Mainline users of the IOMMU API (kvm and omap-iovmm) are adopted
to deal with bytes instead of page order.
Many thanks to Joerg Roedel <Joerg.Roedel@amd.com> for significant review!
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
Cc: KyongHo Cho <pullip.cho@samsung.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: kvm at vger.kernel.org
---
drivers/iommu/iommu.c | 131 +++++++++++++++++++++++++++++++++++++++-----
drivers/iommu/omap-iovmm.c | 17 ++----
include/linux/iommu.h | 20 ++++++-
virt/kvm/iommu.c | 8 +-
4 files changed, 144 insertions(+), 32 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 7a2953d..b278458 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/bug.h>
@@ -47,6 +49,16 @@ int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops)
if (bus->iommu_ops != NULL)
return -EBUSY;
+ /*
+ * Set the default pgsize values, which retain the existing
+ * IOMMU API behavior: drivers will be called to map
+ * regions that are sized/aligned to order of 4KiB pages.
+ *
+ * This will be removed once all drivers are migrated.
+ */
+ if (!ops->pgsize_bitmap)
+ ops->pgsize_bitmap = ~0xFFFUL;
+
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
@@ -157,34 +169,125 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot)
+ phys_addr_t paddr, size_t size, int prot)
{
- size_t size;
+ unsigned long orig_iova = iova;
+ unsigned int min_pagesz;
+ size_t orig_size = size;
+ int ret = 0;
if (unlikely(domain->ops->map == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /* find out the minimum page size supported */
+ min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
+
+ /*
+ * both the virtual address and the physical one, as well as
+ * the size of the mapping, must be aligned (at least) to the
+ * size of the smallest page supported by the hardware
+ */
+ if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz "
+ "0x%x\n", iova, (unsigned long)paddr,
+ (unsigned long)size, min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova,
+ (unsigned long)paddr, (unsigned long)size);
+
+ while (size) {
+ unsigned long pgsize, addr_merge = iova | paddr;
+ unsigned int pgsize_idx;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by both iova and paddr */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
- BUG_ON(!IS_ALIGNED(iova | paddr, size));
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
- return domain->ops->map(domain, iova, paddr, size, prot);
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
+
+ pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
+ (unsigned long)paddr, pgsize);
+
+ ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
+ if (ret)
+ break;
+
+ iova += pgsize;
+ paddr += pgsize;
+ size -= pgsize;
+ }
+
+ /* unroll mapping in case something went wrong */
+ if (ret)
+ iommu_unmap(domain, orig_iova, orig_size - size);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_map);
-int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
+size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
{
- size_t size, unmapped;
+ size_t unmapped_page, unmapped = 0;
+ unsigned int min_pagesz;
if (unlikely(domain->ops->unmap == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
-
- BUG_ON(!IS_ALIGNED(iova, size));
-
- unmapped = domain->ops->unmap(domain, iova, size);
-
- return get_order(unmapped);
+ /* find out the minimum page size supported */
+ min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
+
+ /*
+ * The virtual address, as well as the size of the mapping, must be
+ * aligned (at least) to the size of the smallest page supported
+ * by the hardware
+ */
+ if (!IS_ALIGNED(iova | size, min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n",
+ iova, (unsigned long)size, min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova,
+ (unsigned long)size);
+
+ /*
+ * Keep iterating until we either unmap 'size' bytes (or more)
+ * or we hit an area that isn't mapped.
+ */
+ while (unmapped < size) {
+ size_t left = size - unmapped;
+
+ unmapped_page = domain->ops->unmap(domain, iova, left);
+ if (!unmapped_page)
+ break;
+
+ pr_debug("unmapped: iova 0x%lx size %lx\n", iova,
+ (unsigned long)unmapped_page);
+
+ iova += unmapped_page;
+ unmapped += unmapped_page;
+ }
+
+ return unmapped;
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index e8fdb88..0b7b14c 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -409,7 +409,6 @@ static int map_iovm_area(struct iommu_domain *domain, struct iovm_struct *new,
unsigned int i, j;
struct scatterlist *sg;
u32 da = new->da_start;
- int order;
if (!domain || !sgt)
return -EINVAL;
@@ -428,12 +427,10 @@ static int map_iovm_area(struct iommu_domain *domain, struct iovm_struct *new,
if (bytes_to_iopgsz(bytes) < 0)
goto err_out;
- order = get_order(bytes);
-
pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
i, da, pa, bytes);
- err = iommu_map(domain, da, pa, order, flags);
+ err = iommu_map(domain, da, pa, bytes, flags);
if (err)
goto err_out;
@@ -448,10 +445,9 @@ err_out:
size_t bytes;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
/* ignore failures.. we're already handling one */
- iommu_unmap(domain, da, order);
+ iommu_unmap(domain, da, bytes);
da += bytes;
}
@@ -466,7 +462,8 @@ static void unmap_iovm_area(struct iommu_domain *domain, struct omap_iommu *obj,
size_t total = area->da_end - area->da_start;
const struct sg_table *sgt = area->sgt;
struct scatterlist *sg;
- int i, err;
+ int i;
+ size_t unmapped;
BUG_ON(!sgtable_ok(sgt));
BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
@@ -474,13 +471,11 @@ static void unmap_iovm_area(struct iommu_domain *domain, struct omap_iommu *obj,
start = area->da_start;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes;
- int order;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
- err = iommu_unmap(domain, start, order);
- if (err < 0)
+ unmapped = iommu_unmap(domain, start, bytes);
+ if (unmapped < bytes)
break;
dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index d5ebf3f..cc26f89 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -48,6 +48,19 @@ struct iommu_domain {
#ifdef CONFIG_IOMMU_API
+/**
+ * struct iommu_ops - iommu ops and capabilities
+ * @domain_init: init iommu domain
+ * @domain_destroy: destroy iommu domain
+ * @attach_dev: attach device to an iommu domain
+ * @detach_dev: detach device from an iommu domain
+ * @map: map a physically contiguous memory region to an iommu domain
+ * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @iova_to_phys: translate iova to physical address
+ * @domain_has_cap: domain capabilities query
+ * @commit: commit iommu domain
+ * @pgsize_bitmap: bitmap of supported page sizes
+ */
struct iommu_ops {
int (*domain_init)(struct iommu_domain *domain);
void (*domain_destroy)(struct iommu_domain *domain);
@@ -61,6 +74,7 @@ struct iommu_ops {
unsigned long iova);
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
+ unsigned long pgsize_bitmap;
};
extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
@@ -72,9 +86,9 @@ extern int iommu_attach_device(struct iommu_domain *domain,
extern void iommu_detach_device(struct iommu_domain *domain,
struct device *dev);
extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot);
-extern int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ phys_addr_t paddr, size_t size, int prot);
+extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size);
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index a195c07..304d7e5 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -113,7 +113,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
/* Map into IO address space */
r = iommu_map(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
- get_order(page_size), flags);
+ page_size, flags);
if (r) {
printk(KERN_ERR "kvm_iommu_map_address:"
"iommu failed to map pfn=%llx\n", pfn);
@@ -292,15 +292,15 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
while (gfn < end_gfn) {
unsigned long unmap_pages;
- int order;
+ size_t size;
/* Get physical address */
phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn));
pfn = phys >> PAGE_SHIFT;
/* Unmap address from IO address space */
- order = iommu_unmap(domain, gfn_to_gpa(gfn), 0);
- unmap_pages = 1ULL << order;
+ size = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE);
+ unmap_pages = 1ULL << get_order(size);
/* Unpin all pages we just unmapped to not leak any memory */
kvm_unpin_pages(kvm, pfn, unmap_pages);
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 3/7] iommu/omap: announce supported page sizes
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 1/7] iommu/core: stop converting bytes to page order back and forth Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 2/7] iommu/core: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 4/7] iommu/msm: " Ohad Ben-Cohen
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Let the IOMMU core know we support 4KiB, 64KiB, 1MiB and 16MiB page sizes.
This way the IOMMU core can split any arbitrary-sized physically
contiguous regions (that it needs to map) as needed.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
---
drivers/iommu/omap-iommu.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index ad80b1d..08cf7ec 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -33,6 +33,9 @@
(__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \
__i++)
+/* bitmap of the page sizes currently supported */
+#define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
+
/**
* struct omap_iommu_domain - omap iommu domain
* @pgtable: the page table
@@ -1207,6 +1210,7 @@ static struct iommu_ops omap_iommu_ops = {
.unmap = omap_iommu_unmap,
.iova_to_phys = omap_iommu_iova_to_phys,
.domain_has_cap = omap_iommu_domain_has_cap,
+ .pgsize_bitmap = OMAP_IOMMU_PGSIZES,
};
static int __init omap_iommu_init(void)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 4/7] iommu/msm: announce supported page sizes
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (2 preceding siblings ...)
2011-11-10 9:32 ` [PATCH v4-rebased 3/7] iommu/omap: announce supported page sizes Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 5/7] iommu/amd: " Ohad Ben-Cohen
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Let the IOMMU core know we support 4KiB, 64KiB, 1MiB and 16MiB page sizes.
This way the IOMMU core can split any arbitrary-sized physically
contiguous regions (that it needs to map) as needed.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Acked-by: David Brown <davidb@codeaurora.org>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
---
drivers/iommu/msm_iommu.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 13718d9..08a90b8 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -42,6 +42,9 @@ __asm__ __volatile__ ( \
#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0)
#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1)
+/* bitmap of the page sizes currently supported */
+#define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
+
static int msm_iommu_tex_class[4];
DEFINE_SPINLOCK(msm_iommu_lock);
@@ -679,7 +682,8 @@ static struct iommu_ops msm_iommu_ops = {
.map = msm_iommu_map,
.unmap = msm_iommu_unmap,
.iova_to_phys = msm_iommu_iova_to_phys,
- .domain_has_cap = msm_iommu_domain_has_cap
+ .domain_has_cap = msm_iommu_domain_has_cap,
+ .pgsize_bitmap = MSM_IOMMU_PGSIZES,
};
static int __init get_tex_class(int icp, int ocp, int mt, int nos)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 5/7] iommu/amd: announce supported page sizes
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (3 preceding siblings ...)
2011-11-10 9:32 ` [PATCH v4-rebased 4/7] iommu/msm: " Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 6/7] iommu/intel: " Ohad Ben-Cohen
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Let the IOMMU core know we support arbitrary page sizes (as long as
they're an order of 4KiB).
This way the IOMMU core will retain the existing behavior we're used to;
it will let us map regions that:
- their size is an order of 4KiB
- they are naturally aligned
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
---
drivers/iommu/amd_iommu.c | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a3b7072..3415738 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -41,6 +41,24 @@
#define LOOP_TIMEOUT 100000
+/*
+ * This bitmap is used to advertise the page sizes our hardware support
+ * to the IOMMU core, which will then use this information to split
+ * physically contiguous memory regions it is mapping into page sizes
+ * that we support.
+ *
+ * Traditionally the IOMMU core just handed us the mappings directly,
+ * after making sure the size is an order of a 4KiB page and that the
+ * mapping has natural alignment.
+ *
+ * To retain this behavior, we currently advertise that we support
+ * all page sizes that are an order of 4KiB.
+ *
+ * If at some point we'd like to utilize the IOMMU core's new behavior,
+ * we could change this to advertise the real page sizes we support.
+ */
+#define AMD_IOMMU_PGSIZES (~0xFFFUL)
+
static DEFINE_RWLOCK(amd_iommu_devtable_lock);
/* A list of preallocated protection domains */
@@ -2779,6 +2797,7 @@ static struct iommu_ops amd_iommu_ops = {
.unmap = amd_iommu_unmap,
.iova_to_phys = amd_iommu_iova_to_phys,
.domain_has_cap = amd_iommu_domain_has_cap,
+ .pgsize_bitmap = AMD_IOMMU_PGSIZES,
};
/*****************************************************************************
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 6/7] iommu/intel: announce supported page sizes
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (4 preceding siblings ...)
2011-11-10 9:32 ` [PATCH v4-rebased 5/7] iommu/amd: " Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 7/7] iommu/core: remove the temporary pgsize settings Ohad Ben-Cohen
2011-11-15 15:49 ` [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Joerg Roedel
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Let the IOMMU core know we support arbitrary page sizes (as long as
they're an order of 4KiB).
This way the IOMMU core will retain the existing behavior we're used to;
it will let us map regions that:
- their size is an order of 4KiB
- they are naturally aligned
Note: Intel IOMMU hardware doesn't support arbitrary page sizes,
but the driver does (it splits arbitrary-sized mappings into
the pages supported by the hardware).
To make everything simpler for now, though, this patch effectively tells
the IOMMU core to keep giving this driver the same memory regions it did
before, so nothing is changed as far as it's concerned.
At this point, the page sizes announced remain static within the IOMMU
core. To correctly utilize the pgsize-splitting of the IOMMU core by
this driver, it seems that some core changes should still be done,
because Intel's IOMMU page size capabilities seem to have the potential
to be different between different DMA remapping devices.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---
drivers/iommu/intel-iommu.c | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2a16501..4c780ef 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -78,6 +78,24 @@
#define LEVEL_STRIDE (9)
#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
+/*
+ * This bitmap is used to advertise the page sizes our hardware support
+ * to the IOMMU core, which will then use this information to split
+ * physically contiguous memory regions it is mapping into page sizes
+ * that we support.
+ *
+ * Traditionally the IOMMU core just handed us the mappings directly,
+ * after making sure the size is an order of a 4KiB page and that the
+ * mapping has natural alignment.
+ *
+ * To retain this behavior, we currently advertise that we support
+ * all page sizes that are an order of 4KiB.
+ *
+ * If@some point we'd like to utilize the IOMMU core's new behavior,
+ * we could change this to advertise the real page sizes we support.
+ */
+#define INTEL_IOMMU_PGSIZES (~0xFFFUL)
+
static inline int agaw_to_level(int agaw)
{
return agaw + 2;
@@ -4066,6 +4084,7 @@ static struct iommu_ops intel_iommu_ops = {
.unmap = intel_iommu_unmap,
.iova_to_phys = intel_iommu_iova_to_phys,
.domain_has_cap = intel_iommu_domain_has_cap,
+ .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
};
static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 7/7] iommu/core: remove the temporary pgsize settings
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (5 preceding siblings ...)
2011-11-10 9:32 ` [PATCH v4-rebased 6/7] iommu/intel: " Ohad Ben-Cohen
@ 2011-11-10 9:32 ` Ohad Ben-Cohen
2011-11-15 15:49 ` [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Joerg Roedel
7 siblings, 0 replies; 9+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-10 9:32 UTC (permalink / raw)
To: linux-arm-kernel
Now that all IOMMU drivers are exporting their supported pgsizes,
we can remove the default pgsize settings in register_iommu().
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/iommu/iommu.c | 10 ----------
1 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b278458..84cdd8a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -49,16 +49,6 @@ int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops)
if (bus->iommu_ops != NULL)
return -EBUSY;
- /*
- * Set the default pgsize values, which retain the existing
- * IOMMU API behavior: drivers will be called to map
- * regions that are sized/aligned to order of 4KiB pages.
- *
- * This will be removed once all drivers are migrated.
- */
- if (!ops->pgsize_bitmap)
- ops->pgsize_bitmap = ~0xFFFUL;
-
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
--
1.7.5.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
` (6 preceding siblings ...)
2011-11-10 9:32 ` [PATCH v4-rebased 7/7] iommu/core: remove the temporary pgsize settings Ohad Ben-Cohen
@ 2011-11-15 15:49 ` Joerg Roedel
7 siblings, 0 replies; 9+ messages in thread
From: Joerg Roedel @ 2011-11-15 15:49 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Nov 10, 2011 at 11:32:24AM +0200, Ohad Ben-Cohen wrote:
> Ohad Ben-Cohen (7):
> iommu/core: stop converting bytes to page order back and forth
> iommu/core: split mapping to page sizes as supported by the hardware
> iommu/omap: announce supported page sizes
> iommu/msm: announce supported page sizes
> iommu/amd: announce supported page sizes
> iommu/intel: announce supported page sizes
> iommu/core: remove the temporary pgsize settings
>
> drivers/iommu/amd_iommu.c | 32 +++++++++---
> drivers/iommu/intel-iommu.c | 30 ++++++++---
> drivers/iommu/iommu.c | 119 ++++++++++++++++++++++++++++++++++++++----
> drivers/iommu/msm_iommu.c | 25 ++++-----
> drivers/iommu/omap-iommu.c | 18 +++---
> drivers/iommu/omap-iovmm.c | 17 ++----
> include/linux/iommu.h | 26 +++++++--
> virt/kvm/iommu.c | 8 ++--
> 8 files changed, 205 insertions(+), 70 deletions(-)
Applied, thanks.
--
AMD Operating System Research Center
Advanced Micro Devices GmbH Einsteinring 24 85609 Dornach
General Managers: Alberto Bozzo, Andrew Bowd
Registration: Dornach, Landkr. Muenchen; Registerger. Muenchen, HRB Nr. 43632
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-11-15 15:49 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-10 9:32 [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 1/7] iommu/core: stop converting bytes to page order back and forth Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 2/7] iommu/core: split mapping to page sizes as supported by the hardware Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 3/7] iommu/omap: announce supported page sizes Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 4/7] iommu/msm: " Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 5/7] iommu/amd: " Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 6/7] iommu/intel: " Ohad Ben-Cohen
2011-11-10 9:32 ` [PATCH v4-rebased 7/7] iommu/core: remove the temporary pgsize settings Ohad Ben-Cohen
2011-11-15 15:49 ` [PATCH v4-rebased 0/7] iommu: split mapping to page sizes as supported by the hardware Joerg Roedel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).