[PATCH] iommu/ipmmu-vmsa: Document R-Car V3H and E3 IPMMU DT bindings
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the compat strings for the IPMMU devices included in the R-Car V3H and E3 SoCs. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of renesas-drivers-2018-05-15-v4.17-rc5 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |2 ++ 1 file changed, 2 insertions(+) --- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2018-05-21 23:37:16.370607110 +0900 @@ -20,6 +20,8 @@ Required Properties: - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. +- "renesas,ipmmu-r8a77980" for the R8A77980 (R-Car V3H) IPMMU. +- "renesas,ipmmu-r8a77990" for the R8A77990 (R-Car E3) IPMMU. - "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 or RZ/G1 VMSA-compatible IPMMU. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH] iommu/ipmmu-vmsa: Document R-Car M3-N IPMMU DT bindings
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a77965 compat string for the IPMMU devices included in the R-Car M3-N SoC. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2018-03-20 15:30:50.640607110 +0900 @@ -17,6 +17,7 @@ Required Properties: - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. +- "renesas,ipmmu-r8a77965" for the R8A77965 (R-Car M3-N) IPMMU. - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. - "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature
Hi Robin, On Tue, Jun 20, 2017 at 2:19 AM, Robin Murphy <robin.mur...@arm.com> wrote: > On 19/06/17 10:14, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Add root device handling to the IPMMU driver by allowing certain >> DT compat strings to enable has_cache_leaf_nodes that in turn will >> support both root devices with interrupts and leaf devices that >> face the actual IPMMU consumer devices. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> --- >> >> Changes since V3: >> - Reworked root finding code to make it easier to follow, thanks Geert! >> >> Changes since V2: >> - Fixed a bug in ipmmu_find_root() when only leaf devices are present >> - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices >> >> Changes since V1: >> - Moved patch to earlier in the series >> - Updated code to work with recent changes in: >>[PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 >> >> drivers/iommu/ipmmu-vmsa.c | 95 >> >> 1 file changed, 78 insertions(+), 17 deletions(-) >> >> --- 0015/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 13:59:41.050607110 +0900 >> @@ -36,6 +36,7 @@ >> >> struct ipmmu_features { >> bool use_ns_alias_offset; >> + bool has_cache_leaf_nodes; >> }; >> >> struct ipmmu_vmsa_device { >> @@ -44,6 +45,7 @@ struct ipmmu_vmsa_device { >> struct iommu_device iommu; >> struct list_head list; >> const struct ipmmu_features *features; >> + bool is_leaf; >> unsigned int num_utlbs; >> spinlock_t lock;/* Protects ctx and domains[] >> */ >> DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); >> @@ -54,6 +56,7 @@ struct ipmmu_vmsa_device { >> >> struct ipmmu_vmsa_domain { >> struct ipmmu_vmsa_device *mmu; >> + struct ipmmu_vmsa_device *root; > > Would it not make more sense for this to be a property of the > ipmmu_device itself, rather than per ipmmu_domain? I may of course have > got the wrong idea of the topology here, but it seems as if mmu->is_leaf > could be expressed as mmu->root == mmu vs. mmu->root == some_other_mmu, > at which point there's one less thing to worry about in the domain. Yes, you are right! Please have a look at patch 2 in V5 that is doing that. >> struct iommu_domain io_domain; >> >> struct io_pgtable_cfg cfg; >> @@ -203,6 +206,44 @@ static struct ipmmu_vmsa_iommu_priv *to_ >> #define IMUASID_ASID0_SHIFT 0 >> >> /* >> - >> + * Root device handling >> + */ >> + >> +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu) >> +{ >> + if (mmu->features->has_cache_leaf_nodes) >> + return mmu->is_leaf ? false : true> + else >> + return true; /* older IPMMU hardware treated as single root */ >> +} >> + >> +static struct ipmmu_vmsa_device *__ipmmu_find_root(void) >> +{ >> + struct ipmmu_vmsa_device *mmu; >> + struct ipmmu_vmsa_device *root = NULL; >> + >> + spin_lock(_devices_lock); >> + >> + list_for_each_entry(mmu, _devices, list) { >> + if (ipmmu_is_root(mmu)) { >> + root = mmu; >> + break; >> + } >> + } >> + >> + spin_unlock(_devices_lock); >> + return root; >> +} > > I wonder if it might be tidier to use driver_for_each_device() for this, > and remove the local list at the same time as its previous user. Yep, also included in V5. > Either way, what happens if things end up hapening in this order: > > 1: probe leaf IPMMU B > 2: probe device X behind IPMMU B > 3: create and attach default domain for device X > 4: probe root IPMMU A > > We know X will defer if B isn't ready, but it doesn't seem (at a glance, > admittedly) that there's anything to enforce the expected probe ordering > between A and B. This seems like another argument for moving the > root/leaf association up to the device level, such that B can look up A > once in its own probe routine, and defer itself if necessary. There used to be code to check for presence of root device inside xlate() in "[PATCH v4 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code" however in V5 I'm deferring probe of non-root devices to handle this. >> + >> +s
[PATCH v5 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional
From: Magnus Damm <damm+rene...@opensource.se> Introduce a feature to allow opt-out of setting up IMBUSCR. The default case is unchanged. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - Use leaf node mmu instead of root Changes since V3: - None Changes since V2: - None Changes since V1: - Updated the commit message - Reworked patch to coexist with the multi context feature drivers/iommu/ipmmu-vmsa.c |9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) --- 0018/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 20:20:30.860607110 +0900 @@ -39,6 +39,7 @@ struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; unsigned int number_of_contexts; + bool setup_imbuscr; }; struct ipmmu_vmsa_device { @@ -457,9 +458,10 @@ static int ipmmu_domain_init_context(str domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ - ipmmu_ctx_write_root(domain, IMBUSCR, -ipmmu_ctx_read_root(domain, IMBUSCR) & -~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); + if (domain->mmu->features->setup_imbuscr) + ipmmu_ctx_write_root(domain, IMBUSCR, +ipmmu_ctx_read_root(domain, IMBUSCR) & +~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); /* * IMSTR @@ -979,6 +981,7 @@ static const struct ipmmu_features ipmmu .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, .number_of_contexts = 1, /* software only tested with one context */ + .setup_imbuscr = true, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
From: Magnus Damm <damm+rene...@opensource.se> Tie in r8a7795 features and update the IOMMU_OF_DECLARE compat string to include the updated compat string. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - Got rid of root device availability check in ->xlate() -> deferred probing is used to make sure the root is always present Changes since V3: - Rebased code on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update This includes support for iommu_fwspec_add_ids() - Use dev_err() instead of dev_info() - Thanks Geert! - Moved single-invokation check into of_xlate() - Thanks Geert! - Dropped TODO list Changes since V2: - Check for lack of root device in ->xlate() This fixed a bug when IPMMU-MM is disabled in DT the system hangs on boot - Added code to ipmmu_init_platform_device() to handle multiple ->xlate() calls - Include empty white list by default - Updated TODO list Changes since V1: - Enable multi context feature - Update TODO list drivers/iommu/ipmmu-vmsa.c | 29 + 1 file changed, 29 insertions(+) --- 0019/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 19:53:14.710607110 +0900 @@ -25,6 +25,7 @@ #include #include #include +#include #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include @@ -735,9 +736,24 @@ static int ipmmu_init_platform_device(st return 0; } +static bool ipmmu_slave_whitelist(struct device *dev) +{ + /* By default, do not allow use of IPMMU */ + return false; +} + +static const struct soc_device_attribute soc_r8a7795[] = { + { .soc_id = "r8a7795", }, + { /* sentinel */ } +}; + static int ipmmu_of_xlate(struct device *dev, struct of_phandle_args *spec) { + /* For R-Car Gen3 use a white list to opt-in slave devices */ + if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + return -ENODEV; + iommu_fwspec_add_ids(dev, spec->args, 1); /* Initialize once - xlate() will call multiple times */ @@ -996,11 +1012,22 @@ static const struct ipmmu_features ipmmu .twobit_imttbcr_sl0 = false, }; +static const struct ipmmu_features ipmmu_features_r8a7795 = { + .use_ns_alias_offset = false, + .has_cache_leaf_nodes = true, + .number_of_contexts = 8, + .setup_imbuscr = false, + .twobit_imttbcr_sl0 = true, +}; + static const struct of_device_id ipmmu_of_ids[] = { { .compatible = "renesas,ipmmu-vmsa", .data = _features_default, }, { + .compatible = "renesas,ipmmu-r8a7795", + .data = _features_r8a7795, + }, { /* Terminator */ }, }; @@ -1185,6 +1212,8 @@ static int __init ipmmu_vmsa_iommu_of_se IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", ipmmu_vmsa_iommu_of_setup); +IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795", +ipmmu_vmsa_iommu_of_setup); #endif MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 08/09] iommu/ipmmu-vmsa: Allow two bit SL0
From: Magnus Damm <damm+rene...@opensource.se> Introduce support for two bit SL0 bitfield in IMTTBCR by using a separate feature flag. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - Use leaf node mmu instead of root Changes since V3: - None Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) --- 0019/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 20:24:22.990607110 +0900 @@ -40,6 +40,7 @@ struct ipmmu_features { bool has_cache_leaf_nodes; unsigned int number_of_contexts; bool setup_imbuscr; + bool twobit_imttbcr_sl0; }; struct ipmmu_vmsa_device { @@ -144,6 +145,10 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMTTBCR_TSZ0_MASK (7 << 0) #define IMTTBCR_TSZ0_SHIFT O +#define IMTTBCR_SL0_TWOBIT_LVL_3 (0 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_2 (1 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_1 (2 << 6) + #define IMBUSCR0x000c #define IMBUSCR_DVM(1 << 2) #define IMBUSCR_BUSSEL_SYS (0 << 0) @@ -396,6 +401,7 @@ static void ipmmu_domain_free_context(st static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) { u64 ttbr; + u32 tmp; int ret; /* @@ -449,9 +455,14 @@ static int ipmmu_domain_init_context(str * We use long descriptors with inner-shareable WBWA tables and allocate * the whole 32-bit VA space to TTBR0. */ + if (domain->mmu->features->twobit_imttbcr_sl0) + tmp = IMTTBCR_SL0_TWOBIT_LVL_1; + else + tmp = IMTTBCR_SL0_LVL_1; + ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | -IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); +IMTTBCR_IRGN0_WB_WA | tmp); /* MAIR0 */ ipmmu_ctx_write_root(domain, IMMAIR0, @@ -982,6 +993,7 @@ static const struct ipmmu_features ipmmu .has_cache_leaf_nodes = false, .number_of_contexts = 1, /* software only tested with one context */ .setup_imbuscr = true, + .twobit_imttbcr_sl0 = false, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 06/09] iommu/ipmmu-vmsa: Write IMCTR twice
From: Magnus Damm <damm+rene...@opensource.se> Write IMCTR both in the root device and the leaf node. To allow access of IMCTR introduce the following function: - ipmmu_ctx_write_all() While at it also rename context functions: - ipmmu_ctx_read() -> ipmmu_ctx_read_root() - ipmmu_ctx_write() -> ipmmu_ctx_write_root() Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - Updated to make use of new root pointer location Changes since V3: - Changed function names to improve code readability - Thanks Robin! Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 56 +++- 1 file changed, 35 insertions(+), 21 deletions(-) --- 0015/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 19:50:19.240607110 +0900 @@ -248,19 +248,31 @@ static void ipmmu_write(struct ipmmu_vms iowrite32(data, mmu->base + offset); } -static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) +static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain, + unsigned int reg) { return ipmmu_read(domain->mmu->root, domain->context_id * IM_CTX_SIZE + reg); } -static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, - u32 data) +static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain, +unsigned int reg, u32 data) { ipmmu_write(domain->mmu->root, domain->context_id * IM_CTX_SIZE + reg, data); } +static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain, + unsigned int reg, u32 data) +{ + if (domain->mmu != domain->mmu->root) + ipmmu_write(domain->mmu, + domain->context_id * IM_CTX_SIZE + reg, data); + + ipmmu_write(domain->mmu->root, + domain->context_id * IM_CTX_SIZE + reg, data); +} + /* - * TLB and microTLB Management */ @@ -270,7 +282,7 @@ static void ipmmu_tlb_sync(struct ipmmu_ { unsigned int count = 0; - while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) { + while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) { cpu_relax(); if (++count == TLB_LOOP_TIMEOUT) { dev_err_ratelimited(domain->mmu->dev, @@ -285,9 +297,9 @@ static void ipmmu_tlb_invalidate(struct { u32 reg; - reg = ipmmu_ctx_read(domain, IMCTR); + reg = ipmmu_ctx_read_root(domain, IMCTR); reg |= IMCTR_FLUSH; - ipmmu_ctx_write(domain, IMCTR, reg); + ipmmu_ctx_write_all(domain, IMCTR, reg); ipmmu_tlb_sync(domain); } @@ -428,31 +440,32 @@ static int ipmmu_domain_init_context(str /* TTBR0 */ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; - ipmmu_ctx_write(domain, IMTTLBR0, ttbr); - ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32); + ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr); + ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32); /* * TTBCR * We use long descriptors with inner-shareable WBWA tables and allocate * the whole 32-bit VA space to TTBR0. */ - ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | - IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | - IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); + ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | +IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | +IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); /* MAIR0 */ - ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); + ipmmu_ctx_write_root(domain, IMMAIR0, +domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ - ipmmu_ctx_write(domain, IMBUSCR, - ipmmu_ctx_read(domain, IMBUSCR) & - ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); + ipmmu_ctx_write_root(domain, IMBUSCR, +ipmmu_ctx_read_root(domain, IMBUSCR) & +~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); /* * IMSTR * Clear all interrupt flags. */ - ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR)); + ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR)); /* * IMCTR @@ -461,7 +474,8 @@ static int ipmmu_domain_init_context(str * software management as we have no use for it. Flush the TLB as * required when modifying the context registers. */ - ipmmu_ct
[PATCH v5 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master
From: Magnus Damm <damm+rene...@opensource.se> The r8a7795 IPMMU supports 40-bit bus mastering. Both the coherent DMA mask and the streaming DMA mask are set to unlock the 40-bit address space for coherent allocations and streaming operations. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - None Changes since V3: - None Changes since V2: - Updated the code and commit message to use 40 bits instead of 64 bits Changes since V1: - Updated the commit message drivers/iommu/ipmmu-vmsa.c |1 + 1 file changed, 1 insertion(+) --- 0012/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 20:37:31.480607110 +0900 @@ -996,6 +996,7 @@ static int ipmmu_probe(struct platform_d spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(>dev); + dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(40)); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
From: Magnus Damm <damm+rene...@opensource.se> Hook up IOMMU_OF_DECLARE() support in case CONFIG_IOMMU_DMA is enabled. The only current supported case for 32-bit ARM is disabled, however for 64-bit ARM usage of OF is required. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - Use ipmmu_is_root() instead of now removed is_leaf flag Changes since V3: - Reworked to fit on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update Changes since V2: - Reworked registration code to make use of recently introduced: iommu_device_register() iommu_device_set_ops() iommu_device_set_fwnode() Changes since V1: - Reworked slightly to fit updated patch order and [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 50 1 file changed, 41 insertions(+), 9 deletions(-) --- 0014/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 19:59:42.700607110 +0900 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1055,17 +1056,30 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); } - ret = iommu_device_sysfs_add(>iommu, >dev, NULL, -dev_name(>dev)); - if (ret) - return ret; + /* +* Register the IPMMU to the IOMMU subsystem in the following cases: +* - R-Car Gen2 IPMMU (all devices registered) +* - R-Car Gen3 IPMMU (leaf devices only - skip root IPMMU-MM device) +*/ + if (!mmu->features->has_cache_leaf_nodes || !ipmmu_is_root(mmu)) { + ret = iommu_device_sysfs_add(>iommu, >dev, NULL, +dev_name(>dev)); + if (ret) + return ret; - iommu_device_set_ops(>iommu, _ops); - iommu_device_set_fwnode(>iommu, >dev.of_node->fwnode); + iommu_device_set_ops(>iommu, _ops); + iommu_device_set_fwnode(>iommu, + >dev.of_node->fwnode); - ret = iommu_device_register(>iommu); - if (ret) - return ret; + ret = iommu_device_register(>iommu); + if (ret) + return ret; + +#if defined(CONFIG_IOMMU_DMA) + if (!iommu_present(_bus_type)) + bus_set_iommu(_bus_type, _ops); +#endif + } /* * We can't create the ARM mapping here as it requires the bus to have @@ -1105,15 +1119,22 @@ static struct platform_driver ipmmu_driv static int __init ipmmu_init(void) { + static bool setup_done; int ret; + if (setup_done) + return 0; + ret = platform_driver_register(_driver); if (ret < 0) return ret; +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) if (!iommu_present(_bus_type)) bus_set_iommu(_bus_type, _ops); +#endif + setup_done = true; return 0; } @@ -1125,6 +1146,17 @@ static void __exit ipmmu_exit(void) subsys_initcall(ipmmu_init); module_exit(ipmmu_exit); +#ifdef CONFIG_IOMMU_DMA +static int __init ipmmu_vmsa_iommu_of_setup(struct device_node *np) +{ + ipmmu_init(); + return 0; +} + +IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", +ipmmu_vmsa_iommu_of_setup); +#endif + MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); MODULE_AUTHOR("Laurent Pinchart <laurent.pinch...@ideasonboard.com>"); MODULE_LICENSE("GPL v2"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 02/09] iommu/ipmmu-vmsa: Add optional root device feature
From: Magnus Damm <damm+rene...@opensource.se> Add root device handling to the IPMMU driver by allowing certain DT compat strings to enable has_cache_leaf_nodes that in turn will support both root devices with interrupts and leaf devices that face the actual IPMMU consumer devices. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: (Many thanks to Robin for feedback) - Put the root pointer under struct ipmmu_vmsa_device - Drop is_leaf flag - Use driver_for_each_device instead of local list of devices - Return -EPROBE_DEFER to hook up root device first Changes since V3: - Reworked root finding code to make it easier to follow, thanks Geert! Changes since V2: - Fixed a bug in ipmmu_find_root() when only leaf devices are present - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices Changes since V1: - Moved patch to earlier in the series - Updated code to work with recent changes in: [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 90 +++- 1 file changed, 73 insertions(+), 17 deletions(-) --- 0009/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 19:43:27.020607110 +0900 @@ -36,12 +36,14 @@ struct ipmmu_features { bool use_ns_alias_offset; + bool has_cache_leaf_nodes; }; struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct iommu_device iommu; + struct ipmmu_vmsa_device *root; const struct ipmmu_features *features; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ @@ -199,6 +201,36 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMUASID_ASID0_SHIFT0 /* - + * Root device handling + */ + +static struct platform_driver ipmmu_driver; + +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu) +{ + return mmu->root == mmu; +} + +static int __ipmmu_check_device(struct device *dev, void *data) +{ + struct ipmmu_vmsa_device *mmu = dev_get_drvdata(dev); + struct ipmmu_vmsa_device **rootp = data; + + if (ipmmu_is_root(mmu)) + *rootp = mmu; + + return 0; +} + +static struct ipmmu_vmsa_device *ipmmu_find_root(void) +{ + struct ipmmu_vmsa_device *root = NULL; + + return driver_for_each_device(_driver.driver, NULL, , + __ipmmu_check_device) == 0 ? root : NULL; +} + +/* - * Read/Write Access */ @@ -215,13 +247,15 @@ static void ipmmu_write(struct ipmmu_vms static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) { - return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg); + return ipmmu_read(domain->mmu->root, + domain->context_id * IM_CTX_SIZE + reg); } static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, u32 data) { - ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data); + ipmmu_write(domain->mmu->root, + domain->context_id * IM_CTX_SIZE + reg, data); } /* - @@ -369,12 +403,12 @@ static int ipmmu_domain_init_context(str * TODO: Add support for coherent walk through CCI with DVM and remove * cache handling. For now, delegate it to the io-pgtable code. */ - domain->cfg.iommu_dev = domain->mmu->dev; + domain->cfg.iommu_dev = domain->mmu->root->dev; /* * Find an unused context. */ - ret = ipmmu_domain_allocate_context(domain->mmu, domain); + ret = ipmmu_domain_allocate_context(domain->mmu->root, domain); if (ret == IPMMU_CTX_MAX) return -EBUSY; @@ -383,7 +417,8 @@ static int ipmmu_domain_init_context(str domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, >cfg, domain); if (!domain->iop) { - ipmmu_domain_free_context(domain->mmu, domain->context_id); + ipmmu_domain_free_context(domain->mmu->root, + domain->context_id); return -EINVAL; } @@ -437,7 +472,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); + ipmmu_domain_free_context(domain->mmu->root, domain->context_id); } /* ---
[PATCH v5 03/09] iommu/ipmmu-vmsa: Enable multi context support
From: Magnus Damm <damm+rene...@opensource.se> Add support for up to 8 contexts. Each context is mapped to one domain. One domain is assigned one or more slave devices. Contexts are allocated dynamically and slave devices are grouped together based on which IPMMU device they are connected to. This makes slave devices tied to the same IPMMU device share the same IOVA space. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - None Changes since V3: - Use number_of_contexts unsigned int, drop WARN_ON() - Thanks Robin! Changes since V2: - Updated patch description to reflect code included in: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 Changes since V1: - Support up to 8 contexts instead of 4 - Use feature flag and runtime handling - Default to single context drivers/iommu/ipmmu-vmsa.c | 30 ++ 1 file changed, 22 insertions(+), 8 deletions(-) --- 0011/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-16 19:46:09.900607110 +0900 @@ -32,11 +32,12 @@ #include "io-pgtable.h" -#define IPMMU_CTX_MAX 1 +#define IPMMU_CTX_MAX 8 struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; + unsigned int number_of_contexts; }; struct ipmmu_vmsa_device { @@ -46,6 +47,7 @@ struct ipmmu_vmsa_device { struct ipmmu_vmsa_device *root; const struct ipmmu_features *features; unsigned int num_utlbs; + unsigned int num_ctx; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; @@ -352,11 +354,12 @@ static int ipmmu_domain_allocate_context spin_lock_irqsave(>lock, flags); - ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); - if (ret != IPMMU_CTX_MAX) { + ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx); + if (ret != mmu->num_ctx) { mmu->domains[ret] = domain; set_bit(ret, mmu->ctx); - } + } else + ret = -EBUSY; spin_unlock_irqrestore(>lock, flags); @@ -409,8 +412,8 @@ static int ipmmu_domain_init_context(str * Find an unused context. */ ret = ipmmu_domain_allocate_context(domain->mmu->root, domain); - if (ret == IPMMU_CTX_MAX) - return -EBUSY; + if (ret < 0) + return ret; domain->context_id = ret; @@ -539,7 +542,7 @@ static irqreturn_t ipmmu_irq(int irq, vo /* * Check interrupts for all active contexts. */ - for (i = 0; i < IPMMU_CTX_MAX; i++) { + for (i = 0; i < mmu->num_ctx; i++) { if (!mmu->domains[i]) continue; if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED) @@ -603,6 +606,13 @@ static int ipmmu_attach_device(struct io /* The domain hasn't been used yet, initialize it. */ domain->mmu = mmu; ret = ipmmu_domain_init_context(domain); + if (ret < 0) { + dev_err(dev, "Unable to initialize IPMMU context\n"); + domain->mmu = NULL; + } else { + dev_info(dev, "Using IPMMU context %u\n", +domain->context_id); + } } else if (domain->mmu != mmu) { /* * Something is wrong, we can't attach two devices using @@ -946,13 +956,14 @@ static void ipmmu_device_reset(struct ip unsigned int i; /* Disable all contexts. */ - for (i = 0; i < 4; ++i) + for (i = 0; i < mmu->num_ctx; ++i) ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); } static const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, + .number_of_contexts = 1, /* software only tested with one context */ }; static const struct of_device_id ipmmu_of_ids[] = { @@ -1006,6 +1017,9 @@ static int ipmmu_probe(struct platform_d if (mmu->features->use_ns_alias_offset) mmu->base += IM_NS_ALIAS_OFFSET; + mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX, +mmu->features->number_of_contexts); + irq = platform_get_irq(pdev, 0); /* ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias
From: Magnus Damm <damm+rene...@opensource.se> Introduce struct ipmmu_features to track various hardware and software implementation changes inside the driver for different kinds of IPMMU hardware. Add use_ns_alias_offset as a first example of a feature to control if the secure register bank offset should be used or not. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V4: - None Changes since V3: - Use of_device_get_match_data(), thanks Robin! Changes since V2: - None Changes since V1: - Moved patch to front of the series drivers/iommu/ipmmu-vmsa.c | 31 --- 1 file changed, 24 insertions(+), 7 deletions(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-10-12 15:16:43.510607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,11 +34,15 @@ #define IPMMU_CTX_MAX 1 +struct ipmmu_features { + bool use_ns_alias_offset; +}; + struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct iommu_device iommu; - + const struct ipmmu_features *features; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); @@ -910,6 +915,21 @@ static void ipmmu_device_reset(struct ip ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); } +static const struct ipmmu_features ipmmu_features_default = { + .use_ns_alias_offset = true, +}; + +static const struct of_device_id ipmmu_of_ids[] = { + { + .compatible = "renesas,ipmmu-vmsa", + .data = _features_default, + }, { + /* Terminator */ + }, +}; + +MODULE_DEVICE_TABLE(of, ipmmu_of_ids); + static int ipmmu_probe(struct platform_device *pdev) { struct ipmmu_vmsa_device *mmu; @@ -927,6 +947,7 @@ static int ipmmu_probe(struct platform_d mmu->num_utlbs = 32; spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); + mmu->features = of_device_get_match_data(>dev); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -946,7 +967,8 @@ static int ipmmu_probe(struct platform_d * Offset the registers base unconditionally to point to the non-secure * alias space for now. */ - mmu->base += IM_NS_ALIAS_OFFSET; + if (mmu->features->use_ns_alias_offset) + mmu->base += IM_NS_ALIAS_OFFSET; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -1002,11 +1024,6 @@ static int ipmmu_remove(struct platform_ return 0; } -static const struct of_device_id ipmmu_of_ids[] = { - { .compatible = "renesas,ipmmu-vmsa", }, - { } -}; - static struct platform_driver ipmmu_driver = { .driver = { .name = "ipmmu-vmsa", ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v5 00/09] iommu/ipmmu-vmsa: r8a7795 support V5
iommu/ipmmu-vmsa: r8a7795 support V5 [PATCH v5 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias [PATCH v5 02/09] iommu/ipmmu-vmsa: Add optional root device feature [PATCH v5 03/09] iommu/ipmmu-vmsa: Enable multi context support [PATCH v5 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE() [PATCH v5 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master [PATCH v5 06/09] iommu/ipmmu-vmsa: Write IMCTR twice [PATCH v5 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional [PATCH v5 08/09] iommu/ipmmu-vmsa: Allow two bit SL0 [PATCH v5 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code This is V5 of r8a7795 IPMMU driver where the series has been rebased and reworked to fit on next-20171013 that includes: [PATCH v2 00/05] iommu/ipmmu-vmsa: 32-bit ARM update V2 [PATCH] iommu/ipmmu-vmsa: Use iommu_device_sysfs_add()/remove() The major feature change is in patch 2/9 that now gets by without using a local list of registered IPMMU devices and instead relies on driver_for_each_device(). Thanks to Robin Murphy for his support. The DT binding for r8a7795 has been accepted for upstream merge and this series implements support following such format: d4e42e7 iommu/ipmmu-vmsa: Add r8a7795 DT binding The r8a7795 IPMMU is almost register compatible with earlier devices like r8a7790-r8a7794, however some bitfields have been shifted slightly. On a grander scale topology has been added and interrupts have been reworked. So now there are several "cache" IPMMU units without interrupt that somehow communicate with IPMMU-MM that is the only instance that supports interrupts. The code refers to IPMMU-MM as a "root" device and the other ones as "leaf" nodes. Changes since V4: - Rebased on top of [PATCH v2 00/05] iommu/ipmmu-vmsa: 32-bit ARM update V2 - Reworked root device handling to make use of driver_for_each_device() - Added deferred probing to make sure root device always is present Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of next-20171013 Also applies to renesas-drivers-2017-10-03-v4.14-rc3 Tested on top of renesas-drivers on r8a7796-m3ulcb using /dev/ttySC1 - [PATCH v4 0/3] iommu/ipmmu-vmsa: r8a7796 support V4 - local /dev/ttySC1 enablement for testing purpose - local DTS changes to hook up SYS-DMAC and IPMMU DS0, DS1 and MM - local whitelist code to enable "e731.dma-controller" drivers/iommu/ipmmu-vmsa.c | 310 ++-- 1 file changed, 244 insertions(+), 66 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/3] iommu/ipmmu-vmsa: Document R-Car M3-W IPMMU DT bindings
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a7796 compat string for the IPMMU devices included in the R-Car M3-W SoC. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2017-09-22 06:20:20.720607110 +0900 @@ -16,6 +16,7 @@ Required Properties: - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. +- "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 2/3] iommu/ipmmu-vmsa: Document R-Car V3M IPMMU DT bindings
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a77970 compat string for the IPMMU devices included in the R-Car V3M SoC. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0002/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2017-09-22 06:16:39.180607110 +0900 @@ -17,6 +17,7 @@ Required Properties: - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. +- "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 3/3] iommu/ipmmu-vmsa: Document R-Car D3 IPMMU DT bindings
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a77995 compat string for the IPMMU devices included in the R-Car D3 SoC. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0003/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2017-09-22 06:21:25.640607110 +0900 @@ -18,6 +18,7 @@ Required Properties: - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. +- "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 0/3] iommu/ipmmu-vmsa: R-Car Gen3 IPMMU DT binding update
iommu/ipmmu-vmsa: R-Car Gen3 IPMMU DT binding update [PATCH 1/3] iommu/ipmmu-vmsa: Document R-Car M3-W IPMMU DT bindings [PATCH 2/3] iommu/ipmmu-vmsa: Document R-Car V3M IPMMU DT bindings [PATCH 3/3] iommu/ipmmu-vmsa: Document R-Car D3 IPMMU DT bindings This series documents IPMMU DT bindings for the following SoCs: - R-Car M3-W - R8A7796 - R-Car V3M - R8A77970 - R-Car D3 - R8A77995 Patch 1/3 is ready for upstream merge and includes the following tags: Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> Patch 2/3 and 3/3 are quite trivial but have no acked-by so far. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of v4.14-rc1 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |3 +++ 1 file changed, 3 insertions(+) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH] iommu/ipmmu-vmsa: Use iommu_device_sysfs_add()/remove()
From: Magnus Damm <damm+rene...@opensource.se> Extend the driver to make use of iommu_device_sysfs_add()/remove() functions to hook up initial sysfs support. Suggested-by: Joerg Roedel <jroe...@suse.de> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Applies on top of next-20170817 drivers/iommu/ipmmu-vmsa.c |6 ++ 1 file changed, 6 insertions(+) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-08-21 14:40:13.940607110 +0900 @@ -953,6 +953,11 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); + ret = iommu_device_sysfs_add(>iommu, >dev, NULL, +dev_name(>dev)); + if (ret) + return ret; + iommu_device_set_ops(>iommu, _ops); iommu_device_set_fwnode(>iommu, >dev.of_node->fwnode); @@ -975,6 +980,7 @@ static int ipmmu_remove(struct platform_ { struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev); + iommu_device_sysfs_remove(>iommu); iommu_device_unregister(>iommu); #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 05/05] iommu/ipmmu-vmsa: Clean up device tracking
From: Robin Murphy <robin.mur...@arm.com> Get rid of now unused device tracking code. Future code should instead be able to use driver_for_each_device() for this purpose. This is a simplified version of the following patch from Robin [PATCH] iommu/ipmmu-vmsa: Clean up group allocation Signed-off-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Change since V1: - New patch drivers/iommu/ipmmu-vmsa.c | 12 1 file changed, 12 deletions(-) --- 0008/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-07-17 21:35:26.690607110 +0900 @@ -37,7 +37,6 @@ struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct iommu_device iommu; - struct list_head list; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ @@ -64,9 +63,6 @@ struct ipmmu_vmsa_iommu_priv { struct list_head list; }; -static DEFINE_SPINLOCK(ipmmu_devices_lock); -static LIST_HEAD(ipmmu_devices); - static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom) { return container_of(dom, struct ipmmu_vmsa_domain, io_domain); @@ -970,10 +966,6 @@ static int ipmmu_probe(struct platform_d * ipmmu_init() after the probe function returns. */ - spin_lock(_devices_lock); - list_add(>list, _devices); - spin_unlock(_devices_lock); - platform_set_drvdata(pdev, mmu); return 0; @@ -983,10 +975,6 @@ static int ipmmu_remove(struct platform_ { struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev); - spin_lock(_devices_lock); - list_del(>list); - spin_unlock(_devices_lock); - iommu_device_unregister(>iommu); #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 04/05] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids
From: Magnus Damm <damm+rene...@opensource.se> Now when both 32-bit and 64-bit code inside the driver is using fwspec it is possible to replace the utlb handling with fwspec ids that get populated from ->of_xlate(). Suggested-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Rebased to apply on top of earlier changes in series drivers/iommu/ipmmu-vmsa.c | 104 1 file changed, 19 insertions(+), 85 deletions(-) --- 0006/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-07-17 21:12:11.650607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -59,8 +60,6 @@ struct ipmmu_vmsa_domain { struct ipmmu_vmsa_iommu_priv { struct ipmmu_vmsa_device *mmu; - unsigned int *utlbs; - unsigned int num_utlbs; struct device *dev; struct list_head list; }; @@ -550,13 +549,14 @@ static int ipmmu_attach_device(struct io struct device *dev) { struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); + struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_device *mmu = priv->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned long flags; unsigned int i; int ret = 0; - if (!mmu) { + if (!priv || !priv->mmu) { dev_err(dev, "Cannot attach to IPMMU\n"); return -ENXIO; } @@ -583,8 +583,8 @@ static int ipmmu_attach_device(struct io if (ret < 0) return ret; - for (i = 0; i < priv->num_utlbs; ++i) - ipmmu_utlb_enable(domain, priv->utlbs[i]); + for (i = 0; i < fwspec->num_ids; ++i) + ipmmu_utlb_enable(domain, fwspec->ids[i]); return 0; } @@ -592,12 +592,12 @@ static int ipmmu_attach_device(struct io static void ipmmu_detach_device(struct iommu_domain *io_domain, struct device *dev) { - struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); + struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned int i; - for (i = 0; i < priv->num_utlbs; ++i) - ipmmu_utlb_disable(domain, priv->utlbs[i]); + for (i = 0; i < fwspec->num_ids; ++i) + ipmmu_utlb_disable(domain, fwspec->ids[i]); /* * TODO: Optimize by disabling the context when no device is attached. @@ -633,102 +633,36 @@ static phys_addr_t ipmmu_iova_to_phys(st return domain->iop->iova_to_phys(domain->iop, iova); } -static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, - unsigned int *utlbs, unsigned int num_utlbs) -{ - unsigned int i; - - for (i = 0; i < num_utlbs; ++i) { - struct of_phandle_args args; - int ret; - - ret = of_parse_phandle_with_args(dev->of_node, "iommus", -"#iommu-cells", i, ); - if (ret < 0) - return ret; - - of_node_put(args.np); - - if (args.np != mmu->dev->of_node || args.args_count != 1) - return -EINVAL; - - utlbs[i] = args.args[0]; - } - - return 0; -} - -static int ipmmu_init_platform_device(struct device *dev) +static int ipmmu_init_platform_device(struct device *dev, + struct of_phandle_args *args) { + struct platform_device *ipmmu_pdev; struct ipmmu_vmsa_iommu_priv *priv; - struct ipmmu_vmsa_device *mmu; - unsigned int *utlbs; - unsigned int i; - int num_utlbs; - int ret = -ENODEV; - - /* Find the master corresponding to the device. */ - num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells"); - if (num_utlbs < 0) + ipmmu_pdev = of_find_device_by_node(args->np); + if (!ipmmu_pdev) return -ENODEV; - utlbs = kcalloc(num_utlbs, sizeof(*utlbs), GFP_KERNEL); - if (!utlbs) - return -ENOMEM; - - spin_lock(_devices_lock); - - list_for_each_entry(mmu, _devices, list) { - ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs); - if (!ret) { - /* -* TODO Take a reference to the MMU to protect -* against device removal. -*/ - break; - } - } - - spin_unlock(_devices_lock); - - if (ret < 0) -
[PATCH v2 03/05] iommu/ipmmu-vmsa: Use fwspec on both 32 and 64-bit ARM
From: Robin Murphy <robin.mur...@arm.com> Consolidate the 32-bit and 64-bit code to make use of fwspec instead of archdata for the 32-bit ARM case. This is a simplified version of the fwspec handling code from Robin posted as [PATCH] iommu/ipmmu-vmsa: Convert to iommu_fwspec Signed-off-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Rebased to apply on top of earlier changes in series drivers/iommu/ipmmu-vmsa.c | 21 +++-- 1 file changed, 3 insertions(+), 18 deletions(-) --- 0004/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-07-17 21:04:54.850607110 +0900 @@ -73,22 +73,9 @@ static struct ipmmu_vmsa_domain *to_vmsa return container_of(dom, struct ipmmu_vmsa_domain, io_domain); } - static struct ipmmu_vmsa_iommu_priv *to_priv(struct device *dev) { -#if defined(CONFIG_ARM) - return dev->archdata.iommu; -#else - return dev->iommu_fwspec->iommu_priv; -#endif -} -static void set_priv(struct device *dev, struct ipmmu_vmsa_iommu_priv *p) -{ -#if defined(CONFIG_ARM) - dev->archdata.iommu = p; -#else - dev->iommu_fwspec->iommu_priv = p; -#endif + return dev->iommu_fwspec ? dev->iommu_fwspec->iommu_priv : NULL; } #define TLB_LOOP_TIMEOUT 100 /* 100us */ @@ -726,7 +713,7 @@ static int ipmmu_init_platform_device(st priv->utlbs = utlbs; priv->num_utlbs = num_utlbs; priv->dev = dev; - set_priv(dev, priv); + dev->iommu_fwspec->iommu_priv = priv; return 0; error: @@ -887,14 +874,12 @@ static void ipmmu_domain_free_dma(struct static int ipmmu_add_device_dma(struct device *dev) { - struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct iommu_group *group; /* * Only let through devices that have been verified in xlate() -* We may get called with dev->iommu_fwspec set to NULL. */ - if (!fwspec || !fwspec->iommu_priv) + if (!to_priv(dev)) return -ENODEV; group = iommu_group_get_for_dev(dev); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 02/05] iommu/ipmmu-vmsa: Consistent ->of_xlate() handling
From: Magnus Damm <damm+rene...@opensource.se> The 32-bit ARM code gets updated to make use of ->of_xlate() and the code is shared between 64-bit and 32-bit ARM. The of_device_is_available() check gets dropped since it is included in of_iommu_xlate(). Suggested-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Moved "Initialize once" check to ipmmu_of_xlate() - thanks Geert! drivers/iommu/ipmmu-vmsa.c | 51 ++-- 1 file changed, 17 insertions(+), 34 deletions(-) --- 0002/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-07-17 21:03:38.340607110 +0900 @@ -734,6 +734,16 @@ error: return ret; } +static int ipmmu_of_xlate(struct device *dev, + struct of_phandle_args *spec) +{ + /* Initialize once - xlate() will call multiple times */ + if (to_priv(dev)) + return 0; + + return ipmmu_init_platform_device(dev); +} + #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) static struct iommu_domain *ipmmu_domain_alloc(unsigned type) @@ -750,11 +760,11 @@ static int ipmmu_add_device(struct devic struct iommu_group *group; int ret; - if (to_priv(dev)) { - dev_warn(dev, "IOMMU driver already assigned to device %s\n", -dev_name(dev)); - return -EINVAL; - } + /* +* Only let through devices that have been verified in xlate() +*/ + if (!to_priv(dev)) + return -ENODEV; /* Create a device group and add the device to it. */ group = iommu_group_alloc(); @@ -773,10 +783,6 @@ static int ipmmu_add_device(struct devic goto error; } - ret = ipmmu_init_platform_device(dev); - if (ret < 0) - goto error; - /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate * VAs. This will allocate a corresponding IOMMU domain. @@ -817,24 +823,13 @@ error: if (!IS_ERR_OR_NULL(group)) iommu_group_remove_device(dev); - kfree(to_priv(dev)->utlbs); - kfree(to_priv(dev)); - set_priv(dev, NULL); - return ret; } static void ipmmu_remove_device(struct device *dev) { - struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); - arm_iommu_detach_device(dev); iommu_group_remove_device(dev); - - kfree(priv->utlbs); - kfree(priv); - - set_priv(dev, NULL); } static const struct iommu_ops ipmmu_ops = { @@ -849,6 +844,7 @@ static const struct iommu_ops ipmmu_ops .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, + .of_xlate = ipmmu_of_xlate, }; #endif /* !CONFIG_ARM && CONFIG_IOMMU_DMA */ @@ -958,19 +954,6 @@ static struct iommu_group *ipmmu_find_gr return group; } -static int ipmmu_of_xlate_dma(struct device *dev, - struct of_phandle_args *spec) -{ - /* If the IPMMU device is disabled in DT then return error -* to make sure the of_iommu code does not install ops -* even though the iommu device is disabled -*/ - if (!of_device_is_available(spec->np)) - return -ENODEV; - - return ipmmu_init_platform_device(dev); -} - static const struct iommu_ops ipmmu_ops = { .domain_alloc = ipmmu_domain_alloc_dma, .domain_free = ipmmu_domain_free_dma, @@ -984,7 +967,7 @@ static const struct iommu_ops ipmmu_ops .remove_device = ipmmu_remove_device_dma, .device_group = ipmmu_find_group_dma, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, - .of_xlate = ipmmu_of_xlate_dma, + .of_xlate = ipmmu_of_xlate, }; #endif /* CONFIG_IOMMU_DMA */ ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 01/05] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister()
From: Magnus Damm <damm+rene...@opensource.se> Extend the driver to make use of iommu_device_register()/unregister() functions together with iommu_device_set_ops() and iommu_set_fwnode(). These used to be part of the earlier posted 64-bit ARM (r8a7795) series but it turns out that these days they are required on 32-bit ARM as well. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Perform iommu_device_set_ops() and iommu_device_set_fwnode() before iommu_device_register() - thanks Robin! drivers/iommu/ipmmu-vmsa.c | 10 ++ 1 file changed, 10 insertions(+) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-07-17 21:01:47.140607110 +0900 @@ -35,6 +35,7 @@ struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; + struct iommu_device iommu; struct list_head list; unsigned int num_utlbs; @@ -1054,6 +1055,13 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); + iommu_device_set_ops(>iommu, _ops); + iommu_device_set_fwnode(>iommu, >dev.of_node->fwnode); + + ret = iommu_device_register(>iommu); + if (ret) + return ret; + /* * We can't create the ARM mapping here as it requires the bus to have * an IOMMU, which only happens when bus_set_iommu() is called in @@ -1077,6 +1085,8 @@ static int ipmmu_remove(struct platform_ list_del(>list); spin_unlock(_devices_lock); + iommu_device_unregister(>iommu); + #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) arm_iommu_release_mapping(mmu->mapping); #endif ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 00/05] iommu/ipmmu-vmsa: 32-bit ARM update V2
iommu/ipmmu-vmsa: 32-bit ARM update V2 [PATCH v2 01/05] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister() [PATCH v2 02/05] iommu/ipmmu-vmsa: Consistent ->of_xlate() handling [PATCH v2 03/05] iommu/ipmmu-vmsa: Use fwspec on both 32 and 64-bit ARM [PATCH v2 04/05] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids [PATCH v2 05/05] iommu/ipmmu-vmsa: Clean up device tracking This series updates the IPMMU driver to make use of recent IOMMU framework changes and also improves code sharing in the driver between the 32-bit and 64-bit dma-mapping architecture glue code. Suggested-by: Robin Murphy <robin.mur...@arm.com> (Patch 2 and 4) Signed-off-by: Robin Murphy <robin.mur...@arm.com> (Patch 3 and 5) Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Minor changes to patch 1 and 2 - thanks Robin and Geert! - Added patch 5 to include further clean ups Developed on top of v4.13-rc1 drivers/iommu/ipmmu-vmsa.c | 198 ++-- 1 file changed, 49 insertions(+), 149 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code
From: Magnus Damm <damm+rene...@opensource.se> Support the r8a7796 IPMMU by sharing feature flags between r8a7795 and r8a7796. Also update IOMMU_OF_DECLARE to hook up the updated compat string. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V3: - Added Reviewed-by from Geert - thanks! Changes since V2: - Updated to include white list suppport Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 14 ++ 1 file changed, 10 insertions(+), 4 deletions(-) --- 0016/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 19:48:27.430607110 +0900 @@ -755,8 +755,9 @@ static bool ipmmu_slave_whitelist(struct return false; } -static const struct soc_device_attribute soc_r8a7795[] = { +static const struct soc_device_attribute soc_rcar_gen3[] = { { .soc_id = "r8a7795", }, + { .soc_id = "r8a7796", }, { /* sentinel */ } }; @@ -772,7 +773,7 @@ static int ipmmu_of_xlate(struct device } /* For R-Car Gen3 use a white list to opt-in slave devices */ - if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev)) return -ENODEV; iommu_fwspec_add_ids(dev, spec->args, 1); @@ -1034,7 +1035,7 @@ static const struct ipmmu_features ipmmu .twobit_imttbcr_sl0 = false, }; -static const struct ipmmu_features ipmmu_features_r8a7795 = { +static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .use_ns_alias_offset = false, .has_cache_leaf_nodes = true, .number_of_contexts = 8, @@ -1048,7 +1049,10 @@ static const struct of_device_id ipmmu_o .data = _features_default, }, { .compatible = "renesas,ipmmu-r8a7795", - .data = _features_r8a7795, + .data = _features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a7796", + .data = _features_rcar_gen3, }, { /* Terminator */ }, @@ -1229,6 +1233,8 @@ IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "r ipmmu_vmsa_iommu_of_setup); IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795", ipmmu_vmsa_iommu_of_setup); +IOMMU_OF_DECLARE(ipmmu_r8a7796_iommu_of, "renesas,ipmmu-r8a7796", +ipmmu_vmsa_iommu_of_setup); #endif MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 0/3] iommu/ipmmu-vmsa: r8a7796 support V4
iommu/ipmmu-vmsa: r8a7796 support V4 [PATCH v4 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding [PATCH v4 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48 [PATCH v4 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code This series adds r8a7796 support to the IPMMU driver. The DT binding gets updated, maximum number of micro-TLBs are increased and the driver is adjusted to match on the new DT binding. Changes since V3: - Rebased on top of [PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4 - Patch 3/3 updated with Reviewed-by - thanks Geert! Changes since V2: - Patch 2/3 updated with an outer set of () - thanks Ramesh! - Patch 2/3 updated with Reviewed-by - thanks Geert! - Patch 3/3 updated to include white list support Changes since V1: - Patch 1/3 updated with more Acked-by tags - Patch 2/3 updated with high I/O register range support Patch 1/3 is ready for upstream merge and includes the following tags: Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> Patch 2/3 and 3/3 are quite trivial but have no acked-by so far. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of next-20170614 with the following series applied [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update [PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 drivers/iommu/ipmmu-vmsa.c | 24 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a7796 compat string for R-Car M3-W. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V3: - None Changes since V2: - None Changes since V1: - Included in series, added Acked-by from Geert - thanks! Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2017-06-19 19:51:13.990607110 +0900 @@ -16,6 +16,7 @@ Required Properties: - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. +- "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48
From: Magnus Damm <damm+rene...@opensource.se> Bump up the maximum numbers of micro-TLBS to 48. Each IPMMU device instance get micro-TLB assignment via the "iommus" property in DT. Older SoCs tend to use a maximum number of 32 micro-TLBs per IPMMU instance however newer SoCs such as r8a7796 make use of up to 48 micro-TLBs. At this point no SoC specific handling is done to validate the maximum number of micro-TLBs, and because of that the DT information is assumed to be within correct range for each particular SoC. If needed in the future SoC specific feature flags can be added to handle the maximum number of micro-TLBs without requiring DT changes, however at this point this does not seem necessary. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V3: - None Changes since V2: - Added outer set of () to IMUASID() and IMUCTR() - thanks Ramesh! - Added Reviewed-by from Geert - thanks! Changes since V1: - Added support for the second I/O range at 0x600. drivers/iommu/ipmmu-vmsa.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) --- 0015/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 19:47:28.950607110 +0900 @@ -199,7 +199,9 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMPMBA(n) (0x0280 + ((n) * 4)) #define IMPMBD(n) (0x02c0 + ((n) * 4)) -#define IMUCTR(n) (0x0300 + ((n) * 16)) +#define IMUCTR(n) ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n)) +#define IMUCTR0(n) (0x0300 + ((n) * 16)) +#define IMUCTR32(n)(0x0600 + (((n) - 32) * 16)) #define IMUCTR_FIXADDEN(1 << 31) #define IMUCTR_FIXADD_MASK (0xff << 16) #define IMUCTR_FIXADD_SHIFT16 @@ -209,7 +211,9 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMUCTR_FLUSH (1 << 1) #define IMUCTR_MMUEN (1 << 0) -#define IMUASID(n) (0x0308 + ((n) * 16)) +#define IMUASID(n) ((n) < 32 ? IMUASID0(n) : IMUASID32(n)) +#define IMUASID0(n)(0x0308 + ((n) * 16)) +#define IMUASID32(n) (0x0608 + (((n) - 32) * 16)) #define IMUASID_ASID8_MASK (0xff << 8) #define IMUASID_ASID8_SHIFT8 #define IMUASID_ASID0_MASK (0xff << 0) @@ -1066,7 +1070,7 @@ static int ipmmu_probe(struct platform_d } mmu->dev = >dev; - mmu->num_utlbs = 32; + mmu->num_utlbs = 48; spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(>dev); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
From: Magnus Damm <damm+rene...@opensource.se> Tie in r8a7795 features and update the IOMMU_OF_DECLARE compat string to include the updated compat string. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Rebased code on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update This includes support for iommu_fwspec_add_ids() - Use dev_err() instead of dev_info() - Thanks Geert! - Moved single-invokation check into of_xlate() - Thanks Geert! - Dropped TODO list Changes since V2: - Check for lack of root device in ->xlate() This fixed a bug when IPMMU-MM is disabled in DT the system hangs on boot - Added code to ipmmu_init_platform_device() to handle multiple ->xlate() calls - Include empty white list by default - Updated TODO list Changes since V1: - Enable multi context feature - Update TODO list drivers/iommu/ipmmu-vmsa.c | 48 1 file changed, 44 insertions(+), 4 deletions(-) --- 0029/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:10:58.930607110 +0900 @@ -25,6 +25,7 @@ #include #include #include +#include #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include @@ -730,10 +731,6 @@ static int ipmmu_init_platform_device(st struct platform_device *ipmmu_pdev; struct ipmmu_vmsa_iommu_priv *priv; - /* Initialize once - xlate() will call multiple times */ - if (to_priv(dev)) - return 0; - ipmmu_pdev = of_find_device_by_node(args->np); if (!ipmmu_pdev) return -ENODEV; @@ -748,11 +745,41 @@ static int ipmmu_init_platform_device(st return 0; } +static bool ipmmu_slave_whitelist(struct device *dev) +{ + /* By default, do not allow use of IPMMU */ + return false; +} + +static const struct soc_device_attribute soc_r8a7795[] = { + { .soc_id = "r8a7795", }, + { /* sentinel */ } +}; + static int ipmmu_of_xlate(struct device *dev, struct of_phandle_args *spec) { + /* Failing in ->attach_device() results in a hang, so make +* sure the root device is installed before going there +*/ + if (!__ipmmu_find_root()) { + dev_err(dev, "Unable to locate IPMMU root device\n"); + return -ENODEV; + } + + /* For R-Car Gen3 use a white list to opt-in slave devices */ + if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + return -ENODEV; + iommu_fwspec_add_ids(dev, spec->args, 1); + /* +* Execute ipmmu_init_platform_device() once per device. +* This xlate() callback will be invoked multiple times. +*/ + if (to_priv(dev)) + return 0; + return ipmmu_init_platform_device(dev, spec); } @@ -1003,11 +1030,22 @@ static const struct ipmmu_features ipmmu .twobit_imttbcr_sl0 = false, }; +static const struct ipmmu_features ipmmu_features_r8a7795 = { + .use_ns_alias_offset = false, + .has_cache_leaf_nodes = true, + .number_of_contexts = 8, + .setup_imbuscr = false, + .twobit_imttbcr_sl0 = true, +}; + static const struct of_device_id ipmmu_of_ids[] = { { .compatible = "renesas,ipmmu-vmsa", .data = _features_default, }, { + .compatible = "renesas,ipmmu-r8a7795", + .data = _features_r8a7795, + }, { /* Terminator */ }, }; @@ -1185,6 +1223,8 @@ static int __init ipmmu_vmsa_iommu_of_se IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", ipmmu_vmsa_iommu_of_setup); +IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795", +ipmmu_vmsa_iommu_of_setup); #endif MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 08/09] iommu/ipmmu-vmsa: Allow two bit SL0
From: Magnus Damm <damm+rene...@opensource.se> Introduce support for two bit SL0 bitfield in IMTTBCR by using a separate feature flag. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - None Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) --- 0027/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:08:26.100607110 +0900 @@ -40,6 +40,7 @@ struct ipmmu_features { bool has_cache_leaf_nodes; unsigned int number_of_contexts; bool setup_imbuscr; + bool twobit_imttbcr_sl0; }; struct ipmmu_vmsa_device { @@ -149,6 +150,10 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMTTBCR_TSZ0_MASK (7 << 0) #define IMTTBCR_TSZ0_SHIFT O +#define IMTTBCR_SL0_TWOBIT_LVL_3 (0 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_2 (1 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_1 (2 << 6) + #define IMBUSCR0x000c #define IMBUSCR_DVM(1 << 2) #define IMBUSCR_BUSSEL_SYS (0 << 0) @@ -393,6 +398,7 @@ static int ipmmu_domain_allocate_context static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) { u64 ttbr; + u32 tmp; int ret; /* @@ -445,9 +451,14 @@ static int ipmmu_domain_init_context(str * We use long descriptors with inner-shareable WBWA tables and allocate * the whole 32-bit VA space to TTBR0. */ + if (domain->root->features->twobit_imttbcr_sl0) + tmp = IMTTBCR_SL0_TWOBIT_LVL_1; + else + tmp = IMTTBCR_SL0_LVL_1; + ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | -IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); +IMTTBCR_IRGN0_WB_WA | tmp); /* MAIR0 */ ipmmu_ctx_write_root(domain, IMMAIR0, @@ -989,6 +1000,7 @@ static const struct ipmmu_features ipmmu .has_cache_leaf_nodes = false, .number_of_contexts = 1, /* software only tested with one context */ .setup_imbuscr = true, + .twobit_imttbcr_sl0 = false, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 06/09] iommu/ipmmu-vmsa: Write IMCTR twice
From: Magnus Damm <damm+rene...@opensource.se> Write IMCTR both in the root device and the leaf node. To allow access of IMCTR introduce the following function: - ipmmu_ctx_write_all() While at it also rename context functions: - ipmmu_ctx_read() -> ipmmu_ctx_read_root() - ipmmu_ctx_write() -> ipmmu_ctx_write_root() Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Changed function names to improve code readability - Thanks Robin! Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 55 +++- 1 file changed, 34 insertions(+), 21 deletions(-) --- 0023/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:06:16.770607110 +0900 @@ -261,17 +261,28 @@ static void ipmmu_write(struct ipmmu_vms iowrite32(data, mmu->base + offset); } -static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) +static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain, + unsigned int reg) { return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg); } -static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, - u32 data) +static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain, +unsigned int reg, u32 data) { ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); } +static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain, + unsigned int reg, u32 data) +{ + if (domain->mmu != domain->root) + ipmmu_write(domain->mmu, + domain->context_id * IM_CTX_SIZE + reg, data); + + ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); +} + /* - * TLB and microTLB Management */ @@ -281,7 +292,7 @@ static void ipmmu_tlb_sync(struct ipmmu_ { unsigned int count = 0; - while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) { + while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) { cpu_relax(); if (++count == TLB_LOOP_TIMEOUT) { dev_err_ratelimited(domain->mmu->dev, @@ -296,9 +307,9 @@ static void ipmmu_tlb_invalidate(struct { u32 reg; - reg = ipmmu_ctx_read(domain, IMCTR); + reg = ipmmu_ctx_read_root(domain, IMCTR); reg |= IMCTR_FLUSH; - ipmmu_ctx_write(domain, IMCTR, reg); + ipmmu_ctx_write_all(domain, IMCTR, reg); ipmmu_tlb_sync(domain); } @@ -425,31 +436,32 @@ static int ipmmu_domain_init_context(str /* TTBR0 */ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; - ipmmu_ctx_write(domain, IMTTLBR0, ttbr); - ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32); + ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr); + ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32); /* * TTBCR * We use long descriptors with inner-shareable WBWA tables and allocate * the whole 32-bit VA space to TTBR0. */ - ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | - IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | - IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); + ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | +IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | +IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); /* MAIR0 */ - ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); + ipmmu_ctx_write_root(domain, IMMAIR0, +domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ - ipmmu_ctx_write(domain, IMBUSCR, - ipmmu_ctx_read(domain, IMBUSCR) & - ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); + ipmmu_ctx_write_root(domain, IMBUSCR, +ipmmu_ctx_read_root(domain, IMBUSCR) & +~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); /* * IMSTR * Clear all interrupt flags. */ - ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR)); + ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR)); /* * IMCTR @@ -458,7 +470,8 @@ static int ipmmu_domain_init_context(str * software management as we have no use for it. Flush the TLB as * required when modifying the context registers. */ - ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); + ipmmu_ctx_write_all(domain, IMCTR, + IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); return
[PATCH v4 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional
From: Magnus Damm <damm+rene...@opensource.se> Introduce a feature to allow opt-out of setting up IMBUSCR. The default case is unchanged. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - None Changes since V2: - None Changes since V1: - Updated the commit message - Reworked patch to coexist with the multi context feature drivers/iommu/ipmmu-vmsa.c |9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) --- 0025/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:07:06.850607110 +0900 @@ -39,6 +39,7 @@ struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; unsigned int number_of_contexts; + bool setup_imbuscr; }; struct ipmmu_vmsa_device { @@ -453,9 +454,10 @@ static int ipmmu_domain_init_context(str domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ - ipmmu_ctx_write_root(domain, IMBUSCR, -ipmmu_ctx_read_root(domain, IMBUSCR) & -~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); + if (domain->root->features->setup_imbuscr) + ipmmu_ctx_write_root(domain, IMBUSCR, +ipmmu_ctx_read_root(domain, IMBUSCR) & +~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); /* * IMSTR @@ -986,6 +988,7 @@ static const struct ipmmu_features ipmmu .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, .number_of_contexts = 1, /* software only tested with one context */ + .setup_imbuscr = true, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 03/09] iommu/ipmmu-vmsa: Enable multi context support
From: Magnus Damm <damm+rene...@opensource.se> Add support for up to 8 contexts. Each context is mapped to one domain. One domain is assigned one or more slave devices. Contexts are allocated dynamically and slave devices are grouped together based on which IPMMU device they are connected to. This makes slave devices tied to the same IPMMU device share the same IOVA space. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Use number_of_contexts unsigned int, drop WARN_ON() - Thanks Robin! Changes since V2: - Updated patch description to reflect code included in: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 Changes since V1: - Support up to 8 contexts instead of 4 - Use feature flag and runtime handling - Default to single context drivers/iommu/ipmmu-vmsa.c | 31 +++ 1 file changed, 23 insertions(+), 8 deletions(-) --- 0017/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:00:59.880607110 +0900 @@ -32,11 +32,12 @@ #include "io-pgtable.h" -#define IPMMU_CTX_MAX 1 +#define IPMMU_CTX_MAX 8 struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; + unsigned int number_of_contexts; }; struct ipmmu_vmsa_device { @@ -47,6 +48,7 @@ struct ipmmu_vmsa_device { const struct ipmmu_features *features; bool is_leaf; unsigned int num_utlbs; + unsigned int num_ctx; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; @@ -363,11 +365,12 @@ static int ipmmu_domain_allocate_context spin_lock_irqsave(>lock, flags); - ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); - if (ret != IPMMU_CTX_MAX) { + ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx); + if (ret != mmu->num_ctx) { mmu->domains[ret] = domain; set_bit(ret, mmu->ctx); - } + } else + ret = -EBUSY; spin_unlock_irqrestore(>lock, flags); @@ -412,9 +415,9 @@ static int ipmmu_domain_init_context(str * Find an unused context. */ ret = ipmmu_domain_allocate_context(domain->root, domain); - if (ret == IPMMU_CTX_MAX) { + if (ret < 0) { free_io_pgtable_ops(domain->iop); - return -EBUSY; + return ret; } domain->context_id = ret; @@ -549,7 +552,7 @@ static irqreturn_t ipmmu_irq(int irq, vo /* * Check interrupts for all active contexts. */ - for (i = 0; i < IPMMU_CTX_MAX; i++) { + for (i = 0; i < mmu->num_ctx; i++) { if (!mmu->domains[i]) continue; if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED) @@ -620,6 +623,14 @@ static int ipmmu_attach_device(struct io domain->mmu = mmu; domain->root = root; ret = ipmmu_domain_init_context(domain); + if (ret < 0) { + dev_err(dev, "Unable to initialize IPMMU context\n"); + domain->mmu = NULL; + domain->root = NULL; + } else { + dev_info(dev, "Using IPMMU context %u\n", +domain->context_id); + } } else if (domain->mmu != mmu) { /* * Something is wrong, we can't attach two devices using @@ -953,13 +964,14 @@ static void ipmmu_device_reset(struct ip unsigned int i; /* Disable all contexts. */ - for (i = 0; i < 4; ++i) + for (i = 0; i < mmu->num_ctx; ++i) ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); } static const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, + .number_of_contexts = 1, /* software only tested with one context */ }; static const struct of_device_id ipmmu_of_ids[] = { @@ -1013,6 +1025,9 @@ static int ipmmu_probe(struct platform_d if (mmu->features->use_ns_alias_offset) mmu->base += IM_NS_ALIAS_OFFSET; + mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX, +mmu->features->number_of_contexts); + irq = platform_get_irq(pdev, 0); /* ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
From: Magnus Damm <damm+rene...@opensource.se> Hook up IOMMU_OF_DECLARE() support in case CONFIG_IOMMU_DMA is enabled. The only current supported case for 32-bit ARM is disabled, however for 64-bit ARM usage of OF is required. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Reworked to fit on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update Changes since V2: - Reworked registration code to make use of recently introduced: iommu_device_register() iommu_device_set_ops() iommu_device_set_fwnode() Changes since V1: - Reworked slightly to fit updated patch order and [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 43 +-- 1 file changed, 37 insertions(+), 6 deletions(-) --- 0019/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:03:53.140607110 +0900 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1055,13 +1056,25 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); } - ret = iommu_device_register(>iommu); - if (ret) - return ret; - - iommu_device_set_ops(>iommu, _ops); - iommu_device_set_fwnode(>iommu, >dev.of_node->fwnode); + /* +* Register the IPMMU to the IOMMU subsystem in the following cases: +* - R-Car Gen2 IPMMU (all devices registered) +* - R-Car Gen3 IPMMU (leaf devices only - skip root IPMMU-MM device) +*/ + if (!mmu->features->has_cache_leaf_nodes || mmu->is_leaf) { + ret = iommu_device_register(>iommu); + if (ret) + return ret; + iommu_device_set_ops(>iommu, _ops); + iommu_device_set_fwnode(>iommu, + >dev.of_node->fwnode); + +#if defined(CONFIG_IOMMU_DMA) + if (!iommu_present(_bus_type)) + bus_set_iommu(_bus_type, _ops); +#endif + } /* * We can't create the ARM mapping here as it requires the bus to have * an IOMMU, which only happens when bus_set_iommu() is called in @@ -1107,15 +1120,22 @@ static struct platform_driver ipmmu_driv static int __init ipmmu_init(void) { + static bool setup_done; int ret; + if (setup_done) + return 0; + ret = platform_driver_register(_driver); if (ret < 0) return ret; +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) if (!iommu_present(_bus_type)) bus_set_iommu(_bus_type, _ops); +#endif + setup_done = true; return 0; } @@ -1127,6 +1147,17 @@ static void __exit ipmmu_exit(void) subsys_initcall(ipmmu_init); module_exit(ipmmu_exit); +#ifdef CONFIG_IOMMU_DMA +static int __init ipmmu_vmsa_iommu_of_setup(struct device_node *np) +{ + ipmmu_init(); + return 0; +} + +IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", +ipmmu_vmsa_iommu_of_setup); +#endif + MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); MODULE_AUTHOR("Laurent Pinchart <laurent.pinch...@ideasonboard.com>"); MODULE_LICENSE("GPL v2"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4
iommu/ipmmu-vmsa: r8a7795 support V4 [PATCH v4 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias [PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature [PATCH v4 03/09] iommu/ipmmu-vmsa: Enable multi context support [PATCH v4 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE() [PATCH v4 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master [PATCH v4 06/09] iommu/ipmmu-vmsa: Write IMCTR twice [PATCH v4 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional [PATCH v4 08/09] iommu/ipmmu-vmsa: Allow two bit SL0 [PATCH v4 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code Here's an updated series for r8a7795 IPMMU support. The patches adjust the code based on feedback from Geert and Robin together with a rebase to include changes from the recently posted series: [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update The DT binding for r8a7795 has been accepted for upstream merge and this series implements support following such format: d4e42e7 iommu/ipmmu-vmsa: Add r8a7795 DT binding The r8a7795 IPMMU is almost register compatible with earlier devices like r8a7790-r8a7794, however some bitfields have been shifted slightly. On a grander scale topology has been added and interrupts have been reworked. So now there are several "cache" IPMMU units without interrupt that somehow communicate with IPMMU-MM that is the only instance that supports interrupts. The code refers to IPMMU-MM as a "root" device and the other ones as "leaf" nodes. Changes since V3: - Rebased on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update - Patch 1/9 has been updated to use of_device_get_match_data(), thanks Robin! - Patch 2/9 has been reworked to make it easier to follow, thanks Geert! - Patch 3/9 now uses unsigned int for context counts - thanks Robin! - Patch 6/9 now includes function name changes - thanks Robin! - Patch 9/9 now uses dev_err() instead of dev_info() - thanks Geert! Changes since V2: - Patch 2/9 has been updated with a bug fix and to supply __ipmmu_find_root() - Patch 4/9 now makes use of iommu_device_* functions - Patch 5/9 sets the mask to 40 bits instead of 64 bits - Patch 9/9 implements white list handling via ->xlate() and fixes a bug Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of next-20170614 with the following series applied [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update drivers/iommu/ipmmu-vmsa.c | 327 ++-- 1 file changed, 260 insertions(+), 67 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias
From: Magnus Damm <damm+rene...@opensource.se> Introduce struct ipmmu_features to track various hardware and software implementation changes inside the driver for different kinds of IPMMU hardware. Add use_ns_alias_offset as a first example of a feature to control if the secure register bank offset should be used or not. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Use of_device_get_match_data(), thanks Robin! Changes since V2: - None Changes since V1: - Moved patch to front of the series drivers/iommu/ipmmu-vmsa.c | 31 --- 1 file changed, 24 insertions(+), 7 deletions(-) --- 0014/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 13:57:36.300607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,12 +34,16 @@ #define IPMMU_CTX_MAX 1 +struct ipmmu_features { + bool use_ns_alias_offset; +}; + struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct iommu_device iommu; struct list_head list; - + const struct ipmmu_features *features; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); @@ -904,6 +909,21 @@ static void ipmmu_device_reset(struct ip ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); } +static const struct ipmmu_features ipmmu_features_default = { + .use_ns_alias_offset = true, +}; + +static const struct of_device_id ipmmu_of_ids[] = { + { + .compatible = "renesas,ipmmu-vmsa", + .data = _features_default, + }, { + /* Terminator */ + }, +}; + +MODULE_DEVICE_TABLE(of, ipmmu_of_ids); + static int ipmmu_probe(struct platform_device *pdev) { struct ipmmu_vmsa_device *mmu; @@ -921,6 +941,7 @@ static int ipmmu_probe(struct platform_d mmu->num_utlbs = 32; spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); + mmu->features = of_device_get_match_data(>dev); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -940,7 +961,8 @@ static int ipmmu_probe(struct platform_d * Offset the registers base unconditionally to point to the non-secure * alias space for now. */ - mmu->base += IM_NS_ALIAS_OFFSET; + if (mmu->features->use_ns_alias_offset) + mmu->base += IM_NS_ALIAS_OFFSET; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -998,11 +1020,6 @@ static int ipmmu_remove(struct platform_ return 0; } -static const struct of_device_id ipmmu_of_ids[] = { - { .compatible = "renesas,ipmmu-vmsa", }, - { } -}; - static struct platform_driver ipmmu_driver = { .driver = { .name = "ipmmu-vmsa", ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature
From: Magnus Damm <damm+rene...@opensource.se> Add root device handling to the IPMMU driver by allowing certain DT compat strings to enable has_cache_leaf_nodes that in turn will support both root devices with interrupts and leaf devices that face the actual IPMMU consumer devices. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V3: - Reworked root finding code to make it easier to follow, thanks Geert! Changes since V2: - Fixed a bug in ipmmu_find_root() when only leaf devices are present - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices Changes since V1: - Moved patch to earlier in the series - Updated code to work with recent changes in: [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 95 1 file changed, 78 insertions(+), 17 deletions(-) --- 0015/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 13:59:41.050607110 +0900 @@ -36,6 +36,7 @@ struct ipmmu_features { bool use_ns_alias_offset; + bool has_cache_leaf_nodes; }; struct ipmmu_vmsa_device { @@ -44,6 +45,7 @@ struct ipmmu_vmsa_device { struct iommu_device iommu; struct list_head list; const struct ipmmu_features *features; + bool is_leaf; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); @@ -54,6 +56,7 @@ struct ipmmu_vmsa_device { struct ipmmu_vmsa_domain { struct ipmmu_vmsa_device *mmu; + struct ipmmu_vmsa_device *root; struct iommu_domain io_domain; struct io_pgtable_cfg cfg; @@ -203,6 +206,44 @@ static struct ipmmu_vmsa_iommu_priv *to_ #define IMUASID_ASID0_SHIFT0 /* - + * Root device handling + */ + +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu) +{ + if (mmu->features->has_cache_leaf_nodes) + return mmu->is_leaf ? false : true; + else + return true; /* older IPMMU hardware treated as single root */ +} + +static struct ipmmu_vmsa_device *__ipmmu_find_root(void) +{ + struct ipmmu_vmsa_device *mmu; + struct ipmmu_vmsa_device *root = NULL; + + spin_lock(_devices_lock); + + list_for_each_entry(mmu, _devices, list) { + if (ipmmu_is_root(mmu)) { + root = mmu; + break; + } + } + + spin_unlock(_devices_lock); + return root; +} + +static struct ipmmu_vmsa_device *ipmmu_find_root(struct ipmmu_vmsa_device *leaf) +{ + if (ipmmu_is_root(leaf)) + return leaf; + else + return __ipmmu_find_root(); +} + +/* - * Read/Write Access */ @@ -219,13 +260,13 @@ static void ipmmu_write(struct ipmmu_vms static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) { - return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg); + return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg); } static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, u32 data) { - ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data); + ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); } /* - @@ -360,7 +401,7 @@ static int ipmmu_domain_init_context(str * TODO: Add support for coherent walk through CCI with DVM and remove * cache handling. For now, delegate it to the io-pgtable code. */ - domain->cfg.iommu_dev = domain->mmu->dev; + domain->cfg.iommu_dev = domain->root->dev; domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, >cfg, domain); @@ -370,7 +411,7 @@ static int ipmmu_domain_init_context(str /* * Find an unused context. */ - ret = ipmmu_domain_allocate_context(domain->mmu, domain); + ret = ipmmu_domain_allocate_context(domain->root, domain); if (ret == IPMMU_CTX_MAX) { free_io_pgtable_ops(domain->iop); return -EBUSY; @@ -441,7 +482,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); + ipmmu_domain_free_context(domain->root, domain->context_id); } /* - @@ -555,7 +596,7 @@ static int ipmmu_attach_
Re: [PATCH 04/04] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids
Hi Geert, On Fri, Jun 16, 2017 at 4:18 PM, Geert Uytterhoeven <ge...@linux-m68k.org> wrote: > Hi Magnus, > > On Thu, Jun 15, 2017 at 12:29 PM, Magnus Damm <magnus.d...@gmail.com> wrote: >> Now when both 32-bit and 64-bit code inside the driver is using >> fwspec it is possible to replace the utlb handling with fwspec ids >> that get populated from ->of_xlate(). > > Thanks for your patch! Thanks for the feedback! >> --- 0013/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-15 18:32:27.580607110 +0900 > >> static int ipmmu_of_xlate(struct device *dev, >> struct of_phandle_args *spec) >> { >> - return ipmmu_init_platform_device(dev); >> + iommu_fwspec_add_ids(dev, spec->args, 1); > > Does it hurt if iommu_fwspec_add_ids() is called multiple times, as this is > done before the "Initialize once - xlate() will call multiple times" check? The function needs to be called several times to populate the ids, so that the "initialize once" check happens later is intentional and correct. Perhaps a bit unclear though... >> + >> + return ipmmu_init_platform_device(dev, spec); >> } Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 04/04] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids
From: Magnus Damm <damm+rene...@opensource.se> Now when both 32-bit and 64-bit code inside the driver is using fwspec it is possible to replace the utlb handling with fwspec ids that get populated from ->of_xlate(). Suggested-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c | 104 1 file changed, 19 insertions(+), 85 deletions(-) --- 0013/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-15 18:32:27.580607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -59,8 +60,6 @@ struct ipmmu_vmsa_domain { struct ipmmu_vmsa_iommu_priv { struct ipmmu_vmsa_device *mmu; - unsigned int *utlbs; - unsigned int num_utlbs; struct device *dev; struct list_head list; }; @@ -550,13 +549,14 @@ static int ipmmu_attach_device(struct io struct device *dev) { struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); + struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_device *mmu = priv->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned long flags; unsigned int i; int ret = 0; - if (!mmu) { + if (!priv || !priv->mmu) { dev_err(dev, "Cannot attach to IPMMU\n"); return -ENXIO; } @@ -583,8 +583,8 @@ static int ipmmu_attach_device(struct io if (ret < 0) return ret; - for (i = 0; i < priv->num_utlbs; ++i) - ipmmu_utlb_enable(domain, priv->utlbs[i]); + for (i = 0; i < fwspec->num_ids; ++i) + ipmmu_utlb_enable(domain, fwspec->ids[i]); return 0; } @@ -592,12 +592,12 @@ static int ipmmu_attach_device(struct io static void ipmmu_detach_device(struct iommu_domain *io_domain, struct device *dev) { - struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); + struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned int i; - for (i = 0; i < priv->num_utlbs; ++i) - ipmmu_utlb_disable(domain, priv->utlbs[i]); + for (i = 0; i < fwspec->num_ids; ++i) + ipmmu_utlb_disable(domain, fwspec->ids[i]); /* * TODO: Optimize by disabling the context when no device is attached. @@ -633,102 +633,36 @@ static phys_addr_t ipmmu_iova_to_phys(st return domain->iop->iova_to_phys(domain->iop, iova); } -static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, - unsigned int *utlbs, unsigned int num_utlbs) -{ - unsigned int i; - - for (i = 0; i < num_utlbs; ++i) { - struct of_phandle_args args; - int ret; - - ret = of_parse_phandle_with_args(dev->of_node, "iommus", -"#iommu-cells", i, ); - if (ret < 0) - return ret; - - of_node_put(args.np); - - if (args.np != mmu->dev->of_node || args.args_count != 1) - return -EINVAL; - - utlbs[i] = args.args[0]; - } - - return 0; -} - -static int ipmmu_init_platform_device(struct device *dev) +static int ipmmu_init_platform_device(struct device *dev, + struct of_phandle_args *args) { + struct platform_device *ipmmu_pdev; struct ipmmu_vmsa_iommu_priv *priv; - struct ipmmu_vmsa_device *mmu; - unsigned int *utlbs; - unsigned int i; - int num_utlbs; - int ret = -ENODEV; /* Initialize once - xlate() will call multiple times */ if (to_priv(dev)) return 0; - /* Find the master corresponding to the device. */ - - num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells"); - if (num_utlbs < 0) + ipmmu_pdev = of_find_device_by_node(args->np); + if (!ipmmu_pdev) return -ENODEV; - utlbs = kcalloc(num_utlbs, sizeof(*utlbs), GFP_KERNEL); - if (!utlbs) - return -ENOMEM; - - spin_lock(_devices_lock); - - list_for_each_entry(mmu, _devices, list) { - ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs); - if (!ret) { - /* -* TODO Take a reference to the MMU to protect -* against device removal. -*/ - break; - } - } - - spi
[PATCH 02/04] iommu/ipmmu-vmsa: Consistent ->of_xlate() handling
From: Magnus Damm <damm+rene...@opensource.se> The 32-bit ARM code gets updated to make use of ->of_xlate() and the code is shared between 64-bit and 32-bit ARM. The of_device_is_available() check gets dropped since it is included in of_iommu_xlate(). Suggested-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c | 51 ++-- 1 file changed, 17 insertions(+), 34 deletions(-) --- 0009/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-15 17:22:27.460607110 +0900 @@ -680,6 +680,10 @@ static int ipmmu_init_platform_device(st int num_utlbs; int ret = -ENODEV; + /* Initialize once - xlate() will call multiple times */ + if (to_priv(dev)) + return 0; + /* Find the master corresponding to the device. */ num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", @@ -734,6 +738,12 @@ error: return ret; } +static int ipmmu_of_xlate(struct device *dev, + struct of_phandle_args *spec) +{ + return ipmmu_init_platform_device(dev); +} + #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) static struct iommu_domain *ipmmu_domain_alloc(unsigned type) @@ -750,11 +760,11 @@ static int ipmmu_add_device(struct devic struct iommu_group *group; int ret; - if (to_priv(dev)) { - dev_warn(dev, "IOMMU driver already assigned to device %s\n", -dev_name(dev)); - return -EINVAL; - } + /* +* Only let through devices that have been verified in xlate() +*/ + if (!to_priv(dev)) + return -ENODEV; /* Create a device group and add the device to it. */ group = iommu_group_alloc(); @@ -773,10 +783,6 @@ static int ipmmu_add_device(struct devic goto error; } - ret = ipmmu_init_platform_device(dev); - if (ret < 0) - goto error; - /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate * VAs. This will allocate a corresponding IOMMU domain. @@ -817,24 +823,13 @@ error: if (!IS_ERR_OR_NULL(group)) iommu_group_remove_device(dev); - kfree(to_priv(dev)->utlbs); - kfree(to_priv(dev)); - set_priv(dev, NULL); - return ret; } static void ipmmu_remove_device(struct device *dev) { - struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); - arm_iommu_detach_device(dev); iommu_group_remove_device(dev); - - kfree(priv->utlbs); - kfree(priv); - - set_priv(dev, NULL); } static const struct iommu_ops ipmmu_ops = { @@ -849,6 +844,7 @@ static const struct iommu_ops ipmmu_ops .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, + .of_xlate = ipmmu_of_xlate, }; #endif /* !CONFIG_ARM && CONFIG_IOMMU_DMA */ @@ -958,19 +954,6 @@ static struct iommu_group *ipmmu_find_gr return group; } -static int ipmmu_of_xlate_dma(struct device *dev, - struct of_phandle_args *spec) -{ - /* If the IPMMU device is disabled in DT then return error -* to make sure the of_iommu code does not install ops -* even though the iommu device is disabled -*/ - if (!of_device_is_available(spec->np)) - return -ENODEV; - - return ipmmu_init_platform_device(dev); -} - static const struct iommu_ops ipmmu_ops = { .domain_alloc = ipmmu_domain_alloc_dma, .domain_free = ipmmu_domain_free_dma, @@ -984,7 +967,7 @@ static const struct iommu_ops ipmmu_ops .remove_device = ipmmu_remove_device_dma, .device_group = ipmmu_find_group_dma, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, - .of_xlate = ipmmu_of_xlate_dma, + .of_xlate = ipmmu_of_xlate, }; #endif /* CONFIG_IOMMU_DMA */ ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 03/04] iommu/ipmmu-vmsa: Use fwspec on both 32 and 64-bit ARM
From: Robin Murphy <robin.mur...@arm.com> Consolidate the 32-bit and 64-bit code to make use of fwspec instead of archdata for the 32-bit ARM case. This is a simplified version of the fwspec handling code from Robin posted as [PATCH] iommu/ipmmu-vmsa: Convert to iommu_fwspec Signed-off-by: Robin Murphy <robin.mur...@arm.com> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c | 21 +++-- 1 file changed, 3 insertions(+), 18 deletions(-) --- 0010/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-15 17:29:00.290607110 +0900 @@ -73,22 +73,9 @@ static struct ipmmu_vmsa_domain *to_vmsa return container_of(dom, struct ipmmu_vmsa_domain, io_domain); } - static struct ipmmu_vmsa_iommu_priv *to_priv(struct device *dev) { -#if defined(CONFIG_ARM) - return dev->archdata.iommu; -#else - return dev->iommu_fwspec->iommu_priv; -#endif -} -static void set_priv(struct device *dev, struct ipmmu_vmsa_iommu_priv *p) -{ -#if defined(CONFIG_ARM) - dev->archdata.iommu = p; -#else - dev->iommu_fwspec->iommu_priv = p; -#endif + return dev->iommu_fwspec ? dev->iommu_fwspec->iommu_priv : NULL; } #define TLB_LOOP_TIMEOUT 100 /* 100us */ @@ -730,7 +717,7 @@ static int ipmmu_init_platform_device(st priv->utlbs = utlbs; priv->num_utlbs = num_utlbs; priv->dev = dev; - set_priv(dev, priv); + dev->iommu_fwspec->iommu_priv = priv; return 0; error: @@ -887,14 +874,12 @@ static void ipmmu_domain_free_dma(struct static int ipmmu_add_device_dma(struct device *dev) { - struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct iommu_group *group; /* * Only let through devices that have been verified in xlate() -* We may get called with dev->iommu_fwspec set to NULL. */ - if (!fwspec || !fwspec->iommu_priv) + if (!to_priv(dev)) return -ENODEV; group = iommu_group_get_for_dev(dev); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 01/04] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister()
From: Magnus Damm <damm+rene...@opensource.se> Extend the driver to make use of iommu_device_register()/unregister() functions together with iommu_device_set_ops() and iommu_set_fwnode(). These used to be part of the earlier posted 64-bit ARM (r8a7795) series but it turns out that these days they are required on 32-bit ARM as well. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c | 10 ++ 1 file changed, 10 insertions(+) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-15 16:57:21.890607110 +0900 @@ -35,6 +35,7 @@ struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; + struct iommu_device iommu; struct list_head list; unsigned int num_utlbs; @@ -1054,6 +1055,13 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); + ret = iommu_device_register(>iommu); + if (ret) + return ret; + + iommu_device_set_ops(>iommu, _ops); + iommu_device_set_fwnode(>iommu, >dev.of_node->fwnode); + /* * We can't create the ARM mapping here as it requires the bus to have * an IOMMU, which only happens when bus_set_iommu() is called in @@ -1077,6 +1085,8 @@ static int ipmmu_remove(struct platform_ list_del(>list); spin_unlock(_devices_lock); + iommu_device_unregister(>iommu); + #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) arm_iommu_release_mapping(mmu->mapping); #endif ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update
iommu/ipmmu-vmsa: 32-bit ARM update [PATCH 01/04] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister() [PATCH 02/04] iommu/ipmmu-vmsa: Consistent ->of_xlate() handling [PATCH 03/04] iommu/ipmmu-vmsa: Use fwspec on both 32 and 64-bit ARM [PATCH 04/04] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids This series updates the IPMMU driver to make use of recent IOMMU framework changes and also improves code sharing in the driver between the 32-bit and 64-bit dma-mapping architecture glue code. Suggested-by: Robin Murphy <robin.mur...@arm.com> (Patch 2 and 4) Signed-off-by: Robin Murphy <robin.mur...@arm.com> (Patch 3) Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on renesas-drivers-2017-06-13-v4.12-rc5 and rebased to next-20170614 drivers/iommu/ipmmu-vmsa.c | 186 +++- 1 file changed, 49 insertions(+), 137 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC] iommu: Move over to unsigned int domain type
Hi Joerg, On Wed, May 17, 2017 at 10:18 PM, Joerg Roedel <j...@8bytes.org> wrote: > On Wed, May 17, 2017 at 07:29:12PM +0900, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Checkpatch dislikes the type unsigned, so update the iommu >> domain type and consumers to use unsigned int to reduce noise. > > And I hate stupid checkpatch warnings and refuse to fix them. This > clearly is one. Gotcha, fine by me! Let me know if there is anything more non-cosmetic in the IOMMU subsystem that you think would be more useful to spend cycles on. Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 06/08] iommu/ipmmu-vmsa: Use fwspec iommu_priv on ARM64
Hi Robin, On Wed, May 17, 2017 at 11:29 PM, Robin Murphy <robin.mur...@arm.com> wrote: > Hi Magnus, > > On 17/05/17 11:07, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Convert from archdata to iommu_priv via iommu_fwspec on ARM64 but >> let 32-bit ARM keep on using archdata for now. >> >> Once the 32-bit ARM code and the IPMMU driver is able to move over >> to CONFIG_IOMMU_DMA=y then coverting to fwspec via ->of_xlate() will >> be easy. >> >> For now fwspec ids and num_ids are not used to allow code sharing between >> 32-bit and 64-bit ARM code inside the driver. > > That's not what I meant at all - this just looks like a crazy > unmaintainable mess that's making things that much harder to unpick in > future. > > Leaving the existing code fossilised and building up half of a second > separate driver around it wrapped in ifdefs is not only hideous, it's > more work in the end than simply pulling things into the right shape to > begin with. What I meant was to start with the below (compile-tested > only), and add the of_xlate support on top. AFAICS the arm/arm64 > differences overall should only come down to a bit of special-casing in > add_device(), and (optionally) whether you outright reject > IOMMU_DOMAIN_DMA or not. > > Sorry, but I just can't agree with the two-drivers-in-one approach. Thanks for checking the code and sorry to disappoint you by not using ->ids[] and ->num_ids right away. The two-drivers-on-one approach comes from wanting to use the same IOMMU driver on both 32-bit and 64-bit ARM architectures but the former is lacking IOMMU_DMA support upstream. Obviously using ->ids[] and ->num_ids is the right forward, and in my mind it is only a question of time and merge order. I'm more than happy to make use of your patch but I'm wondering if it will work on 32-bit ARM and R-Car Gen2 that currently does not use ->of_xlate(). I can see that you're using iommu_fwspec_init() so it might work right out of the box. Thanks for your help cooking up the patch by the way. >From my side I was hoping on doing one larger feature jump for 32-bit ARM by moving over to IOMMU_DMA=y together with ->of_xlate()and fwspec at the same time. Doing minor increments of the legacy code that is still using special mapping code instead of OMMU_DMA=y in case of 32-bit ARM just feels like a lot of potential breakage and little gain to me. What's the plan for supporting IOMMU_DMA=y on 32-bit ARM? Anything I can do to help? Or do you prefer minor increments on 32-bit ARM over larger feature jumps? Let me know what you think. My plan is to revisit this topic early next week. Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC] iommu: Move over to unsigned int domain type
From: Magnus Damm <damm+rene...@opensource.se> Checkpatch dislikes the type unsigned, so update the iommu domain type and consumers to use unsigned int to reduce noise. $ ./scripts/checkpatch.pl ../linux-v4.13-pre-drivers-iommu-ipmmu-dma-ops-20170517b.patch WARNING: Prefer 'unsigned int' to bare use of 'unsigned' #89: FILE: drivers/iommu/ipmmu-vmsa.c:720: +static struct iommu_domain *ipmmu_domain_alloc(unsigned type) WARNING: Prefer 'unsigned int' to bare use of 'unsigned' #111: FILE: drivers/iommu/ipmmu-vmsa.c:844: +static struct iommu_domain *ipmmu_domain_alloc_dma(unsigned type) Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Untested for now. drivers/iommu/amd_iommu.c |2 +- drivers/iommu/arm-smmu-v3.c |2 +- drivers/iommu/arm-smmu.c|2 +- drivers/iommu/exynos-iommu.c|2 +- drivers/iommu/fsl_pamu_domain.c |2 +- drivers/iommu/intel-iommu.c |2 +- drivers/iommu/iommu.c |4 ++-- drivers/iommu/ipmmu-vmsa.c |2 +- drivers/iommu/msm_iommu.c |2 +- drivers/iommu/mtk_iommu.c |2 +- drivers/iommu/mtk_iommu_v1.c|2 +- drivers/iommu/omap-iommu.c |2 +- drivers/iommu/rockchip-iommu.c |2 +- drivers/iommu/s390-iommu.c |2 +- drivers/iommu/tegra-gart.c |2 +- drivers/iommu/tegra-smmu.c |2 +- include/linux/iommu.h |4 ++-- 17 files changed, 19 insertions(+), 19 deletions(-) --- 0001/drivers/iommu/amd_iommu.c +++ work/drivers/iommu/amd_iommu.c 2017-05-17 19:19:00.810607110 +0900 @@ -2940,7 +2940,7 @@ out_err: return NULL; } -static struct iommu_domain *amd_iommu_domain_alloc(unsigned type) +static struct iommu_domain *amd_iommu_domain_alloc(unsigned int type) { struct protection_domain *pdomain; struct dma_ops_domain *dma_domain; --- 0001/drivers/iommu/arm-smmu-v3.c +++ work/drivers/iommu/arm-smmu-v3.c2017-05-17 19:17:18.300607110 +0900 @@ -1381,7 +1381,7 @@ static bool arm_smmu_capable(enum iommu_ } } -static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) +static struct iommu_domain *arm_smmu_domain_alloc(unsigned int type) { struct arm_smmu_domain *smmu_domain; --- 0001/drivers/iommu/arm-smmu.c +++ work/drivers/iommu/arm-smmu.c 2017-05-17 19:17:35.410607110 +0900 @@ -1078,7 +1078,7 @@ static void arm_smmu_destroy_domain_cont __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); } -static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) +static struct iommu_domain *arm_smmu_domain_alloc(unsigned int type) { struct arm_smmu_domain *smmu_domain; --- 0001/drivers/iommu/exynos-iommu.c +++ work/drivers/iommu/exynos-iommu.c 2017-05-17 19:15:55.760607110 +0900 @@ -730,7 +730,7 @@ static inline void update_pte(sysmmu_pte DMA_TO_DEVICE); } -static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) +static struct iommu_domain *exynos_iommu_domain_alloc(unsigned int type) { struct exynos_iommu_domain *domain; dma_addr_t handle; --- 0001/drivers/iommu/fsl_pamu_domain.c +++ work/drivers/iommu/fsl_pamu_domain.c2017-05-17 19:15:19.190607110 +0900 @@ -416,7 +416,7 @@ static void fsl_pamu_domain_free(struct kmem_cache_free(fsl_pamu_domain_cache, dma_domain); } -static struct iommu_domain *fsl_pamu_domain_alloc(unsigned type) +static struct iommu_domain *fsl_pamu_domain_alloc(unsigned int type) { struct fsl_dma_domain *dma_domain; --- 0001/drivers/iommu/intel-iommu.c +++ work/drivers/iommu/intel-iommu.c2017-05-17 19:14:56.520607110 +0900 @@ -5021,7 +5021,7 @@ static int md_domain_init(struct dmar_do return 0; } -static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) +static struct iommu_domain *intel_iommu_domain_alloc(unsigned int type) { struct dmar_domain *dmar_domain; struct iommu_domain *domain; --- 0001/drivers/iommu/iommu.c +++ work/drivers/iommu/iommu.c 2017-05-17 19:20:48.720607110 +0900 @@ -105,7 +105,7 @@ void iommu_device_unregister(struct iomm } static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, -unsigned type); +unsigned int type); static int __iommu_attach_device(struct iommu_domain *domain, struct device *dev); static int __iommu_attach_group(struct iommu_domain *domain, @@ -1255,7 +1255,7 @@ void iommu_set_fault_handler(struct iomm EXPORT_SYMBOL_GPL(iommu_set_fault_handler); static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, -unsigned type) +unsigned int type) { struct iommu_domain *domain; --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 19:13:42.3106071
[PATCH v8 07/08] iommu/ipmmu-vmsa: Drop LPAE Kconfig dependency
From: Magnus Damm <damm+rene...@opensource.se> Neither 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 <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V7: - None drivers/iommu/Kconfig |1 - 1 file changed, 1 deletion(-) --- 0010/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2017-05-17 16:45:15.530607110 +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 v8 08/08] iommu/ipmmu-vmsa: Fix pgsize_bitmap semicolon typo
From: Magnus Damm <damm+rene...@opensource.se> Fix comma-instead-of-semicolon typo error present in the latest version of the IPMMU driver. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Earlier posted as: [PATCH] iommu/ipmmu-vmsa: Fix pgsize_bitmap semicolon typo drivers/iommu/ipmmu-vmsa.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- 0014/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:50:02.850607110 +0900 @@ -358,7 +358,7 @@ static int ipmmu_domain_init_context(str * non-secure mode. */ domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS; - domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, + domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K; domain->cfg.ias = 32; domain->cfg.oas = 40; domain->cfg.tlb = _gather_ops; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v8 06/08] iommu/ipmmu-vmsa: Use fwspec iommu_priv on ARM64
From: Magnus Damm <damm+rene...@opensource.se> Convert from archdata to iommu_priv via iommu_fwspec on ARM64 but let 32-bit ARM keep on using archdata for now. Once the 32-bit ARM code and the IPMMU driver is able to move over to CONFIG_IOMMU_DMA=y then coverting to fwspec via ->of_xlate() will be easy. For now fwspec ids and num_ids are not used to allow code sharing between 32-bit and 64-bit ARM code inside the driver. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V7: - Rewrote code to use iommu_fwspec, thanks Robin! - Dropped reviewed-by from Joerg, also skipped tag from Geert drivers/iommu/ipmmu-vmsa.c | 97 ++-- 1 file changed, 58 insertions(+), 39 deletions(-) --- 0011/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:45:07.510607110 +0900 @@ -56,7 +56,7 @@ struct ipmmu_vmsa_domain { spinlock_t lock;/* Protects mappings */ }; -struct ipmmu_vmsa_archdata { +struct ipmmu_vmsa_iommu_priv { struct ipmmu_vmsa_device *mmu; unsigned int *utlbs; unsigned int num_utlbs; @@ -72,6 +72,24 @@ static struct ipmmu_vmsa_domain *to_vmsa return container_of(dom, struct ipmmu_vmsa_domain, io_domain); } + +static struct ipmmu_vmsa_iommu_priv *to_priv(struct device *dev) +{ +#if defined(CONFIG_ARM) + return dev->archdata.iommu; +#else + return dev->iommu_fwspec->iommu_priv; +#endif +} +static void set_priv(struct device *dev, struct ipmmu_vmsa_iommu_priv *p) +{ +#if defined(CONFIG_ARM) + dev->archdata.iommu = p; +#else + dev->iommu_fwspec->iommu_priv = p; +#endif +} + #define TLB_LOOP_TIMEOUT 100 /* 100us */ /* - @@ -543,8 +561,8 @@ 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_device *mmu = archdata->mmu; + struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev); + struct ipmmu_vmsa_device *mmu = priv->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned long flags; unsigned int i; @@ -577,8 +595,8 @@ static int ipmmu_attach_device(struct io if (ret < 0) return ret; - for (i = 0; i < archdata->num_utlbs; ++i) - ipmmu_utlb_enable(domain, archdata->utlbs[i]); + for (i = 0; i < priv->num_utlbs; ++i) + ipmmu_utlb_enable(domain, priv->utlbs[i]); return 0; } @@ -586,12 +604,12 @@ 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_iommu_priv *priv = to_priv(dev); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); unsigned int i; - for (i = 0; i < archdata->num_utlbs; ++i) - ipmmu_utlb_disable(domain, archdata->utlbs[i]); + for (i = 0; i < priv->num_utlbs; ++i) + ipmmu_utlb_disable(domain, priv->utlbs[i]); /* * TODO: Optimize by disabling the context when no device is attached. @@ -654,7 +672,7 @@ static int ipmmu_find_utlbs(struct ipmmu static int ipmmu_init_platform_device(struct device *dev) { - struct ipmmu_vmsa_archdata *archdata; + struct ipmmu_vmsa_iommu_priv *priv; struct ipmmu_vmsa_device *mmu; unsigned int *utlbs; unsigned int i; @@ -697,17 +715,17 @@ static int ipmmu_init_platform_device(st } } - archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); - if (!archdata) { + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { ret = -ENOMEM; goto error; } - archdata->mmu = mmu; - archdata->utlbs = utlbs; - archdata->num_utlbs = num_utlbs; - archdata->dev = dev; - dev->archdata.iommu = archdata; + priv->mmu = mmu; + priv->utlbs = utlbs; + priv->num_utlbs = num_utlbs; + priv->dev = dev; + set_priv(dev, priv); return 0; error: @@ -727,12 +745,11 @@ static struct iommu_domain *ipmmu_domain 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_priv(dev)) { dev_warn(dev, "IOMMU driver already assigned to device %s\n", dev_name(dev)); retur
[PATCH v8 04/08] iommu/ipmmu-vmsa: Break out domain allocation code
From: Magnus Damm <damm+rene...@opensource.se> Break out the domain allocation code into a separate function. This is preparation for future code sharing. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> Reviewed-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V7: - Added Reviewed-by from Geert - Thanks! drivers/iommu/ipmmu-vmsa.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) --- 0006/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:39:05.380607110 +0900 @@ -509,13 +509,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; @@ -525,6 +522,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 v8 01/08] iommu/ipmmu-vmsa: Remove platform data handling
From: Magnus Damm <damm+rene...@opensource.se> The 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 <damm+rene...@opensource.se> Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Reviewed-by: Joerg Roedel <jroe...@suse.de> Reviewed-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V7: - Added Reviewed-by from Geert - Thanks! drivers/iommu/ipmmu-vmsa.c |5 - 1 file changed, 5 deletions(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:30:57.620607110 +0900 @@ -768,11 +768,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 v8 00/08] iommu/ipmmu-vmsa: IPMMU multi-arch update V8
iommu/ipmmu-vmsa: IPMMU multi-arch update V8 [PATCH v8 01/08] iommu/ipmmu-vmsa: Remove platform data handling [PATCH v8 02/08] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context [PATCH v8 03/08] iommu/ipmmu-vmsa: Break out utlb parsing code [PATCH v8 04/08] iommu/ipmmu-vmsa: Break out domain allocation code [PATCH v8 05/08] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops [PATCH v8 06/08] iommu/ipmmu-vmsa: Use fwspec iommu_priv on ARM64 [PATCH v8 07/08] iommu/ipmmu-vmsa: Drop LPAE Kconfig dependency [PATCH v8 08/08] iommu/ipmmu-vmsa: Fix pgsize_bitmap semicolon typo These patches update the IPMMU driver with a modifications to support build on multiple architectures. In the process of doing so the interrupt code gets reworked, the foundation for supporting multiple contexts are added and in case of CONFIG_IOMMU_DMA=y (on 64-bit or 32-bit ARM) devices are grouped together and handled via ->xlate(). In this verison fwspec is used on 64-bit ARM instead of archdata. Support for existing 32-bit ARM SoCs from R-Car Gen2 is kept as-is. Changes since V7: - Rebased on top of v4.12-rc1 - Added Reviewed-by from Geert to patch 1/8 and 4/8, thanks! - Reworked patch 6/8 to use fwspec, thanks Robin! - Added patch 8/8 Changes since V6: - Rebased on top of v4.11-rc1 and the following fast-tracked change: 3b6bb5b iommu/ipmmu-vmsa: Restrict IOMMU Domain Geometry to 32-bit address spac - Updated patch 5/7 to roll in a few patches from other series See individual patch for more details - Build tested on 32-bit and 64-bit ARM - Run time tested on 64-bit ARM (with additional SoC-specific patches) Changes since V5: - Rebased series on top of next-20161019 - Updated patch 5/7 to simplify domain allocation/free code - thanks Joerg! - Added reviewed-by tag from Joerg for patch 1-4 and 6-7. 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> --- Developed on top of a95cfad (v4.12-rc1 + fixes): Compile tested on 32-bit and 64-bit ARM Run time tested on 64-bit ARM r8a7796 Salvator-X drivers/iommu/Kconfig |2 drivers/iommu/ipmmu-vmsa.c | 421 ++-- 2 files changed, 331 insertions(+), 92 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v8 02/08] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context
From: Magnus Damm <damm+rene...@opensource.se> Introduce 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 <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V7: - None drivers/iommu/ipmmu-vmsa.c | 76 ++-- 1 file changed, 66 insertions(+), 10 deletions(-) --- 0002/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:33:02.380607110 +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. @@ -327,10 +353,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]; @@ -372,6 +403,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) { /* @@ -382,6 +426,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); } /* - @@ -439,16 +484,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); - return ipmmu_domain_irq(domain); + return status; } /* - @@ -776,6 +830,8 @@ static int ipmmu_probe(struct platform_d mmu->dev = >dev; mmu->num_utlbs = 32; + spin_lock_init(>lock); + bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v8 05/08] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops
From: Magnus Damm <damm+rene...@opensource.se> Introduce 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. Initialize the device from ->xlate() when CONFIG_IOMMU_DMA=y. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V7: - None drivers/iommu/Kconfig |1 drivers/iommu/ipmmu-vmsa.c | 164 +--- 2 files changed, 156 insertions(+), 9 deletions(-) --- 0001/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2017-05-17 16:41:43.030607110 +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 --- 0009/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:42:02.730607110 +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" @@ -57,6 +60,8 @@ struct ipmmu_vmsa_archdata { struct ipmmu_vmsa_device *mmu; unsigned int *utlbs; unsigned int num_utlbs; + struct device *dev; + struct list_head list; }; static DEFINE_SPINLOCK(ipmmu_devices_lock); @@ -522,14 +527,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); @@ -572,7 +569,8 @@ static int ipmmu_attach_device(struct io dev_err(dev, "Can't attach IPMMU %s to domain on IPMMU %s\n", dev_name(mmu->dev), dev_name(domain->mmu->dev)); ret = -EINVAL; - } + } else + dev_info(dev, "Reusing IPMMU context %u\n", domain->context_id); spin_unlock_irqrestore(>lock, flags); @@ -708,6 +706,7 @@ static int ipmmu_init_platform_device(st archdata->mmu = mmu; archdata->utlbs = utlbs; archdata->num_utlbs = num_utlbs; + archdata->dev = dev; dev->archdata.iommu = archdata; return 0; @@ -716,6 +715,16 @@ error: return ret; } +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) + +static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +{ + if (type != IOMMU_DOMAIN_UNMANAGED) + return NULL; + + return __ipmmu_domain_alloc(type); +} + static int ipmmu_add_device(struct device *dev) { struct ipmmu_vmsa_archdata *archdata; @@ -825,6 +834,141 @@ 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 DEFINE_SPINLOCK(ipmmu_slave_devices_lock); +static LIST_HEAD(ipmmu_slave_devices); + +static struct iommu_domain *ipmmu_domain_alloc_dma(unsigned type) +{ + struct iommu_domain *io_domain = NULL; + + switch (type) { + case IOMMU_DOMAIN_UNMANAGED: + io_domain = __ipmmu_domain_alloc(type); + break; + + case IOMMU_DOMAIN_DMA: + io_domain = __ipmmu_domain_alloc(type); + if (io_domain) + iommu_get_dma_cookie(io_domain); + break; + } + + return io_domain; +} + +static void ipmmu_domain_free_dma(struct iommu_domain *io_domain) +{ + switch (io_domain->type) { + case IOMMU_DOMAIN_DMA: + iommu_put_dma_cookie(io_domain); + /* fall-through */ + default: + ipmmu_domain_free(io_domain); + break; + } +} + +static int ipmmu_add_device_dma(struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct iommu_group *group; + + /* The device has been verified in xlate() */ + if (!archdata) + return -ENODEV; + + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) + return PTR_ERR(group); + + spin_lock(_slave_devices_lock); + list_add(>list, _slave_devices); + spin_unlock(_slave_devices_lock); + return 0; +} + +static void ipmmu_remove_device_dma(struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + + spin_lock(_slave_devices_lock); + list_del(>list); + spin_unlock(_slave_devices_lock); + + iommu_group_remo
[PATCH v8 03/08] iommu/ipmmu-vmsa: Break out utlb parsing code
From: Magnus Damm <damm+rene...@opensource.se> Break 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 <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V7: - Free archdata and utlbs in case of error drivers/iommu/ipmmu-vmsa.c | 64 1 file changed, 41 insertions(+), 23 deletions(-) --- 0004/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-05-17 16:37:29.080607110 +0900 @@ -649,22 +649,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", @@ -701,6 +694,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)) { @@ -718,16 +741,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 @@ -738,6 +754,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; @@ -762,16 +780,16 @@ static int ipmmu_add_device(struct devic return 0; error: - arm_iommu_release_mapping(mmu->mapping); - - kfree(dev->archdata.iommu); - kfree(utlbs); - - dev->archdata.iommu = NULL; + if (mmu) + arm_iommu_release_mapping(mmu->mapping); if (!IS_ERR_OR_NULL(group)) iommu_group_remove_device(dev); + kfree(archdata->utlbs); + kfree(archdata); + dev->archdata.iommu = NULL; + return ret; } ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH V8 07/11] iommu: of: Handle IOMMU lookup failure with deferred probing or error
Hi Geert, everyone, On Fri, May 5, 2017 at 10:23 PM, Geert Uytterhoevenwrote: > Hi Sricharan, Robin, > > On Wed, May 3, 2017 at 12:24 PM, Sricharan R wrote: >> On 5/3/2017 3:24 PM, Robin Murphy wrote: >>> On 02/05/17 19:35, Geert Uytterhoeven wrote: On Fri, Feb 3, 2017 at 4:48 PM, Sricharan R wrote: > From: Laurent Pinchart > > Failures to look up an IOMMU when parsing the DT iommus property need to > be handled separately from the .of_xlate() failures to support deferred > probing. > > The lack of a registered IOMMU can be caused by the lack of a driver for > the IOMMU, the IOMMU device probe not having been performed yet, having > been deferred, or having failed. > > The first case occurs when the device tree describes the bus master and > IOMMU topology correctly but no device driver exists for the IOMMU yet > or the device driver has not been compiled in. Return NULL, the caller > will configure the device without an IOMMU. > > The second and third cases are handled by deferring the probe of the bus > master device which will eventually get reprobed after the IOMMU. > > The last case is currently handled by deferring the probe of the bus > master device as well. A mechanism to either configure the bus master > device without an IOMMU or to fail the bus master device probe depending > on whether the IOMMU is optional or mandatory would be a good > enhancement. > > Tested-by: Marek Szyprowski > Signed-off-by: Laurent Pichart > Signed-off-by: Sricharan R This patch broke Renesas R-Car Gen3 platforms in renesas-drivers. As the IOMMU nodes in DT are not yet enabled, all devices having iommus properties in DT now fail to probe. >>> >>> How exactly do they fail to probe? Per d7b0558230e4, if there are no ops >>> registered then they should merely defer until we reach the point of >>> giving up and ignoring the IOMMU. Is it just that you have no other >>> late-probing drivers or post-init module loads to kick the deferred >>> queue after that point? I did try to find a way to explicitly kick it >>> from a suitably late initcall, but there didn't seem to be any obvious >>> public interface - anyone have any suggestions? >>> >>> I think that's more of a general problem with the probe deferral >>> mechanism itself (I've seen the same thing happen with some of the >>> CoreSight stuff on Juno due to the number of inter-component >>> dependencies) rather than any specific fault of this series. > > I had a deeper look into the issue. > > What changed, is that of_dma_configure() now returns an error code, > and dma_configure() looks at it. > > Actually there are two failure modes: > 1. Devices with an iommus property pointing to a disabled IOMMU node. > These return -EPROBE_DEFER, and are now retried forever. > 2. Devices that are blacklisted in the IPMMU driver, as we don't want to > use them with an IOMMU yet. > These return -ENODEV, due to ipmmu_of_xlate_dma(). > >> I was thinking of an additional check like below to avoid the >> situation ? >> >> From 499b6e662f60f23740b8880882b0a16f16434501 Mon Sep 17 00:00:00 2001 >> From: Sricharan R >> Date: Wed, 3 May 2017 13:16:59 +0530 >> Subject: [PATCH] iommu: of: Fix check for returning EPROBE_DEFER >> >> While returning EPROBE_DEFER for iommu masters >> take in to account of iommu nodes that could be >> marked in DT as 'status=disabled', in which case >> simply return NULL and let the master's probe >> continue rather than deferring. >> >> Signed-off-by: Sricharan R >> --- >> drivers/iommu/of_iommu.c | 1 + >> 1 file changed, 1 insertion(+) >> >> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c >> index 9f44ee8..e6e9bec 100644 >> --- a/drivers/iommu/of_iommu.c >> +++ b/drivers/iommu/of_iommu.c >> @@ -118,6 +118,7 @@ static bool of_iommu_driver_present(struct device_node >> *np) >> >> ops = iommu_ops_from_fwnode(fwnode); >> if ((ops && !ops->of_xlate) || >> + !of_device_is_available(iommu_spec->np) || >> (!ops && !of_iommu_driver_present(iommu_spec->np))) >> return NULL; > > Thanks, this fixes the first class of failures. > > The second class can be worked around using: > > --- a/drivers/iommu/of_iommu.c > +++ b/drivers/iommu/of_iommu.c > @@ -196,6 +196,11 @@ static const struct iommu_ops > ops = of_iommu_xlate(dev, _spec); > of_node_put(iommu_spec.np); > idx++; > + if (PTR_ERR(ops) == -ENODEV) { > + dev_info(dev, "%s: Ignoring -ENODEV => NULL\n", > +__func__);
[PATCH] iommu/ipmmu-vmsa: Fix pgsize_bitmap semicolon typo
From: Magnus Damm <damm+rene...@opensource.se> Fix comman-instead-of-semicolon typo error present in the latest version of the IPMMU driver. Will in the future be rolled into next driver update. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Applies on top of renesas-drivers-2017-04-18-v4.11-rc7 or -next plus: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 [PATCH v3 00/09] iommu/ipmmu-vmsa: r8a7795 support V3 [PATCH v3 0/3] iommu/ipmmu-vmsa: r8a7796 support V3 drivers/iommu/ipmmu-vmsa.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-04-20 22:30:07.000607110 +0900 @@ -431,7 +431,7 @@ static int ipmmu_domain_init_context(str * non-secure mode. */ domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS; - domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, + domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K; domain->cfg.ias = 32; domain->cfg.oas = 40; domain->cfg.tlb = _gather_ops; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48
From: Magnus Damm <damm+rene...@opensource.se> Bump up the maximum numbers of micro-TLBS to 48. Each IPMMU device instance get micro-TLB assignment via the "iommus" property in DT. Older SoCs tend to use a maximum number of 32 micro-TLBs per IPMMU instance however newer SoCs such as r8a7796 make use of up to 48 micro-TLBs. At this point no SoC specific handling is done to validate the maximum number of micro-TLBs, and because of that the DT information is assumed to be within correct range for each particular SoC. If needed in the future SoC specific feature flags can be added to handle the maximum number of micro-TLBs without requiring DT changes, however at this point this does not seem necessary. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V2: - Added outer set of () to IMUASID() and IMUCTR() - thanks Ramesh! - Added Reviewed-by from Geert - thanks! Changes since V1: - Added support for the second I/O range at 0x600. drivers/iommu/ipmmu-vmsa.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) --- 0020/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-12 14:11:23.020607110 +0900 @@ -213,7 +213,9 @@ static void set_archdata(struct device * #define IMPMBA(n) (0x0280 + ((n) * 4)) #define IMPMBD(n) (0x02c0 + ((n) * 4)) -#define IMUCTR(n) (0x0300 + ((n) * 16)) +#define IMUCTR(n) ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n)) +#define IMUCTR0(n) (0x0300 + ((n) * 16)) +#define IMUCTR32(n)(0x0600 + (((n) - 32) * 16)) #define IMUCTR_FIXADDEN(1 << 31) #define IMUCTR_FIXADD_MASK (0xff << 16) #define IMUCTR_FIXADD_SHIFT16 @@ -223,7 +225,9 @@ static void set_archdata(struct device * #define IMUCTR_FLUSH (1 << 1) #define IMUCTR_MMUEN (1 << 0) -#define IMUASID(n) (0x0308 + ((n) * 16)) +#define IMUASID(n) ((n) < 32 ? IMUASID0(n) : IMUASID32(n)) +#define IMUASID0(n)(0x0308 + ((n) * 16)) +#define IMUASID32(n) (0x0608 + (((n) - 32) * 16)) #define IMUASID_ASID8_MASK (0xff << 8) #define IMUASID_ASID8_SHIFT8 #define IMUASID_ASID0_MASK (0xff << 0) @@ -1164,7 +1168,7 @@ static int ipmmu_probe(struct platform_d } mmu->dev = >dev; - mmu->num_utlbs = 32; + mmu->num_utlbs = 48; spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = match->data; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code
From: Magnus Damm <damm+rene...@opensource.se> Support the r8a7796 IPMMU by sharing feature flags between r8a7795 and r8a7796. Also update IOMMU_OF_DECLARE to hook up the updated compat string. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Updated to include white list suppport Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 14 ++ 1 file changed, 10 insertions(+), 4 deletions(-) --- 0024/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-12 14:14:32.550607110 +0900 @@ -1058,8 +1058,9 @@ static bool ipmmu_slave_whitelist(struct return false; } -static const struct soc_device_attribute soc_r8a7795[] = { +static const struct soc_device_attribute soc_rcar_gen3[] = { { .soc_id = "r8a7795", }, + { .soc_id = "r8a7796", }, { /* sentinel */ } }; @@ -1082,7 +1083,7 @@ static int ipmmu_of_xlate_dma(struct dev } /* For R-Car Gen3 use a white list to opt-in slave devices */ - if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev)) return -ENODEV; return ipmmu_init_platform_device(dev); @@ -1127,7 +1128,7 @@ static const struct ipmmu_features ipmmu .twobit_imttbcr_sl0 = false, }; -static const struct ipmmu_features ipmmu_features_r8a7795 = { +static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .use_ns_alias_offset = false, .has_cache_leaf_nodes = true, .has_eight_ctx = true, @@ -1141,7 +1142,10 @@ static const struct of_device_id ipmmu_o .data = _features_default, }, { .compatible = "renesas,ipmmu-r8a7795", - .data = _features_r8a7795, + .data = _features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a7796", + .data = _features_rcar_gen3, }, { /* Terminator */ }, @@ -1333,6 +1337,8 @@ IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "r ipmmu_vmsa_iommu_of_setup); IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795", ipmmu_vmsa_iommu_of_setup); +IOMMU_OF_DECLARE(ipmmu_r8a7796_iommu_of, "renesas,ipmmu-r8a7796", +ipmmu_vmsa_iommu_of_setup); #endif MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 0/3] iommu/ipmmu-vmsa: r8a7796 support V3
iommu/ipmmu-vmsa: r8a7796 support V3 [PATCH v3 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding [PATCH v3 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48 [PATCH v3 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code This series adds r8a7796 support to the IPMMU driver. The DT binding gets updated, maximum number of micro-TLBs are increased and the driver is adjusted to match on the new DT binding. Changes since V2: - Patch 2/3 updated with an outer set of () - thanks Ramesh! - Patch 2/3 updated with Reviewed-by - thanks Geert! - Patch 3/3 updated to include white list support Changes since V1: - Patch 1/3 updated with more Acked-by tags - Patch 2/3 updated with high I/O register range support Patch 1/3 is ready for upstream merge and includes the following tags: Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> Patch 2/3 and 3/3 are quite trivial but have now acked-by so far. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of v4.11-rc1 with the following series applied: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 [PATCH v3 00/09] iommu/ipmmu-vmsa: r8a7795 support V3 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 drivers/iommu/ipmmu-vmsa.c | 24 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding
From: Magnus Damm <damm+rene...@opensource.se> Update the IPMMU DT binding documentation to include the r8a7796 compat string for R-Car M3-W. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Acked-by: Rob Herring <r...@kernel.org> Acked-by: Simon Horman <horms+rene...@verge.net.au> Acked-by: Geert Uytterhoeven <geert+rene...@glider.be> --- Changes since V2: - None Changes since V1: - Included in series, added Acked-by from Geert - thanks! Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 + 1 file changed, 1 insertion(+) --- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 2017-03-12 14:09:01.920607110 +0900 @@ -16,6 +16,7 @@ Required Properties: - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. +- "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 02/09] iommu/ipmmu-vmsa: Add optional root device feature
Hi Geert, On Wed, Mar 8, 2017 at 10:47 PM, Geert Uytterhoeven <ge...@linux-m68k.org> wrote: > Hi Magnus, > > On Wed, Mar 8, 2017 at 12:01 PM, Magnus Damm <magnus.d...@gmail.com> wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Add root device handling to the IPMMU driver by allowing certain >> DT compat strings to enable has_cache_leaf_nodes that in turn will >> support both root devices with interrupts and leaf devices that >> face the actual IPMMU consumer devices. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> > >> --- 0011/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 17:56:51.770607110 +0900 > >> @@ -216,6 +219,44 @@ static void set_archdata(struct device * >> #define IMUASID_ASID0_SHIFT0 >> >> /* >> - >> + * Root device handling >> + */ >> + >> +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu) >> +{ >> + if (mmu->features->has_cache_leaf_nodes) >> + return mmu->is_leaf ? false : true; > > Expressions using the ternary operator are sometimes hard to read. > In this case, you want negation, so why not use that? > > return !mmu->is_leaf; > >> + else > > I'd drop the else. Yeah, your suggestion makes the code easier to read. Will fix. >> + return true; /* older IPMMU hardware treated as single root >> */ >> +} >> + >> +static struct ipmmu_vmsa_device *__ipmmu_find_root(void) >> +{ >> + struct ipmmu_vmsa_device *mmu; >> + bool found = false; > > struct ipmmu_vmsa_device *root = NULL; I used to have it initialized to NULL and not use any found variable and only return the variable. But then I ran into the error case when devices exist on the ipmmu_devices list however none of them are root. I returned the last one on the list regardless if they were root or not. So I updated the code to use the found variable, and because of that I thought I could simply drop the NULL assignment. >> + >> + spin_lock(_devices_lock); >> + >> + list_for_each_entry(mmu, _devices, list) { >> + if (ipmmu_is_root(mmu)) { >> + found = true; > > root = mmu; > >> + break; >> + } >> + } >> + >> + spin_unlock(_devices_lock); >> + return found ? mmu : NULL; > > return root; I agree it makes sense to use root as variable name, will fix. Not sure about the NULL assignment though, can you enlighten me? Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
Hi Geert, On Wed, Mar 8, 2017 at 10:58 PM, Geert Uytterhoeven <ge...@linux-m68k.org> wrote: > Hi Magnus, > > On Wed, Mar 8, 2017 at 12:02 PM, Magnus Damm <magnus.d...@gmail.com> wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Tie in r8a7795 features and update the IOMMU_OF_DECLARE >> compat string to include the updated compat string. >> >> TODO: >> - Consider making use of iommu_fwspec_add_ids() for uTLB handling >> Needed to coexist with non-OF R-Car Gen2 somehow... >> - Break out stuff useful for R-Car Gen2 from this series >> Fix up the Gen2 IPMMU support code >>and/or >> Fold more stuff into the multi-arch series >> - Add support for sysfs and iommu_device_link()/unlink() >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> > >> --- 0018/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 19:11:53.600607110 +0900 > >> @@ -1043,6 +1048,17 @@ static struct iommu_group *ipmmu_find_gr >> return group; >> } >> >> +static bool ipmmu_slave_whitelist(struct device *dev) >> +{ >> + /* By default, do not allow use of IPMMU */ >> + return false; >> +} >> + >> +static const struct soc_device_attribute soc_r8a7795[] = { >> + { .soc_id = "r8a7795", }, > > If/when the whitelist is/becomes device/revision specific, you probably want > to store a pointer to the *_slave_whitelist() function in the .data member? Yeah, for sure. It is a bit early to tell exactly how the code will look like at this point, but I think it will become more clear in the future. Just want to send out a new version of r8a7796 IPMMU support and some r8a7795 DT integration to get a coherent working set of patch series out of the door first. >> + { /* sentinel */ } >> +}; >> + >> static int ipmmu_of_xlate_dma(struct device *dev, >> struct of_phandle_args *spec) >> { >> @@ -1053,6 +1069,18 @@ static int ipmmu_of_xlate_dma(struct dev >> if (!of_device_is_available(spec->np)) >> return -ENODEV; >> >> + /* Failing in ->attach_device() results in a hang, so make >> +* sure the root device is installed before going there >> +*/ >> + if (!__ipmmu_find_root()) { >> + dev_info(dev, "Unable to locate IPMMU root device\n"); > > dev_err? Good idea. Will fix. >> + return -ENODEV; >> + } >> + >> + /* For R-Car Gen3 use a white list to opt-in slave devices */ >> + if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) >> + return -ENODEV; This will have to be updated for r8a7796 somehow as well. Thanks for your help! Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 03/09] iommu/ipmmu-vmsa: Enable multi context support
Hi Robin, Thanks for your feedback! On Wed, Mar 8, 2017 at 9:21 PM, Robin Murphy <robin.mur...@arm.com> wrote: > On 08/03/17 11:01, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Add support for up to 8 contexts. Each context is mapped to one >> domain. One domain is assigned one or more slave devices. Contexts >> are allocated dynamically and slave devices are grouped together >> based on which IPMMU device they are connected to. This makes slave >> devices tied to the same IPMMU device share the same IOVA space. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> --- >> >> Changes since V2: >> - Updated patch description to reflect code included in: >>[PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 >> >> Changes since V1: >> - Support up to 8 contexts instead of 4 >> - Use feature flag and runtime handling >> - Default to single context >> >> drivers/iommu/ipmmu-vmsa.c | 38 ++ >> 1 file changed, 30 insertions(+), 8 deletions(-) >> >> --- 0012/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 17:59:19.900607110 +0900 >> @@ -30,11 +30,12 @@ >> >> #include "io-pgtable.h" >> >> -#define IPMMU_CTX_MAX 1 >> +#define IPMMU_CTX_MAX 8 >> >> struct ipmmu_features { >> bool use_ns_alias_offset; >> bool has_cache_leaf_nodes; >> + bool has_eight_ctx; > > Wouldn't it be more sensible to just encode a number of contexts > directly, if it isn't reported by the hardware itself? I'm just > imagining future hardware generations... :P > > bool also_has_another_eight_ctx_on_top_of_that; > bool wait_no_this_is_the_one_where_ctx_15_isnt_usable; =) Sure, I agree with you! Please note that this is currently a mix of software and hardware policy. On R-Car Gen2 (ARM32) the legacy code only uses a single context for now but 4 contexts are supported by hardware according to the data sheet. The remaining 3 contexts are untested at this point. For R-Car Gen3 (ARM64) the hardware supports 8 contexts and this patch enables all of them. >> }; >> >> struct ipmmu_vmsa_device { >> @@ -44,6 +45,7 @@ struct ipmmu_vmsa_device { >> const struct ipmmu_features *features; >> bool is_leaf; >> unsigned int num_utlbs; >> + unsigned int num_ctx; >> spinlock_t lock;/* Protects ctx and domains[] >> */ >> DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); >> struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; >> @@ -376,11 +378,12 @@ static int ipmmu_domain_allocate_context >> >> spin_lock_irqsave(>lock, flags); >> >> - ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); >> - if (ret != IPMMU_CTX_MAX) { >> + ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx); >> + if (ret != mmu->num_ctx) { >> mmu->domains[ret] = domain; >> set_bit(ret, mmu->ctx); > > Using test_and_set_bit() in a loop would avoid having to take a lock here. So you mean that in case of test_and_set_bit() returns 1 then we try find_first_zero_bit() again? This is not really a performance sensitive part of the driver, so I'm currently optimizing for code readability. I'm of course all for dropping the lock, but I have a hard time figuring out how your suggestion could result in semi-readable code. Any pointers? =) >> @@ -1112,6 +1123,17 @@ static int ipmmu_probe(struct platform_d >> if (mmu->features->use_ns_alias_offset) >> mmu->base += IM_NS_ALIAS_OFFSET; >> >> + /* >> + * The number of contexts varies with generation and instance. >> + * Newer SoCs get a total of 8 contexts enabled, older ones just one. >> + */ >> + if (mmu->features->has_eight_ctx) >> + mmu->num_ctx = 8; >> + else >> + mmu->num_ctx = 1; >> + >> + WARN_ON(mmu->num_ctx > IPMMU_CTX_MAX); > > The likelihood of that happening doesn't appear to warrant a runtime > check. Especially one which probably isn't even generated because it's > trivially resolvable to "if (false)..." at compile time. Sure, I agree. Will drop. Thanks, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias
Hi Robin, On Wed, Mar 8, 2017 at 8:53 PM, Robin Murphy <robin.mur...@arm.com> wrote: > Hi Magnus, > > On 08/03/17 11:01, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Introduce struct ipmmu_features to track various hardware >> and software implementation changes inside the driver for >> different kinds of IPMMU hardware. Add use_ns_alias_offset >> as a first example of a feature to control if the secure >> register bank offset should be used or not. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> --- >> >> Changes since V2: >> - None >> >> Changes since V1: >> - Moved patch to front of the series >> >> drivers/iommu/ipmmu-vmsa.c | 35 --- >> 1 file changed, 28 insertions(+), 7 deletions(-) >> >> --- 0007/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-07 12:25:47.0 +0900 >> @@ -32,11 +32,15 @@ >> >> #define IPMMU_CTX_MAX 1 >> >> +struct ipmmu_features { >> + bool use_ns_alias_offset; >> +}; >> + >> struct ipmmu_vmsa_device { >> struct device *dev; >> void __iomem *base; >> struct list_head list; >> - >> + const struct ipmmu_features *features; >> unsigned int num_utlbs; >> spinlock_t lock;/* Protects ctx and domains[] >> */ >> DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); >> @@ -999,13 +1003,33 @@ static void ipmmu_device_reset(struct ip >> ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); >> } >> >> +static const struct ipmmu_features ipmmu_features_default = { >> + .use_ns_alias_offset = true, >> +}; >> + >> +static const struct of_device_id ipmmu_of_ids[] = { >> + { >> + .compatible = "renesas,ipmmu-vmsa", >> + .data = _features_default, >> + }, { >> + /* Terminator */ >> + }, >> +}; >> + >> +MODULE_DEVICE_TABLE(of, ipmmu_of_ids); >> + >> static int ipmmu_probe(struct platform_device *pdev) >> { >> struct ipmmu_vmsa_device *mmu; >> + const struct of_device_id *match; >> struct resource *res; >> int irq; >> int ret; >> >> + match = of_match_node(ipmmu_of_ids, pdev->dev.of_node); > > of_device_get_match_data() makes this a lot easier. > >> + if (!match) >> + return -EINVAL; > > Also, if the driver is DT-only per the other series, note that this > cannot happen anyway, since of_driver_match_device() would have to have > found a match for your probe function to be called in the first place. Yeah, you are right. As you know, in the IPMMU driver (with the r8a7795 V3 series applied) the init handling is a bit special with ARM32 and ARM64 being treated differently. I would like to clean it up and share a common implementation. Until that happens, how do you think we should handle the (!match) case? BUG_ON()? Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 06/09] iommu/ipmmu-vmsa: Write IMCTR twice
Hi Robin, On Wed, Mar 8, 2017 at 9:34 PM, Robin Murphy <robin.mur...@arm.com> wrote: > On 08/03/17 11:02, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Write IMCTR both in the root device and the leaf node. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> --- >> >> Changes since V2: >> - None >> >> Changes since V1: >> - None >> >> drivers/iommu/ipmmu-vmsa.c | 17 ++--- >> 1 file changed, 14 insertions(+), 3 deletions(-) >> >> --- 0018/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 18:30:36.870607110 +0900 >> @@ -286,6 +286,16 @@ static void ipmmu_ctx_write(struct ipmmu >> ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, >> data); >> } >> >> +static void ipmmu_ctx_write2(struct ipmmu_vmsa_domain *domain, unsigned int >> reg, >> + u32 data) > > That's pretty cryptic. Maybe both functions could do with less ambiguous > names - something like ipmmu_ctx_write_root() vs. ipmmu_ctx_write_all(), > perhaps? (and if there's a more specific hardware term than "all" that > describes this kind of configuration, even better). Yeah I agree. Will fix in next version! Thanks, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
Hi Geert, On Wed, Mar 8, 2017 at 10:52 PM, Geert Uytterhoeven <ge...@linux-m68k.org> wrote: > Hi Magnus, > > On Wed, Mar 8, 2017 at 12:02 PM, Magnus Damm <magnus.d...@gmail.com> wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Hook up IOMMU_OF_DECLARE() support in case CONFIG_IOMMU_DMA >> is enabled. The only current supported case for 32-bit ARM >> is disabled, however for 64-bit ARM usage of OF is required. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se > > While I'm not such a big fan of *_OF_DECLARE() (it doesn't support deferred > probing, which is needed for any device with dependencies, like clocks and > power domains), what's the rationale for not using IOMMU_OF_DECLARE() > on arm32, and thus the need for setup_done? ARM32 could (and should) be converted over to IOMMU_OF_DECLARE(), but it is just a matter of timing. If we try to do it before ARM32 is converted over to CONFIG_IOMMU_DMA=y then we have to handle all the hairy legacy implementation details of IOMMU support in case of CONFIG_IOMMU_DMA=n _and_ deal with just moving over the init order bits to OF. Testing and keeping all the combinations working is a lot of work. I prefer to kill two birds with one stone and do a larger feature jump and move over ARM32 to same state of ARM64 (with OF init) once CONFIG_IOMMU_DMA=y is ready for 32-bit ARM. Just changing the init order bits to OF while keeping legacy CONFIG_IOMMU_DMA=n code is introducing potential errors with not much upside. Unless there is some other reason to do it that I can't see that is. =) Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v7 06/07] iommu/ipmmu-vmsa: ARM and ARM64 archdata access
Hi Robin, On Wed, Mar 8, 2017 at 9:48 PM, Robin Murphy <robin.mur...@arm.com> wrote: > On 07/03/17 03:17, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Not all architectures have an iommu member in their archdata, so >> use #ifdefs support build with COMPILE_TEST on any architecture. > > I have a feeling I might be repeating myself, but ipmmu_vmsa_archdata > looks to be trivially convertible to iommu_fwspec, which I strongly > encourage, not least because it would obviate bodges like this. Yeah, I think it should be possible to use iommu_fwspec for this purpose. The question is when to do it. =) I actually looked into it recently, but then realised that for this to work then due to code sharing I need to make use of iommu_fwspec on both 32-bit and 64-bit ARM. So it requires rework of the existing IPMMU for 32-bit ARM (including hairy legacy CONFIG_IOMMU_DMA=n code). I was actually thinking of doing some rework of 32-bit ARM IPMMU code anyway (I suspect iommu_device_* conversion caused breakage) and it probably has to happen on top of current -next. I would also like to start reducing burden of forward porting all these patches, and stirring up the ground does not really help much there... Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 08/09] iommu/ipmmu-vmsa: Allow two bit SL0
From: Magnus Damm <damm+rene...@opensource.se> Introduce support for two bit SL0 bitfield in IMTTBCR by using a separate feature flag. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) --- 0022/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 18:33:07.630607110 +0900 @@ -38,6 +38,7 @@ struct ipmmu_features { bool has_cache_leaf_nodes; bool has_eight_ctx; bool setup_imbuscr; + bool twobit_imttbcr_sl0; }; struct ipmmu_vmsa_device { @@ -163,6 +164,10 @@ static void set_archdata(struct device * #define IMTTBCR_TSZ0_MASK (7 << 0) #define IMTTBCR_TSZ0_SHIFT O +#define IMTTBCR_SL0_TWOBIT_LVL_3 (0 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_2 (1 << 6) +#define IMTTBCR_SL0_TWOBIT_LVL_1 (2 << 6) + #define IMBUSCR0x000c #define IMBUSCR_DVM(1 << 2) #define IMBUSCR_BUSSEL_SYS (0 << 0) @@ -406,6 +411,7 @@ static int ipmmu_domain_allocate_context static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) { u64 ttbr; + u32 tmp; int ret; /* @@ -458,9 +464,15 @@ static int ipmmu_domain_init_context(str * We use long descriptors with inner-shareable WBWA tables and allocate * the whole 32-bit VA space to TTBR0. */ + + if (domain->root->features->twobit_imttbcr_sl0) + tmp = IMTTBCR_SL0_TWOBIT_LVL_1; + else + tmp = IMTTBCR_SL0_LVL_1; + ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | - IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); + IMTTBCR_IRGN0_WB_WA | tmp); /* MAIR0 */ ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); @@ -1080,6 +1092,7 @@ static const struct ipmmu_features ipmmu .has_cache_leaf_nodes = false, .has_eight_ctx = false, .setup_imbuscr = true, + .twobit_imttbcr_sl0 = false, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
From: Magnus Damm <damm+rene...@opensource.se> Tie in r8a7795 features and update the IOMMU_OF_DECLARE compat string to include the updated compat string. TODO: - Consider making use of iommu_fwspec_add_ids() for uTLB handling Needed to coexist with non-OF R-Car Gen2 somehow... - Break out stuff useful for R-Car Gen2 from this series Fix up the Gen2 IPMMU support code and/or Fold more stuff into the multi-arch series - Add support for sysfs and iommu_device_link()/unlink() Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Check for lack of root device in ->xlate() This fixed a bug when IPMMU-MM is disabled in DT the system hangs on boot - Added code to ipmmu_init_platform_device() to handle multiple ->xlate() calls - Include empty white list by default - Updated TODO list Changes since V1: - Enable multi context feature - Update TODO list drivers/iommu/ipmmu-vmsa.c | 41 + 1 file changed, 41 insertions(+) --- 0018/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 19:11:53.600607110 +0900 @@ -23,6 +23,7 @@ #include #include #include +#include #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include @@ -770,6 +771,10 @@ static int ipmmu_init_platform_device(st int num_utlbs; int ret = -ENODEV; + /* Initialize once - xlate() will call multiple times */ + if (to_archdata(dev)) + return 0; + /* Find the master corresponding to the device. */ num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", @@ -1043,6 +1048,17 @@ static struct iommu_group *ipmmu_find_gr return group; } +static bool ipmmu_slave_whitelist(struct device *dev) +{ + /* By default, do not allow use of IPMMU */ + return false; +} + +static const struct soc_device_attribute soc_r8a7795[] = { + { .soc_id = "r8a7795", }, + { /* sentinel */ } +}; + static int ipmmu_of_xlate_dma(struct device *dev, struct of_phandle_args *spec) { @@ -1053,6 +1069,18 @@ static int ipmmu_of_xlate_dma(struct dev if (!of_device_is_available(spec->np)) return -ENODEV; + /* Failing in ->attach_device() results in a hang, so make +* sure the root device is installed before going there +*/ + if (!__ipmmu_find_root()) { + dev_info(dev, "Unable to locate IPMMU root device\n"); + return -ENODEV; + } + + /* For R-Car Gen3 use a white list to opt-in slave devices */ + if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + return -ENODEV; + return ipmmu_init_platform_device(dev); } @@ -1095,11 +1123,22 @@ static const struct ipmmu_features ipmmu .twobit_imttbcr_sl0 = false, }; +static const struct ipmmu_features ipmmu_features_r8a7795 = { + .use_ns_alias_offset = false, + .has_cache_leaf_nodes = true, + .has_eight_ctx = true, + .setup_imbuscr = false, + .twobit_imttbcr_sl0 = true, +}; + static const struct of_device_id ipmmu_of_ids[] = { { .compatible = "renesas,ipmmu-vmsa", .data = _features_default, }, { + .compatible = "renesas,ipmmu-r8a7795", + .data = _features_r8a7795, + }, { /* Terminator */ }, }; @@ -1288,6 +1327,8 @@ static int __init ipmmu_vmsa_iommu_of_se IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", ipmmu_vmsa_iommu_of_setup); +IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795", +ipmmu_vmsa_iommu_of_setup); #endif MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional
From: Magnus Damm <damm+rene...@opensource.se> Introduce a feature to allow opt-out of setting up IMBUSCR. The default case is unchanged. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - None Changes since V1: - Updated the commit message - Reworked patch to coexist with the multi context feature drivers/iommu/ipmmu-vmsa.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) --- 0020/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 18:32:26.280607110 +0900 @@ -37,6 +37,7 @@ struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; bool has_eight_ctx; + bool setup_imbuscr; }; struct ipmmu_vmsa_device { @@ -465,10 +466,10 @@ static int ipmmu_domain_init_context(str ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ - ipmmu_ctx_write(domain, IMBUSCR, - ipmmu_ctx_read(domain, IMBUSCR) & - ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); - + if (domain->root->features->setup_imbuscr) + ipmmu_ctx_write(domain, IMBUSCR, + ipmmu_ctx_read(domain, IMBUSCR) & + ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); /* * IMSTR * Clear all interrupt flags. @@ -1078,6 +1079,7 @@ static const struct ipmmu_features ipmmu .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, .has_eight_ctx = false, + .setup_imbuscr = true, }; static const struct of_device_id ipmmu_of_ids[] = { ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 06/09] iommu/ipmmu-vmsa: Write IMCTR twice
From: Magnus Damm <damm+rene...@opensource.se> Write IMCTR both in the root device and the leaf node. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - None Changes since V1: - None drivers/iommu/ipmmu-vmsa.c | 17 ++--- 1 file changed, 14 insertions(+), 3 deletions(-) --- 0018/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 18:30:36.870607110 +0900 @@ -286,6 +286,16 @@ static void ipmmu_ctx_write(struct ipmmu ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); } +static void ipmmu_ctx_write2(struct ipmmu_vmsa_domain *domain, unsigned int reg, +u32 data) +{ + if (domain->mmu != domain->root) + ipmmu_write(domain->mmu, + domain->context_id * IM_CTX_SIZE + reg, data); + + ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); +} + /* - * TLB and microTLB Management */ @@ -312,7 +322,7 @@ static void ipmmu_tlb_invalidate(struct reg = ipmmu_ctx_read(domain, IMCTR); reg |= IMCTR_FLUSH; - ipmmu_ctx_write(domain, IMCTR, reg); + ipmmu_ctx_write2(domain, IMCTR, reg); ipmmu_tlb_sync(domain); } @@ -472,7 +482,8 @@ static int ipmmu_domain_init_context(str * software management as we have no use for it. Flush the TLB as * required when modifying the context registers. */ - ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); + ipmmu_ctx_write2(domain, IMCTR, +IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); return 0; } @@ -498,7 +509,7 @@ static void ipmmu_domain_destroy_context * * TODO: Is TLB flush really needed ? */ - ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH); + ipmmu_ctx_write2(domain, IMCTR, IMCTR_FLUSH); ipmmu_tlb_sync(domain); ipmmu_domain_free_context(domain->root, domain->context_id); } ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master
From: Magnus Damm <damm+rene...@opensource.se> The r8a7795 IPMMU supports 40-bit bus mastering. Both the coherent DMA mask and the streaming DMA mask are set to unlock the 40-bit address space for coherent allocations and streaming operations. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Updated the code and commit message to use 40 bits instead of 64 bits Changes since V1: - Updated the commit message drivers/iommu/ipmmu-vmsa.c |1 + 1 file changed, 1 insertion(+) --- 0016/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 18:29:56.390607110 +0900 @@ -1103,6 +1103,7 @@ static int ipmmu_probe(struct platform_d spin_lock_init(>lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = match->data; + dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(40)); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
From: Magnus Damm <damm+rene...@opensource.se> Hook up IOMMU_OF_DECLARE() support in case CONFIG_IOMMU_DMA is enabled. The only current supported case for 32-bit ARM is disabled, however for 64-bit ARM usage of OF is required. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Reworked registration code to make use of recently introduced: iommu_device_register() iommu_device_set_ops() iommu_device_set_fwnode() Changes since V1: - Reworked slightly to fit updated patch order and [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 39 +++ 1 file changed, 39 insertions(+) --- 0012/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 19:08:31.610607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ struct ipmmu_features { struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; + struct iommu_device iommu; struct list_head list; const struct ipmmu_features *features; bool is_leaf; @@ -1161,6 +1163,25 @@ static int ipmmu_probe(struct platform_d ipmmu_device_reset(mmu); } +#if defined(CONFIG_IOMMU_DMA) + /* +* Register the IPMMU to the IOMMU subsystem in the following cases: +* - R-Car Gen2 IPMMU (all devices registered) +* - R-Car Gen3 IPMMU (leaf devices only - skip root IPMMU-MM device) +*/ + if (!mmu->features->has_cache_leaf_nodes || mmu->is_leaf) { + ret = iommu_device_register(>iommu); + if (ret) + return ret; + + iommu_device_set_ops(>iommu, _ops); + iommu_device_set_fwnode(>iommu, + >dev.of_node->fwnode); + + if (!iommu_present(_bus_type)) + bus_set_iommu(_bus_type, _ops); + } +#endif /* * We can't create the ARM mapping here as it requires the bus to have * an IOMMU, which only happens when bus_set_iommu() is called in @@ -1204,15 +1225,22 @@ static struct platform_driver ipmmu_driv static int __init ipmmu_init(void) { + static bool setup_done; int ret; + if (setup_done) + return 0; + ret = platform_driver_register(_driver); if (ret < 0) return ret; +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) if (!iommu_present(_bus_type)) bus_set_iommu(_bus_type, _ops); +#endif + setup_done = true; return 0; } @@ -1224,6 +1252,17 @@ static void __exit ipmmu_exit(void) subsys_initcall(ipmmu_init); module_exit(ipmmu_exit); +#ifdef CONFIG_IOMMU_DMA +static int __init ipmmu_vmsa_iommu_of_setup(struct device_node *np) +{ + ipmmu_init(); + return 0; +} + +IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa", +ipmmu_vmsa_iommu_of_setup); +#endif + MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); MODULE_AUTHOR("Laurent Pinchart <laurent.pinch...@ideasonboard.com>"); MODULE_LICENSE("GPL v2"); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 03/09] iommu/ipmmu-vmsa: Enable multi context support
From: Magnus Damm <damm+rene...@opensource.se> Add support for up to 8 contexts. Each context is mapped to one domain. One domain is assigned one or more slave devices. Contexts are allocated dynamically and slave devices are grouped together based on which IPMMU device they are connected to. This makes slave devices tied to the same IPMMU device share the same IOVA space. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Updated patch description to reflect code included in: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 Changes since V1: - Support up to 8 contexts instead of 4 - Use feature flag and runtime handling - Default to single context drivers/iommu/ipmmu-vmsa.c | 38 ++ 1 file changed, 30 insertions(+), 8 deletions(-) --- 0012/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 17:59:19.900607110 +0900 @@ -30,11 +30,12 @@ #include "io-pgtable.h" -#define IPMMU_CTX_MAX 1 +#define IPMMU_CTX_MAX 8 struct ipmmu_features { bool use_ns_alias_offset; bool has_cache_leaf_nodes; + bool has_eight_ctx; }; struct ipmmu_vmsa_device { @@ -44,6 +45,7 @@ struct ipmmu_vmsa_device { const struct ipmmu_features *features; bool is_leaf; unsigned int num_utlbs; + unsigned int num_ctx; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; @@ -376,11 +378,12 @@ static int ipmmu_domain_allocate_context spin_lock_irqsave(>lock, flags); - ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX); - if (ret != IPMMU_CTX_MAX) { + ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx); + if (ret != mmu->num_ctx) { mmu->domains[ret] = domain; set_bit(ret, mmu->ctx); - } + } else + ret = -EBUSY; spin_unlock_irqrestore(>lock, flags); @@ -425,9 +428,9 @@ static int ipmmu_domain_init_context(str * Find an unused context. */ ret = ipmmu_domain_allocate_context(domain->root, domain); - if (ret == IPMMU_CTX_MAX) { + if (ret < 0) { free_io_pgtable_ops(domain->iop); - return -EBUSY; + return ret; } domain->context_id = ret; @@ -562,7 +565,7 @@ static irqreturn_t ipmmu_irq(int irq, vo /* * Check interrupts for all active contexts. */ - for (i = 0; i < IPMMU_CTX_MAX; i++) { + for (i = 0; i < mmu->num_ctx; i++) { if (!mmu->domains[i]) continue; if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED) @@ -632,6 +635,13 @@ static int ipmmu_attach_device(struct io domain->mmu = mmu; domain->root = root; ret = ipmmu_domain_init_context(domain); + if (ret < 0) { + dev_err(dev, "Unable to initialize IPMMU context\n"); + domain->mmu = NULL; + } else { + dev_info(dev, "Using IPMMU context %u\n", +domain->context_id); + } } else if (domain->mmu != mmu) { /* * Something is wrong, we can't attach two devices using @@ -1047,13 +1057,14 @@ static void ipmmu_device_reset(struct ip unsigned int i; /* Disable all contexts. */ - for (i = 0; i < 4; ++i) + for (i = 0; i < mmu->num_ctx; ++i) ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); } static const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, + .has_eight_ctx = false, }; static const struct of_device_id ipmmu_of_ids[] = { @@ -1112,6 +1123,17 @@ static int ipmmu_probe(struct platform_d if (mmu->features->use_ns_alias_offset) mmu->base += IM_NS_ALIAS_OFFSET; + /* +* The number of contexts varies with generation and instance. +* Newer SoCs get a total of 8 contexts enabled, older ones just one. +*/ + if (mmu->features->has_eight_ctx) + mmu->num_ctx = 8; + else + mmu->num_ctx = 1; + + WARN_ON(mmu->num_ctx > IPMMU_CTX_MAX); + irq = platform_get_irq(pdev, 0); /* ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 02/09] iommu/ipmmu-vmsa: Add optional root device feature
From: Magnus Damm <damm+rene...@opensource.se> Add root device handling to the IPMMU driver by allowing certain DT compat strings to enable has_cache_leaf_nodes that in turn will support both root devices with interrupts and leaf devices that face the actual IPMMU consumer devices. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V2: - Fixed a bug in ipmmu_find_root() when only leaf devices are present - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices Changes since V1: - Moved patch to earlier in the series - Updated code to work with recent changes in: [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3 drivers/iommu/ipmmu-vmsa.c | 95 1 file changed, 78 insertions(+), 17 deletions(-) --- 0011/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-08 17:56:51.770607110 +0900 @@ -34,6 +34,7 @@ struct ipmmu_features { bool use_ns_alias_offset; + bool has_cache_leaf_nodes; }; struct ipmmu_vmsa_device { @@ -41,6 +42,7 @@ struct ipmmu_vmsa_device { void __iomem *base; struct list_head list; const struct ipmmu_features *features; + bool is_leaf; unsigned int num_utlbs; spinlock_t lock;/* Protects ctx and domains[] */ DECLARE_BITMAP(ctx, IPMMU_CTX_MAX); @@ -51,6 +53,7 @@ struct ipmmu_vmsa_device { struct ipmmu_vmsa_domain { struct ipmmu_vmsa_device *mmu; + struct ipmmu_vmsa_device *root; struct iommu_domain io_domain; struct io_pgtable_cfg cfg; @@ -216,6 +219,44 @@ static void set_archdata(struct device * #define IMUASID_ASID0_SHIFT0 /* - + * Root device handling + */ + +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu) +{ + if (mmu->features->has_cache_leaf_nodes) + return mmu->is_leaf ? false : true; + else + return true; /* older IPMMU hardware treated as single root */ +} + +static struct ipmmu_vmsa_device *__ipmmu_find_root(void) +{ + struct ipmmu_vmsa_device *mmu; + bool found = false; + + spin_lock(_devices_lock); + + list_for_each_entry(mmu, _devices, list) { + if (ipmmu_is_root(mmu)) { + found = true; + break; + } + } + + spin_unlock(_devices_lock); + return found ? mmu : NULL; +} + +static struct ipmmu_vmsa_device *ipmmu_find_root(struct ipmmu_vmsa_device *leaf) +{ + if (ipmmu_is_root(leaf)) + return leaf; + else + return __ipmmu_find_root(); +} + +/* - * Read/Write Access */ @@ -232,13 +273,13 @@ static void ipmmu_write(struct ipmmu_vms static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) { - return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg); + return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg); } static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, u32 data) { - ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data); + ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data); } /* - @@ -373,7 +414,7 @@ static int ipmmu_domain_init_context(str * TODO: Add support for coherent walk through CCI with DVM and remove * cache handling. For now, delegate it to the io-pgtable code. */ - domain->cfg.iommu_dev = domain->mmu->dev; + domain->cfg.iommu_dev = domain->root->dev; domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, >cfg, domain); @@ -383,7 +424,7 @@ static int ipmmu_domain_init_context(str /* * Find an unused context. */ - ret = ipmmu_domain_allocate_context(domain->mmu, domain); + ret = ipmmu_domain_allocate_context(domain->root, domain); if (ret == IPMMU_CTX_MAX) { free_io_pgtable_ops(domain->iop); return -EBUSY; @@ -454,7 +495,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); + ipmmu_domain_free_context(domain->root, domain->context_id); } /* - @@ -567,7 +608,7 @@ static int ipmmu_attach_device(struct io struct device *dev) { struct ipmmu_vmsa
[PATCH v3 00/09] iommu/ipmmu-vmsa: r8a7795 support V3
iommu/ipmmu-vmsa: r8a7795 support V3 [PATCH v3 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias [PATCH v3 02/09] iommu/ipmmu-vmsa: Add optional root device feature [PATCH v3 03/09] iommu/ipmmu-vmsa: Enable multi context support [PATCH v3 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE() [PATCH v3 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master [PATCH v3 06/09] iommu/ipmmu-vmsa: Write IMCTR twice [PATCH v3 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional [PATCH v3 08/09] iommu/ipmmu-vmsa: Allow two bit SL0 [PATCH v3 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code This series contains a much needed r8a7795 support update for the IPMMU driver. Last series was earlier posted as: [PATCH v2 00/11] iommu/ipmmu-vmsa: r8a7795 support V2 The DT binding for r8a7795 has been accepted for upstream merge and this series implements support following such format: d4e42e7 iommu/ipmmu-vmsa: Add r8a7795 DT binding The r8a7795 IPMMU is almost register compatible with earlier devices like r8a7790-r8a7794, however some bitfields have been shifted slightly. On a grander scale topology has been added and interrupts have been reworked. So now there are several "cache" IPMMU units without interrupt that somehow communicate with IPMMU-MM that is the only instance that supports interrupts. The code refers to IPMMU-MM as a "root" device and the other ones as "leaf" nodes. To make this more interesting the IPMMU driver needs to be shared between 32-bit ARM for r8a7790-r8a7794 and 64-bit ARM for r8a7795. In practice this means that two separate implementations are needed inside the driver to attach to the rather different architecture specific code. CONFIG_IOMMU_DMA=y is needed on 64-bit ARM while on 32-bit ARM the arch specific dma-mapping code is hooked up rather directly. During init 64-bit ARM IPMMU support is relying on IOMMU_OF_DECLARE(). This version of the code is known to build on 32-bit and 64-bit ARM. Some patches that existed in V1 have been folded into: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 Changes since V2: - Patch 2/9 has been updated with a bug fix and to supply __ipmmu_find_root() - Patch 4/9 now makes use of iommu_device_* functions - Patch 5/9 sets the mask to 40 bits instead of 64 bits - Patch 9/9 implements white list handling via ->xlate() and fixes a bug Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of v4.11-rc1 and: [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7 drivers/iommu/ipmmu-vmsa.c | 291 +--- 1 file changed, 251 insertions(+), 40 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 07/07] iommu/ipmmu-vmsa: Drop LPAE Kconfig dependency
From: Magnus Damm <damm+rene...@opensource.se> Neither 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 <damm+rene...@opensource.se> Acked-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - None drivers/iommu/Kconfig |1 - 1 file changed, 1 deletion(-) --- 0011/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2017-03-06 18:50:49.260607110 +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 v7 05/07] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops
From: Magnus Damm <damm+rene...@opensource.se> Introduce 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. Initialize the device from ->xlate() when CONFIG_IOMMU_DMA=y. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V6: - Rolled in the following patches from "r8a7795 support V2": [PATCH v2 04/11] iommu/ipmmu-vmsa: Reuse iommu groups [PATCH v2 06/11] iommu/ipmmu-vmsa: Teach xlate() to skip disabled iommus - Moved find_group() implementation to prevent warning on 32-bit ARM - Rolled in the following patch from "IPMMU slave device whitelist V2": [PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Check devices in xlate() drivers/iommu/Kconfig |1 drivers/iommu/ipmmu-vmsa.c | 164 +--- 2 files changed, 157 insertions(+), 8 deletions(-) --- 0001/drivers/iommu/Kconfig +++ work/drivers/iommu/Kconfig 2017-03-06 18:42:42.0 +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 --- 0009/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 19:22:27.700607110 +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" @@ -57,6 +60,8 @@ struct ipmmu_vmsa_archdata { struct ipmmu_vmsa_device *mmu; unsigned int *utlbs; unsigned int num_utlbs; + struct device *dev; + struct list_head list; }; static DEFINE_SPINLOCK(ipmmu_devices_lock); @@ -522,14 +527,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); @@ -572,6 +569,9 @@ static int ipmmu_attach_device(struct io dev_err(dev, "Can't attach IPMMU %s to domain on IPMMU %s\n", dev_name(mmu->dev), dev_name(domain->mmu->dev)); ret = -EINVAL; + } else { + dev_info(dev, "Reusing IPMMU context %u\n", +domain->context_id); } spin_unlock_irqrestore(>lock, flags); @@ -708,6 +708,7 @@ static int ipmmu_init_platform_device(st archdata->mmu = mmu; archdata->utlbs = utlbs; archdata->num_utlbs = num_utlbs; + archdata->dev = dev; dev->archdata.iommu = archdata; return 0; @@ -716,6 +717,16 @@ error: return ret; } +#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) + +static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +{ + if (type != IOMMU_DOMAIN_UNMANAGED) + return NULL; + + return __ipmmu_domain_alloc(type); +} + static int ipmmu_add_device(struct device *dev) { struct ipmmu_vmsa_archdata *archdata; @@ -823,6 +834,141 @@ 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 DEFINE_SPINLOCK(ipmmu_slave_devices_lock); +static LIST_HEAD(ipmmu_slave_devices); + +static struct iommu_domain *ipmmu_domain_alloc_dma(unsigned type) +{ + struct iommu_domain *io_domain = NULL; + + switch (type) { + case IOMMU_DOMAIN_UNMANAGED: + io_domain = __ipmmu_domain_alloc(type); + break; + + case IOMMU_DOMAIN_DMA: + io_domain = __ipmmu_domain_alloc(type); + if (io_domain) + iommu_get_dma_cookie(io_domain); + break; + } + + return io_domain; +} + +static void ipmmu_domain_free_dma(struct iommu_domain *io_domain) +{ + switch (io_domain->type) { + case IOMMU_DOMAIN_DMA: + iommu_put_dma_cookie(io_domain); + /* fall-through */ + default: + ipmmu_domain_free(io_domain); + break; + } +} + +static int ipmmu_add_device_dma(struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct iommu_group *group; + + /* The device has been verified in xlate() */ + if (!archdata) + return -ENODEV; + + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) +
[PATCH v7 06/07] iommu/ipmmu-vmsa: ARM and ARM64 archdata access
From: Magnus Damm <damm+rene...@opensource.se> Not all architectures have an iommu member in their archdata, so use #ifdefs support build with COMPILE_TEST on any architecture. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - Updated patch to handle newly introduced functions in: [PATCH v7 05/07] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops drivers/iommu/ipmmu-vmsa.c | 43 ++- 1 file changed, 30 insertions(+), 13 deletions(-) --- 0010/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 19:26:26.070607110 +0900 @@ -72,6 +72,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 */ /* - @@ -543,7 +562,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; @@ -588,7 +607,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; @@ -709,7 +728,7 @@ static int ipmmu_init_platform_device(st archdata->utlbs = utlbs; archdata->num_utlbs = num_utlbs; archdata->dev = dev; - dev->archdata.iommu = archdata; + set_archdata(dev, archdata); return 0; error: @@ -729,12 +748,11 @@ static struct iommu_domain *ipmmu_domain 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; @@ -770,8 +788,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; @@ -799,7 +816,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); @@ -809,7 +826,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); @@ -817,7 +834,7 @@ static void ipmmu_remove_device(struct d kfree(archdata->utlbs); kfree(archdata); - dev->archdata.iommu = NULL; + set_archdata(dev, NULL); } static const struct iommu_ops ipmmu_ops = { @@ -874,7 +891,7 @@ static void ipmmu_domain_free_dma(struct static int ipmmu_add_device_dma(struct device *dev) { - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_archdata *archdata = to_archdata(dev); struct iommu_group *group; /* The device has been verified in xlate() */ @@ -893,7 +910,7 @@ static int ipmmu_add_device_dma(struct d static void ipmmu_remove_device_dma(struct device *dev) { - struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_archdata *archdata = to_archdata(dev); spin_lock(_slave_devices_lock); lis
[PATCH v7 02/07] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context
From: Magnus Damm <damm+rene...@opensource.se> Introduce 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 <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - None drivers/iommu/ipmmu-vmsa.c | 76 ++-- 1 file changed, 66 insertions(+), 10 deletions(-) --- 0003/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 18:32:38.350607110 +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. @@ -327,10 +353,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]; @@ -372,6 +403,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) { /* @@ -382,6 +426,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); } /* - @@ -439,16 +484,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); - return ipmmu_domain_irq(domain); + return status; } /* - @@ -776,6 +830,8 @@ static int ipmmu_probe(struct platform_d mmu->dev = >dev; mmu->num_utlbs = 32; + spin_lock_init(>lock); + bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 04/07] iommu/ipmmu-vmsa: Break out domain allocation code
From: Magnus Damm <damm+rene...@opensource.se> Break out the domain allocation code into a separate function. This is preparation for future code sharing. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - None drivers/iommu/ipmmu-vmsa.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) --- 0006/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 18:34:59.520607110 +0900 @@ -509,13 +509,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; @@ -525,6 +522,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 v7 03/07] iommu/ipmmu-vmsa: Break out utlb parsing code
From: Magnus Damm <damm+rene...@opensource.se> Break 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 <damm+rene...@opensource.se> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - None drivers/iommu/ipmmu-vmsa.c | 58 1 file changed, 37 insertions(+), 21 deletions(-) --- 0004/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 18:33:38.600607110 +0900 @@ -649,22 +649,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", @@ -701,6 +694,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)) { @@ -718,16 +741,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 @@ -738,6 +754,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; @@ -762,10 +780,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 v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7
iommu/ipmmu-vmsa: IPMMU multi-arch update V7 [PATCH v7 01/07] iommu/ipmmu-vmsa: Remove platform data handling [PATCH v7 02/07] iommu/ipmmu-vmsa: Rework interrupt code and use bitmap for context [PATCH v7 03/07] iommu/ipmmu-vmsa: Break out utlb parsing code [PATCH v7 04/07] iommu/ipmmu-vmsa: Break out domain allocation code [PATCH v7 05/07] iommu/ipmmu-vmsa: Add new IOMMU_DOMAIN_DMA ops [PATCH v7 06/07] iommu/ipmmu-vmsa: ARM and ARM64 archdata access [PATCH v7 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, the foundation for supporting multiple contexts are added and in case of CONFIG_IOMMU_DMA=y (on 64-bit or 32-bit ARM) devices are grouped together and handled via ->xlate() - thanks Robin! Support for existing 32-bit ARM SoCs from R-Car Gen2 is kept as-is. Changes since V6: - Rebased on top of v4.11-rc1 and the following fast-tracked change: 3b6bb5b iommu/ipmmu-vmsa: Restrict IOMMU Domain Geometry to 32-bit address spac - Updated patch 5/7 to roll in a few patches from other series See individual patch for more details - Build tested on 32-bit and 64-bit ARM - Run time tested on 64-bit ARM (with additional SoC-specific patches) Changes since V5: - Rebased series on top of next-20161019 - Updated patch 5/7 to simplify domain allocation/free code - thanks Joerg! - Added reviewed-by tag from Joerg for patch 1-4 and 6-7. 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 v4.11-rc1: drivers/iommu/Kconfig |2 drivers/iommu/ipmmu-vmsa.c | 359 2 files changed, 299 insertions(+), 62 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 01/07] iommu/ipmmu-vmsa: Remove platform data handling
From: Magnus Damm <damm+rene...@opensource.se> The 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 <damm+rene...@opensource.se> Reviewed-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com> Reviewed-by: Joerg Roedel <jroe...@suse.de> --- Changes since V6: - None drivers/iommu/ipmmu-vmsa.c |5 - 1 file changed, 5 deletions(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-03-06 17:25:49.0 +0900 @@ -768,11 +768,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
Re: [PATCH/RFC v2 0/4] iommu/ipmmu-vmsa: IPMMU slave device whitelist V2
On Fri, Jan 27, 2017 at 3:14 PM, Magnus Damm <magnus.d...@gmail.com> wrote: > iommu/ipmmu-vmsa: IPMMU slave device whitelist V2 > > [PATCH/RFC v2 1/4] iommu/of: Skip IOMMU devices disabled in DT > [PATCH/RFC v2 2/4] iommu/ipmmu-vmsa: Get rid of disabled device check > [PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Check devices in xlate() > [PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version > > Here's an updated prototype that shows how DT integration of IPMMU details > may be integrated and merged upstream based on SoC data sheet ahead of > time followed by enablement in the IPMMU driver code once the appropriate > SoC ES version has been released and the hardware has been tested. > > Changes since V1: > - Broke out patch 1 from the IPMMU driver > - Moved slave device check from ->add_device() to ->xlate() (Thanks Robin!) > - Updated white list patch to hook into ->xlate() > > Patch 1 may be suitable for upstream merge, however other patches should > in the future if agreed on be rolled into the IPMMU driver series. Hi Geert, everyone, Do you have any opinion about the code in this version of the series? I recall that you agreed with the approach in "[PATCH/RFC 2/2] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version", however it was suggested to me by Robin that my code in "[PATCH/RFC 1/2] arm64: mm: Silently allow devices lacking IOMMU group" should be reworked to use ->xlate(). Now this series makes use of ->xlate() to implement the white list, so I hope that makes everyone happy. Also, based on your suggestion I finally managed to break out the code that skips over disabled devices in "[PATCH/RFC v2 1/4] iommu/of: Skip IOMMU devices disabled in DT" but I'm not sure if this will cause problem for other platforms. Anyway, my current plan is to wait for feedback for "[PATCH/RFC v2 1/4] iommu/of: Skip IOMMU devices disabled in DT" and handle that independently, and also roll in the other changes in this series into my other IPMMU code. Thanks, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48
Hi Joerg, On Fri, Jan 27, 2017 at 8:47 PM, Joerg Roedel <j...@8bytes.org> wrote: > On Mon, Jan 23, 2017 at 08:40:29PM +0900, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Bump up the maximum numbers of micro-TLBS to 48. >> >> Each IPMMU device instance get micro-TLB assignment via >> the "iommus" property in DT. Older SoCs tend to use a >> maximum number of 32 micro-TLBs per IPMMU instance however >> newer SoCs such as r8a7796 make use of up to 48 micro-TLBs. >> >> At this point no SoC specific handling is done to validate >> the maximum number of micro-TLBs, and because of that the >> DT information is assumed to be within correct range for >> each particular SoC. >> >> If needed in the future SoC specific feature flags can be >> added to handle the maximum number of micro-TLBs without >> requiring DT changes, however at this point this does not >> seem necessary. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> > > I get a conflict when applying this to v4.10-rc5. What is this based on, > any patches I missed? Thanks for giving it a go. The second patch in this series should apply as-is: [PATCH v2 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding However for driver code there are two series in between: [PATCH v6 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V6 [PATCH v2 00/11] iommu/ipmmu-vmsa: r8a7795 support V2 For more detailed dependency information please see the cover letter! Regarding the driver code please wait for "IPMMU multi-arch update V7" that takes comments from Laurent into consideration. Hopefully I should be able to send it out some time this week. As for "[PATCH v2 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding", would it be possible to fast track mainline merge of that particular DT binding patch? Can you take it in your tree? To give some background, we already have the IPMMU DT binding for older devices and the sister device r8a7795 in mainline, so the r8a7796 DT binding is just a small incremental step. To make sure we don't go too wild with DT changes we tend to require that the DT binding change should be queued up before starting to merge changes to DTS files. So currently some DT changes are blocking on that r8a7796 DT binding and it would be nice to unblock those if possible.. Thanks! / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC] iommu/dma: Per-domain flag to control size-alignment
From: Magnus Damm <damm+rene...@opensource.se> Introduce the flag "no_size_align" to allow disabling size-alignment on a per-domain basis. This follows the suggestion by the comment in the code, however a per-device control may be preferred? Needed to make virtual space contiguous for certain devices. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/dma-iommu.c |6 +- include/linux/iommu.h |1 + 2 files changed, 6 insertions(+), 1 deletion(-) --- 0001/drivers/iommu/dma-iommu.c +++ work/drivers/iommu/dma-iommu.c 2017-01-27 15:17:50.280607110 +0900 @@ -209,14 +209,18 @@ static struct iova *__alloc_iova(struct struct iova_domain *iovad = cookie_iovad(domain); unsigned long shift = iova_shift(iovad); unsigned long length = iova_align(iovad, size) >> shift; + bool size_aligned = true; if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); + + if (domain->no_size_align) + size_aligned = false; /* * Enforce size-alignment to be safe - there could perhaps be an * attribute to control this per-device, or at least per-domain... */ - return alloc_iova(iovad, length, dma_limit >> shift, true); + return alloc_iova(iovad, length, dma_limit >> shift, size_aligned); } /* The IOVA allocator knows what we mapped, so just unmap whatever that was */ --- 0001/include/linux/iommu.h +++ work/include/linux/iommu.h 2017-01-27 15:16:37.630607110 +0900 @@ -83,6 +83,7 @@ struct iommu_domain { iommu_fault_handler_t handler; void *handler_token; struct iommu_domain_geometry geometry; + bool no_size_align; void *iova_cookie; }; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version
From: Magnus Damm <damm+rene...@opensource.se> Match on r8a7795 ES2 and enable a certain DMA controller. In other cases the IPMMU driver remains disabled. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Changes since V1: - Perform white list check in ->xlate() instead of ->add_device() drivers/iommu/ipmmu-vmsa.c | 25 + 1 file changed, 25 insertions(+) --- 0009/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-27 13:14:47.470607110 +0900 @@ -23,6 +23,7 @@ #include #include #include +#include #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include @@ -1032,9 +1033,33 @@ static void ipmmu_remove_device_dma(stru iommu_group_remove_device(dev); } +static const struct soc_device_attribute r8a7795es2[] = { + { .soc_id = "r8a7795", .revision = "ES2.*" }, + { /* sentinel */ } +}; + +static int ipmmu_slave_whitelist(struct device *dev) +{ + /* Opt-in slave devices based on SoC and ES version */ + if (soc_device_match(r8a7795es2)) { + if (!strcmp(dev_name(dev), "e731.dma-controller")) + return 0; + } + + /* By default, do not allow use of IPMMU */ + return -ENODEV; +} + static int ipmmu_of_xlate_dma(struct device *dev, struct of_phandle_args *spec) { + int ret; + + /* Opt-in devices based on SoC and ES version */ + ret = ipmmu_slave_whitelist(dev); + if (ret) + return ret; + /* For now only tested on R-Car Gen3 with ARM64 arch init order * TODO: Test R-Car Gen2 with ARM32 arch init order */ ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC v2 1/4] iommu/of: Skip IOMMU devices disabled in DT
From: Magnus Damm <damm+rene...@opensource.se> Extend the shared IOMMU code to skip over ->xlate() in case the IOMMU device pointed to by a slave device has been disabled in DT. Difficult to trigger in case a single IOMMU device is used, however when multiple IOMMUs are used and some of them are disabled in DT then this patch makes sure that ->xlate() only gets invoked for the enabled ones. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- I used to keep this as a local check in the xlate() callback for the not-yet-merged-upstream R-Car Gen3 IPMMU driver stack. Since honoring DT disabled devices probably makes sense for most users it seems like a good plan to try to push it into the common subsystem level. Thanks to Geert for suggesting this ages ago. Developed on top of renesas-drivers-2017-01-24-v4.10-rc5 which includes a recent version of iommu/next. drivers/iommu/of_iommu.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- 0001/drivers/iommu/of_iommu.c +++ work/drivers/iommu/of_iommu.c 2017-01-27 13:19:22.540607110 +0900 @@ -159,7 +159,7 @@ const struct iommu_ops *of_iommu_configu np = iommu_spec.np; ops = of_iommu_get_ops(np); - if (!ops || !ops->of_xlate || + if (!ops || !ops->of_xlate || !of_device_is_available(np) || iommu_fwspec_init(dev, >fwnode, ops) || ops->of_xlate(dev, _spec)) goto err_put_node; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Check devices in xlate()
From: Magnus Damm <damm+rene...@opensource.se> Rework the IPMMU code to validate devices in ->xlate() instead of accepting all devices in xlate() and instead validating devices in ->add_device(). This makes it possible for the IPMMU device driver to reject slave devices based on software policy. Once a slave device is rejected by the ->xlate() callback the shared function of_iommu_configure() will fail as well which in turn disables per-device IOMMU handing in the arch-specific mapping code by not passing any IOMMU callbacks to arch_setup_dma_ops(). Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- TODO: Make sure this does not break R-Car Gen2 support drivers/iommu/ipmmu-vmsa.c | 27 +++ 1 file changed, 7 insertions(+), 20 deletions(-) --- 0007/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-27 13:11:35.970607110 +0900 @@ -1007,16 +1007,14 @@ static int ipmmu_add_device_dma(struct d struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; struct iommu_group *group; - /* only accept devices with iommus property */ - if (of_count_phandle_with_args(dev->of_node, "iommus", - "#iommu-cells") < 0) + /* The device needs to be verified in xlate() */ + if (!archdata) return -ENODEV; group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); - archdata = dev->archdata.iommu; spin_lock(_slave_devices_lock); list_add(>list, _slave_devices); spin_unlock(_slave_devices_lock); @@ -1034,24 +1032,13 @@ static void ipmmu_remove_device_dma(stru iommu_group_remove_device(dev); } -static struct iommu_group *ipmmu_device_group_dma(struct device *dev) -{ - struct iommu_group *group; - int ret; - - ret = ipmmu_init_platform_device(dev); - if (!ret) - group = ipmmu_find_group(dev); - else - group = ERR_PTR(ret); - - return group; -} - static int ipmmu_of_xlate_dma(struct device *dev, struct of_phandle_args *spec) { - return 0; + /* For now only tested on R-Car Gen3 with ARM64 arch init order +* TODO: Test R-Car Gen2 with ARM32 arch init order +*/ + return ipmmu_init_platform_device(dev); } static const struct iommu_ops ipmmu_ops = { @@ -1065,7 +1052,7 @@ static const struct iommu_ops ipmmu_ops .iova_to_phys = ipmmu_iova_to_phys, .add_device = ipmmu_add_device_dma, .remove_device = ipmmu_remove_device_dma, - .device_group = ipmmu_device_group_dma, + .device_group = ipmmu_find_group, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, .of_xlate = ipmmu_of_xlate_dma, }; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC v2 2/4] iommu/ipmmu-vmsa: Get rid of disabled device check
From: Magnus Damm <damm+rene...@opensource.se> Since of_iommu_configure() now skips over disabled devices we can simply drop this check in the IPMMU driver. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c |7 --- 1 file changed, 7 deletions(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-27 13:09:36.840607110 +0900 @@ -1051,13 +1051,6 @@ static struct iommu_group *ipmmu_device_ static int ipmmu_of_xlate_dma(struct device *dev, struct of_phandle_args *spec) { - /* If the IPMMU device is disabled in DT then return error -* to make sure the of_iommu code does not install ops -* even though the iommu device is disabled -*/ - if (!of_device_is_available(spec->np)) - return -ENODEV; - return 0; } ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC v2 0/4] iommu/ipmmu-vmsa: IPMMU slave device whitelist V2
iommu/ipmmu-vmsa: IPMMU slave device whitelist V2 [PATCH/RFC v2 1/4] iommu/of: Skip IOMMU devices disabled in DT [PATCH/RFC v2 2/4] iommu/ipmmu-vmsa: Get rid of disabled device check [PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Check devices in xlate() [PATCH/RFC v2 3/4] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version Here's an updated prototype that shows how DT integration of IPMMU details may be integrated and merged upstream based on SoC data sheet ahead of time followed by enablement in the IPMMU driver code once the appropriate SoC ES version has been released and the hardware has been tested. Changes since V1: - Broke out patch 1 from the IPMMU driver - Moved slave device check from ->add_device() to ->xlate() (Thanks Robin!) - Updated white list patch to hook into ->xlate() Patch 1 may be suitable for upstream merge, however other patches should in the future if agreed on be rolled into the IPMMU driver series. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- Developed on top of renesas-drivers-2017-01-24-v4.10-rc5 drivers/iommu/ipmmu-vmsa.c | 59 +++- drivers/iommu/of_iommu.c |2 - 2 files changed, 33 insertions(+), 28 deletions(-) ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC] iommu/ipmmu-vmsa: Restrict IOMMU Domain Geometry to 32-bit address space
Hi Geert, On Thu, Jan 26, 2017 at 6:53 PM, Geert Uytterhoevenwrote: > Currently, the IPMMU/VMSA driver supports 32-bit I/O Virtual Addresses > only, and thus sets io_pgtable_cfg.ias = 32. However, it doesn't force > a 32-bit IOVA space through the IOMMU Domain Geometry. > > Hence if a device (e.g. SYS-DMAC) rightfully configures a 40-bit DMA > mask, it will still be handed out a 40-bit IOVA, outside the 32-bit IOVA > space, leading to out-of-bounds accesses of the PGD when mapping the > IOVA. > > Force a 32-bit IOMMU Domain Geometry to fix this. Nice, thanks! > Signed-off-by: Geert Uytterhoeven > --- > Should the generic code restrict the geometry based on IAS instead? Might make sense. Since this is a software policy limited by hardware it might be good to use as small IOVA space as possible to improve performance. So selecting IOVA space based on slave device or domain policy or something similar might be a good thing to do. Not sure how to tie that into the IOMMU subsystem though... Thanks! / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC 3/4] iommu: dma: iommu iova domain reset
Hi Robin, Shimoda-san, everyone, Thanks for your feedback! On Thu, Jan 26, 2017 at 1:38 AM, Robin Murphy <robin.mur...@arm.com> wrote: > On 25/01/17 12:54, Yoshihiro Shimoda wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> To add a workaround code for ipmmu-vmsa driver, this patch adds >> a new geometry "force_reset_when_empty" not to reuse iova space. > > The domain geometry is absolutely not the appropriate place for that. If > anything, it could possibly be a domain attribute, but it has nothing to > do with describing the range of input addresses the hardware is able to > translate. I agree, this flag was added without too much consideration about correct location. >> When all pfns happen to get unmapped then ask the IOMMU driver to >> flush the state followed by starting from an empty iova space. > > And what happens if all the PFNs are never unmapped? Many devices (USB > being among them) use a coherent allocation for some kind of descriptor > buffer which exists for the lifetime of the device, then use streaming > mappings for data transfers - the net result of that is that the number > of PFNs mapped will always be >=1, and eventually streaming mapping will > fail because you've exhausted the address space. And if the device *is* > a USB controller, at that point the thread will hang because the USB > core's response to a DMA mapping failure happens to be "keep trying > indefinitely". You are absolutely right. My apologies for not providing more information in the first place. Like you mention, the workaround can not be made into something general purpose, however for some restricted use case it might be helpful. For instance, we have some MMC controllers that are able to perform on-chip bus mastering but they lack scatter gather support. >From the hardware design point of view the scatter gather feature was decided to be put into the IPMMU hardware. Because of that we would like to use the IPMMU hardware for this purpose, however with some ES specific errata we need to handle unmapping in a special way. Fortunately the MMC controllers are grouped together using the same IPMMU and we are able to make sure that all the buffers are unmapped now and then from a workaround in the MMC device driver. Not pretty but not super intrusive. > Essentially, however long this allocation workaround postpones it, one > or other failure mode is unavoidable with certain devices unless you can > do something drastic like periodically suspend and resume the entire > system to reset everything. Yeah, suspend/resume or unbind/bind might work. >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com> >> --- >> drivers/iommu/dma-iommu.c | 42 +- >> drivers/iommu/iova.c | 9 + >> include/linux/iommu.h | 2 ++ >> include/linux/iova.h | 1 + >> 4 files changed, 49 insertions(+), 5 deletions(-) >> >> diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c >> index a0b8c0f..d0fa0b1 100644 >> --- a/drivers/iommu/dma-iommu.c >> +++ b/drivers/iommu/dma-iommu.c >> @@ -42,6 +42,7 @@ struct iommu_dma_cookie { >> struct iova_domain iovad; >> struct list_headmsi_page_list; >> spinlock_t msi_lock; >> + spinlock_t reset_lock; > > So now we do get something in the cookie, but it's protecting a bunch of > machinery that's accessible from a wider scope? That doesn't seem like a > good design. It's not. =) There is room for improvement in the implementation for sure! We also had other ideas of tracking mapped pages per device instead of per domain. We have other requirements from the hardware to serialize some MMC data handling, so grouping the MMC devices together into a single IOMMU domain seemed light weight and simple for a first shot! >> }; >> >> static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) >> @@ -74,6 +75,7 @@ int iommu_get_dma_cookie(struct iommu_domain *domain) >> >> spin_lock_init(>msi_lock); >> INIT_LIST_HEAD(>msi_page_list); >> + spin_lock_init(>reset_lock); >> domain->iova_cookie = cookie; >> return 0; >> } >> @@ -208,9 +210,11 @@ int dma_direction_to_prot(enum dma_data_direction dir, >> bool coherent) >> static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, >> dma_addr_t dma_limit) >> { >> + struct iommu_dma_cookie *cookie = domain->iova_cookie; >> struct iova_domain *iovad = cookie_iovad(domain); >
Re: [PATCH/RFC 1/4] iommu: dma: track mapped iova
Hi Robin, Shimoda-san, everyone, On Thu, Jan 26, 2017 at 1:27 AM, Robin Murphy <robin.mur...@arm.com> wrote: > On 25/01/17 12:53, Yoshihiro Shimoda wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> To track mapped iova for a workaround code in the future. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com> >> --- >> drivers/iommu/dma-iommu.c | 29 +++-- >> include/linux/iommu.h | 2 ++ > > So what's being added here is a counter of allocations within the > iova_domain held by an iommu_dma_cookie? Then why is it all the way down > in the iommu_domain and not in the cookie? That's needlessly invasive - > it would be almost understandable (but still horrible) if you needed to > refer to it directly from the IOMMU driver, but as far as I can see you > don't. You are very correct about all points. =) As you noticed, the counter is kept per-domain. History is a bit blurry but I think the reason for my abstraction-breaking is that i decided to implement the simplest possible code to get the reset callback to near the iova code and the domain level seemed suitable as a first step. Moving it to a different level is of course no problem. My main concern for this series is however if a subsystem-level intrusive workaround like this ever could be beaten into acceptable form for upstream merge.The code is pretty simple - the main portion of the workaround is this counter that used to detect when the number of mapped pages drops back to zero together with the callback. But unless the code can be made pluggable it introduces overhead for all users. In your other email you asked what happens if the counter never drops to zero. You are right that this workaround is not a general-purpose fix suitable for all kinds of devices. Because of that the workaround is designed to be enabled on only some of the IPMMU instances on the system. It is also most likely an errata workaround for a particular ES version, so we would most likely have to enable it with soc_device_match(). I'll reply to patch 3/4 with some more details. Thanks! / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC 1/2] arm64: mm: Silently allow devices lacking IOMMU group
Hi Robin, On Mon, Jan 23, 2017 at 9:34 PM, Robin Murphy <robin.mur...@arm.com> wrote: > Hi Magnus, > > On 23/01/17 12:12, Magnus Damm wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Consider failure of iommu_get_domain_for_dev() as non-critical and >> get rid of the warning printout. This allows IOMMU properties to be >> included in the DTB even though the kernel is configured with >> CONFIG_IOMMU_API=n or in case a particular IOMMU driver refuses to >> enable IOMMU support for a certain slave device and returns error >> from the ->add_device() callback. >> >> This is only a cosmetic change that removes console warning printouts. > > The warning is there for a reason - at this point, we *expected* the > device to be using an IOMMU for DMA, so a failure is significant. Rather > than masking genuine failures in other cases because your case > deliberately breaks that expectation, simply change the expectation - > i.e. rather than letting of_xlate() succeed then failing add_device() > later, reject the of_xlate() call up-front such that the DMA layer never > gets told about the IOMMU in the first place. Thanks for pointing me in the right direction! I will try to handle this in xlate() instead. Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH/RFC 2/2] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version
Hi Geert, On Mon, Jan 23, 2017 at 9:50 PM, Geert Uytterhoeven <ge...@linux-m68k.org> wrote: > Hi Magnus, > > On Mon, Jan 23, 2017 at 1:12 PM, Magnus Damm <magnus.d...@gmail.com> wrote: >> From: Magnus Damm <damm+rene...@opensource.se> >> >> Match on r8a7795 ES2 and enable a certain DMA controller. >> In other cases the IPMMU driver remains disabled. >> >> Signed-off-by: Magnus Damm <damm+rene...@opensource.se> >> --- >> >> drivers/iommu/ipmmu-vmsa.c | 24 >> 1 file changed, 24 insertions(+) >> >> --- 0001/drivers/iommu/ipmmu-vmsa.c >> +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-23 20:57:02.620607110 +0900 >> @@ -23,6 +23,7 @@ >> #include >> #include >> #include >> +#include >> >> #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) >> #include >> @@ -1002,16 +1003,39 @@ static void ipmmu_domain_free_dma(struct >> } >> } >> >> +static const struct soc_device_attribute r8a7795es2[] = { >> + { .soc_id = "r8a7795", .revision = "ES2.*" }, >> + { /* sentinel */ } >> +}; >> + >> +static int ipmmu_slave_whitelist(struct device *dev) >> +{ >> + /* Opt-in slave devices based on SoC and ES version */ >> + if (soc_device_match(r8a7795es2)) { >> + if (!strcmp(dev_name(dev), "e731.dma-controller")) >> + return 0; >> + } > > I have two comments about the construct above: > 1. IPMMU will be disabled on all non-r8a7795 SoCs. > Is that what you want? Sort of. This patch is just an example to stir up some discussion about this topic. I realize this code as-is changes R-Car Gen2 behavior (that is merged upstream) so perhaps we should keep devices enabled for those SoCs. > 2. Usually we match on the old broken versions instead (e.g. against > "ES1.*"), as (1) it marks more clearly support for old SoCs, and > (2) it makes it easier to remove the check later when these > old SoCs are deemed extinct later. Right, if I understand correctly then you're saying opt-out might be better instead of opt-in. In case of IPMMU and R-Car Gen3 I believe it might be less work to use opt-in rather than excluding not-yet-working stuff. =) With this series I would like to propose to disconnect the DT integration timing from the enablement of IPMMU support for slave devices. If we can enable the IPMMU in DT early on we can reduce potential out-of-tree IPMMU enablement DT patches. So with the DT bindings fixed and accurate data sheet we can merge DT bits ahead of enablement time. And then use run time logic to determine what to enable based on test results. As you are aware, currently we have used the presence of "iommus" in DT to determine if a device is going to be enabled or not. So if the IPMMU Kconfig bits enable the IPMMU driver and the "iommus" DT property tie a certain slave device to the IPMMU then we will make use of IPMMU for a certain device. Currently we assume it will work on all ES versions that use that particular DTB. However ES specific hardware errata together with a wide range of ES versions for r8a7795 and r8a7796 (and whatever SoCs and ES versions that comes next) makes it difficult to use DT like above to enable stuff seemingly on one ES version without potentially breaking other ES versions. I would like to share DT files between the ES versions as much as possible but still only enable IPMMU support for devices that are known to work. Let me know if you think it makes sense to enable DT in a different way than my proposal. I'll have a look at putting the white list code in ->xlate() instead of ->add_device(). Thanks for your comments! Cheers, / magnus ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC 2/2] iommu/ipmmu-vmsa: Opt-in slave devices based on ES version
From: Magnus Damm <damm+rene...@opensource.se> Match on r8a7795 ES2 and enable a certain DMA controller. In other cases the IPMMU driver remains disabled. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- drivers/iommu/ipmmu-vmsa.c | 24 1 file changed, 24 insertions(+) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-23 20:57:02.620607110 +0900 @@ -23,6 +23,7 @@ #include #include #include +#include #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA) #include @@ -1002,16 +1003,39 @@ static void ipmmu_domain_free_dma(struct } } +static const struct soc_device_attribute r8a7795es2[] = { + { .soc_id = "r8a7795", .revision = "ES2.*" }, + { /* sentinel */ } +}; + +static int ipmmu_slave_whitelist(struct device *dev) +{ + /* Opt-in slave devices based on SoC and ES version */ + if (soc_device_match(r8a7795es2)) { + if (!strcmp(dev_name(dev), "e731.dma-controller")) + return 0; + } + + /* By default, do not allow use of IPMMU */ + return -ENODEV; +} + static int ipmmu_add_device_dma(struct device *dev) { struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; struct iommu_group *group; + int ret; /* only accept devices with iommus property */ if (of_count_phandle_with_args(dev->of_node, "iommus", "#iommu-cells") < 0) return -ENODEV; + /* opt-in devices based on SoC and ES version */ + ret = ipmmu_slave_whitelist(dev); + if (ret) + return ret; + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH/RFC 1/2] arm64: mm: Silently allow devices lacking IOMMU group
From: Magnus Damm <damm+rene...@opensource.se> Consider failure of iommu_get_domain_for_dev() as non-critical and get rid of the warning printout. This allows IOMMU properties to be included in the DTB even though the kernel is configured with CONFIG_IOMMU_API=n or in case a particular IOMMU driver refuses to enable IOMMU support for a certain slave device and returns error from the ->add_device() callback. This is only a cosmetic change that removes console warning printouts. Signed-off-by: Magnus Damm <damm+rene...@opensource.se> --- arch/arm64/mm/dma-mapping.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) --- 0001/arch/arm64/mm/dma-mapping.c +++ work/arch/arm64/mm/dma-mapping.c2017-01-23 20:54:40.060607110 +0900 @@ -827,11 +827,19 @@ static bool do_iommu_attach(struct devic struct iommu_domain *domain = iommu_get_domain_for_dev(dev); /* +* In case IOMMU support is excluded from the kernel or if the device +* is not hooked up to any IOMMU group then be silent and keep the +* old dma_ops. +*/ + if (!domain) + return false; + + /* * If the IOMMU driver has the DMA domain support that we require, * then the IOMMU core will have already configured a group for this * device, and allocated the default domain for that group. */ - if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) { + if (iommu_dma_init_domain(domain, dma_base, size, dev)) { pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", dev_name(dev)); return false; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu