aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch')
-rw-r--r--target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch506
1 files changed, 506 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch b/target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch
new file mode 100644
index 0000000000..e0daa4334e
--- /dev/null
+++ b/target/linux/layerscape/patches-4.14/821-smmu-support-layerscape.patch
@@ -0,0 +1,506 @@
+From 05375244c8e74f90239db92646a771905fdfc0db Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Tue, 30 Oct 2018 18:28:22 +0800
+Subject: [PATCH 38/40] smmu: support layerscape
+This is an integrated patch of smmu for layerscape
+
+Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
+Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
+Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 39 ++++++
+ drivers/iommu/arm-smmu.c | 7 +
+ drivers/iommu/iommu.c | 21 +++
+ drivers/iommu/of_iommu.c | 126 +++++++++++++++++-
+ drivers/of/irq.c | 6 +-
+ drivers/of/of_pci.c | 101 --------------
+ include/linux/iommu.h | 2 +
+ include/linux/of_iommu.h | 10 ++
+ include/linux/of_pci.h | 10 --
+ 9 files changed, 205 insertions(+), 117 deletions(-)
+
+--- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
++++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+@@ -9,6 +9,25 @@ blocks that can be used to create functi
+ such as network interfaces, crypto accelerator instances, L2 switches,
+ etc.
+
++For an overview of the DPAA2 architecture and fsl-mc bus see:
++drivers/staging/fsl-mc/README.txt
++
++As described in the above overview, all DPAA2 objects in a DPRC share the
++same hardware "isolation context" and a 10-bit value called an ICID
++(isolation context id) is expressed by the hardware to identify
++the requester.
++
++The generic 'iommus' property is insufficient to describe the relationship
++between ICIDs and IOMMUs, so an iommu-map property is used to define
++the set of possible ICIDs under a root DPRC and how they map to
++an IOMMU.
++
++For generic IOMMU bindings, see
++Documentation/devicetree/bindings/iommu/iommu.txt.
++
++For arm-smmu binding, see:
++Documentation/devicetree/bindings/iommu/arm,smmu.txt.
++
+ Required properties:
+
+ - compatible
+@@ -88,14 +107,34 @@ Sub-nodes:
+ Value type: <phandle>
+ Definition: Specifies the phandle to the PHY device node associated
+ with the this dpmac.
++Optional properties:
++
++- iommu-map: Maps an ICID to an IOMMU and associated iommu-specifier
++ data.
++
++ The property is an arbitrary number of tuples of
++ (icid-base,iommu,iommu-base,length).
++
++ Any ICID i in the interval [icid-base, icid-base + length) is
++ associated with the listed IOMMU, with the iommu-specifier
++ (i - icid-base + iommu-base).
+
+ Example:
+
++ smmu: iommu@5000000 {
++ compatible = "arm,mmu-500";
++ #iommu-cells = <2>;
++ stream-match-mask = <0x7C00>;
++ ...
++ };
++
+ fsl_mc: fsl-mc@80c000000 {
+ compatible = "fsl,qoriq-mc";
+ reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */
+ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */
+ msi-parent = <&its>;
++ /* define map for ICIDs 23-64 */
++ iommu-map = <23 &smmu 23 41>;
+ #address-cells = <3>;
+ #size-cells = <1>;
+
+--- a/drivers/iommu/arm-smmu.c
++++ b/drivers/iommu/arm-smmu.c
+@@ -52,6 +52,7 @@
+ #include <linux/spinlock.h>
+
+ #include <linux/amba/bus.h>
++#include <linux/fsl/mc.h>
+
+ #include "io-pgtable.h"
+ #include "arm-smmu-regs.h"
+@@ -1464,6 +1465,8 @@ static struct iommu_group *arm_smmu_devi
+
+ if (dev_is_pci(dev))
+ group = pci_device_group(dev);
++ else if (dev_is_fsl_mc(dev))
++ group = fsl_mc_device_group(dev);
+ else
+ group = generic_device_group(dev);
+
+@@ -2040,6 +2043,10 @@ static void arm_smmu_bus_init(void)
+ bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+ }
+ #endif
++#ifdef CONFIG_FSL_MC_BUS
++ if (!iommu_present(&fsl_mc_bus_type))
++ bus_set_iommu(&fsl_mc_bus_type, &arm_smmu_ops);
++#endif
+ }
+
+ static int arm_smmu_device_probe(struct platform_device *pdev)
+--- a/drivers/iommu/iommu.c
++++ b/drivers/iommu/iommu.c
+@@ -33,6 +33,7 @@
+ #include <linux/bitops.h>
+ #include <linux/property.h>
+ #include <trace/events/iommu.h>
++#include <linux/fsl/mc.h>
+
+ static struct kset *iommu_group_kset;
+ static DEFINE_IDA(iommu_group_ida);
+@@ -987,6 +988,26 @@ struct iommu_group *pci_device_group(str
+ return iommu_group_alloc();
+ }
+
++/* Get the IOMMU group for device on fsl-mc bus */
++struct iommu_group *fsl_mc_device_group(struct device *dev)
++{
++ struct device *cont_dev = fsl_mc_cont_dev(dev);
++ struct iommu_group *group;
++
++ /* Container device is responsible for creating the iommu group */
++ if (fsl_mc_is_cont_dev(dev)) {
++ group = iommu_group_alloc();
++ if (IS_ERR(group))
++ return NULL;
++ } else {
++ get_device(cont_dev);
++ group = iommu_group_get(cont_dev);
++ put_device(cont_dev);
++ }
++
++ return group;
++}
++
+ /**
+ * iommu_group_get_for_dev - Find or create the IOMMU group for a device
+ * @dev: target device
+--- a/drivers/iommu/of_iommu.c
++++ b/drivers/iommu/of_iommu.c
+@@ -24,6 +24,7 @@
+ #include <linux/of_iommu.h>
+ #include <linux/of_pci.h>
+ #include <linux/slab.h>
++#include <linux/fsl/mc.h>
+
+ #define NO_IOMMU 1
+
+@@ -143,15 +144,115 @@ struct of_pci_iommu_alias_info {
+ struct device_node *np;
+ };
+
++/**
++ * of_map_rid - Translate a requester ID through a downstream mapping.
++ * @np: root complex device node.
++ * @rid: Requester ID to map.
++ * @map_name: property name of the map to use.
++ * @map_mask_name: optional property name of the mask to use.
++ * @target: optional pointer to a target device node.
++ * @id_out: optional pointer to receive the translated ID.
++ *
++ * Given PCI/MC requester ID, look up the appropriate implementation-defined
++ * platform ID and/or the target device which receives transactions on that
++ * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
++ * @id_out may be NULL if only the other is required. If @target points to
++ * a non-NULL device node pointer, only entries targeting that node will be
++ * matched; if it points to a NULL value, it will receive the device node of
++ * the first matching target phandle, with a reference held.
++ *
++ * Return: 0 on success or a standard error code on failure.
++ */
++int of_map_rid(struct device_node *np, u32 rid,
++ const char *map_name, const char *map_mask_name,
++ struct device_node **target, u32 *id_out)
++{
++ u32 map_mask, masked_rid;
++ int map_len;
++ const __be32 *map = NULL;
++
++ if (!np || !map_name || (!target && !id_out))
++ return -EINVAL;
++
++ map = of_get_property(np, map_name, &map_len);
++ if (!map) {
++ if (target)
++ return -ENODEV;
++ /* Otherwise, no map implies no translation */
++ *id_out = rid;
++ return 0;
++ }
++
++ if (!map_len || map_len % (4 * sizeof(*map))) {
++ pr_err("%pOF: Error: Bad %s length: %d\n", np,
++ map_name, map_len);
++ return -EINVAL;
++ }
++
++ /* The default is to select all bits. */
++ map_mask = 0xffffffff;
++
++ /*
++ * Can be overridden by "{iommu,msi}-map-mask" property.
++ * If of_property_read_u32() fails, the default is used.
++ */
++ if (map_mask_name)
++ of_property_read_u32(np, map_mask_name, &map_mask);
++
++ masked_rid = map_mask & rid;
++ for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
++ struct device_node *phandle_node;
++ u32 rid_base = be32_to_cpup(map + 0);
++ u32 phandle = be32_to_cpup(map + 1);
++ u32 out_base = be32_to_cpup(map + 2);
++ u32 rid_len = be32_to_cpup(map + 3);
++
++ if (rid_base & ~map_mask) {
++ pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
++ np, map_name, map_name,
++ map_mask, rid_base);
++ return -EFAULT;
++ }
++
++ if (masked_rid < rid_base || masked_rid >= rid_base + rid_len)
++ continue;
++
++ phandle_node = of_find_node_by_phandle(phandle);
++ if (!phandle_node)
++ return -ENODEV;
++
++ if (target) {
++ if (*target)
++ of_node_put(phandle_node);
++ else
++ *target = phandle_node;
++
++ if (*target != phandle_node)
++ continue;
++ }
++
++ if (id_out)
++ *id_out = masked_rid - rid_base + out_base;
++
++ pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
++ np, map_name, map_mask, rid_base, out_base,
++ rid_len, rid, *id_out);
++ return 0;
++ }
++
++ pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
++ np, map_name, rid, target && *target ? *target : NULL);
++ return -EFAULT;
++}
+ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
+ {
+ struct of_pci_iommu_alias_info *info = data;
+ struct of_phandle_args iommu_spec = { .args_count = 1 };
+ int err;
+
+- err = of_pci_map_rid(info->np, alias, "iommu-map",
+- "iommu-map-mask", &iommu_spec.np,
+- iommu_spec.args);
++ err = of_map_rid(info->np, alias, "iommu-map",
++ "iommu-map-mask", &iommu_spec.np,
++ iommu_spec.args);
+ if (err)
+ return err == -ENODEV ? NO_IOMMU : err;
+
+@@ -160,6 +261,23 @@ static int of_pci_iommu_init(struct pci_
+ return err;
+ }
+
++static int of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev,
++ struct device_node *master_np)
++{
++ struct of_phandle_args iommu_spec = { .args_count = 1 };
++ int err;
++
++ err = of_map_rid(master_np, mc_dev->icid, "iommu-map",
++ "iommu-map-mask", &iommu_spec.np,
++ iommu_spec.args);
++ if (err)
++ return err == -ENODEV ? NO_IOMMU : err;
++
++ err = of_iommu_xlate(&mc_dev->dev, &iommu_spec);
++ of_node_put(iommu_spec.np);
++ return err;
++}
++
+ const struct iommu_ops *of_iommu_configure(struct device *dev,
+ struct device_node *master_np)
+ {
+@@ -191,6 +309,8 @@ const struct iommu_ops *of_iommu_configu
+
+ err = pci_for_each_dma_alias(to_pci_dev(dev),
+ of_pci_iommu_init, &info);
++ } else if (dev_is_fsl_mc(dev)) {
++ err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np);
+ } else {
+ struct of_phandle_args iommu_spec;
+ int idx = 0;
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -26,7 +26,7 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/of_irq.h>
+-#include <linux/of_pci.h>
++#include <linux/of_iommu.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
+
+@@ -593,8 +593,8 @@ static u32 __of_msi_map_rid(struct devic
+ * "msi-map" property.
+ */
+ for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
+- if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map",
+- "msi-map-mask", np, &rid_out))
++ if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map",
++ "msi-map-mask", np, &rid_out))
+ break;
+ return rid_out;
+ }
+--- a/drivers/of/of_pci.c
++++ b/drivers/of/of_pci.c
+@@ -281,104 +281,3 @@ parse_failed:
+ }
+ EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
+ #endif /* CONFIG_OF_ADDRESS */
+-
+-/**
+- * of_pci_map_rid - Translate a requester ID through a downstream mapping.
+- * @np: root complex device node.
+- * @rid: PCI requester ID to map.
+- * @map_name: property name of the map to use.
+- * @map_mask_name: optional property name of the mask to use.
+- * @target: optional pointer to a target device node.
+- * @id_out: optional pointer to receive the translated ID.
+- *
+- * Given a PCI requester ID, look up the appropriate implementation-defined
+- * platform ID and/or the target device which receives transactions on that
+- * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
+- * @id_out may be NULL if only the other is required. If @target points to
+- * a non-NULL device node pointer, only entries targeting that node will be
+- * matched; if it points to a NULL value, it will receive the device node of
+- * the first matching target phandle, with a reference held.
+- *
+- * Return: 0 on success or a standard error code on failure.
+- */
+-int of_pci_map_rid(struct device_node *np, u32 rid,
+- const char *map_name, const char *map_mask_name,
+- struct device_node **target, u32 *id_out)
+-{
+- u32 map_mask, masked_rid;
+- int map_len;
+- const __be32 *map = NULL;
+-
+- if (!np || !map_name || (!target && !id_out))
+- return -EINVAL;
+-
+- map = of_get_property(np, map_name, &map_len);
+- if (!map) {
+- if (target)
+- return -ENODEV;
+- /* Otherwise, no map implies no translation */
+- *id_out = rid;
+- return 0;
+- }
+-
+- if (!map_len || map_len % (4 * sizeof(*map))) {
+- pr_err("%pOF: Error: Bad %s length: %d\n", np,
+- map_name, map_len);
+- return -EINVAL;
+- }
+-
+- /* The default is to select all bits. */
+- map_mask = 0xffffffff;
+-
+- /*
+- * Can be overridden by "{iommu,msi}-map-mask" property.
+- * If of_property_read_u32() fails, the default is used.
+- */
+- if (map_mask_name)
+- of_property_read_u32(np, map_mask_name, &map_mask);
+-
+- masked_rid = map_mask & rid;
+- for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
+- struct device_node *phandle_node;
+- u32 rid_base = be32_to_cpup(map + 0);
+- u32 phandle = be32_to_cpup(map + 1);
+- u32 out_base = be32_to_cpup(map + 2);
+- u32 rid_len = be32_to_cpup(map + 3);
+-
+- if (rid_base & ~map_mask) {
+- pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
+- np, map_name, map_name,
+- map_mask, rid_base);
+- return -EFAULT;
+- }
+-
+- if (masked_rid < rid_base || masked_rid >= rid_base + rid_len)
+- continue;
+-
+- phandle_node = of_find_node_by_phandle(phandle);
+- if (!phandle_node)
+- return -ENODEV;
+-
+- if (target) {
+- if (*target)
+- of_node_put(phandle_node);
+- else
+- *target = phandle_node;
+-
+- if (*target != phandle_node)
+- continue;
+- }
+-
+- if (id_out)
+- *id_out = masked_rid - rid_base + out_base;
+-
+- pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
+- np, map_name, map_mask, rid_base, out_base,
+- rid_len, rid, *id_out);
+- return 0;
+- }
+-
+- pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
+- np, map_name, rid, target && *target ? *target : NULL);
+- return -EFAULT;
+-}
+--- a/include/linux/iommu.h
++++ b/include/linux/iommu.h
+@@ -389,6 +389,8 @@ static inline size_t iommu_map_sg(struct
+ extern struct iommu_group *pci_device_group(struct device *dev);
+ /* Generic device grouping function */
+ extern struct iommu_group *generic_device_group(struct device *dev);
++/* FSL-MC device grouping function */
++struct iommu_group *fsl_mc_device_group(struct device *dev);
+
+ /**
+ * struct iommu_fwspec - per-device IOMMU instance data
+--- a/include/linux/of_iommu.h
++++ b/include/linux/of_iommu.h
+@@ -15,6 +15,9 @@ extern int of_get_dma_window(struct devi
+ extern const struct iommu_ops *of_iommu_configure(struct device *dev,
+ struct device_node *master_np);
+
++int of_map_rid(struct device_node *np, u32 rid,
++ const char *map_name, const char *map_mask_name,
++ struct device_node **target, u32 *id_out);
+ #else
+
+ static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
+@@ -30,6 +33,13 @@ static inline const struct iommu_ops *of
+ return NULL;
+ }
+
++static inline int of_map_rid(struct device_node *np, u32 rid,
++ const char *map_name, const char *map_mask_name,
++ struct device_node **target, u32 *id_out)
++{
++ return -EINVAL;
++}
++
+ #endif /* CONFIG_OF_IOMMU */
+
+ extern struct of_device_id __iommu_of_table;
+--- a/include/linux/of_pci.h
++++ b/include/linux/of_pci.h
+@@ -19,9 +19,6 @@ int of_pci_parse_bus_range(struct device
+ int of_get_pci_domain_nr(struct device_node *node);
+ int of_pci_get_max_link_speed(struct device_node *node);
+ void of_pci_check_probe_only(void);
+-int of_pci_map_rid(struct device_node *np, u32 rid,
+- const char *map_name, const char *map_mask_name,
+- struct device_node **target, u32 *id_out);
+ #else
+ static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
+ {
+@@ -57,13 +54,6 @@ of_get_pci_domain_nr(struct device_node
+ return -1;
+ }
+
+-static inline int of_pci_map_rid(struct device_node *np, u32 rid,
+- const char *map_name, const char *map_mask_name,
+- struct device_node **target, u32 *id_out)
+-{
+- return -EINVAL;
+-}
+-
+ static inline int
+ of_pci_get_max_link_speed(struct device_node *node)
+ {