* [PATCH 1/6] iommu/arm-smmu: Introduce driver option handling
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 18:18 ` [PATCH 2/6] iommu/arm-smmu: Support buggy implementation where all config accesses are secure Andreas Herrmann
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
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 iommu_group
notifier block.)
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 879da20..7111461 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -348,6 +348,9 @@ struct arm_smmu_device {
#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
u32 features;
+
+#define ARM_SMMU_OPT_ISOLATE_DEVICES (1 << 0)
+ u32 options;
int version;
u32 num_context_banks;
@@ -398,6 +401,29 @@ 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 parse_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;
+ dev_notice(smmu->dev, "option %s\n",
+ arm_smmu_options[i].prop);
+ }
+ } while (arm_smmu_options[++i].opt);
+}
+
static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
struct device_node *dev_node)
{
@@ -1864,6 +1890,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err)
goto out_put_parent;
+ parse_driver_options(smmu);
+
if (smmu->version > 1 &&
smmu->num_context_banks != smmu->num_context_irqs) {
dev_err(dev,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/6] iommu/arm-smmu: Support buggy implementation where all config accesses are secure
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
2014-01-30 18:18 ` [PATCH 1/6] iommu/arm-smmu: Introduce driver option handling Andreas Herrmann
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 18:18 ` [PATCH 3/6] iommu/arm-smmu: Check for duplicate stream IDs when registering master devices Andreas Herrmann
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In such a case we have to use secure aliases of some non-secure
registers.
This handling is switched on by DT property
"calxeda,smmu-secure-config-access" for an SMMU node.
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 7111461..0438ec1 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -60,6 +60,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)
@@ -350,6 +359,7 @@ struct arm_smmu_device {
u32 features;
#define ARM_SMMU_OPT_ISOLATE_DEVICES (1 << 0)
+#define ARM_SMMU_OPT_SECURE_CONFIG_ACCESS (1 << 1)
u32 options;
int version;
@@ -408,6 +418,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_SECURE_CONFIG_ACCESS, "calxeda,smmu-secure-config-access" },
{ 0, NULL},
};
@@ -637,16 +648,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,
@@ -1601,9 +1612,9 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
int i = 0;
u32 reg;
- /* Clear Global FSR */
- reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
- writel(reg, gr0_base + ARM_SMMU_GR0_sGFSR);
+ /* clear global FSR */
+ 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) {
@@ -1623,7 +1634,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);
@@ -1642,7 +1653,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
/* Push the button */
arm_smmu_tlb_sync(smmu);
- writel_relaxed(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)
@@ -1976,7 +1987,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
free_irq(smmu->irqs[i], smmu);
/* Turn the thing off */
- writel_relaxed(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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/6] iommu/arm-smmu: Check for duplicate stream IDs when registering master devices
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
2014-01-30 18:18 ` [PATCH 1/6] iommu/arm-smmu: Introduce driver option handling Andreas Herrmann
2014-01-30 18:18 ` [PATCH 2/6] iommu/arm-smmu: Support buggy implementation where all config accesses are secure Andreas Herrmann
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 18:18 ` [PATCH 4/6] iommu/arm-smmu: Introduce automatic stream-id-masking Andreas Herrmann
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
If DT information lists one stream ID twice for the master devices of
an SMMU this can cause a multi match when stream ID matching is used.
For stream ID indexing this might trigger an overwrite of an S2CR that
is already in use.
So better check for duplicates when DT information is parsed.
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 0438ec1..4a32fde 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -50,6 +50,9 @@
/* Maximum number of stream IDs assigned to a single device */
#define MAX_MASTER_STREAMIDS 8
+/* Maximum stream ID */
+#define ARM_SMMU_MAX_STREAMID (SZ_64K - 1)
+
/* Maximum number of context banks per SMMU */
#define ARM_SMMU_MAX_CBS 128
@@ -482,9 +485,10 @@ static int insert_smmu_master(struct arm_smmu_device *smmu,
static int register_smmu_master(struct arm_smmu_device *smmu,
struct device *dev,
- struct of_phandle_args *masterspec)
+ struct of_phandle_args *masterspec,
+ unsigned long *smmu_sids)
{
- int i;
+ int i, sid;
struct arm_smmu_master *master;
master = find_smmu_master(smmu, masterspec->np);
@@ -509,8 +513,14 @@ 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];
+ for (i = 0; i < master->num_streamids; ++i) {
+ sid = masterspec->args[i];
+ if (test_and_set_bit(sid, smmu_sids)) {
+ dev_err(dev, "duplicate stream ID (%d)\n", sid);
+ return -EEXIST;
+ }
+ master->streamids[i] = sid;
+ }
return insert_smmu_master(smmu, master);
}
@@ -1828,6 +1838,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rb_node *node;
struct of_phandle_args masterspec;
+ unsigned long *smmu_sids;
int num_irqs, i, err;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
@@ -1878,20 +1889,30 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
smmu->irqs[i] = irq;
}
+ smmu_sids = kzalloc(BITS_TO_LONGS(ARM_SMMU_MAX_STREAMID) *
+ sizeof(long), GFP_KERNEL);
+ if (!smmu_sids) {
+ dev_err(dev,
+ "failed to allocate bitmap for stream ID tracking\n");
+ return -ENOMEM;
+ }
+
i = 0;
smmu->masters = RB_ROOT;
while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
"#stream-id-cells", i,
&masterspec)) {
- err = register_smmu_master(smmu, dev, &masterspec);
+ err = register_smmu_master(smmu, dev, &masterspec, smmu_sids);
if (err) {
dev_err(dev, "failed to add master %s\n",
masterspec.np->name);
+ kfree(smmu_sids);
goto out_put_masters;
}
i++;
}
+ kfree(smmu_sids);
dev_notice(dev, "registered %d master devices\n", i);
if ((dev_node = of_parse_phandle(dev->of_node, "smmu-parent", 0)))
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/6] iommu/arm-smmu: Introduce automatic stream-id-masking
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
` (2 preceding siblings ...)
2014-01-30 18:18 ` [PATCH 3/6] iommu/arm-smmu: Check for duplicate stream IDs when registering master devices Andreas Herrmann
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 18:18 ` [PATCH 5/6] iommu/arm-smmu: Set MAX_MASTER_STREAMIDS to MAX_PHANDLE_ARGS Andreas Herrmann
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Try to determine mask/id values that match several stream IDs of a
master device when doing Stream ID matching. Thus the number of used
SMR groups that are required to map all stream IDs of a master device
to a context should be less than the number of SMR groups used so far
(currently one SMR group is used for one stream ID).
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 172 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 157 insertions(+), 15 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 4a32fde..31d9458 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -42,6 +42,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/bitops.h>
#include <linux/amba/bus.h>
@@ -336,8 +337,9 @@ struct arm_smmu_master {
* SMMU chain.
*/
struct rb_node node;
- int num_streamids;
+ u32 num_streamids;
u16 streamids[MAX_MASTER_STREAMIDS];
+ int num_s2crs;
/*
* We only need to allocate these on the root SMMU, as we
@@ -382,6 +384,9 @@ struct arm_smmu_device {
u32 num_context_irqs;
unsigned int *irqs;
+ u32 smr_mask_mask;
+ u32 smr_id_mask;
+
struct list_head list;
struct rb_root masters;
};
@@ -1033,10 +1038,140 @@ static void arm_smmu_domain_destroy(struct iommu_domain *domain)
kfree(smmu_domain);
}
+/*
+ * For a given set N of 2**order different stream IDs (no duplicates
+ * please!) we determine values mask and id such that
+ *
+ * (1) (x & mask) == id
+ *
+ * for each stream ID x from the given set N.
+ *
+ * If the number of bits that are set in mask equals n, then there
+ * exist 2**n different values y for which
+ *
+ * (2) (y & mask) == id
+ *
+ * Thus if n equals order we know that for the calculated mask and id
+ * values there are exactly 2**order == 2**n stream IDs for which (1)
+ * is true. And we finally can use mask and id to configure an SMR to
+ * match all stream IDs in the set N.
+ */
+static int determine_smr_mask(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master,
+ struct arm_smmu_smr *smr, int start, int order)
+{
+ u16 i, zero_bits_mask, one_bits_mask, const_mask;
+ int nr;
+
+ nr = 1 << order;
+
+ if (nr == 1) {
+ /* no mask, use streamid to match and be done with it */
+ smr->mask = 0;
+ smr->id = master->streamids[start];
+ return 0;
+ }
+
+ zero_bits_mask = 0;
+ one_bits_mask = 0xffff;
+ for (i = start; i < start + nr; i++) {
+ zero_bits_mask |= master->streamids[i]; /* const 0 bits */
+ one_bits_mask &= master->streamids[i]; /* const 1 bits */
+ }
+ zero_bits_mask = ~zero_bits_mask;
+
+ /* bits having constant values (either 0 or 1) */
+ const_mask = zero_bits_mask | one_bits_mask;
+
+ i = hweight16(~const_mask);
+ if (i == order) {
+ /*
+ * We have found a mask/id pair that matches exactly
+ * nr = 2**order stream IDs which we used for its
+ * calculation.
+ */
+ smr->mask = ~const_mask;
+ smr->id = one_bits_mask;
+ } else {
+ /*
+ * No usable mask/id pair for this set of streamids.
+ * If i > order then mask/id would match more than nr
+ * streamids.
+ * If i < order then mask/id would match less than nr
+ * streamids. (In this case we potentially have used
+ * some duplicate streamids for the calculation.)
+ */
+ return 1;
+ }
+
+ if (((smr->mask & smmu->smr_mask_mask) != smr->mask) ||
+ ((smr->id & smmu->smr_id_mask) != smr->id))
+ /* insufficient number of mask/id bits */
+ return 1;
+
+ return 0;
+}
+
+static int determine_smr_mapping(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master,
+ struct arm_smmu_smr *smrs, int max_smrs)
+{
+ int nr_sid, nr, i, bit, start;
+
+ /*
+ * This function is called only once -- when a master is added
+ * to a domain. If master->num_s2crs != 0 then this master
+ * was already added to a domain.
+ */
+ if (master->num_s2crs)
+ return -EINVAL;
+
+ start = nr = 0;
+ nr_sid = master->num_streamids;
+ do {
+ /*
+ * largest power-of-2 number of streamids for which to
+ * determine a usable mask/id pair for stream matching
+ */
+ bit = __fls(nr_sid);
+ if (bit < 0)
+ return 0;
+
+ /*
+ * iterate over power-of-2 numbers to determine
+ * largest possible mask/id pair for stream matching
+ * of next 2**i streamids
+ */
+ for (i = bit; i >= 0; i--) {
+ if (!determine_smr_mask(smmu, master,
+ &smrs[master->num_s2crs],
+ start, i))
+ break;
+ }
+
+ if (i < 0)
+ goto out;
+
+ nr = 1 << i;
+ nr_sid -= nr;
+ start += nr;
+ master->num_s2crs++;
+ } while (master->num_s2crs <= max_smrs);
+
+out:
+ if (nr_sid) {
+ /* not enough mapping groups available */
+ master->num_s2crs = 0;
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
struct arm_smmu_master *master)
{
- int i;
+ int i, max_smrs, ret;
struct arm_smmu_smr *smrs;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
@@ -1046,31 +1181,31 @@ 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);
+ max_smrs = min(smmu->num_mapping_groups, master->num_streamids);
+ smrs = kmalloc(sizeof(*smrs) * max_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);
+ max_smrs, master->of_node->name);
return -ENOMEM;
}
+ ret = determine_smr_mapping(smmu, master, smrs, max_smrs);
+ if (ret)
+ goto err_free_smrs;
+
/* Allocate the SMRs on the root SMMU */
- for (i = 0; i < master->num_streamids; ++i) {
+ for (i = 0; i < master->num_s2crs; ++i) {
int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
smmu->num_mapping_groups);
if (IS_ERR_VALUE(idx)) {
dev_err(smmu->dev, "failed to allocate free SMR\n");
- goto err_free_smrs;
+ goto err_free_bitmap;
}
-
- smrs[i] = (struct arm_smmu_smr) {
- .idx = idx,
- .mask = 0, /* We don't currently share SMRs */
- .id = master->streamids[i],
- };
+ smrs[i].idx = idx;
}
/* It worked! Now, poke the actual hardware */
- for (i = 0; i < master->num_streamids; ++i) {
+ for (i = 0; i < master->num_s2crs; ++i) {
u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT |
smrs[i].mask << SMR_MASK_SHIFT;
writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx));
@@ -1079,9 +1214,11 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
master->smrs = smrs;
return 0;
-err_free_smrs:
+err_free_bitmap:
while (--i >= 0)
__arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx);
+ master->num_s2crs = 0;
+err_free_smrs:
kfree(smrs);
return -ENOSPC;
}
@@ -1144,11 +1281,14 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
}
/* Now we're at the root, time to point at our context bank */
- for (i = 0; i < master->num_streamids; ++i) {
+ if (!master->num_s2crs)
+ master->num_s2crs = master->num_streamids;
+ for (i = 0; i < master->num_s2crs; ++i) {
u32 idx, s2cr;
idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
(smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
+ dev_dbg(smmu->dev, "S2CR%d: 0x%x\n", idx, s2cr);
writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
}
@@ -1758,6 +1898,8 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
mask, sid);
return -ENODEV;
}
+ smmu->smr_mask_mask = mask;
+ smmu->smr_id_mask = sid;
dev_notice(smmu->dev,
"\tstream matching with %u register groups, mask 0x%x",
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/6] iommu/arm-smmu: Set MAX_MASTER_STREAMIDS to MAX_PHANDLE_ARGS
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
` (3 preceding siblings ...)
2014-01-30 18:18 ` [PATCH 4/6] iommu/arm-smmu: Introduce automatic stream-id-masking Andreas Herrmann
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 18:18 ` [PATCH 6/6] iommu/arm-smmu: Introduce iommu_group notifier block Andreas Herrmann
2014-01-30 20:17 ` [PATCH] documentation/iommu: Update description of ARM System MMU binding Andreas Herrmann
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
The DT parsing code that determines stream IDs uses
of_parse_phandle_with_args and thus MAX_MASTER_STREAMIDS
is always bound by MAX_PHANDLE_ARGS.
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 31d9458..d1f166f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -49,7 +49,7 @@
#include <asm/pgalloc.h>
/* Maximum number of stream IDs assigned to a single device */
-#define MAX_MASTER_STREAMIDS 8
+#define MAX_MASTER_STREAMIDS MAX_PHANDLE_ARGS
/* Maximum stream ID */
#define ARM_SMMU_MAX_STREAMID (SZ_64K - 1)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 6/6] iommu/arm-smmu: Introduce iommu_group notifier block
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
` (4 preceding siblings ...)
2014-01-30 18:18 ` [PATCH 5/6] iommu/arm-smmu: Set MAX_MASTER_STREAMIDS to MAX_PHANDLE_ARGS Andreas Herrmann
@ 2014-01-30 18:18 ` Andreas Herrmann
2014-01-30 20:17 ` [PATCH] documentation/iommu: Update description of ARM System MMU binding Andreas Herrmann
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 18:18 UTC (permalink / raw)
To: Will Deacon
Cc: Andreas Herrmann, Varun Sethi,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
At the moment just handle IOMMU_GROUP_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. Additional patches will address this
restriction and allow automatic growth of mapping size.
Cc: Varun Sethi <Varun.Sethi-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index d1f166f..bee88c8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -47,6 +47,7 @@
#include <linux/amba/bus.h>
#include <asm/pgalloc.h>
+#include <asm/dma-iommu.h>
/* Maximum number of stream IDs assigned to a single device */
#define MAX_MASTER_STREAMIDS MAX_PHANDLE_ARGS
@@ -1677,6 +1678,47 @@ static int arm_smmu_domain_has_cap(struct iommu_domain *domain,
return !!(cap & caps);
}
+static int arm_smmu_group_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct dma_iommu_mapping *mapping;
+ struct arm_smmu_device *smmu;
+ int ret;
+
+ switch (action) {
+ case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
+
+ 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);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block group_nb = {
+ .notifier_call = arm_smmu_group_notifier,
+};
+
static int arm_smmu_add_device(struct device *dev)
{
struct arm_smmu_device *child, *parent, *smmu;
@@ -1726,6 +1768,8 @@ static int arm_smmu_add_device(struct device *dev)
return PTR_ERR(group);
}
+ iommu_group_register_notifier(group, &group_nb);
+
ret = iommu_group_add_device(group, dev);
iommu_group_put(group);
dev->archdata.iommu = smmu;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH] documentation/iommu: Update description of ARM System MMU binding
[not found] ` <1391105889-32718-1-git-send-email-andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
` (5 preceding siblings ...)
2014-01-30 18:18 ` [PATCH 6/6] iommu/arm-smmu: Introduce iommu_group notifier block Andreas Herrmann
@ 2014-01-30 20:17 ` Andreas Herrmann
6 siblings, 0 replies; 9+ messages in thread
From: Andreas Herrmann @ 2014-01-30 20:17 UTC (permalink / raw)
To: Will Deacon
Cc: Grant Likely, Rob Herring,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This patch adds descriptions fore new properties of device tree
binding for the ARM SMMU architecture. These properties control
arm-smmu driver options.
Cc: Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Andreas Herrmann <herrmann.der.user-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Andreas Herrmann <andreas.herrmann-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
---
.../devicetree/bindings/iommu/arm,smmu.txt | 11 +++++++++++
1 file changed, 11 insertions(+)
Hi Will,
I should have included this patch in the series as it describes the
options introduced there.
Andreas
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index e34c6cd..7ad8ff0 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -48,6 +48,16 @@ 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.
+
+- calxeda,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 +77,5 @@ Example:
*/
mmu-masters = <&dma0 0xd01d 0xd01e>,
<&dma1 0xd11c>;
+ arm,smmu-isolate-devices;
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 9+ messages in thread