iommu/ipmmu-vmsa: Initial r8a7795 support
cover iommu/ipmmu-vmsa: Initial r8a7795 support
iommu/ipmmu-vmsa: Initial r8a7795 support
[PATCH 01/10] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE() [PATCH 02/10] iommu/ipmmu-vmsa: Enable multi context support [PATCH 03/10] iommu/ipmmu-vmsa: Teach xlate() to skip disabled iommus [PATCH 04/10] iommu/ipmmu-vmsa: IPMMU device is 64-bit bus master [PATCH 05/10] iommu/ipmmu-vmsa: Introduce features, break out alias [PATCH 06/10] iommu/ipmmu-vmsa: Add optional root device feature [PATCH 07/10] iommu/ipmmu-vmsa: Write IMCTR twice
[PATCH 08/10] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional [PATCH 09/10] iommu/ipmmu-vmsa: Allow two bit SL0
[PATCH 10/10] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
This series contains slightly more mature r8a7795 support for the IPMMU driver compared to the earlier series posted as:
[PATCH/RFC 00/10] iommu/ipmmu-vmsa: Experimental r8a7795 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.
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().
The code is known to build on 32-bit and 64-bit ARM and x86_64. Tested on 32-bit ARM and 64-bit ARM with addtional DT integration changes.
---
Developed on top of next-20160315 and:
[PATCH v2 00/04] iommu/ipmmu-vmsa: IPMMU multi-arch update V2 [PATCH 00/04] iommu/ipmmu-vmsa: IPMMU CONFIG_IOMMU_DMA update
drivers/iommu/ipmmu-vmsa.c | 231 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 191 insertions(+), 40 deletions(-)
PATCH 1/10 iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
From: Magnus Damm <[email protected]>
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 this is required.
---
drivers/iommu/ipmmu-vmsa.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-)
drivers/iommu/ipmmu-vmsa.c +27 -4
@@ -19,6 +19,7 @@#include <linux/iommu.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_iommu.h> #include <linux/platform_device.h> #include <linux/sizes.h> #include <linux/slab.h>
@@ -1016,18 +1017,22 @@ static struct platform_driver ipmmu_drivstatic int __init ipmmu_init (void ) { -const struct iommu_ops *ops; +static bool setup_done;int ret; +if (setup_done) +return 0 ; + ret =platform_driver_register (&ipmmu_driver);if (ret <0 )return ret; - ops =IS_ENABLED (CONFIG_IOMMU_DMA ) ? &ipmmu_ops_dma : &ipmmu_ops; - +#if defined(CONFIG_ARM ) && !defined(CONFIG_IOMMU_DMA )if (!iommu_present (&platform_bus_type)) -bus_set_iommu (&platform_bus_type, ops); +bus_set_iommu (&platform_bus_type, &ipmmu_ops); +#endif + setup_done = true;return 0 ; }
@@ -1039,6 +1044,24 @@ 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) +{ +static const struct iommu_ops *ops = &ipmmu_ops_dma; + +ipmmu_init (); + +of_iommu_set_ops (np, (struct iommu_ops *)ops); +if (!iommu_present (&platform_bus_type)) +bus_set_iommu (&platform_bus_type, ops); + +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 <[email protected]>" );MODULE_LICENSE ("GPL v2" );
PATCH 2/10 iommu/ipmmu-vmsa: Enable multi context support
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Add support for up to 4 contexts. Each context is mapped to one domain. One domain is associated with each device, however one or more uTLBs for a single device are kept in the same domain.
---
drivers/iommu/ipmmu-vmsa.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/iommu/ipmmu-vmsa.c +9 -2
@@ -31,7 +31,7 @@#include "io-pgtable.h" -#define IPMMU_CTX_MAX 1 +#define IPMMU_CTX_MAX 4struct ipmmu_vmsa_device {struct device *dev;
@@ -536,6 +536,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
@@ -915,7 +922,7 @@ static void ipmmu_device_reset(struct ipunsigned int i;/* Disable all contexts. */ -for (i =0 ; i <4 ; ++i) +for (i =0 ; i <IPMMU_CTX_MAX ; ++i)ipmmu_write (mmu, i *IM_CTX_SIZE +IMCTR ,0 ); }
PATCH 3/10 iommu/ipmmu-vmsa: Teach xlate() to skip disabled iommus
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Right now the ->xlate() call gets invoked even though the iommu device has status = "disabled" in DT, so make sure we skip over disabled devices.
In my mind it would make sense to have this at some shared level, but I guess some users may want to configure the iommu regardless of DT state.
---
drivers/iommu/ipmmu-vmsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/iommu/ipmmu-vmsa.c +7 -1
@@ -890,7 +890,13 @@ static struct iommu_group *ipmmu_device_static int ipmmu_of_xlate_dma (struct device *dev,struct of_phandle_args *spec) { -/* dummy callback to satisfy of_iommu_configure() */ +/* 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 ; }#endif
Re: [PATCH 03/10] iommu/ipmmu-vmsa: Teach xlate() to skip disabled iommus
Quoted 21 lines · Magnus Damm
From: Magnus Damm <[email protected]>
Right now the ->xlate() call gets invoked even though the iommu device has status = "disabled" in DT, so make sure we skip over disabled devices.
In my mind it would make sense to have this at some shared level, but I guess some users may want to configure the iommu regardless of DT state.
Signed-off-by Magnus Damm <[email protected]>---
drivers/iommu/ipmmu-vmsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)drivers/iommu/ipmmu-vmsa.c 2016-03-18 00:16:51.200513000 +0900 renamed from drivers/iommu/ipmmu-vmsa.c +0
-0@@ -890,7 +890,13 @@ static struct iommu_group *ipmmu_device_ static int ipmmu_of_xlate_dma(struct device *dev, struct of_phandle_args *spec)
drivers/iommu/ipmmu-vmsa.c 2016-03-18 00:16:51.200513000 +0900 static struct iommu_group *ipmmu_device_ · line 900
Quoted 10 lines
drivers/iommu/ipmmu-vmsa.c 2016-03-18 00:16:51.200513000 +0900 renamed from drivers/iommu/ipmmu-vmsa.c +7
-1{ - /* dummy callback to satisfy of_iommu_configure() */ + /* 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;
I think this should be handled in drivers/iommu/of_iommu.c:of_iommu_init() instead, cfr. commit 3e5dd6f6e690048d ("clk: Ignore disabled DT clock providers").
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
PATCH 4/10 iommu/ipmmu-vmsa: IPMMU device is 64-bit bus master
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
The r8a7795 IPMMU supports 64-bit bus mastering and coherency for page tables.
---
drivers/iommu/ipmmu-vmsa.c | 1 + 1 file changed, 1 insertion(+)
drivers/iommu/ipmmu-vmsa.c +1 -0
@@ -948,6 +948,7 @@ static int ipmmu_probe(struct platform_d mmu->dev = &pdev->dev; mmu->num_utlbs =32 ;bitmap_zero (mmu->ctx,IPMMU_CTX_MAX ); +dma_set_mask_and_coherent (&pdev->dev,DMA_BIT_MASK (64 ));/* Map I/O memory and request IRQ. */ res =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
PATCH 5/10 iommu/ipmmu-vmsa: Introduce features, break out alias
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
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.
---
drivers/iommu/ipmmu-vmsa.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-)
drivers/iommu/ipmmu-vmsa.c +28 -6
@@ -33,6 +33,10 @@#define IPMMU_CTX_MAX 4 +struct ipmmu_features { +bool use_ns_alias_offset; +}; +struct ipmmu_vmsa_device {struct device *dev;void __iomem *base;
@@ -45,6 +49,7 @@ struct ipmmu_vmsa_device {#if defined(CONFIG_ARM ) && !defined(CONFIG_IOMMU_DMA )struct dma_iommu_mapping *mapping;#endif +const struct ipmmu_features *features; };struct ipmmu_vmsa_domain {
@@ -932,13 +937,33 @@ static void ipmmu_device_reset(struct ipipmmu_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 = &ipmmu_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); +if (!match) +return -EINVAL ; + mmu =devm_kzalloc (&pdev->dev,sizeof (*mmu),GFP_KERNEL );if (!mmu) {dev_err (&pdev->dev,"cannot allocate device data\n" );
@@ -948,6 +973,7 @@ static int ipmmu_probe(struct platform_d mmu->dev = &pdev->dev; mmu->num_utlbs =32 ;bitmap_zero (mmu->ctx,IPMMU_CTX_MAX ); + mmu->features = match->data;dma_set_mask_and_coherent (&pdev->dev,DMA_BIT_MASK (64 ));/* Map I/O memory and request IRQ. */
@@ -968,7 +994,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 ) {
@@ -1015,11 +1042,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" ,
PATCH 6/10 iommu/ipmmu-vmsa: Add optional root device feature
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
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.
---
drivers/iommu/ipmmu-vmsa.c | 92 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 19 deletions(-)
drivers/iommu/ipmmu-vmsa.c +73 -19
@@ -35,6 +35,7 @@struct ipmmu_features {bool use_ns_alias_offset; +bool has_cache_leaf_nodes; };struct ipmmu_vmsa_device {
@@ -50,10 +51,12 @@ struct ipmmu_vmsa_device {struct dma_iommu_mapping *mapping;#endif const struct ipmmu_features *features; +bool is_leaf; };struct ipmmu_vmsa_domain {struct ipmmu_vmsa_device *mmu; +struct ipmmu_vmsa_device *root;struct iommu_domain io_domain;struct io_pgtable_cfg cfg;
@@ -198,6 +201,36 @@ static struct ipmmu_vmsa_domain *to_vmsa#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 (struct ipmmu_vmsa_device *leaf) +{ +struct ipmmu_vmsa_device *mmu =NULL ; + +if (ipmmu_is_root (leaf)) +return leaf; + +spin_lock (&ipmmu_devices_lock); + +list_for_each_entry (mmu, &ipmmu_devices, list) { +if (ipmmu_is_root (mmu)) +break ; + } + +spin_unlock (&ipmmu_devices_lock); +return mmu; +} + +/* ----------------------------------------------------------------------------- * Read/Write Access */
@@ -214,13 +247,13 @@ static void ipmmu_write(struct ipmmu_vmsstatic 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); }/* -----------------------------------------------------------------------------
@@ -334,7 +367,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 , &domain->cfg, domain);
@@ -344,15 +377,15 @@ static int ipmmu_domain_init_context(str/* * Find an unused context. */ - ret =find_first_zero_bit (domain->mmu->ctx,IPMMU_CTX_MAX ); + ret =find_first_zero_bit (domain->root->ctx,IPMMU_CTX_MAX );if (ret ==IPMMU_CTX_MAX ) {free_io_pgtable_ops (domain->iop);return -EBUSY ; } domain->context_id = ret; - domain->mmu->domains[ret] = domain; -set_bit (ret, domain->mmu->ctx); + domain->root->domains[ret] = domain; +set_bit (ret, domain->root->ctx);/* TTBR0 */ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0 ];
@@ -396,7 +429,7 @@ static int ipmmu_domain_init_context(strstatic void ipmmu_domain_destroy_context (struct ipmmu_vmsa_domain *domain) { -clear_bit (domain->context_id, domain->mmu->ctx); +clear_bit (domain->context_id, domain->root->ctx);/* * Disable the context. Flush the TLB as required when modifying the
@@ -524,7 +557,7 @@ static int ipmmu_attach_device(struct io struct device *dev) {struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; -struct ipmmu_vmsa_device *mmu = archdata->mmu; +struct ipmmu_vmsa_device *root, *mmu = archdata->mmu;struct ipmmu_vmsa_domain *domain =to_vmsa_domain (io_domain);unsigned long flags;unsigned int i;
@@ -535,15 +568,23 @@ static int ipmmu_attach_device(struct ioreturn -ENXIO ; } + root =ipmmu_find_root (archdata->mmu); +if (!root) { +dev_err (dev,"Unable to locate root IPMMU\n" ); +return -EAGAIN ; + } +spin_lock_irqsave (&domain->lock, flags);if (!domain->mmu) {/* The domain hasn't been used yet, initialize it. */ 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);
@@ -939,6 +980,7 @@ static void ipmmu_device_reset(struct ipstatic const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, + .has_cache_leaf_nodes = false, };static const struct of_device_id ipmmu_of_ids[] = {
@@ -998,19 +1040,31 @@ static int ipmmu_probe(struct platform_d mmu->base +=IM_NS_ALIAS_OFFSET ; irq =platform_get_irq (pdev,0 ); -if (irq <0 ) { -dev_err (&pdev->dev,"no IRQ found\n" ); -return irq; - } - ret =devm_request_irq (&pdev->dev, irq, ipmmu_irq,0 , -dev_name (&pdev->dev), mmu); -if (ret <0 ) { -dev_err (&pdev->dev,"failed to request IRQ %d\n" , irq); -return ret; - } +/* +* Determine if this IPMMU instance is a leaf device by checking +* if the renesas,ipmmu-main property exists or not. +*/ +if (mmu->features->has_cache_leaf_nodes && +of_find_property (pdev->dev.of_node,"renesas,ipmmu-main" ,NULL )) + mmu->is_leaf = true; + +/* Root devices have mandatory IRQs */ +if (ipmmu_is_root (mmu)) { +if (irq <0 ) { +dev_err (&pdev->dev,"no IRQ found\n" ); +return irq; + } + + ret =devm_request_irq (&pdev->dev, irq, ipmmu_irq,0 , +dev_name (&pdev->dev), mmu); +if (ret <0 ) { +dev_err (&pdev->dev,"failed to request IRQ %d\n" , irq); +return ret; + } -ipmmu_device_reset (mmu); +ipmmu_device_reset (mmu); + }/* * We can't create the ARM mapping here as it requires the bus to have
PATCH 7/10 iommu/ipmmu-vmsa: Write IMCTR twice
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Write IMCTR both in the root device and the leaf node.
---
drivers/iommu/ipmmu-vmsa.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/iommu/ipmmu-vmsa.c +14 -3
@@ -256,6 +256,16 @@ static void ipmmu_ctx_write(struct ipmmuipmmu_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 */
@@ -282,7 +292,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); }
@@ -422,7 +432,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 ; }
@@ -437,7 +448,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); }
PATCH 8/10 iommu/ipmmu-vmsa: Make IMBUSCTR setup optional
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Allow certain DT compat strings to opt-out of setting up IMBUSCR. The default case is unchanged.
---
drivers/iommu/ipmmu-vmsa.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iommu/ipmmu-vmsa.c +6 -4
@@ -36,6 +36,7 @@struct ipmmu_features {bool use_ns_alias_offset;bool has_cache_leaf_nodes; +bool setup_imbuscr; };struct ipmmu_vmsa_device {
@@ -415,10 +416,10 @@ static int ipmmu_domain_init_context(stripmmu_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.
@@ -992,6 +993,7 @@ static void ipmmu_device_reset(struct ipstatic const struct ipmmu_features ipmmu_features_default = { .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, + .setup_imbuscr = true, };static const struct of_device_id ipmmu_of_ids[] = {
PATCH 9/10 iommu/ipmmu-vmsa: Allow two bit SL0
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Introduce support for two bit SL0 bitfield in IMTTBCR by using a separate feature flag.
---
drivers/iommu/ipmmu-vmsa.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/iommu/ipmmu-vmsa.c +14 -1
@@ -37,6 +37,7 @@ struct ipmmu_features {bool use_ns_alias_offset;bool has_cache_leaf_nodes;bool setup_imbuscr; +bool twobit_imttbcr_sl0; };struct ipmmu_vmsa_device {
@@ -141,6 +142,10 @@ static struct ipmmu_vmsa_domain *to_vmsa#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 IMBUSCR 0x000c#define IMBUSCR_DVM (1 << 2)#define IMBUSCR_BUSSEL_SYS (0 << 0)
@@ -356,6 +361,7 @@ static struct iommu_gather_ops ipmmu_gatstatic int ipmmu_domain_init_context (struct ipmmu_vmsa_domain *domain) {u64 ttbr; +u32 tmp;int ret;/*
@@ -408,9 +414,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 ]);
@@ -994,6 +1006,7 @@ static const struct ipmmu_features ipmmu .use_ns_alias_offset = true, .has_cache_leaf_nodes = false, .setup_imbuscr = true, + .twobit_imttbcr_sl0 = false, };static const struct of_device_id ipmmu_of_ids[] = {
PATCH 10/10 iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code
In reply to Magnus DammFrom: Magnus Damm <[email protected]>
Tie in r8a7795 features and update the IOMMU_OF_DECLARE compat string to hook up the updated compat string.
TODO:
- Go over init order once more
- Consider counting number of IPMMU devices from ->xlate()
- Experiment with delaying call to bus_set_iommu()
- Poke around with IPMMU-MP1 and the associated dma-controller
- 64-bit bus mastering and coherency may need per-device enablement
---
drivers/iommu/ipmmu-vmsa.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/iommu/ipmmu-vmsa.c +12 -0
@@ -1009,11 +1009,21 @@ 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, + .setup_imbuscr = false, + .twobit_imttbcr_sl0 = true, +}; +static const struct of_device_id ipmmu_of_ids[] = { { .compatible ="renesas,ipmmu-vmsa" , .data = &ipmmu_features_default, }, { + .compatible ="renesas,ipmmu-r8a7795" , + .data = &ipmmu_features_r8a7795, + }, {/* Terminator */ }, };
@@ -1176,6 +1186,8 @@ static int __init ipmmu_vmsa_iommu_of_seIOMMU_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" );