Re: [PATCH v7 05/22] Docs: dt: document ARM SMMUv3 generic binding usage
On Mon, Sep 12, 2016 at 05:13:43PM +0100, Robin Murphy wrote: > We're about to ratify our use of the generic binding, so document it. > > CC: Rob Herring> CC: Mark Rutland > Signed-off-by: Robin Murphy > > --- > > - Reference PCI "iommu-map" binding instead, as that's our main concern > - Fix "IDs" typo > --- > Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | 8 +++- > 1 file changed, 7 insertions(+), 1 deletion(-) Acked-by: Rob Herring ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 07/07] iommu/ipmmu-vmsa: Drop LPAE Kconfig dependency
From: Magnus DammNeither the ARM page table code enabled by IOMMU_IO_PGTABLE_LPAE nor the IPMMU_VMSA driver actually depends on ARM_LPAE, so get rid of the dependency. Tested with ipmmu-vmsa on r8a7794 ALT and a kernel config using: # CONFIG_ARM_LPAE is not set Signed-off-by: Magnus Damm Acked-by: Laurent Pinchart --- Changes since V4: - Rebased patch to fit on top of earlier Kconfig changes in series Changes since V3: - None Changes since V2: - None Changes since V1: - Rebased on top of ARCH_RENESAS change - Added Acked-by from Laurent drivers/iommu/Kconfig |1 - 1 file changed, 1 deletion(-) --- 0008/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2016-09-20 22:13:03.500607110 +0900 @@ -275,7 +275,6 @@ config EXYNOS_IOMMU_DEBUG config IPMMU_VMSA bool "Renesas VMSA-compatible IPMMU" depends on ARM || IOMMU_DMA - depends on ARM_LPAE depends on ARCH_RENESAS || COMPILE_TEST select IOMMU_API select IOMMU_IO_PGTABLE_LPAE ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 05/07] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops
From: Magnus DammIntroduce an alternative set of iommu_ops suitable for 64-bit ARM as well as 32-bit ARM when CONFIG_IOMMU_DMA=y. Also adjust the Kconfig to depend on ARM or IOMMU_DMA. Signed-off-by: Magnus Damm --- Changes since V4: - Added Kconfig hunk to depend on ARM or IOMMU_DMA Changes since V3: - Removed group parameter from ipmmu_init_platform_device() Changes since V2: - Included this new patch from the following series: [PATCH 00/04] iommu/ipmmu-vmsa: IPMMU CONFIG_IOMMU_DMA update - Use only a single iommu_ops structure with #ifdef CONFIG_IOMMU_DMA - Folded in #ifdefs to handle CONFIG_ARM and CONFIG_IOMMU_DMA - of_xlate() is now used without #ifdefs - Made sure code compiles on both 32-bit and 64-bit ARM. drivers/iommu/Kconfig |1 drivers/iommu/ipmmu-vmsa.c | 111 2 files changed, 104 insertions(+), 8 deletions(-) --- 0001/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2016-09-20 22:10:15.280607110 +0900 @@ -274,6 +274,7 @@ config EXYNOS_IOMMU_DEBUG config IPMMU_VMSA bool "Renesas VMSA-compatible IPMMU" + depends on ARM || IOMMU_DMA depends on ARM_LPAE depends on ARCH_RENESAS || COMPILE_TEST select IOMMU_API --- 0006/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 22:08:58.300607110 +0900 @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -22,8 +23,10 @@ #include #include +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include #include +#endif #include "io-pgtable.h" @@ -520,14 +523,6 @@ static struct iommu_domain *__ipmmu_doma return >io_domain; } -static struct iommu_domain *ipmmu_domain_alloc(unsigned type) -{ - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - - return __ipmmu_domain_alloc(type); -} - static void ipmmu_domain_free(struct iommu_domain *io_domain) { struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); @@ -714,6 +709,8 @@ error: return ret; } +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) + static int ipmmu_add_device(struct device *dev) { struct ipmmu_vmsa_archdata *archdata; @@ -807,6 +804,14 @@ static void ipmmu_remove_device(struct d dev->archdata.iommu = NULL; } +static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +{ + if (type != IOMMU_DOMAIN_UNMANAGED) + return NULL; + + return __ipmmu_domain_alloc(type); +} + static const struct iommu_ops ipmmu_ops = { .domain_alloc = ipmmu_domain_alloc, .domain_free = ipmmu_domain_free, @@ -821,6 +826,94 @@ static const struct iommu_ops ipmmu_ops .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, }; +#endif /* !CONFIG_ARM && CONFIG_IOMMU_DMA */ + +#ifdef CONFIG_IOMMU_DMA + +static struct iommu_domain *ipmmu_domain_alloc_dma(unsigned type) +{ + struct iommu_domain *io_domain; + + if (type != IOMMU_DOMAIN_DMA) + return NULL; + + io_domain = __ipmmu_domain_alloc(type); + if (io_domain) + iommu_get_dma_cookie(io_domain); + + return io_domain; +} + +static void ipmmu_domain_free_dma(struct iommu_domain *io_domain) +{ + iommu_put_dma_cookie(io_domain); + ipmmu_domain_free(io_domain); +} + +static int ipmmu_add_device_dma(struct device *dev) +{ + struct iommu_group *group; + + /* only accept devices with iommus property */ + if (of_count_phandle_with_args(dev->of_node, "iommus", + "#iommu-cells") < 0) + return -ENODEV; + + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) + return PTR_ERR(group); + + return 0; +} + +static void ipmmu_remove_device_dma(struct device *dev) +{ + iommu_group_remove_device(dev); +} + +static struct iommu_group *ipmmu_device_group_dma(struct device *dev) +{ + struct iommu_group *group; + int ret; + + group = generic_device_group(dev); + if (IS_ERR(group)) + return group; + + ret = ipmmu_init_platform_device(dev); + if (ret) { + iommu_group_put(group); + group = ERR_PTR(ret); + } + + return group; +} + +static int ipmmu_of_xlate_dma(struct device *dev, + struct of_phandle_args *spec) +{ + /* dummy callback to satisfy of_iommu_configure() */ + return 0; +} + +static const struct iommu_ops ipmmu_ops = { + .domain_alloc = ipmmu_domain_alloc_dma, + .domain_free = ipmmu_domain_free_dma, + .attach_dev = ipmmu_attach_device, + .detach_dev = ipmmu_detach_device, + .map = ipmmu_map, + .unmap = ipmmu_unmap, + .map_sg = default_iommu_map_sg, + .iova_to_phys = ipmmu_iova_to_phys, + .add_device = ipmmu_add_device_dma, + .remove_device =
[PATCH v5 06/07] iommu/ipmmu-vmsa: ARM and ARM64 archdata access
From: Magnus DammNot all architectures have an iommu member in their archdata, so use #ifdefs support build wit COMPILE_TEST on any architecture. Signed-off-by: Magnus Damm --- Changes since V4: - None Changes since V3: - New patch drivers/iommu/ipmmu-vmsa.c | 37 +++-- 1 file changed, 27 insertions(+), 10 deletions(-) --- 0012/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 21:59:21.690607110 +0900 @@ -70,6 +70,25 @@ static struct ipmmu_vmsa_domain *to_vmsa return container_of(dom, struct ipmmu_vmsa_domain, io_domain); } +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +static struct ipmmu_vmsa_archdata *to_archdata(struct device *dev) +{ + return dev->archdata.iommu; +} +static void set_archdata(struct device *dev, struct ipmmu_vmsa_archdata *p) +{ + dev->archdata.iommu = p; +} +#else +static struct ipmmu_vmsa_archdata *to_archdata(struct device *dev) +{ + return NULL; +} +static void set_archdata(struct device *dev, struct ipmmu_vmsa_archdata *p) +{ +} +#endif + #define TLB_LOOP_TIMEOUT 100 /* 100us */ /* - @@ -539,7 +558,7 @@ static void ipmmu_domain_free(struct iom static int ipmmu_attach_device(struct iommu_domain *io_domain, struct device *dev) { - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_archdata *archdata = to_archdata(dev); struct ipmmu_vmsa_device *mmu = archdata->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned long flags; @@ -581,7 +600,7 @@ static int ipmmu_attach_device(struct io static void ipmmu_detach_device(struct iommu_domain *io_domain, struct device *dev) { - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_archdata *archdata = to_archdata(dev); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned int i; @@ -701,7 +720,7 @@ static int ipmmu_init_platform_device(st archdata->mmu = mmu; archdata->utlbs = utlbs; archdata->num_utlbs = num_utlbs; - dev->archdata.iommu = archdata; + set_archdata(dev, archdata); return 0; error: @@ -713,12 +732,11 @@ error: static int ipmmu_add_device(struct device *dev) { - struct ipmmu_vmsa_archdata *archdata; struct ipmmu_vmsa_device *mmu = NULL; struct iommu_group *group; int ret; - if (dev->archdata.iommu) { + if (to_archdata(dev)) { dev_warn(dev, "IOMMU driver already assigned to device %s\n", dev_name(dev)); return -EINVAL; @@ -754,8 +772,7 @@ static int ipmmu_add_device(struct devic * - Make the mapping size configurable ? We currently use a 2GB mapping * at a 1GB offset to ensure that NULL VAs will fault. */ - archdata = dev->archdata.iommu; - mmu = archdata->mmu; + mmu = to_archdata(dev)->mmu; if (!mmu->mapping) { struct dma_iommu_mapping *mapping; @@ -783,7 +800,7 @@ error: if (mmu) arm_iommu_release_mapping(mmu->mapping); - dev->archdata.iommu = NULL; + set_archdata(dev, NULL); if (!IS_ERR_OR_NULL(group)) iommu_group_remove_device(dev); @@ -793,7 +810,7 @@ error: static void ipmmu_remove_device(struct device *dev) { - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_archdata *archdata = to_archdata(dev); arm_iommu_detach_device(dev); iommu_group_remove_device(dev); @@ -801,7 +818,7 @@ static void ipmmu_remove_device(struct d kfree(archdata->utlbs); kfree(archdata); - dev->archdata.iommu = NULL; + set_archdata(dev, NULL); } static struct iommu_domain *ipmmu_domain_alloc(unsigned type) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 04/07] iommu/ipmmu-vmsa: Break out domain allocation code
From: Magnus DammBreak out the domain allocation code into a separate function. This is preparation for future code sharing. Signed-off-by: Magnus Damm --- Changes since V4: - None Changes since V3: - None Changes since V2: - Included this new patch as-is from the following series: [PATCH 00/04] iommu/ipmmu-vmsa: IPMMU CONFIG_IOMMU_DMA update drivers/iommu/ipmmu-vmsa.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) --- 0008/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 21:56:59.220607110 +0900 @@ -507,13 +507,10 @@ static irqreturn_t ipmmu_irq(int irq, vo * IOMMU Operations */ -static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +static struct iommu_domain *__ipmmu_domain_alloc(unsigned type) { struct ipmmu_vmsa_domain *domain; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; @@ -523,6 +520,14 @@ static struct iommu_domain *ipmmu_domain return >io_domain; } +static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +{ + if (type != IOMMU_DOMAIN_UNMANAGED) + return NULL; + + return __ipmmu_domain_alloc(type); +} + static void ipmmu_domain_free(struct iommu_domain *io_domain) { struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 03/07] iommu/ipmmu-vmsa: Break out utlb parsing code
From: Magnus DammBreak out the utlb parsing code and dev_data allocation into a separate function. This is preparation for future code sharing. Signed-off-by: Magnus Damm --- Changes since V4: - Dropped hunk with fix to apply on top of: b1e2afc iommu/ipmmu-vmsa: Fix wrong error handle of ipmmu_add_device Changes since V3: - Initialize "mmu" to NULL, check before accessing - Removed group parameter from ipmmu_init_platform_device() Changes since V2: - Included this new patch from the following series: [PATCH 00/04] iommu/ipmmu-vmsa: IPMMU CONFIG_IOMMU_DMA update - Reworked code to fit on top on previous two patches in current series. drivers/iommu/ipmmu-vmsa.c | 58 1 file changed, 37 insertions(+), 21 deletions(-) --- 0006/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 21:49:34.580607110 +0900 @@ -647,22 +647,15 @@ static int ipmmu_find_utlbs(struct ipmmu return 0; } -static int ipmmu_add_device(struct device *dev) +static int ipmmu_init_platform_device(struct device *dev) { struct ipmmu_vmsa_archdata *archdata; struct ipmmu_vmsa_device *mmu; - struct iommu_group *group = NULL; unsigned int *utlbs; unsigned int i; int num_utlbs; int ret = -ENODEV; - if (dev->archdata.iommu) { - dev_warn(dev, "IOMMU driver already assigned to device %s\n", -dev_name(dev)); - return -EINVAL; - } - /* Find the master corresponding to the device. */ num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", @@ -699,6 +692,36 @@ static int ipmmu_add_device(struct devic } } + archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); + if (!archdata) { + ret = -ENOMEM; + goto error; + } + + archdata->mmu = mmu; + archdata->utlbs = utlbs; + archdata->num_utlbs = num_utlbs; + dev->archdata.iommu = archdata; + return 0; + +error: + kfree(utlbs); + return ret; +} + +static int ipmmu_add_device(struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata; + struct ipmmu_vmsa_device *mmu = NULL; + struct iommu_group *group; + int ret; + + if (dev->archdata.iommu) { + dev_warn(dev, "IOMMU driver already assigned to device %s\n", +dev_name(dev)); + return -EINVAL; + } + /* Create a device group and add the device to it. */ group = iommu_group_alloc(); if (IS_ERR(group)) { @@ -716,16 +739,9 @@ static int ipmmu_add_device(struct devic goto error; } - archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); - if (!archdata) { - ret = -ENOMEM; + ret = ipmmu_init_platform_device(dev); + if (ret < 0) goto error; - } - - archdata->mmu = mmu; - archdata->utlbs = utlbs; - archdata->num_utlbs = num_utlbs; - dev->archdata.iommu = archdata; /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate @@ -736,6 +752,8 @@ static int ipmmu_add_device(struct devic * - Make the mapping size configurable ? We currently use a 2GB mapping * at a 1GB offset to ensure that NULL VAs will fault. */ + archdata = dev->archdata.iommu; + mmu = archdata->mmu; if (!mmu->mapping) { struct dma_iommu_mapping *mapping; @@ -760,10 +778,8 @@ static int ipmmu_add_device(struct devic return 0; error: - arm_iommu_release_mapping(mmu->mapping); - - kfree(dev->archdata.iommu); - kfree(utlbs); + if (mmu) + arm_iommu_release_mapping(mmu->mapping); dev->archdata.iommu = NULL; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 02/07] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context
From: Magnus DammIntroduce a bitmap for context handing and convert the interrupt routine to handle all registered contexts. At this point the number of contexts are still limited. Also remove the use of the ARM specific mapping variable from ipmmu_irq() to allow compile on ARM64. Signed-off-by: Magnus Damm --- Changes since V4: - None Changes since V3: - None Changes since V2: (Thanks again to Laurent!) - Introduce a spinlock together with the bitmap and domain array. - Break out code into separate functions for alloc and free. - Perform free after (instead of before) configuring hardware registers. - Use the spinlock to protect the domain array in the interrupt handler. Changes since V1: (Thanks to Laurent for feedback!) - Use simple find_first_zero()/set_bit()/clear_bit() for context management. - For allocation rely on spinlock held when calling ipmmu_domain_init_context() - For test/free use atomic bitops - Return IRQ_HANDLED if any of the contexts generated interrupts drivers/iommu/ipmmu-vmsa.c | 76 ++-- 1 file changed, 66 insertions(+), 10 deletions(-) --- 0004/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 21:48:23.770607110 +0900 @@ -8,6 +8,7 @@ * the Free Software Foundation; version 2 of the License. */ +#include #include #include #include @@ -26,12 +27,17 @@ #include "io-pgtable.h" +#define IPMMU_CTX_MAX 1 + struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct list_head list; unsigned int num_utlbs; + spinlock_t lock;/* Protects ctx and domains[] */ + DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); + struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; struct dma_iommu_mapping *mapping; }; @@ -293,9 +299,29 @@ static struct iommu_gather_ops ipmmu_gat * Domain/Context Management */ +static int ipmmu_domain_allocate_context(struct ipmmu_vmsa_device *mmu, +struct ipmmu_vmsa_domain *domain) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(>lock, flags); + + ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); + if (ret != IPMMU_CTX_MAX) { + mmu->domains[ret] = domain; + set_bit(ret, mmu->ctx); + } + + spin_unlock_irqrestore(>lock, flags); + + return ret; +} + static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) { u64 ttbr; + int ret; /* * Allocate the page table operations. @@ -325,10 +351,15 @@ static int ipmmu_domain_init_context(str return -EINVAL; /* -* TODO: When adding support for multiple contexts, find an unused -* context. +* Find an unused context. */ - domain->context_id = 0; + ret = ipmmu_domain_allocate_context(domain->mmu, domain); + if (ret == IPMMU_CTX_MAX) { + free_io_pgtable_ops(domain->iop); + return -EBUSY; + } + + domain->context_id = ret; /* TTBR0 */ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; @@ -370,6 +401,19 @@ static int ipmmu_domain_init_context(str return 0; } +static void ipmmu_domain_free_context(struct ipmmu_vmsa_device *mmu, + unsigned int context_id) +{ + unsigned long flags; + + spin_lock_irqsave(>lock, flags); + + clear_bit(context_id, mmu->ctx); + mmu->domains[context_id] = NULL; + + spin_unlock_irqrestore(>lock, flags); +} + static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain) { /* @@ -380,6 +424,7 @@ static void ipmmu_domain_destroy_context */ ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH); ipmmu_tlb_sync(domain); + ipmmu_domain_free_context(domain->mmu, domain->context_id); } /* - @@ -437,16 +482,25 @@ static irqreturn_t ipmmu_domain_irq(stru static irqreturn_t ipmmu_irq(int irq, void *dev) { struct ipmmu_vmsa_device *mmu = dev; - struct iommu_domain *io_domain; - struct ipmmu_vmsa_domain *domain; + irqreturn_t status = IRQ_NONE; + unsigned int i; + unsigned long flags; - if (!mmu->mapping) - return IRQ_NONE; + spin_lock_irqsave(>lock, flags); + + /* +* Check interrupts for all active contexts. +*/ + for (i = 0; i < IPMMU_CTX_MAX; i++) { + if (!mmu->domains[i]) + continue; + if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED) + status = IRQ_HANDLED; + } - io_domain = mmu->mapping->domain; - domain = to_vmsa_domain(io_domain); + spin_unlock_irqrestore(>lock, flags); -
[PATCH v5 01/07] iommu/ipmmu-vmsa: Remove platform data handling
From: Magnus DammThe IPMMU driver is using DT these days, and platform data is no longer used by the driver. Remove unused code. Signed-off-by: Magnus Damm Reviewed-by: Laurent Pinchart --- Changes since V4: - None Changes since V3: - None Changes since V2: - None Changes since V1: - Added Reviewed-by from Laurent drivers/iommu/ipmmu-vmsa.c |5 - 1 file changed, 5 deletions(-) --- 0002/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 21:46:26.0 +0900 @@ -766,11 +766,6 @@ static int ipmmu_probe(struct platform_d int irq; int ret; - if (!IS_ENABLED(CONFIG_OF) && !pdev->dev.platform_data) { - dev_err(>dev, "missing platform data\n"); - return -EINVAL; - } - mmu = devm_kzalloc(>dev, sizeof(*mmu), GFP_KERNEL); if (!mmu) { dev_err(>dev, "cannot allocate device data\n"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V5
iommu/ipmmu-vmsa: IPMMU multi-arch update V5 [PATCH v5 01/07] iommu/ipmmu-vmsa: Remove platform data handling [PATCH v5 02/07] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context [PATCH v5 03/07] iommu/ipmmu-vmsa: Break out utlb parsing code [PATCH v5 04/07] iommu/ipmmu-vmsa: Break out domain allocation code [PATCH v5 05/07] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops [PATCH v5 06/07] iommu/ipmmu-vmsa: ARM and ARM64 archdata access [PATCH v5 07/07] iommu/ipmmu-vmsa: Drop LPAE Kconfig dependency These patches update the IPMMU driver with a couple of changes to support build on multiple architectures. In the process of doing so the interrupt code gets reworked and the foundation for supporting multiple contexts are added. Changes since V4: - Updated patch 3/7 to work on top on the following commit in next-20160920: b1e2afc iommu/ipmmu-vmsa: Fix wrong error handle of ipmmu_add_device - Add Kconfig hunk to patch 5/7 to avoid undeclared ipmmu_ops if COMPILE_TEST - Rebased patch 7/7 to fit on top of new Kconfig bits in 5/7 Changes since V3: - Updated patch 3/7 to fix hang-on-boot issue on 32-bit ARM - thanks Geert! - Reworked group parameter handling in patch 3/7 and 5/7. - Added patch 6/7 to fix build of the driver on s390/tile/um architectures Changes since V2: - Got rid of patch 3 from the V2 however patch 1, 2 and 4 are kept. - V3 patch 3, 4 and 5 come from [PATCH 00/04] iommu/ipmmu-vmsa: IPMMU CONFIG_IOMMU_DMA update - Patch 5 has been reworked to include patch 3 of the V1 of this series Changes since V1: - Got rid of patch 2 and 3 from initial series - Updated bitmap code locking and also used lighter bitop functions - Updated the Kconfig bits to apply on top of ARCH_RENESAS Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Built on top next-20160920 as well as the optional fast-track patch [PATCH/RFC] iommu/ipmmu-vmsa: Update ->add_device() return value drivers/iommu/Kconfig |2 drivers/iommu/ipmmu-vmsa.c | 300 +++- 2 files changed, 243 insertions(+), 59 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC] iommu/ipmmu-vmsa: Update ->add_device() return value
Hi Magnus, On 20/09/16 13:41, Magnus Damm wrote: > From: Magnus Damm <damm+rene...@opensource.se> > > Update the IPMMU driver to return -ENODEV when adding devices > not hooked up a particular IPMMU instance. > > Currently the ->add_device() callback implementation in the IPMMU > driver returns -ENODEV for devices with no "iommus" property, > however the function ipmmu_find_utlbs() may return -EINVAL. If there were no "iommus" property at all, of_parse_phandle_with_args() should return -ENOENT - that probably does want to be caught and passed back as -ENODEV to imply an untranslated device. On the other hand, -EINVAL would stem from the existence of the property, but in a somehow erroneous manner - other than the "args.np != mmu->dev->of_node" check (which could legitimately fail and be safely ignored if there are multiple IOMMUs in the system), any other reason implies a DT error which probably shouldn't be papered over. Robin. > This patch updates the ipmmu_find_utlbs() return value to -ENODEV > for the case when multiple IPMMU instances exist. That way the > code matches the expected behaviour described in the comment of > the add_iommu_group() function in iommu.c: > > /* > * We ignore -ENODEV errors for now, as they just mean that the > * device is not translated by an IOMMU. We still care about > * other errors and fail to initialize when they happen. > */ > > Signed-off-by: Magnus Damm <damm+rene...@opensource.se> > --- > > Applies to next-20160920 on top of: > b1e2afc iommu/ipmmu-vmsa: Fix wrong error handle of ipmmu_add_device > > drivers/iommu/ipmmu-vmsa.c |2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > --- 0002/drivers/iommu/ipmmu-vmsa.c > +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-08 18:20:06.270607110 +0900 > @@ -781,7 +781,7 @@ static int ipmmu_find_utlbs(struct ipmmu > of_node_put(args.np); > > if (args.np != mmu->dev->of_node || args.args_count != 1) > - return -EINVAL; > + return -ENODEV; > > utlbs[i] = args.args[0]; > } > ___ > iommu mailing list > iommu@lists.linux-foundation.org > https://lists.linuxfoundation.org/mailman/listinfo/iommu > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v5 8/8] iommu/amd: Update domain into to dte entry during device driver init
On Thu, Sep 15, 2016 at 11:03:26PM +0800, Baoquan He wrote: > All devices are supposed to reset themselves at device driver initialization > stage. At this time if in kdump kernel those on-flight DMA will be stopped > because of device reset. It's best time to update the protection domain info, > especially pte_root, to dte entry which the device relates to. > > Signed-off-by: Baoquan He> --- > drivers/iommu/amd_iommu.c | 21 + > 1 file changed, 21 insertions(+) > > diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c > index 6c37300..00b64ee 100644 > --- a/drivers/iommu/amd_iommu.c > +++ b/drivers/iommu/amd_iommu.c > @@ -2310,6 +2310,10 @@ static dma_addr_t __map_single(struct device *dev, > unsigned int pages; > int prot = 0; > int i; > + struct iommu_dev_data *dev_data = get_dev_data(dev); > + struct protection_domain *domain = get_domain(dev); > + u16 alias = amd_iommu_alias_table[dev_data->devid]; > + struct amd_iommu *iommu = amd_iommu_rlookup_table[dev_data->devid]; > > pages = iommu_num_pages(paddr, size, PAGE_SIZE); > paddr &= PAGE_MASK; > @@ -2319,6 +2323,13 @@ static dma_addr_t __map_single(struct device *dev, > goto out; > > prot = dir2prot(direction); > + if (translation_pre_enabled(iommu) && !dev_data->domain_updated) { > + dev_data->domain_updated = true; > + set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled); > + if (alias != dev_data->devid) > + set_dte_entry(alias, domain, dev_data->ats.enabled); > + device_flush_dte(dev_data); > + } Hmm, have you tried hooking this into the set_dma_mask call-back? Every driver should call it for its device, so that should be a better indicator to now map a new domain. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC] iommu/ipmmu-vmsa: Update ->add_device() return value
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU driver to return -ENODEV when adding devices not hooked up a particular IPMMU instance. Currently the ->add_device() callback implementation in the IPMMU driver returns -ENODEV for devices with no "iommus" property, however the function ipmmu_find_utlbs() may return -EINVAL. This patch updates the ipmmu_find_utlbs() return value to -ENODEV for the case when multiple IPMMU instances exist. That way the code matches the expected behaviour described in the comment of the add_iommu_group() function in iommu.c: /* * We ignore -ENODEV errors for now, as they just mean that the * device is not translated by an IOMMU. We still care about * other errors and fail to initialize when they happen. */ Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Applies to next-20160920 on top of: b1e2afc iommu/ipmmu-vmsa: Fix wrong error handle of ipmmu_add_device drivers/iommu/ipmmu-vmsa.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- 0002/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-08 18:20:06.270607110 +0900 @@ -781,7 +781,7 @@ static int ipmmu_find_utlbs(struct ipmmu of_node_put(args.np); if (args.np != mmu->dev->of_node || args.args_count != 1) - return -EINVAL; + return -ENODEV; utlbs[i] = args.args[0]; } ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v5 7/8] iommu/amd: Don't update domain info to dte entry at iommu init stage
On Thu, Sep 15, 2016 at 11:03:25PM +0800, Baoquan He wrote: > AMD iommu creates protection domain and assign each device to it during > iommu driver initialization stage. This happened just after system pci > bus scanning stage, and much earlier than device driver init stage. So > at this time if in kdump kernel the domain info, especially pte_root, > can't be updated to dte entry. We should wait until device driver init > stage. > > Signed-off-by: Baoquan He> --- > drivers/iommu/amd_iommu.c | 18 ++ > 1 file changed, 18 insertions(+) > > diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c > index fcb69ff..6c37300 100644 > --- a/drivers/iommu/amd_iommu.c > +++ b/drivers/iommu/amd_iommu.c > @@ -137,6 +137,7 @@ struct iommu_dev_data { > bool pri_tlp; /* PASID TLB required for >PPR completions */ > u32 errata; /* Bitmap for errata to apply */ > + bool domain_updated; > }; > > /* > @@ -1708,6 +1709,15 @@ static void set_dte_entry(u16 devid, struct > protection_domain *domain, bool ats) > { > u64 pte_root = 0; > u64 flags = 0; > + struct iommu_dev_data *dev_data; > + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; > + > + dev_data = find_dev_data(devid); > +if (!dev_data) > +return; > + > + if (translation_pre_enabled(iommu) && !dev_data->domain_updated) > + return; > > if (domain->mode != PAGE_MODE_NONE) > pte_root = virt_to_phys(domain->pt_root); > @@ -1756,6 +1766,14 @@ static void set_dte_entry(u16 devid, struct > protection_domain *domain, bool ats) > > static void clear_dte_entry(u16 devid) > { > + struct iommu_dev_data *dev_data; > + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; > + > + dev_data = find_dev_data(devid); > +if (!dev_data) > +return; > + if (translation_pre_enabled(iommu) && !dev_data->domain_updated) > + return; This should be moved to do_attach/do_detach. There you also already have the dev_data you need here. > /* remove entry from the device table seen by the hardware */ > amd_iommu_dev_table[devid].data[0] = DTE_FLAG_V | DTE_FLAG_TV; > amd_iommu_dev_table[devid].data[1] &= DTE_FLAG_MASK; > -- > 2.5.5 > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v5 6/8] iommu/amd: Do not re-enable dev table entries in kdump
On Thu, Sep 15, 2016 at 11:03:24PM +0800, Baoquan He wrote: > This enabling should have been done in normal kernel. It's unnecessary > to enable it again in kdump kernel. > > And clean up the function comments of init_device_table_dma. Well, no. We don't want to make any assumptions on what the previous kernel did and what it did not. The init_device_table_dma() code should run anyway. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v5 5/8] iommu/amd: copy old trans table from old kernel
On Thu, Sep 15, 2016 at 11:03:23PM +0800, Baoquan He wrote: > Here several things need be done: > 1) If iommu is pre-enabled in a normal kernel, just disable it and print >warning. > 2) If failed to copy dev table of old kernel, continue to proceed as >it does in normal kernel. > 3) Re-enable event/cmd buffer and install the new DTE table to reg. > 4) Flush all caches > > Signed-off-by: Baoquan He> --- > drivers/iommu/amd_iommu_init.c | 44 > +++--- > 1 file changed, 41 insertions(+), 3 deletions(-) > > diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c > index ce49641..47a8fc9 100644 > --- a/drivers/iommu/amd_iommu_init.c > +++ b/drivers/iommu/amd_iommu_init.c > @@ -34,7 +34,7 @@ > #include > #include > #include > - > +#include Please keep that empty line, it is there for readability. > #include "amd_iommu_proto.h" > #include "amd_iommu_types.h" > #include "irq_remapping.h" > @@ -1344,6 +1344,12 @@ static int __init init_iommu_one(struct amd_iommu > *iommu, struct ivhd_header *h) > iommu->int_enabled = false; > > init_translation_status(iommu); > + if (translation_pre_enabled(iommu) && !is_kdump_kernel()) { > + iommu_disable(iommu); > + clear_translation_pre_enabled(iommu); > + pr_warn("Translation was enabled for IOMMU:%d but we are not in > kdump mode\n", > + iommu->index); > + } > > if (translation_pre_enabled(iommu)) > pr_warn("Translation is already enabled - trying to copy > translation structures\n"); > @@ -1946,9 +1952,41 @@ static void early_enable_iommu(struct amd_iommu *iommu) > static void early_enable_iommus(void) > { > struct amd_iommu *iommu; > + bool is_pre_enabled=false; > > - for_each_iommu(iommu) > - early_enable_iommu(iommu); > + for_each_iommu(iommu) { > + if ( translation_pre_enabled(iommu) ) { Coding style, too many spaces. There is more of that below. > + is_pre_enabled = true; > + break; > + } > + } > + > + if ( !is_pre_enabled) { > + for_each_iommu(iommu) > + early_enable_iommu(iommu); > + } else { > + if (copy_dev_tables()) { > + pr_err("Failed to copy DEV table from previous > kernel.\n"); > + /* > + * If failed to copy dev tables from old kernel, > continue to proceed > + * as it does in normal kernel. > + */ > + for_each_iommu(iommu) { > + clear_translation_pre_enabled(iommu); > + early_enable_iommu(iommu); > + } > + } else { > + pr_info("Copied DEV table from previous kernel.\n"); > + for_each_iommu(iommu) { > + iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); > + iommu_feature_disable(iommu, > CONTROL_EVT_LOG_EN); Could you move that into new helpers (iommu_disable_command_buffer...)? > + iommu_enable_command_buffer(iommu); > + iommu_enable_event_buffer(iommu); > + iommu_set_device_table(iommu); > + iommu_flush_all_caches(iommu); > + } > + } > + } > } > > static void enable_iommus_v2(void) > -- > 2.5.5 > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v5 4/8] iommu/amd: Add function copy_dev_tables
Hi Baoquan, On Thu, Sep 15, 2016 at 11:03:22PM +0800, Baoquan He wrote: > +static int copy_dev_tables(void) > +{ > + u64 entry; > + u32 lo, hi, devid; > + phys_addr_t old_devtb_phys; > + struct dev_table_entry *old_devtb = NULL; > + u16 dom_id, dte_v; > + struct amd_iommu *iommu; > + static int copied; Please order this by line-length, longer lines first. > +for_each_iommu(iommu) { > + if (!translation_pre_enabled(iommu)) { > + pr_err("IOMMU:%d is not pre-enabled!/n", iommu->index); > + return -1; > + } > + > + if (copied) > + continue; > + > +lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET); > +hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4); > +entry = (((u64) hi) << 32) + lo; > +old_devtb_phys = entry & PAGE_MASK; > +old_devtb = memremap(old_devtb_phys, dev_table_size, > MEMREMAP_WB); > + if (!old_devtb) > + return -1; > +for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) { > +amd_iommu_dev_table[devid] = old_devtb[devid]; > +dom_id = amd_iommu_dev_table[devid].data[1] & > DEV_DOMID_MASK; > + dte_v = amd_iommu_dev_table[devid].data[0] & DTE_FLAG_V; > + if (!dte_v || !dom_id) > + continue; > +__set_bit(dom_id, amd_iommu_pd_alloc_bitmap); > +} > + memunmap(old_devtb); > + copied = 1; > +} This loop need more refinement and sanity checking code. I suggest using two loops and do the sanity checking in the first one. The sanity checks should do: * Check whether all IOMMUs actually use the same device table with the same size * Verify that the size of the old device table is the expected size. * Also sanity check the irq-remapping information and remapping table sizes. If any of these checks fail, just bail out of copying. What is further needed it some more selection on what is copied from the old kernel. There is no need to copy all the GCR3 root-pointer information. If a device is set up with guest translations (DTE.GV=1), then don't copy that information but move the device over to an empty guest-cr3 table and handle the faults in the PPR log (which should just answer them with INVALID). After all these PPR faults are recoverable for the device and we should not allow the device to change old-kernels data when we don't have to. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[GIT PULL] iommu/arm-smmu: Updates for 4.9
Hi Joerg, Please pull these significant arm-smmu updates for 4.9. The vast majority of the code here is Robin's series to move the drivers over to the generic DT bindings, which finally hooks up the DMA API and MSI mapping for host machines. This has been stewing for a while and is now at the point where I feel it's much better in mainline than languishing outside. A consequence of that is that there are some non-trivial changes outside of the drivers, but these are all acked by the relevant subsystem maintainers. Other stuff here includes some non-critical fixes to the queue handling on SMMUv3 and a small devm cleanup that missed the boat last time around. Cheers, Will --->8 The following changes since commit 3eab887a55424fc2c27553b7bfe32330df83f7b8: Linux 4.8-rc4 (2016-08-28 15:04:33 -0700) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git for-joerg/arm-smmu/updates for you to fetch changes up to 82db33dc5e49fb625262d81125625d07a0d6184e: iommu/io-pgtable-arm: Check for v7s-incapable systems (2016-09-16 09:34:23 +0100) Jean-Philippe Brucker (2): iommu/arm-smmu: Fix event queues synchronization iommu/arm-smmu: Fix polling of command queue Mark Rutland (1): Docs: dt: add PCI IOMMU map bindings Peng Fan (1): iommu/arm-smmu: Drop devm_free_irq when driver detach Robin Murphy (23): iommu/arm-smmu: Support v7s context format of/irq: Break out msi-map lookup (again) iommu/of: Handle iommu-map property for PCI iommu: Introduce iommu_fwspec Docs: dt: document ARM SMMUv3 generic binding usage iommu/arm-smmu: Fall back to global bypass iommu/arm-smmu: Implement of_xlate() for SMMUv3 iommu/arm-smmu: Support non-PCI devices with SMMUv3 iommu/arm-smmu: Set PRIVCFG in stage 1 STEs iommu/arm-smmu: Handle stream IDs more dynamically iommu/arm-smmu: Consolidate stream map entry state iommu/arm-smmu: Keep track of S2CR state iommu/arm-smmu: Refactor mmu-masters handling iommu/arm-smmu: Streamline SMMU data lookups iommu/arm-smmu: Add a stream map entry iterator iommu/arm-smmu: Intelligent SMR allocation iommu/arm-smmu: Convert to iommu_fwspec Docs: dt: document ARM SMMU generic binding usage iommu/arm-smmu: Wire up generic configuration support iommu/arm-smmu: Set domain geometry iommu/dma: Add support for mapping MSIs iommu/dma: Avoid PCI host bridge windows iommu/io-pgtable-arm: Check for v7s-incapable systems Will Deacon (1): iommu/arm-smmu: Disable interrupts whilst holding the cmdq lock .../devicetree/bindings/iommu/arm,smmu-v3.txt | 8 +- .../devicetree/bindings/iommu/arm,smmu.txt | 61 +- .../devicetree/bindings/pci/pci-iommu.txt | 171 arch/arm64/mm/dma-mapping.c| 2 +- drivers/gpu/drm/exynos/exynos_drm_iommu.h | 2 +- drivers/iommu/Kconfig | 2 +- drivers/iommu/arm-smmu-v3.c| 561 ++-- drivers/iommu/arm-smmu.c | 995 ++--- drivers/iommu/dma-iommu.c | 161 +++- drivers/iommu/io-pgtable-arm-v7s.c | 4 + drivers/iommu/iommu.c | 58 ++ drivers/iommu/of_iommu.c | 52 +- drivers/irqchip/irq-gic-v2m.c | 3 + drivers/irqchip/irq-gic-v3-its.c | 3 + drivers/of/irq.c | 78 +- drivers/of/of_pci.c| 102 +++ include/linux/device.h | 3 + include/linux/dma-iommu.h | 12 +- include/linux/iommu.h | 39 + include/linux/of_pci.h | 10 + 20 files changed, 1430 insertions(+), 897 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/pci-iommu.txt ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH RESEND 4/4] iommu/amd: No need to wait iommu completion if no dte irq entry change
On Tue, Sep 20, 2016 at 09:05:34AM +0800, Baoquan He wrote: > This is a clean up. In get_irq_table() only if DTE entry is changed > iommu_completion_wait() need be called. Otherwise no need to do it. > > Signed-off-by: Baoquan He> --- > drivers/iommu/amd_iommu.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) Applied, thanks. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 0/2] Exynos IOMMU: proper runtime PM support (use device dependencies)
Hi All, On 2016-09-19 23:45, Tobias Jakobi wrote: I did some tests with the new version today. Sadly the reboot/shutdown issues are still present. Thanks for the report. I've managed to reproduce this issue and it is again caused by modifying device on devices_kset list before it will be finally added by device_add(). I thought that the new patchset allows creating links to a device, which has not been yet added to system device list. Rafael: What is your opinion? Should it be allowed to create a link to device, which has not yet been added to system device list by device_add()? My code used to do that, because IOMMUs are configured from of_platform_device_create_pdata() of_dma_configure() of_iommu_configure(), which happens before device_add(). To solve the reported corruption of devices_kset list, following change is needed: diff --git a/drivers/base/core.c b/drivers/base/core.c index aa8196508db9..4542ba9f60d4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1039,11 +1039,18 @@ static void devices_kset_move_after(struct device *deva, struct device *devb) */ void devices_kset_move_last(struct device *dev) { + struct device *d; + if (!devices_kset) return; pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); spin_lock(_kset->list_lock); - list_move_tail(>kobj.entry, _kset->list); + list_for_each_entry(d, _kset->list, kobj.entry) { + if (d == dev) { + list_move_tail(>kobj.entry, _kset->list); + break; + } + } spin_unlock(_kset->list_lock); } If you think that links can be created only to a device, which has been fully added to the system, I will register a bus notifier and create a link on consumers device probe then. [...] Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu