Re: [PATCH 3/5] iommu/arm-smmu: Introduce stream ID masking

2013-10-09 Thread Andreas Herrmann
On Wed, Oct 09, 2013 at 06:09:17AM -0400, Will Deacon wrote:
> On Tue, Oct 08, 2013 at 07:43:50PM +0100, Rob Herring wrote:
> > On 10/08/2013 11:59 AM, Will Deacon wrote:
> > > On Tue, Oct 08, 2013 at 05:40:21PM +0100, Andreas Herrmann wrote:
> > >> On Tue, Oct 08, 2013 at 05:20:08PM +0200, Andreas Herrmann wrote:
> > >> To be more specific: For SATA I'd need to specify 10 StreamIds. This
> > >> would
> > >>
> > >> (1) exceed MAX_MASTER_STREAMIDS (currently it's 8)
> > >>
> > >>(Can easily be fixed by adapting a macro.)
> > >>
> > >> (2) exceed number of available SMR groups to map the IDs to a context.
> > >>
> > >>This can be solved by caclulating an appropriate mask for the
> > >>mapping (but with a non-power-of-two number of StreamIds that's
> > >>already non-trivial -- for the trivial case I have some code to do
> > >>this).
> > >>
> > >> Both problems are avoided by introducing this patch -- use
> > >> smr_mask_bits to map all StreamIDs to the same context and be done
> > >> with it. (for the "single-master-SMMU" case)
> > > 
> > > The problem is, this information *really* doesn't belong in the device 
> > > tree,
> > > but I think computing the general case dynamically is incredibly difficult
> > > too (and requires *complete* topological information in the device-tree, 
> > > so
> > > you don't accidentally pull in other devices).
> > 
> > Couldn't this information be implied from the DT when you have no
> > streamID and only a single mmu-master?
> 
> It's still fairly fragile though, since you (a) don't know that the stream
> IDs of the master are matchable by the SMRs (if we had the stream IDs, we
> can check this) and (b) you can still end up pulling devices into your
> address space that would otherwise happily operate using passthrough.

FYI, for SATA I'd have to specify below IDs (which requires some other
minor adaptions). I really would like to avoid specification of all
these StreamIDs and rather use stream matching with an appropriate
mask.

I can't end up pulling other devices into that mapping. It's just this
single master device at this SMMU.

And I also think that this "mask-all-stream-ids" option belongs to the
device tree as an hint to the driver that it is sane to use
smr_mask_bits as a mask for stream matching for this particular SMMU.


Andreas

---
ecx-2000, iommu/arm-smmu, of: Add all 10 StreamIDs for sata-smmu

Unfortunately this requires adaptions of MAX_MASTER_STREAMIDS and
MAX_PHANDLE_ARGS.

It still won't work with the current arm-smmu driver as it strictly
uses one SMR group for each StreamID. (But the corresponding SMMU has
just 4 SMR groups).

Signed-off-by: Andreas Herrmann 
---
 arch/arm/boot/dts/ecx-2000.dts|2 +-
 arch/arm/boot/dts/ecx-common.dtsi |2 +-
 drivers/iommu/arm-smmu.c  |2 +-
 include/linux/of.h|2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/ecx-2000.dts b/arch/arm/boot/dts/ecx-2000.dts
index 270f052..3904c2b 100644
--- a/arch/arm/boot/dts/ecx-2000.dts
+++ b/arch/arm/boot/dts/ecx-2000.dts
@@ -135,7 +135,7 @@
smmu_sata: smmu@92018 {
compatible = "arm,mmu-400";
reg = <0x0009 0x2018 0x1>;
-   mmu-masters = <&sata>;
+   mmu-masters = <&sata 0 1 2 3 4 5 6 7 8 9>;
#global-interrupts = <1>;
interrupts = <0 114 4 0 114 4>;
arm,smmu-secure-config-access;
diff --git a/arch/arm/boot/dts/ecx-common.dtsi 
b/arch/arm/boot/dts/ecx-common.dtsi
index 50e401e..961dc5b 100644
--- a/arch/arm/boot/dts/ecx-common.dtsi
+++ b/arch/arm/boot/dts/ecx-common.dtsi
@@ -35,7 +35,7 @@
 &combophy0 3>;
calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>;
calxeda,led-order = <4 0 1 2 3>;
-   #stream-id-cells = <0>;
+   #stream-id-cells = <10>;
};
 
sdhci@ffe0e000 {
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 4e8ceab..cd370f7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -55,7 +55,7 @@
 #define ARM_SMMU_OPT_SECURE_CONFIG_ACCESS  (1 << 2)
 
 /* Maximum number of stream IDs assigned to a single device */
-#define MAX_MASTER_STREAMIDS   8
+#define MAX_MASTER_STREAMIDS   10
 
 /* Maximum number of context banks per SMMU */
 #define ARM_SMMU_MAX_CBS   128
diff --git a/include/linux/of.h b/include/linux/of.h
index f95aee3..47f4857 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -67,7 +67,7 @@ struct device_node {
 #endif
 };
 
-#define MAX_PHANDLE_ARGS 8
+#define MAX_PHANDLE_ARGS 10
 struct of_phandle_args {
struct device_node *np;
int args_count;
-- 
1.7.9.5


___
iommu mailing list
iommu@

Re: [PATCH 3/5] iommu/arm-smmu: Introduce stream ID masking

2013-10-09 Thread Andreas Herrmann
On Tue, Oct 08, 2013 at 12:59:20PM -0400, Will Deacon wrote:
> On Tue, Oct 08, 2013 at 05:40:21PM +0100, Andreas Herrmann wrote:
> > On Tue, Oct 08, 2013 at 05:20:08PM +0200, Andreas Herrmann wrote:
> > To be more specific: For SATA I'd need to specify 10 StreamIds. This
> > would
> > 
> > (1) exceed MAX_MASTER_STREAMIDS (currently it's 8)
> > 
> >(Can easily be fixed by adapting a macro.)
> > 
> > (2) exceed number of available SMR groups to map the IDs to a context.
> > 
> >This can be solved by caclulating an appropriate mask for the
> >mapping (but with a non-power-of-two number of StreamIds that's
> >already non-trivial -- for the trivial case I have some code to do
> >this).
> > 
> > Both problems are avoided by introducing this patch -- use
> > smr_mask_bits to map all StreamIDs to the same context and be done
> > with it. (for the "single-master-SMMU" case)
> 
> The problem is, this information *really* doesn't belong in the device tree,
> but I think computing the general case dynamically is incredibly difficult
> too (and requires *complete* topological information in the device-tree, so
> you don't accidentally pull in other devices).

So, if this kind of driver option does not belong to the device tree,
what's the preferred solution to tell the driver to use smr_mask_bits
as a mask for stream matching for a certain SMMU (that has only one
master)?
 
> > PS: I think (2) needs to be addressed sooner or later. We should use
> > only as many SMR groups as really required -- ie. use masking of
> > StreamIds if possible. If more than one StreamID is given for a
> > master it might be possible to calculate a mask for a
> > (power-of-two) number of adjacent StreamIds and then use only one
> > SMR group to map these IDs to a context. (But I think that should
> > only be done if multiple masters are attached to an SMMU.)
> 
> I spent a few weeks looking at doing minimal SMR grouping whilst writing the
> driver and ended up convincing myself that it's an NP-complete problem (I
> tried a reduction involving Hamiltonian Cycles). Of course, if you have some
> ideas here, we can try to implement something for a constrained instance of
> the problem.
> 
> For example, a simple solution is to xor all the IDs together and check no
> other IDs fall under the resulting mask. However, this again relies on the
> DT telling us complete topological information as well as the IDs being
> organised in a particular way.

Yes, it is an ugly problem. But assuming that the StreamIDs in many
cases have a particular organsiation it should be possible to
calculate a mask with reasonable effort. (I've attached a patch to do
this for certain cases).

I think it could be extended, such that in a case where StreamIDs 0,
... 9 are specified for a master the driver could set up

 SMR0 with mask 0x7, id 0 (mapping StreamIDs 0, ..., 7)
 SMR1 for StreamID 8
 SMR2 for StreamID 9

Thus 3 SMR groups would be used instead of 10 (as it is done with the
current implementation).



Andreas

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 7/7] iommu/arm-smmu: Introduce automatic stream-id-masking

2013-10-09 Thread Andreas Herrmann
Try to determine a mask that can be used for all StreamIDs of a master
device. This allows to use just one SMR group instead of
number-of-streamids SMR groups for a master device.

Signed-off-by: Andreas Herrmann 
---
 drivers/iommu/arm-smmu.c |   79 --
 1 file changed, 63 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 91316a8..4e8ceab 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,7 @@
  * - Context fault reporting
  */
 
+#define DEBUG
 #define pr_fmt(fmt) "arm-smmu: " fmt
 
 #include 
@@ -341,6 +342,9 @@ struct arm_smmu_master {
struct rb_node  node;
int num_streamids;
u16 streamids[MAX_MASTER_STREAMIDS];
+   int num_smrs;
+   u16 smr_mask;
+   u16 smr_id;
 
/*
 * We only need to allocate these on the root SMMU, as we
@@ -530,14 +534,11 @@ static int register_smmu_master(struct arm_smmu_device 
*smmu,
ARM_SMMU_OPT_MASK_STREAM_IDS));
return -EINVAL;
}
-   /* set fixed streamid (0) that will be used for masking */
-   master->num_streamids = 1;
-   master->streamids[0] = 0;
-   } else {
-   for (i = 0; i < master->num_streamids; ++i)
-   master->streamids[i] = masterspec->args[i];
}
 
+   for (i = 0; i < master->num_streamids; ++i)
+   master->streamids[i] = masterspec->args[i];
+
return insert_smmu_master(smmu, master);
 }
 
@@ -1049,6 +1050,41 @@ static void arm_smmu_domain_destroy(struct iommu_domain 
*domain)
kfree(smmu_domain);
 }
 
+/*
+ * no duplicates streamids please
+ */
+static void determine_smr_mapping(struct arm_smmu_device *smmu,
+   struct arm_smmu_master *master)
+{
+   int nr_sid;
+   u16 i, v1, v2, const_mask;
+
+   if (smmu->options & ARM_SMMU_OPT_MASK_STREAM_IDS) {
+   master->smr_mask = smmu->smr_mask_bits;
+   master->smr_id = 0;
+   return;
+   }
+
+   nr_sid = master->num_streamids;
+   if (!is_power_of_2(nr_sid))
+   return;
+
+   v1 = 0;
+   v2 = -1;
+   for (i = 0; i < nr_sid; i++) {
+   v1 |= master->streamids[i]; /* for const 0 bits */
+   v2 &= ~(master->streamids[i]);  /* const 1 bits */
+   }
+   const_mask = (~v1) | v2;/* const bits (either 0 or 1) */
+
+   v1 = hweight16(~const_mask);
+   if ((1 << v1) == nr_sid) {
+   /* if smr_mask is set, only 1 SMR group is used smr[0] = 0 */
+   master->smr_mask = ~const_mask;
+   master->smr_id = v1 & const_mask;
+   }
+}
+
 static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
  struct arm_smmu_master *master)
 {
@@ -1062,15 +1098,22 @@ static int arm_smmu_master_configure_smrs(struct 
arm_smmu_device *smmu,
if (master->smrs)
return -EEXIST;
 
-   smrs = kmalloc(sizeof(*smrs) * master->num_streamids, GFP_KERNEL);
+   determine_smr_mapping(smmu, master);
+
+   if (master->smr_mask)
+   master->num_smrs = 1;
+   else
+   master->num_smrs = master->num_streamids;
+
+   smrs = kmalloc(sizeof(*smrs) * master->num_smrs, GFP_KERNEL);
if (!smrs) {
dev_err(smmu->dev, "failed to allocate %d SMRs for master %s\n",
-   master->num_streamids, master->of_node->name);
+   master->num_smrs, master->of_node->name);
return -ENOMEM;
}
 
/* Allocate the SMRs on the root SMMU */
-   for (i = 0; i < master->num_streamids; ++i) {
+   for (i = 0; i < master->num_smrs; ++i) {
int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
  smmu->num_mapping_groups);
if (IS_ERR_VALUE(idx)) {
@@ -1079,16 +1122,18 @@ static int arm_smmu_master_configure_smrs(struct 
arm_smmu_device *smmu,
}
 
smrs[i].idx = idx;
-   smrs[i].id = master->streamids[i];
 
-   if (smmu->options & ARM_SMMU_OPT_MASK_STREAM_IDS)
-   smrs[i].mask = smmu->smr_mask_bits;
-   else
+   if (master->smr_mask) {
+   smrs[i].mask = master->smr_mask;
+   smrs[i].id = master->smr_id;
+   } else {
smrs[i].mask = 0;
+   smrs[i].id = master->streamids[i];
+   }
}
 
/* It worked! Now, poke the actual hardware */
-   for (i = 0; i < master->num_streamid

[PATCH 2/7] iommu/arm-smmu: Introduce bus notifier block

2013-10-09 Thread Andreas Herrmann
At the moment just handle BUS_NOTIFY_BIND_DRIVER to conditionally
isolate all master devices for an SMMU.

Depending on DT information each device is put into its own protection
domain (if possible).  For configuration with one or just a few
masters per SMMU that is easy to achieve.

In case of many devices per SMMU (e.g. MMU-500 with it's distributed
translation support) isolation of each device might not be possible --
depending on number of available SMR groups and/or context banks.

Default is that device isolation is contolled per SMMU with SMMU node
property "arm,smmu-isolate-devices" in a DT. If this property is set
for an SMMU node, device isolation is performed.

W/o device isolation the driver detects SMMUs but no translation is
configured (transactions just bypass translation process).

Note that for device isolation dma_base and size are fixed as 0 and
SZ_128M at the moment.

Signed-off-by: Andreas Herrmann 
---
 drivers/iommu/arm-smmu.c |   53 ++
 1 file changed, 53 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 478c8ad..87239e8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -46,6 +46,7 @@
 #include 
 
 #include 
+#include 
 
 /* Driver options */
 #define ARM_SMMU_OPT_ISOLATE_DEVICES   (1 << 0)
@@ -1983,6 +1984,56 @@ static int arm_smmu_device_remove(struct platform_device 
*pdev)
return 0;
 }
 
+static int arm_smmu_device_notifier(struct notifier_block *nb,
+   unsigned long action, void *data)
+{
+   struct device *dev = data;
+   struct dma_iommu_mapping *mapping;
+   struct arm_smmu_device *smmu;
+   void __iomem *gr0_base;
+   u32 cr0;
+   int ret;
+
+   switch (action) {
+   case BUS_NOTIFY_BIND_DRIVER:
+
+   arm_smmu_add_device(dev);
+   smmu = dev->archdata.iommu;
+   if (!smmu || !(smmu->options & ARM_SMMU_OPT_ISOLATE_DEVICES))
+   break;
+
+   mapping = arm_iommu_create_mapping(&platform_bus_type,
+   0, SZ_128M, 0);
+   if (IS_ERR(mapping)) {
+   ret = PTR_ERR(mapping);
+   dev_info(dev, "arm_iommu_create_mapping failed\n");
+   break;
+   }
+
+   ret = arm_iommu_attach_device(dev, mapping);
+   if (ret < 0) {
+   dev_info(dev, "arm_iommu_attach_device failed\n");
+   arm_iommu_release_mapping(mapping);
+   }
+
+   gr0_base = ARM_SMMU_GR0_NS(smmu);
+   cr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
+   cr0 |= sCR0_USFCFG;
+   writel(cr0, gr0_base + ARM_SMMU_GR0_sCR0);
+
+   break;
+
+   default:
+   break;
+   }
+
+   return 0;
+}
+
+static struct notifier_block device_nb = {
+   .notifier_call = arm_smmu_device_notifier,
+};
+
 #ifdef CONFIG_OF
 static struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,smmu-v1", },
@@ -2019,6 +2070,8 @@ static int __init arm_smmu_init(void)
if (!iommu_present(&amba_bustype))
bus_set_iommu(&amba_bustype, &arm_smmu_ops);
 
+   bus_register_notifier(&platform_bus_type, &device_nb);
+
return 0;
 }
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 6/7] documentation/iommu: Update description of ARM System MMU binding

2013-10-09 Thread Andreas Herrmann
This patch adds descriptions fore new properties of device tree
binding for the ARM SMMU architecture. These properties control
arm-smmu driver options.

Cc: Rob Herring 
Cc: Grant Likely 
Cc: Will Deacon 
Signed-off-by: Andreas Herrmann 
---
 .../devicetree/bindings/iommu/arm,smmu.txt |   23 
 1 file changed, 23 insertions(+)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt 
b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index e34c6cd..6415a88 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -48,6 +48,28 @@ conditions.
   from the mmu-masters towards memory) node for this
   SMMU.
 
+- arm,smmu-isolate-devices : Enable device isolation for all masters
+ of this SMMU. Ie. each master will be
+ attached to its own iommu domain.
+
+- arm,smmu-mask-stream-ids : Enable mapping of all StreamIDs to one
+ context for this SMMU. It is only allowed
+ if there is one single master. It saves
+ the need to know and specify all
+ StreamIDs in cases where just one master
+ is attached to an SMMU. If StreamIDs are
+ specified in the mmu-masters property
+ those are ignored. (The referred device
+ node must still have a "#stream-id-cells"
+ property. But it can be set to 0.)
+
+- arm,smmu-secure-config-access : Enable proper handling of buggy
+  implementations that always use
+  secure access to SMMU configuration
+  registers. In this case non-secure
+  aliases of secure registers have to
+  be used during SMMU configuration.
+
 Example:
 
 smmu {
@@ -67,4 +89,5 @@ Example:
  */
 mmu-masters = <&dma0 0xd01d 0xd01e>,
   <&dma1 0xd11c>;
+arm,smmu-isolate-devices;
 };
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 3/7] iommu/arm-smmu: Introduce stream ID masking

2013-10-09 Thread Andreas Herrmann
Ie. use a mask based on smr_mask_bits to map all stream IDs of an SMMU
to one context.

This behaviour is controlled per SMMU node with DT property
"arm,smmu-mask-stream-ids" and is only allowed if just a single master
is attached to an SMMU. If the option is specified, all stream-ids
that are provided in DT for the single master have no relevance.

This is useful/convenient if a master has more than 8 stream-ids or if
not all stream-ids are known for a master device.

Signed-off-by: Andreas Herrmann 
---
 drivers/iommu/arm-smmu.c |   44 
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 87239e8..f877d02 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -50,6 +50,7 @@
 
 /* Driver options */
 #define ARM_SMMU_OPT_ISOLATE_DEVICES   (1 << 0)
+#define ARM_SMMU_OPT_MASK_STREAM_IDS   (1 << 1)
 
 /* Maximum number of stream IDs assigned to a single device */
 #define MAX_MASTER_STREAMIDS   8
@@ -362,6 +363,7 @@ struct arm_smmu_device {
 
u32 num_mapping_groups;
DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
+   u32 smr_mask_bits;
 
unsigned long   input_size;
unsigned long   s1_output_size;
@@ -373,6 +375,7 @@ struct arm_smmu_device {
 
struct list_headlist;
struct rb_root  masters;
+   u32 num_masters;
 };
 
 struct arm_smmu_cfg {
@@ -410,6 +413,7 @@ struct arm_smmu_option_prop {
 
 static struct arm_smmu_option_prop arm_smmu_options [] = {
{ ARM_SMMU_OPT_ISOLATE_DEVICES, "arm,smmu-isolate-devices" },
+   { ARM_SMMU_OPT_MASK_STREAM_IDS, "arm,smmu-mask-stream-ids" },
{ 0, NULL},
 };
 
@@ -475,6 +479,7 @@ static int insert_smmu_master(struct arm_smmu_device *smmu,
 
rb_link_node(&master->node, parent, new);
rb_insert_color(&master->node, &smmu->masters);
+   smmu->num_masters++;
return 0;
 }
 
@@ -507,8 +512,20 @@ static int register_smmu_master(struct arm_smmu_device 
*smmu,
master->of_node = masterspec->np;
master->num_streamids   = masterspec->args_count;
 
-   for (i = 0; i < master->num_streamids; ++i)
-   master->streamids[i] = masterspec->args[i];
+   if (smmu->options & ARM_SMMU_OPT_MASK_STREAM_IDS) {
+   if (smmu->num_masters) {
+   dev_err(dev, "%s not supported with multiple masters\n",
+   get_driver_option_property(
+   ARM_SMMU_OPT_MASK_STREAM_IDS));
+   return -EINVAL;
+   }
+   /* set fixed streamid (0) that will be used for masking */
+   master->num_streamids = 1;
+   master->streamids[0] = 0;
+   } else {
+   for (i = 0; i < master->num_streamids; ++i)
+   master->streamids[i] = masterspec->args[i];
+   }
 
return insert_smmu_master(smmu, master);
 }
@@ -1050,17 +1067,20 @@ static int arm_smmu_master_configure_smrs(struct 
arm_smmu_device *smmu,
goto err_free_smrs;
}
 
-   smrs[i] = (struct arm_smmu_smr) {
-   .idx= idx,
-   .mask   = 0, /* We don't currently share SMRs */
-   .id = master->streamids[i],
-   };
+   smrs[i].idx = idx;
+   smrs[i].id = master->streamids[i];
+
+   if (smmu->options & ARM_SMMU_OPT_MASK_STREAM_IDS)
+   smrs[i].mask = smmu->smr_mask_bits;
+   else
+   smrs[i].mask = 0;
}
 
/* It worked! Now, poke the actual hardware */
for (i = 0; i < master->num_streamids; ++i) {
u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT |
  smrs[i].mask << SMR_MASK_SHIFT;
+   dev_dbg(smmu->dev, "SMR%d: 0x%x\n", smrs[i].idx, reg);
writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx));
}
 
@@ -1713,7 +1733,7 @@ static int arm_smmu_device_cfg_probe(struct 
arm_smmu_device *smmu)
}
 
if (id & ID0_SMS) {
-   u32 smr, sid, mask;
+   u32 smr, sid;
 
smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) &
@@ -1729,18 +1749,18 @@ static int arm_smmu_device_cfg_probe(struct 
arm_smmu_device *smmu)
writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
 
-   mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
+   smmu->smr_mask_bits = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
sid = (smr >> SMR_I

[PATCH v2 0/7] iommu/arm-smmu: Misc modifications to support SMMUs on Calxeda ECX-2000

2013-10-09 Thread Andreas Herrmann
Hi,

Here is v2 of arm-smmu changes to support SMMUs on Calxeda ECX-2000.

Note that patch 7/7 (Introduce automatic stream-id-masking) is not
required to support SMMUs on Calxeda ECX-2000. In fact the algorithm
implemented won't help to determine a suitable smr-mask for 10
StreamIDs that we have for SATA.

In case of 2, 4, 8, ... (power-of-two) ... number of StreamIDs for a
master device it might be able (depending on further restriction for
the StreamIDs) to determine the right mask which then allows to use
only one SMR group for stream matching for this master instead of
using several SMR groups (one for each StreamID).

Changelog:
v2:
- Modified options handling
- Added patch to document new DT properties (that select driver options)
- Added patch to introduce automatic stream-id-masking
v1:
   http://marc.info/?l=linux-arm-kernel&m=138122450023564


Regards,
Andreas

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 1/7] iommu/arm-smmu: Introduce driver option handling

2013-10-09 Thread Andreas Herrmann
Introduce handling of driver options. Options are set based on DT
information when probing an SMMU device. The first option introduced
is "arm,smmu-isolate-devices". (It will be used in the bus notifier
block.)

Signed-off-by: Andreas Herrmann 
---
 drivers/iommu/arm-smmu.c |   36 
 1 file changed, 36 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index b632bcd..478c8ad 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -47,6 +47,9 @@
 
 #include 
 
+/* Driver options */
+#define ARM_SMMU_OPT_ISOLATE_DEVICES   (1 << 0)
+
 /* Maximum number of stream IDs assigned to a single device */
 #define MAX_MASTER_STREAMIDS   8
 
@@ -348,6 +351,7 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
 #define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
u32 features;
+   u32 options;
int version;
 
u32 num_context_banks;
@@ -398,6 +402,36 @@ struct arm_smmu_domain {
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
 static LIST_HEAD(arm_smmu_devices);
 
+struct arm_smmu_option_prop {
+   u32 opt;
+   const char *prop;
+};
+
+static struct arm_smmu_option_prop arm_smmu_options [] = {
+   { ARM_SMMU_OPT_ISOLATE_DEVICES, "arm,smmu-isolate-devices" },
+   { 0, NULL},
+};
+
+static void check_driver_options(struct arm_smmu_device *smmu)
+{
+   int i = 0;
+   do {
+   if (of_property_read_bool(smmu->dev->of_node,
+   arm_smmu_options[i].prop))
+   smmu->options |= arm_smmu_options[i].opt;
+   } while (arm_smmu_options[++i].opt);
+}
+
+static const char *get_driver_option_property(u32 opt)
+{
+   int i = 0;
+   do {
+   if (arm_smmu_options[i].opt == opt)
+   return arm_smmu_options[i].prop;
+   } while (arm_smmu_options[++i].opt);
+   return NULL;
+}
+
 static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
struct device_node *dev_node)
 {
@@ -1791,6 +1825,8 @@ static int arm_smmu_device_dt_probe(struct 
platform_device *pdev)
}
smmu->dev = dev;
 
+   check_driver_options(smmu);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing base address/size\n");
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 4/7] iommu/arm-smmu: Support buggy implementations where all config accesses are secure

2013-10-09 Thread Andreas Herrmann
In such a case we have to use secure aliases of some non-secure
registers.

This handling is switched on by DT property
"arm,smmu-secure-config-access" for an SMMU node.

Signed-off-by: Andreas Herrmann 
---
 drivers/iommu/arm-smmu.c |   30 +-
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index f877d02..91316a8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -51,6 +51,7 @@
 /* Driver options */
 #define ARM_SMMU_OPT_ISOLATE_DEVICES   (1 << 0)
 #define ARM_SMMU_OPT_MASK_STREAM_IDS   (1 << 1)
+#define ARM_SMMU_OPT_SECURE_CONFIG_ACCESS  (1 << 2)
 
 /* Maximum number of stream IDs assigned to a single device */
 #define MAX_MASTER_STREAMIDS   8
@@ -65,6 +66,15 @@
 #define ARM_SMMU_GR0(smmu) ((smmu)->base)
 #define ARM_SMMU_GR1(smmu) ((smmu)->base + (smmu)->pagesize)
 
+/*
+ * SMMU global address space with conditional offset to access secure aliases 
of
+ * non-secure registers (e.g. nsCR0: 0x400, nsGFSR: 0x448, nsGFSYNR0: 0x450)
+ */
+#define ARM_SMMU_GR0_NS(smmu)  \
+   ((smmu)->base + \
+   ((smmu->options & ARM_SMMU_OPT_SECURE_CONFIG_ACCESS)\
+   ? 0x400 : 0))
+
 /* Page table bits */
 #define ARM_SMMU_PTE_PAGE  (((pteval_t)3) << 0)
 #define ARM_SMMU_PTE_CONT  (((pteval_t)1) << 52)
@@ -414,6 +424,7 @@ struct arm_smmu_option_prop {
 static struct arm_smmu_option_prop arm_smmu_options [] = {
{ ARM_SMMU_OPT_ISOLATE_DEVICES, "arm,smmu-isolate-devices" },
{ ARM_SMMU_OPT_MASK_STREAM_IDS, "arm,smmu-mask-stream-ids" },
+   { ARM_SMMU_OPT_SECURE_CONFIG_ACCESS, "arm,smmu-secure-config-access" },
{ 0, NULL},
 };
 
@@ -663,16 +674,16 @@ static irqreturn_t arm_smmu_global_fault(int irq, void 
*dev)
 {
u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
struct arm_smmu_device *smmu = dev;
-   void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+   void __iomem *gr0_base = ARM_SMMU_GR0_NS(smmu);
 
gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
-   if (!gfsr)
-   return IRQ_NONE;
-
gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
 
+   if (!gfsr)
+   return IRQ_NONE;
+
dev_err_ratelimited(smmu->dev,
"Unexpected global fault, this could be serious\n");
dev_err_ratelimited(smmu->dev,
@@ -1622,8 +1633,8 @@ static void arm_smmu_device_reset(struct arm_smmu_device 
*smmu)
u32 reg;
 
/* clear global FSR */
-   reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
-   writel(reg, gr0_base + ARM_SMMU_GR0_sGFSR);
+   reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR);
+   writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sGFSR);
 
/* Mark all SMRn as invalid and all S2CRn as bypass */
for (i = 0; i < smmu->num_mapping_groups; ++i) {
@@ -1643,7 +1654,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device 
*smmu)
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
 
-   reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
+   reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
 
/* Enable fault reporting */
reg |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE);
@@ -1662,7 +1673,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device 
*smmu)
 
/* Push the button */
arm_smmu_tlb_sync(smmu);
-   writel(reg, gr0_base + ARM_SMMU_GR0_sCR0);
+   writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
 }
 
 static int arm_smmu_id_size_to_bits(int size)
@@ -2000,7 +2011,8 @@ static int arm_smmu_device_remove(struct platform_device 
*pdev)
free_irq(smmu->irqs[i], smmu);
 
/* Turn the thing off */
-   writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0);
+   writel(sCR0_CLIENTPD,
+   ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
return 0;
 }
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 5/7] ARM: dts: Add nodes for SMMUs on Calxeda ECX-2000

2013-10-09 Thread Andreas Herrmann
Signed-off-by: Andreas Herrmann 
---
 arch/arm/boot/dts/ecx-2000.dts|   45 +++--
 arch/arm/boot/dts/ecx-common.dtsi |9 +---
 2 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/ecx-2000.dts b/arch/arm/boot/dts/ecx-2000.dts
index 139b40c..270f052 100644
--- a/arch/arm/boot/dts/ecx-2000.dts
+++ b/arch/arm/boot/dts/ecx-2000.dts
@@ -76,10 +76,11 @@
};
 
soc {
-   ranges = <0x 0x 0x 0x>;
+   ranges = <0x0 0x0 0x0 0x>;
 
timer {
-   compatible = "arm,cortex-a15-timer", "arm,armv7-timer"; 
interrupts = <1 13 0xf08>,
+   compatible = "arm,cortex-a15-timer", "arm,armv7-timer";
+   interrupts = <1 13 0xf08>,
<1 14 0xf08>,
<1 11 0xf08>,
<1 10 0xf08>;
@@ -103,6 +104,46 @@
interrupts = <0 76 4  0 75 4  0 74 4  0 73 4>;
};
};
+
+   soc@92000 {
+   ranges = <0x9 0x2000 0x9 0x2000 0x29>;
+   #address-cells = <2>;
+   #size-cells = <1>;
+   compatible = "simple-bus";
+   interrupt-parent = <&intc>;
+
+   smmu_mac0: smmu@92000 {
+   compatible = "arm,mmu-400";
+   reg = <0x9 0x2000 0x1>;
+   #global-interrupts = <1>;
+   interrupts = <0 106 4 0 106 4>;
+   mmu-masters = <&mac0 0 1>;
+   arm,smmu-secure-config-access;
+   arm,smmu-isolate-devices;
+   };
+
+   smmu_mac1: smmu@92008 {
+   compatible = "arm,mmu-400";
+   reg = <0x9 0x2008 0x1>;
+   #global-interrupts = <1>;
+   interrupts = <0 108 4 0 108 4>;
+   mmu-masters = <&mac1 0 1>;
+   arm,smmu-secure-config-access;
+   arm,smmu-isolate-devices;
+   };
+
+   smmu_sata: smmu@92018 {
+   compatible = "arm,mmu-400";
+   reg = <0x0009 0x2018 0x1>;
+   mmu-masters = <&sata>;
+   #global-interrupts = <1>;
+   interrupts = <0 114 4 0 114 4>;
+   arm,smmu-secure-config-access;
+   arm,smmu-isolate-devices;
+   arm,smmu-mask-stream-ids;
+   };
+   };
+
 };
 
 /include/ "ecx-common.dtsi"
diff --git a/arch/arm/boot/dts/ecx-common.dtsi 
b/arch/arm/boot/dts/ecx-common.dtsi
index e8559b7..50e401e 100644
--- a/arch/arm/boot/dts/ecx-common.dtsi
+++ b/arch/arm/boot/dts/ecx-common.dtsi
@@ -25,7 +25,7 @@
compatible = "simple-bus";
interrupt-parent = <&intc>;
 
-   sata@ffe08000 {
+   sata: sata@ffe08000 {
compatible = "calxeda,hb-ahci";
reg = <0xffe08000 0x1>;
interrupts = <0 83 4>;
@@ -35,6 +35,7 @@
 &combophy0 3>;
calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>;
calxeda,led-order = <4 0 1 2 3>;
+   #stream-id-cells = <0>;
};
 
sdhci@ffe0e000 {
@@ -208,18 +209,20 @@
clock-names = "apb_pclk";
};
 
-   ethernet@fff5 {
+   mac0: ethernet@fff5 {
compatible = "calxeda,hb-xgmac";
reg = <0xfff5 0x1000>;
interrupts = <0 77 4  0 78 4  0 79 4>;
dma-coherent;
+   #stream-id-cells = <2>;
};
 
-   ethernet@fff51000 {
+   mac1: ethernet@fff51000 {
compatible = "calxeda,hb-xgmac";
reg = <0xfff51000 0x1000>;
interrupts = <0 80 4  0 81 4  0 82 4>;
dma-coherent;
+   #stream-id-cells = <2>;
};
 
combophy0: combo-phy@fff58000 {
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 1/2] iommu/fsl: Factor out PCI specific code.

2013-10-09 Thread Varun Sethi
Factor out PCI specific code in the PAMU driver.

Signed-off-by: Varun Sethi 
---
 drivers/iommu/fsl_pamu_domain.c |   81 +++
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c857c30..e02e1de 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -677,13 +677,9 @@ static int handle_attach_device(struct fsl_dma_domain 
*dma_domain,
return ret;
 }
 
-static int fsl_pamu_attach_device(struct iommu_domain *domain,
- struct device *dev)
+static void check_for_pci_dma_device(struct device **dev)
 {
-   struct fsl_dma_domain *dma_domain = domain->priv;
-   const u32 *liodn;
-   u32 liodn_cnt;
-   int len, ret = 0;
+#ifdef CONFIG_PCI
struct pci_dev *pdev = NULL;
struct pci_controller *pci_ctl;
 
@@ -691,25 +687,38 @@ static int fsl_pamu_attach_device(struct iommu_domain 
*domain,
 * Use LIODN of the PCI controller while attaching a
 * PCI device.
 */
-   if (dev->bus == &pci_bus_type) {
-   pdev = to_pci_dev(dev);
+   if ((*dev)->bus == &pci_bus_type) {
+   pdev = to_pci_dev(*dev);
pci_ctl = pci_bus_to_host(pdev->bus);
/*
 * make dev point to pci controller device
 * so we can get the LIODN programmed by
 * u-boot.
 */
-   dev = pci_ctl->parent;
+   *dev = pci_ctl->parent;
}
+#endif
+}
 
-   liodn = of_get_property(dev->of_node, "fsl,liodn", &len);
+static int fsl_pamu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+   struct fsl_dma_domain *dma_domain = domain->priv;
+   struct device *dma_dev = dev;
+   const u32 *liodn;
+   u32 liodn_cnt;
+   int len, ret = 0;
+
+   check_for_pci_dma_device(&dma_dev);
+
+   liodn = of_get_property(dma_dev->of_node, "fsl,liodn", &len);
if (liodn) {
liodn_cnt = len / sizeof(u32);
ret = handle_attach_device(dma_domain, dev,
 liodn, liodn_cnt);
} else {
pr_debug("missing fsl,liodn property at %s\n",
- dev->of_node->full_name);
+ dma_dev->of_node->full_name);
ret = -EINVAL;
}
 
@@ -720,32 +729,18 @@ static void fsl_pamu_detach_device(struct iommu_domain 
*domain,
  struct device *dev)
 {
struct fsl_dma_domain *dma_domain = domain->priv;
+   struct device *dma_dev = dev;
const u32 *prop;
int len;
-   struct pci_dev *pdev = NULL;
-   struct pci_controller *pci_ctl;
 
-   /*
-* Use LIODN of the PCI controller while detaching a
-* PCI device.
-*/
-   if (dev->bus == &pci_bus_type) {
-   pdev = to_pci_dev(dev);
-   pci_ctl = pci_bus_to_host(pdev->bus);
-   /*
-* make dev point to pci controller device
-* so we can get the LIODN programmed by
-* u-boot.
-*/
-   dev = pci_ctl->parent;
-   }
+   check_for_pci_dma_device(&dma_dev);
 
-   prop = of_get_property(dev->of_node, "fsl,liodn", &len);
+   prop = of_get_property(dma_dev->of_node, "fsl,liodn", &len);
if (prop)
detach_device(dev, dma_domain);
else
pr_debug("missing fsl,liodn property at %s\n",
- dev->of_node->full_name);
+ dma_dev->of_node->full_name);
 }
 
 static  int configure_domain_geometry(struct iommu_domain *domain, void *data)
@@ -905,6 +900,7 @@ static struct iommu_group *get_device_iommu_group(struct 
device *dev)
return group;
 }
 
+#ifdef CONFIG_PCI
 static  bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
 {
u32 version;
@@ -945,13 +941,18 @@ static struct iommu_group 
*get_shared_pci_device_group(struct pci_dev *pdev)
return NULL;
 }
 
-static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
+static struct iommu_group *get_pci_device_group(struct device *dev)
 {
struct pci_controller *pci_ctl;
bool pci_endpt_partioning;
struct iommu_group *group = NULL;
-   struct pci_dev *bridge, *dma_pdev = NULL;
+   struct pci_dev *bridge, *pdev;
+   struct pci_dev *dma_pdev = NULL;
 
+   pdev = to_pci_dev(dev);
+   /* Don't create device groups for virtual PCI bridges */
+   if (pdev->subordinate)
+   return NULL;
pci_ctl = pci_bus_to_host(pdev->bus);
pci_endpt_partioning = check_pci_ctl_endpt_part(pci_ctl);
/* We can partition PCIe devices so assign device group to the device */
@@ -1044,11 +1045,11 @@ root_bus:

[PATCH 2/2] iommu/fsl: Enable default DMA window for PCIe devices once detached

2013-10-09 Thread Varun Sethi
Once the PCIe device assigned to a guest VM (via VFIO) gets detached from the 
iommu domain
(when guest terminates), its PAMU table entry is disabled. So, this would 
prevent the device
from being used once it's assigned back to the host.

This patch allows for creation of a default DMA window corresponding to the 
device
and subsequently enabling the PAMU table entry. Before we enable the entry, we 
ensure that
the device's bus master capability is disabled (device quiesced).  

Signed-off-by: Varun Sethi 
---
 drivers/iommu/fsl_pamu.c|   43 +++
 drivers/iommu/fsl_pamu.h|1 +
 drivers/iommu/fsl_pamu_domain.c |   35 +++
 3 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index cba0498..fb4a031 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -225,6 +225,21 @@ static struct paace *pamu_get_spaace(struct paace *paace, 
u32 wnum)
return spaace;
 }
 
+/*
+ * Defaul PPAACE settings for an LIODN.
+ */
+static void setup_default_ppaace(struct paace *ppaace)
+{
+   pamu_init_ppaace(ppaace);
+   /* window size is 2^(WSE+1) bytes */
+   set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
+   ppaace->wbah = 0;
+   set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
+   set_bf(ppaace->impl_attr, PAACE_IA_ATM,
+   PAACE_ATM_NO_XLATE);
+   set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
+   PAACE_AP_PERMS_ALL);
+}
 /**
  * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves subwindows
  *required for primary PAACE in the secondary
@@ -253,6 +268,24 @@ static unsigned long pamu_get_fspi_and_allocate(u32 
subwin_cnt)
return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace));
 }
 
+/* Reset the PAACE entry to the default state */
+void enable_default_dma_window(int liodn)
+{
+   struct paace *ppaace;
+
+   ppaace = pamu_get_ppaace(liodn);
+   if (!ppaace) {
+   pr_debug("Invalid liodn entry\n");
+   return;
+   }
+
+   memset(ppaace, 0, sizeof(struct paace));
+
+   setup_default_ppaace(ppaace);
+   mb();
+   pamu_enable_liodn(liodn);
+}
+
 /* Release the subwindows reserved for a particular LIODN */
 void pamu_free_subwins(int liodn)
 {
@@ -752,15 +785,7 @@ static void __init setup_liodns(void)
continue;
}
ppaace = pamu_get_ppaace(liodn);
-   pamu_init_ppaace(ppaace);
-   /* window size is 2^(WSE+1) bytes */
-   set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
-   ppaace->wbah = 0;
-   set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
-   set_bf(ppaace->impl_attr, PAACE_IA_ATM,
-   PAACE_ATM_NO_XLATE);
-   set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
-   PAACE_AP_PERMS_ALL);
+   setup_default_ppaace(ppaace);
if (of_device_is_compatible(node, "fsl,qman-portal"))
setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE);
if (of_device_is_compatible(node, "fsl,qman"))
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index 8fc1a12..0edc 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -406,5 +406,6 @@ void get_ome_index(u32 *omi_index, struct device *dev);
 int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value);
 int pamu_disable_spaace(int liodn, u32 subwin);
 u32 pamu_get_max_subwin_cnt(void);
+void enable_default_dma_window(int liodn);
 
 #endif  /* __FSL_PAMU_H */
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index e02e1de..553ef3c 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -340,6 +340,40 @@ static inline struct device_domain_info 
*find_domain(struct device *dev)
return dev->archdata.iommu_domain;
 }
 
+/* Disable device DMA capability and enable default DMA window */
+static void disable_device_dma(struct device_domain_info *info)
+{
+   struct device_domain_info *tmp;
+   int enable_dma_window = 1;
+
+#ifdef CONFIG_PCI
+   if (info->dev->bus == &pci_bus_type) {
+   struct pci_dev *pdev = NULL;
+   pdev = to_pci_dev(info->dev);
+   if (pci_is_enabled(pdev))
+   pci_disable_device(pdev);
+   }
+#endif
+   /*
+* Sanity check, to ensure that this is not a
+* shared LIODN. In case of a PCIe controller
+* it's possible that all PCIe devices share
+* the same LIODN. We can't enable the default
+* DMA window till all the devices have been
+* quiesced (for PCIe devices, we expl

[GIT PULL] iommu/arm-smmu: updates for 3.13

2013-10-09 Thread Will Deacon
Hi Joerg,

Please pull these ARM SMMU updates for 3.13. The bulk of the changes are
from Andreas, who has been having fun running the driver on real hardware. I
expect some additional patches from him in the future to add support for
things like device isolation once we've ironed out the wrinkles in the
current proposals.

I've successfully tested this lot in my modelled environments without any
observed regressions.

Cheers,

Will

--->8

The following changes since commit d0e639c9e06d44e713170031fe05fb60ebe680af:

  Linux 3.12-rc4 (2013-10-06 14:00:20 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git 
for-joerg/arm-smmu/updates

for you to fetch changes up to 659db6f6beacae6fe49b5566debc4e82f678ff63:

  iommu/arm-smmu: Clear global and context bank fault status registers 
(2013-10-09 14:14:41 +0100)


Andreas Herrmann (5):
  iommu/arm-smmu: Switch to subsys_initcall for driver registration
  iommu/arm-smmu: Refine check for proper size of mapped region
  iommu/arm-smmu: Check for num_context_irqs > 0 to avoid divide by zero 
exception
  iommu/arm-smmu: Print context fault information
  iommu/arm-smmu: Clear global and context bank fault status registers

Julia Lawall (1):
  iommu/arm-smmu: replace devm_request_and_ioremap by devm_ioremap_resource

Will Deacon (1):
  iommu/arm-smmu: use relaxed accessors where possible

 drivers/iommu/arm-smmu.c | 69 ++--
 1 file changed, 37 insertions(+), 32 deletions(-)
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 3/5] iommu/arm-smmu: Introduce stream ID masking

2013-10-09 Thread Will Deacon
On Tue, Oct 08, 2013 at 07:43:50PM +0100, Rob Herring wrote:
> On 10/08/2013 11:59 AM, Will Deacon wrote:
> > On Tue, Oct 08, 2013 at 05:40:21PM +0100, Andreas Herrmann wrote:
> >> On Tue, Oct 08, 2013 at 05:20:08PM +0200, Andreas Herrmann wrote:
> >> To be more specific: For SATA I'd need to specify 10 StreamIds. This
> >> would
> >>
> >> (1) exceed MAX_MASTER_STREAMIDS (currently it's 8)
> >>
> >>(Can easily be fixed by adapting a macro.)
> >>
> >> (2) exceed number of available SMR groups to map the IDs to a context.
> >>
> >>This can be solved by caclulating an appropriate mask for the
> >>mapping (but with a non-power-of-two number of StreamIds that's
> >>already non-trivial -- for the trivial case I have some code to do
> >>this).
> >>
> >> Both problems are avoided by introducing this patch -- use
> >> smr_mask_bits to map all StreamIDs to the same context and be done
> >> with it. (for the "single-master-SMMU" case)
> > 
> > The problem is, this information *really* doesn't belong in the device tree,
> > but I think computing the general case dynamically is incredibly difficult
> > too (and requires *complete* topological information in the device-tree, so
> > you don't accidentally pull in other devices).
> 
> Couldn't this information be implied from the DT when you have no
> streamID and only a single mmu-master?

It's still fairly fragile though, since you (a) don't know that the stream
IDs of the master are matchable by the SMRs (if we had the stream IDs, we
can check this) and (b) you can still end up pulling devices into your
address space that would otherwise happily operate using passthrough.

Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH] vfio, iommu: Fixed interaction of VFIO_IOMMU_MAP_DMA with IOMMU address limits

2013-10-09 Thread Julian Stecklina
The BUG_ON in drivers/iommu/intel-iommu.c:785 can be triggered from userspace 
via
VFIO by calling the VFIO_IOMMU_MAP_DMA ioctl on a vfio device with any address
beyond the addressing capabilities of the IOMMU. The problem is that the ioctl 
code
calls iommu_iova_to_phys before it calls iommu_map. iommu_map handles the case 
that
it gets addresses beyond the addressing capabilities of its IOMMU.
intel_iommu_iova_to_phys does not.

This patch fixes iommu_iova_to_phys to return NULL for addresses beyond what the
IOMMU can handle. This in turn causes the ioctl call to fail in iommu_map and
(correctly) return EFAULT to the user with a helpful warning message in the 
kernel
log.

Signed-off-by: Julian Stecklina 
Acked-by: Alex Williamson 
---
 drivers/iommu/intel-iommu.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 15e9b57..40203ad 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -782,7 +782,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain 
*domain,
int offset;
 
BUG_ON(!domain->pgd);
-   BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
+
+   if (addr_width < BITS_PER_LONG && pfn >> addr_width)
+   /* Address beyond IOMMU's addressing capabilities. */
+   return NULL;
+
parent = domain->pgd;
 
while (level > 0) {
-- 
1.8.3.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu