* [PATCH v7 09/22] iommu/arm-smmu: Set PRIVCFG in stage 1 STEs
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
Implement the SMMUv3 equivalent of d346180e70b9 ("iommu/arm-smmu: Treat
all device transactions as unprivileged"), so that once again those
pesky DMA controllers with their privileged instruction fetches don't
unexpectedly fault in stage 1 domains due to VMSAv8 rules.
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/arm-smmu-v3.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 52860bcf80f2..0c45c1e02e04 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -267,6 +267,9 @@
#define STRTAB_STE_1_SHCFG_INCOMING 1UL
#define STRTAB_STE_1_SHCFG_SHIFT 44
+#define STRTAB_STE_1_PRIVCFG_UNPRIV 2UL
+#define STRTAB_STE_1_PRIVCFG_SHIFT 48
+
#define STRTAB_STE_2_S2VMID_SHIFT 0
#define STRTAB_STE_2_S2VMID_MASK 0xffffUL
#define STRTAB_STE_2_VTCR_SHIFT 32
@@ -1068,7 +1071,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
#ifdef CONFIG_PCI_ATS
STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT |
#endif
- STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT);
+ STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT |
+ STRTAB_STE_1_PRIVCFG_UNPRIV <<
+ STRTAB_STE_1_PRIVCFG_SHIFT);
if (smmu->features & ARM_SMMU_FEAT_STALLS)
dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 08/22] iommu/arm-smmu: Support non-PCI devices with SMMUv3
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
With the device <-> stream ID relationship suitably abstracted and
of_xlate() hooked up, the PCI dependency now looks, and is, entirely
arbitrary. Any bus using the of_dma_configure() mechanism will work,
so extend support to the platform and AMBA buses which do just that.
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/Kconfig | 2 +-
drivers/iommu/arm-smmu-v3.c | 37 +++++++++++++++++++++++++++++++------
2 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index d432ca828472..8ee54d71c7eb 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -309,7 +309,7 @@ config ARM_SMMU
config ARM_SMMU_V3
bool "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
- depends on ARM64 && PCI
+ depends on ARM64
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select GENERIC_MSI_IRQ_DOMAIN
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 15ba80db6465..52860bcf80f2 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -35,6 +35,8 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+
#include "io-pgtable.h"
/* MMIO registers */
@@ -1805,6 +1807,23 @@ static void arm_smmu_remove_device(struct device *dev)
iommu_fwspec_free(dev);
}
+static struct iommu_group *arm_smmu_device_group(struct device *dev)
+{
+ struct iommu_group *group;
+
+ /*
+ * We don't support devices sharing stream IDs other than PCI RID
+ * aliases, since the necessary ID-to-device lookup becomes rather
+ * impractical given a potential sparse 32-bit stream ID space.
+ */
+ if (dev_is_pci(dev))
+ group = pci_device_group(dev);
+ else
+ group = generic_device_group(dev);
+
+ return group;
+}
+
static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
enum iommu_attr attr, void *data)
{
@@ -1851,10 +1870,6 @@ out_unlock:
static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
{
- /* We only support PCI, for now */
- if (!dev_is_pci(dev))
- return -ENODEV;
-
return iommu_fwspec_add_ids(dev, args->args, 1);
}
@@ -1869,7 +1884,7 @@ static struct iommu_ops arm_smmu_ops = {
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
- .device_group = pci_device_group,
+ .device_group = arm_smmu_device_group,
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
.of_xlate = arm_smmu_of_xlate,
@@ -2613,8 +2628,18 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
/* And we're up. Go go go! */
of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+#ifdef CONFIG_PCI
pci_request_acs();
- return bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+ ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+ if (ret)
+ return ret;
+#endif
+#ifdef CONFIG_ARM_AMBA
+ ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+ if (ret)
+ return ret;
+#endif
+ return bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
}
static int arm_smmu_device_remove(struct platform_device *pdev)
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 07/22] iommu/arm-smmu: Implement of_xlate() for SMMUv3
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
Now that we can properly describe the mapping between PCI RIDs and
stream IDs via "iommu-map", and have it fed it to the driver
automatically via of_xlate(), rework the SMMUv3 driver to benefit from
that, and get rid of the current misuse of the "iommus" binding.
Since having of_xlate wired up means that masters will now be given the
appropriate DMA ops, we also need to make sure that default domains work
properly. This necessitates dispensing with the "whole group at a time"
notion for attaching to a domain, as devices which share a group get
attached to the group's default domain one by one as they are initially
probed.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Convert to updated fwspec mechanism
---
drivers/iommu/arm-smmu-v3.c | 304 +++++++++++++++++++-------------------------
1 file changed, 131 insertions(+), 173 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index d7fef5f99bfc..15ba80db6465 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -30,6 +30,7 @@
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
@@ -610,12 +611,9 @@ struct arm_smmu_device {
struct arm_smmu_strtab_cfg strtab_cfg;
};
-/* SMMU private data for an IOMMU group */
-struct arm_smmu_group {
+/* SMMU private data for each master */
+struct arm_smmu_master_data {
struct arm_smmu_device *smmu;
- struct arm_smmu_domain *domain;
- int num_sids;
- u32 *sids;
struct arm_smmu_strtab_ent ste;
};
@@ -1555,20 +1553,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
return ret;
}
-static struct arm_smmu_group *arm_smmu_group_get(struct device *dev)
-{
- struct iommu_group *group;
- struct arm_smmu_group *smmu_group;
-
- group = iommu_group_get(dev);
- if (!group)
- return NULL;
-
- smmu_group = iommu_group_get_iommudata(group);
- iommu_group_put(group);
- return smmu_group;
-}
-
static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
{
__le64 *step;
@@ -1591,27 +1575,17 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
return step;
}
-static int arm_smmu_install_ste_for_group(struct arm_smmu_group *smmu_group)
+static int arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
{
int i;
- struct arm_smmu_domain *smmu_domain = smmu_group->domain;
- struct arm_smmu_strtab_ent *ste = &smmu_group->ste;
- struct arm_smmu_device *smmu = smmu_group->smmu;
+ struct arm_smmu_master_data *master = fwspec->iommu_priv;
+ struct arm_smmu_device *smmu = master->smmu;
- if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
- ste->s1_cfg = &smmu_domain->s1_cfg;
- ste->s2_cfg = NULL;
- arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
- } else {
- ste->s1_cfg = NULL;
- ste->s2_cfg = &smmu_domain->s2_cfg;
- }
-
- for (i = 0; i < smmu_group->num_sids; ++i) {
- u32 sid = smmu_group->sids[i];
+ for (i = 0; i < fwspec->num_ids; ++i) {
+ u32 sid = fwspec->ids[i];
__le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
- arm_smmu_write_strtab_ent(smmu, sid, step, ste);
+ arm_smmu_write_strtab_ent(smmu, sid, step, &master->ste);
}
return 0;
@@ -1619,13 +1593,11 @@ static int arm_smmu_install_ste_for_group(struct arm_smmu_group *smmu_group)
static void arm_smmu_detach_dev(struct device *dev)
{
- struct arm_smmu_group *smmu_group = arm_smmu_group_get(dev);
+ struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv;
- smmu_group->ste.bypass = true;
- if (arm_smmu_install_ste_for_group(smmu_group) < 0)
+ master->ste.bypass = true;
+ if (arm_smmu_install_ste_for_dev(dev->iommu_fwspec) < 0)
dev_warn(dev, "failed to install bypass STE\n");
-
- smmu_group->domain = NULL;
}
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -1633,16 +1605,20 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
int ret = 0;
struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- struct arm_smmu_group *smmu_group = arm_smmu_group_get(dev);
+ struct arm_smmu_master_data *master;
+ struct arm_smmu_strtab_ent *ste;
- if (!smmu_group)
+ if (!dev->iommu_fwspec)
return -ENOENT;
+ master = dev->iommu_fwspec->iommu_priv;
+ smmu = master->smmu;
+ ste = &master->ste;
+
/* Already attached to a different domain? */
- if (smmu_group->domain && smmu_group->domain != smmu_domain)
+ if (!ste->bypass)
arm_smmu_detach_dev(dev);
- smmu = smmu_group->smmu;
mutex_lock(&smmu_domain->init_mutex);
if (!smmu_domain->smmu) {
@@ -1661,21 +1637,21 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
goto out_unlock;
}
- /* Group already attached to this domain? */
- if (smmu_group->domain)
- goto out_unlock;
+ ste->bypass = false;
+ ste->valid = true;
- smmu_group->domain = smmu_domain;
+ if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+ ste->s1_cfg = &smmu_domain->s1_cfg;
+ ste->s2_cfg = NULL;
+ arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
+ } else {
+ ste->s1_cfg = NULL;
+ ste->s2_cfg = &smmu_domain->s2_cfg;
+ }
- /*
- * FIXME: This should always be "false" once we have IOMMU-backed
- * DMA ops for all devices behind the SMMU.
- */
- smmu_group->ste.bypass = domain->type == IOMMU_DOMAIN_DMA;
-
- ret = arm_smmu_install_ste_for_group(smmu_group);
+ ret = arm_smmu_install_ste_for_dev(dev->iommu_fwspec);
if (ret < 0)
- smmu_group->domain = NULL;
+ ste->valid = false;
out_unlock:
mutex_unlock(&smmu_domain->init_mutex);
@@ -1734,40 +1710,19 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
return ret;
}
-static int __arm_smmu_get_pci_sid(struct pci_dev *pdev, u16 alias, void *sidp)
+static struct platform_driver arm_smmu_driver;
+
+static int arm_smmu_match_node(struct device *dev, void *data)
{
- *(u32 *)sidp = alias;
- return 0; /* Continue walking */
+ return dev->of_node == data;
}
-static void __arm_smmu_release_pci_iommudata(void *data)
+static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
{
- kfree(data);
-}
-
-static struct arm_smmu_device *arm_smmu_get_for_pci_dev(struct pci_dev *pdev)
-{
- struct device_node *of_node;
- struct platform_device *smmu_pdev;
- struct arm_smmu_device *smmu = NULL;
- struct pci_bus *bus = pdev->bus;
-
- /* Walk up to the root bus */
- while (!pci_is_root_bus(bus))
- bus = bus->parent;
-
- /* Follow the "iommus" phandle from the host controller */
- of_node = of_parse_phandle(bus->bridge->parent->of_node, "iommus", 0);
- if (!of_node)
- return NULL;
-
- /* See if we can find an SMMU corresponding to the phandle */
- smmu_pdev = of_find_device_by_node(of_node);
- if (smmu_pdev)
- smmu = platform_get_drvdata(smmu_pdev);
-
- of_node_put(of_node);
- return smmu;
+ struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
+ np, arm_smmu_match_node);
+ put_device(dev);
+ return dev ? dev_get_drvdata(dev) : NULL;
}
static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
@@ -1780,94 +1735,74 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
return sid < limit;
}
+static struct iommu_ops arm_smmu_ops;
+
static int arm_smmu_add_device(struct device *dev)
{
int i, ret;
- u32 sid, *sids;
- struct pci_dev *pdev;
- struct iommu_group *group;
- struct arm_smmu_group *smmu_group;
struct arm_smmu_device *smmu;
+ struct arm_smmu_master_data *master;
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ struct iommu_group *group;
- /* We only support PCI, for now */
- if (!dev_is_pci(dev))
+ if (!fwspec || fwspec->ops != &arm_smmu_ops)
return -ENODEV;
-
- pdev = to_pci_dev(dev);
- group = iommu_group_get_for_dev(dev);
- if (IS_ERR(group))
- return PTR_ERR(group);
-
- smmu_group = iommu_group_get_iommudata(group);
- if (!smmu_group) {
- smmu = arm_smmu_get_for_pci_dev(pdev);
- if (!smmu) {
- ret = -ENOENT;
- goto out_remove_dev;
- }
-
- smmu_group = kzalloc(sizeof(*smmu_group), GFP_KERNEL);
- if (!smmu_group) {
- ret = -ENOMEM;
- goto out_remove_dev;
- }
-
- smmu_group->ste.valid = true;
- smmu_group->smmu = smmu;
- iommu_group_set_iommudata(group, smmu_group,
- __arm_smmu_release_pci_iommudata);
+ /*
+ * We _can_ actually withstand dodgy bus code re-calling add_device()
+ * without an intervening remove_device()/of_xlate() sequence, but
+ * we're not going to do so quietly...
+ */
+ if (WARN_ON_ONCE(fwspec->iommu_priv)) {
+ master = fwspec->iommu_priv;
+ smmu = master->smmu;
} else {
- smmu = smmu_group->smmu;
+ smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
+ if (!smmu)
+ return -ENODEV;
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ master->smmu = smmu;
+ fwspec->iommu_priv = master;
}
- /* Assume SID == RID until firmware tells us otherwise */
- pci_for_each_dma_alias(pdev, __arm_smmu_get_pci_sid, &sid);
- for (i = 0; i < smmu_group->num_sids; ++i) {
- /* If we already know about this SID, then we're done */
- if (smmu_group->sids[i] == sid)
- goto out_put_group;
+ /* Check the SIDs are in range of the SMMU and our stream table */
+ for (i = 0; i < fwspec->num_ids; i++) {
+ u32 sid = fwspec->ids[i];
+
+ if (!arm_smmu_sid_in_range(smmu, sid))
+ return -ERANGE;
+
+ /* Ensure l2 strtab is initialised */
+ if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+ ret = arm_smmu_init_l2_strtab(smmu, sid);
+ if (ret)
+ return ret;
+ }
}
- /* Check the SID is in range of the SMMU and our stream table */
- if (!arm_smmu_sid_in_range(smmu, sid)) {
- ret = -ERANGE;
- goto out_remove_dev;
- }
+ group = iommu_group_get_for_dev(dev);
+ if (!IS_ERR(group))
+ iommu_group_put(group);
- /* Ensure l2 strtab is initialised */
- if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
- ret = arm_smmu_init_l2_strtab(smmu, sid);
- if (ret)
- goto out_remove_dev;
- }
-
- /* Resize the SID array for the group */
- smmu_group->num_sids++;
- sids = krealloc(smmu_group->sids, smmu_group->num_sids * sizeof(*sids),
- GFP_KERNEL);
- if (!sids) {
- smmu_group->num_sids--;
- ret = -ENOMEM;
- goto out_remove_dev;
- }
-
- /* Add the new SID */
- sids[smmu_group->num_sids - 1] = sid;
- smmu_group->sids = sids;
-
-out_put_group:
- iommu_group_put(group);
- return 0;
-
-out_remove_dev:
- iommu_group_remove_device(dev);
- iommu_group_put(group);
- return ret;
+ return PTR_ERR_OR_ZERO(group);
}
static void arm_smmu_remove_device(struct device *dev)
{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ struct arm_smmu_master_data *master;
+
+ if (!fwspec || fwspec->ops != &arm_smmu_ops)
+ return;
+
+ master = fwspec->iommu_priv;
+ if (master && master->ste.valid)
+ arm_smmu_detach_dev(dev);
iommu_group_remove_device(dev);
+ kfree(master);
+ iommu_fwspec_free(dev);
}
static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
@@ -1914,6 +1849,15 @@ out_unlock:
return ret;
}
+static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+ /* We only support PCI, for now */
+ if (!dev_is_pci(dev))
+ return -ENODEV;
+
+ return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
@@ -1928,6 +1872,7 @@ static struct iommu_ops arm_smmu_ops = {
.device_group = pci_device_group,
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
+ .of_xlate = arm_smmu_of_xlate,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
@@ -2662,7 +2607,14 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, smmu);
/* Reset the device */
- return arm_smmu_device_reset(smmu, bypass);
+ ret = arm_smmu_device_reset(smmu, bypass);
+ if (ret)
+ return ret;
+
+ /* And we're up. Go go go! */
+ of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+ pci_request_acs();
+ return bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
}
static int arm_smmu_device_remove(struct platform_device *pdev)
@@ -2690,22 +2642,14 @@ static struct platform_driver arm_smmu_driver = {
static int __init arm_smmu_init(void)
{
- struct device_node *np;
- int ret;
+ static bool registered;
+ int ret = 0;
- np = of_find_matching_node(NULL, arm_smmu_of_match);
- if (!np)
- return 0;
-
- of_node_put(np);
-
- ret = platform_driver_register(&arm_smmu_driver);
- if (ret)
- return ret;
-
- pci_request_acs();
-
- return bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+ if (!registered) {
+ ret = platform_driver_register(&arm_smmu_driver);
+ registered = !ret;
+ }
+ return ret;
}
static void __exit arm_smmu_exit(void)
@@ -2716,6 +2660,20 @@ static void __exit arm_smmu_exit(void)
subsys_initcall(arm_smmu_init);
module_exit(arm_smmu_exit);
+static int __init arm_smmu_of_init(struct device_node *np)
+{
+ int ret = arm_smmu_init();
+
+ if (ret)
+ return ret;
+
+ if (!of_platform_device_create(np, NULL, platform_bus_type.dev_root))
+ return -ENODEV;
+
+ return 0;
+}
+IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
MODULE_LICENSE("GPL v2");
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 06/22] iommu/arm-smmu: Fall back to global bypass
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
Unlike SMMUv2, SMMUv3 has no easy way to bypass unknown stream IDs,
other than allocating and filling in the entire stream table with bypass
entries, which for some configurations would waste *gigabytes* of RAM.
Otherwise, all transactions on unknown stream IDs will simply be aborted
with a C_BAD_STREAMID event.
Rather than render the system unusable in the case of an invalid DT,
avoid enabling the SMMU altogether such that everything bypasses
(though letting the explicit disable_bypass option take precedence).
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Implement proper GBPA update procedure per the spec
---
drivers/iommu/arm-smmu-v3.c | 48 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 5db6931c715c..d7fef5f99bfc 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -123,6 +123,10 @@
#define CR2_RECINVSID (1 << 1)
#define CR2_E2H (1 << 0)
+#define ARM_SMMU_GBPA 0x44
+#define GBPA_ABORT (1 << 20)
+#define GBPA_UPDATE (1 << 31)
+
#define ARM_SMMU_IRQ_CTRL 0x50
#define IRQ_CTRL_EVTQ_IRQEN (1 << 2)
#define IRQ_CTRL_PRIQ_IRQEN (1 << 1)
@@ -2124,6 +2128,24 @@ static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,
1, ARM_SMMU_POLL_TIMEOUT_US);
}
+/* GBPA is "special" */
+static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
+{
+ int ret;
+ u32 reg, __iomem *gbpa = smmu->base + ARM_SMMU_GBPA;
+
+ ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
+ 1, ARM_SMMU_POLL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ reg &= ~clr;
+ reg |= set;
+ writel_relaxed(reg | GBPA_UPDATE, gbpa);
+ return readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
+ 1, ARM_SMMU_POLL_TIMEOUT_US);
+}
+
static void arm_smmu_free_msis(void *data)
{
struct device *dev = data;
@@ -2269,7 +2291,7 @@ static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
return ret;
}
-static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
+static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
{
int ret;
u32 reg, enables;
@@ -2370,8 +2392,17 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
return ret;
}
- /* Enable the SMMU interface */
- enables |= CR0_SMMUEN;
+
+ /* Enable the SMMU interface, or ensure bypass */
+ if (!bypass || disable_bypass) {
+ enables |= CR0_SMMUEN;
+ } else {
+ ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
+ if (ret) {
+ dev_err(smmu->dev, "GBPA not responding to update\n");
+ return ret;
+ }
+ }
ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
ARM_SMMU_CR0ACK);
if (ret) {
@@ -2570,6 +2601,15 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
struct resource *res;
struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
+ bool bypass = true;
+ u32 cells;
+
+ if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
+ dev_err(dev, "missing #iommu-cells property\n");
+ else if (cells != 1)
+ dev_err(dev, "invalid #iommu-cells value (%d)\n", cells);
+ else
+ bypass = false;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
@@ -2622,7 +2662,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, smmu);
/* Reset the device */
- return arm_smmu_device_reset(smmu);
+ return arm_smmu_device_reset(smmu, bypass);
}
static int arm_smmu_device_remove(struct platform_device *pdev)
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 05/22] Docs: dt: document ARM SMMUv3 generic binding usage
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
We're about to ratify our use of the generic binding, so document it.
CC: Rob Herring <robh+dt@kernel.org>
CC: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Reference PCI "iommu-map" binding instead, as that's our main concern
- Fix "IDs" typo
---
Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
index 7b94c88cf2ee..be57550e14e4 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
@@ -27,6 +27,12 @@ the PCIe specification.
* "cmdq-sync" - CMD_SYNC complete
* "gerror" - Global Error activated
+- #iommu-cells : See the generic IOMMU binding described in
+ devicetree/bindings/pci/pci-iommu.txt
+ for details. For SMMUv3, must be 1, with each cell
+ describing a single stream ID. All possible stream
+ IDs which a device may emit must be described.
+
** SMMUv3 optional properties:
- dma-coherent : Present if DMA operations made by the SMMU (page
@@ -54,6 +60,6 @@ the PCIe specification.
<GIC_SPI 79 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eventq", "priq", "cmdq-sync", "gerror";
dma-coherent;
- #iommu-cells = <0>;
+ #iommu-cells = <1>;
msi-parent = <&its 0xff0000>;
};
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 04/22] iommu: Introduce iommu_fwspec
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
Introduce a common structure to hold the per-device firmware data that
most IOMMU drivers need to keep track of. This enables us to configure
much of that data from common firmware code, and consolidate a lot of
the equivalent implementations, device look-up tables, etc. which are
currently strewn across IOMMU drivers.
This will also be enable us to address the outstanding "multiple IOMMUs
on the platform bus" problem by tweaking IOMMU API calls to prefer
dev->fwspec->ops before falling back to dev->bus->iommu_ops, and thus
gracefully handle those troublesome systems which we currently cannot.
As the first user, hook up the OF IOMMU configuration mechanism. The
driver-defined nature of DT cells means that we still need the drivers
to translate and add the IDs themselves, but future users such as the
much less free-form ACPI IORT will be much simpler and self-contained.
CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Suggested-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Drop the 'gradual introduction' fiddling and go straight to struct
device and common code, as it prevents all the silly build issues
and ultimately makes life simpler for everyone
---
drivers/iommu/iommu.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/iommu/of_iommu.c | 8 +++++--
include/linux/device.h | 3 +++
include/linux/iommu.h | 38 ++++++++++++++++++++++++++++++++
4 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b06d93594436..816e320d3ad8 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/pci.h>
#include <linux/bitops.h>
+#include <linux/property.h>
#include <trace/events/iommu.h>
static struct kset *iommu_group_kset;
@@ -1613,3 +1614,58 @@ out:
return ret;
}
+
+int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
+ const struct iommu_ops *ops)
+{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+ if (fwspec)
+ return ops == fwspec->ops ? 0 : -EINVAL;
+
+ fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
+ if (!fwspec)
+ return -ENOMEM;
+
+ of_node_get(to_of_node(iommu_fwnode));
+ fwspec->iommu_fwnode = iommu_fwnode;
+ fwspec->ops = ops;
+ dev->iommu_fwspec = fwspec;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_fwspec_init);
+
+void iommu_fwspec_free(struct device *dev)
+{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+ if (fwspec) {
+ fwnode_handle_put(fwspec->iommu_fwnode);
+ kfree(fwspec);
+ dev->iommu_fwspec = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(iommu_fwspec_free);
+
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
+{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ size_t size;
+ int i;
+
+ if (!fwspec)
+ return -EINVAL;
+
+ size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
+ fwspec = krealloc(dev->iommu_fwspec, size, GFP_KERNEL);
+ if (!fwspec)
+ return -ENOMEM;
+
+ for (i = 0; i < num_ids; i++)
+ fwspec->ids[fwspec->num_ids + i] = ids[i];
+
+ fwspec->num_ids += num_ids;
+ dev->iommu_fwspec = fwspec;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 19e1e8f2f871..5b82862f571f 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -167,7 +167,9 @@ static const struct iommu_ops
return NULL;
ops = of_iommu_get_ops(iommu_spec.np);
- if (!ops || !ops->of_xlate || ops->of_xlate(&pdev->dev, &iommu_spec))
+ if (!ops || !ops->of_xlate ||
+ iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) ||
+ ops->of_xlate(&pdev->dev, &iommu_spec))
ops = NULL;
of_node_put(iommu_spec.np);
@@ -196,7 +198,9 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
np = iommu_spec.np;
ops = of_iommu_get_ops(np);
- if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec))
+ if (!ops || !ops->of_xlate ||
+ iommu_fwspec_init(dev, &np->fwnode, ops) ||
+ ops->of_xlate(dev, &iommu_spec))
goto err_put_node;
of_node_put(np);
diff --git a/include/linux/device.h b/include/linux/device.h
index 38f02814d53a..bc41e87a969b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -41,6 +41,7 @@ struct device_node;
struct fwnode_handle;
struct iommu_ops;
struct iommu_group;
+struct iommu_fwspec;
struct bus_attribute {
struct attribute attr;
@@ -765,6 +766,7 @@ struct device_dma_parameters {
* gone away. This should be set by the allocator of the
* device (i.e. the bus driver that discovered the device).
* @iommu_group: IOMMU group the device belongs to.
+ * @iommu_fwspec: IOMMU-specific properties supplied by firmware.
*
* @offline_disabled: If set, the device is permanently online.
* @offline: Set after successful invocation of bus type's .offline().
@@ -849,6 +851,7 @@ struct device {
void (*release)(struct device *dev);
struct iommu_group *iommu_group;
+ struct iommu_fwspec *iommu_fwspec;
bool offline_disabled:1;
bool offline:1;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a35fb8b42e1a..2ea15842e9f6 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -331,10 +331,32 @@ extern struct iommu_group *pci_device_group(struct device *dev);
/* Generic device grouping function */
extern struct iommu_group *generic_device_group(struct device *dev);
+/**
+ * struct iommu_fwspec - per-device IOMMU instance data
+ * @ops: ops for this device's IOMMU
+ * @iommu_fwnode: firmware handle for this device's IOMMU
+ * @iommu_priv: IOMMU driver private data for this device
+ * @num_ids: number of associated device IDs
+ * @ids: IDs which this device may present to the IOMMU
+ */
+struct iommu_fwspec {
+ const struct iommu_ops *ops;
+ struct fwnode_handle *iommu_fwnode;
+ void *iommu_priv;
+ unsigned int num_ids;
+ u32 ids[];
+};
+
+int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
+ const struct iommu_ops *ops);
+void iommu_fwspec_free(struct device *dev);
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+
#else /* CONFIG_IOMMU_API */
struct iommu_ops {};
struct iommu_group {};
+struct iommu_fwspec {};
static inline bool iommu_present(struct bus_type *bus)
{
@@ -541,6 +563,22 @@ static inline void iommu_device_unlink(struct device *dev, struct device *link)
{
}
+static inline int iommu_fwspec_init(struct device *dev,
+ struct fwnode_handle *iommu_fwnode,
+ const struct iommu_ops *ops)
+{
+ return -ENODEV;
+}
+
+void iommu_fwspec_free(struct device *dev)
+{
+}
+
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_IOMMU_API */
#endif /* __LINUX_IOMMU_H */
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 03/22] iommu/of: Handle iommu-map property for PCI
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
Now that we have a way to pick up the RID translation and target IOMMU,
hook up of_iommu_configure() to bring PCI devices into the of_xlate
mechanism and allow them IOMMU-backed DMA ops without the need for
driver-specific handling.
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Split PCI handling into a separate function
---
drivers/iommu/of_iommu.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 57f23eaaa2f9..19e1e8f2f871 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -22,6 +22,7 @@
#include <linux/limits.h>
#include <linux/of.h>
#include <linux/of_iommu.h>
+#include <linux/of_pci.h>
#include <linux/slab.h>
static const struct of_device_id __iommu_of_table_sentinel
@@ -134,6 +135,45 @@ const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
return ops;
}
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+ struct of_phandle_args *iommu_spec = data;
+
+ iommu_spec->args[0] = alias;
+ return iommu_spec->np == pdev->bus->dev.of_node;
+}
+
+static const struct iommu_ops
+*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np)
+{
+ const struct iommu_ops *ops;
+ struct of_phandle_args iommu_spec;
+
+ /*
+ * Start by tracing the RID alias down the PCI topology as
+ * far as the host bridge whose OF node we have...
+ * (we're not even attempting to handle multi-alias devices yet)
+ */
+ iommu_spec.args_count = 1;
+ iommu_spec.np = bridge_np;
+ pci_for_each_dma_alias(pdev, __get_pci_rid, &iommu_spec);
+ /*
+ * ...then find out what that becomes once it escapes the PCI
+ * bus into the system beyond, and which IOMMU it ends up at.
+ */
+ iommu_spec.np = NULL;
+ if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
+ "iommu-map-mask", &iommu_spec.np, iommu_spec.args))
+ return NULL;
+
+ ops = of_iommu_get_ops(iommu_spec.np);
+ if (!ops || !ops->of_xlate || ops->of_xlate(&pdev->dev, &iommu_spec))
+ ops = NULL;
+
+ of_node_put(iommu_spec.np);
+ return ops;
+}
+
const struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np)
{
@@ -142,12 +182,8 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
const struct iommu_ops *ops = NULL;
int idx = 0;
- /*
- * We can't do much for PCI devices without knowing how
- * device IDs are wired up from the PCI bus to the IOMMU.
- */
if (dev_is_pci(dev))
- return NULL;
+ return of_pci_iommu_configure(to_pci_dev(dev), master_np);
/*
* We don't currently walk up the tree looking for a parent IOMMU.
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 02/22] of/irq: Break out msi-map lookup (again)
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
The PCI msi-map code is already doing double-duty translating IDs and
retrieving MSI parents, which unsurprisingly is the same functionality
we need for the identically-formatted PCI iommu-map property. Drag the
core parsing routine up yet another layer into the general OF-PCI code,
and further generalise it for either kind of lookup in either flavour
of map property.
Acked-by: Rob Herring <robh+dt@kernel.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/of/irq.c | 78 ++-----------------------------------
drivers/of/of_pci.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_pci.h | 10 +++++
3 files changed, 116 insertions(+), 74 deletions(-)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index a2e68f740eda..393fea85eb4e 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_pci.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -592,87 +593,16 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
u32 rid_in)
{
struct device *parent_dev;
- struct device_node *msi_controller_node;
- struct device_node *msi_np = *np;
- u32 map_mask, masked_rid, rid_base, msi_base, rid_len, phandle;
- int msi_map_len;
- bool matched;
u32 rid_out = rid_in;
- const __be32 *msi_map = NULL;
/*
* Walk up the device parent links looking for one with a
* "msi-map" property.
*/
- for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) {
- if (!parent_dev->of_node)
- continue;
-
- msi_map = of_get_property(parent_dev->of_node,
- "msi-map", &msi_map_len);
- if (!msi_map)
- continue;
-
- if (msi_map_len % (4 * sizeof(__be32))) {
- dev_err(parent_dev, "Error: Bad msi-map length: %d\n",
- msi_map_len);
- return rid_out;
- }
- /* We have a good parent_dev and msi_map, let's use them. */
- break;
- }
- if (!msi_map)
- return rid_out;
-
- /* The default is to select all bits. */
- map_mask = 0xffffffff;
-
- /*
- * Can be overridden by "msi-map-mask" property. If
- * of_property_read_u32() fails, the default is used.
- */
- of_property_read_u32(parent_dev->of_node, "msi-map-mask", &map_mask);
-
- masked_rid = map_mask & rid_in;
- matched = false;
- while (!matched && msi_map_len >= 4 * sizeof(__be32)) {
- rid_base = be32_to_cpup(msi_map + 0);
- phandle = be32_to_cpup(msi_map + 1);
- msi_base = be32_to_cpup(msi_map + 2);
- rid_len = be32_to_cpup(msi_map + 3);
-
- if (rid_base & ~map_mask) {
- dev_err(parent_dev,
- "Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n",
- map_mask, rid_base);
- return rid_out;
- }
-
- msi_controller_node = of_find_node_by_phandle(phandle);
-
- matched = (masked_rid >= rid_base &&
- masked_rid < rid_base + rid_len);
- if (msi_np)
- matched &= msi_np == msi_controller_node;
-
- if (matched && !msi_np) {
- *np = msi_np = msi_controller_node;
+ 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))
break;
- }
-
- of_node_put(msi_controller_node);
- msi_map_len -= 4 * sizeof(__be32);
- msi_map += 4;
- }
- if (!matched)
- return rid_out;
-
- rid_out = masked_rid - rid_base + msi_base;
- dev_dbg(dev,
- "msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n",
- dev_name(parent_dev), map_mask, rid_base, msi_base,
- rid_len, rid_in, rid_out);
-
return rid_out;
}
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 589b30c68e14..b58be12ab277 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -308,3 +308,105 @@ struct msi_controller *of_pci_find_msi_chip_by_node(struct device_node *of_node)
EXPORT_SYMBOL_GPL(of_pci_find_msi_chip_by_node);
#endif /* CONFIG_PCI_MSI */
+
+/**
+ * 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("%s: Error: Bad %s length: %d\n", np->full_name,
+ 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("%s: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
+ np->full_name, 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("%s: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
+ np->full_name, map_name, map_mask, rid_base, out_base,
+ rid_len, rid, *id_out);
+ return 0;
+ }
+
+ pr_err("%s: Invalid %s translation - no match for rid 0x%x on %s\n",
+ np->full_name, map_name, rid,
+ target && *target ? (*target)->full_name : "any target");
+ return -EFAULT;
+}
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index b969e9443962..7fd5cfce9140 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -17,6 +17,9 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
int of_get_pci_domain_nr(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)
{
@@ -52,6 +55,13 @@ of_get_pci_domain_nr(struct device_node *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 void of_pci_check_probe_only(void) { }
#endif
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 01/22] Docs: dt: add PCI IOMMU map bindings
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1473695704.git.robin.murphy@arm.com>
From: Mark Rutland <mark.rutland@arm.com>
The existing IOMMU bindings are able to specify the relationship between
masters and IOMMUs, but they are insufficient for describing the general
case of hotpluggable busses such as PCI where the set of masters is not
known until runtime, and the relationship between masters and IOMMUs is
a property of the integration of the system.
This patch adds a generic binding for mapping PCI devices to IOMMUs,
using a new iommu-map property (specific to PCI*) which may be used to
map devices (identified by their Requester ID) to sideband data for the
IOMMU which they master through.
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
.../devicetree/bindings/pci/pci-iommu.txt | 171 +++++++++++++++++++++
1 file changed, 171 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/pci-iommu.txt
diff --git a/Documentation/devicetree/bindings/pci/pci-iommu.txt b/Documentation/devicetree/bindings/pci/pci-iommu.txt
new file mode 100644
index 000000000000..56c829621b9a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pci-iommu.txt
@@ -0,0 +1,171 @@
+This document describes the generic device tree binding for describing the
+relationship between PCI(e) devices and IOMMU(s).
+
+Each PCI(e) device under a root complex is uniquely identified by its Requester
+ID (AKA RID). A Requester ID is a triplet of a Bus number, Device number, and
+Function number.
+
+For the purpose of this document, when treated as a numeric value, a RID is
+formatted such that:
+
+* Bits [15:8] are the Bus number.
+* Bits [7:3] are the Device number.
+* Bits [2:0] are the Function number.
+* Any other bits required for padding must be zero.
+
+IOMMUs may distinguish PCI devices through sideband data derived from the
+Requester ID. While a given PCI device can only master through one IOMMU, a
+root complex may split masters across a set of IOMMUs (e.g. with one IOMMU per
+bus).
+
+The generic 'iommus' property is insufficient to describe this relationship,
+and a mechanism is required to map from a PCI device to its IOMMU and sideband
+data.
+
+For generic IOMMU bindings, see
+Documentation/devicetree/bindings/iommu/iommu.txt.
+
+
+PCI root complex
+================
+
+Optional properties
+-------------------
+
+- iommu-map: Maps a Requester ID to an IOMMU and associated iommu-specifier
+ data.
+
+ The property is an arbitrary number of tuples of
+ (rid-base,iommu,iommu-base,length).
+
+ Any RID r in the interval [rid-base, rid-base + length) is associated with
+ the listed IOMMU, with the iommu-specifier (r - rid-base + iommu-base).
+
+- iommu-map-mask: A mask to be applied to each Requester ID prior to being
+ mapped to an iommu-specifier per the iommu-map property.
+
+
+Example (1)
+===========
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ iommu: iommu at a {
+ reg = <0xa 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ pci: pci at f {
+ reg = <0xf 0x1>;
+ compatible = "vendor,pcie-root-complex";
+ device_type = "pci";
+
+ /*
+ * The sideband data provided to the IOMMU is the RID,
+ * identity-mapped.
+ */
+ iommu-map = <0x0 &iommu 0x0 0x10000>;
+ };
+};
+
+
+Example (2)
+===========
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ iommu: iommu at a {
+ reg = <0xa 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ pci: pci at f {
+ reg = <0xf 0x1>;
+ compatible = "vendor,pcie-root-complex";
+ device_type = "pci";
+
+ /*
+ * The sideband data provided to the IOMMU is the RID with the
+ * function bits masked out.
+ */
+ iommu-map = <0x0 &iommu 0x0 0x10000>;
+ iommu-map-mask = <0xfff8>;
+ };
+};
+
+
+Example (3)
+===========
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ iommu: iommu at a {
+ reg = <0xa 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ pci: pci at f {
+ reg = <0xf 0x1>;
+ compatible = "vendor,pcie-root-complex";
+ device_type = "pci";
+
+ /*
+ * The sideband data provided to the IOMMU is the RID,
+ * but the high bits of the bus number are flipped.
+ */
+ iommu-map = <0x0000 &iommu 0x8000 0x8000>,
+ <0x8000 &iommu 0x0000 0x8000>;
+ };
+};
+
+
+Example (4)
+===========
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ iommu_a: iommu at a {
+ reg = <0xa 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ iommu_b: iommu at b {
+ reg = <0xb 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ iommu_c: iommu at c {
+ reg = <0xc 0x1>;
+ compatible = "vendor,some-iommu";
+ #iommu-cells = <1>;
+ };
+
+ pci: pci at f {
+ reg = <0xf 0x1>;
+ compatible = "vendor,pcie-root-complex";
+ device_type = "pci";
+
+ /*
+ * Devices with bus number 0-127 are mastered via IOMMU
+ * a, with sideband data being RID[14:0].
+ * Devices with bus number 128-255 are mastered via
+ * IOMMU b, with sideband data being RID[14:0].
+ * No devices master via IOMMU c.
+ */
+ iommu-map = <0x0000 &iommu_a 0x0000 0x8000>,
+ <0x8000 &iommu_b 0x0000 0x8000>;
+ };
+};
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH v7 00/22] Generic DT bindings for PCI IOMMUs and ARM SMMU
From: Robin Murphy @ 2016-09-12 16:13 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
To any more confusing fixups and crazily numbered extra patches, here's
a quick v7 with everything rebased into the right order. The significant
change this time is to implement iommu_fwspec properly from the start,
which ends up being far simpler and more robust than faffing about
introducing it somewhere 'less intrusive' to move toward core code later.
New branch in the logical place:
git://linux-arm.org/linux-rm iommu/generic-v7
Robin.
Mark Rutland (1):
Docs: dt: add PCI IOMMU map bindings
Robin Murphy (21):
of/irq: Break out msi-map lookup (again)
iommu/of: Handle iommu-map property for PCI
iommu: Introduce iommu_fwspec
Docs: dt: document ARM SMMUv3 generic binding usage
iommu/arm-smmu: Fall back to global bypass
iommu/arm-smmu: Implement of_xlate() for SMMUv3
iommu/arm-smmu: Support non-PCI devices with SMMUv3
iommu/arm-smmu: Set PRIVCFG in stage 1 STEs
iommu/arm-smmu: Handle stream IDs more dynamically
iommu/arm-smmu: Consolidate stream map entry state
iommu/arm-smmu: Keep track of S2CR state
iommu/arm-smmu: Refactor mmu-masters handling
iommu/arm-smmu: Streamline SMMU data lookups
iommu/arm-smmu: Add a stream map entry iterator
iommu/arm-smmu: Intelligent SMR allocation
iommu/arm-smmu: Convert to iommu_fwspec
Docs: dt: document ARM SMMU generic binding usage
iommu/arm-smmu: Wire up generic configuration support
iommu/arm-smmu: Set domain geometry
iommu/dma: Add support for mapping MSIs
iommu/dma: Avoid PCI host bridge windows
.../devicetree/bindings/iommu/arm,smmu-v3.txt | 8 +-
.../devicetree/bindings/iommu/arm,smmu.txt | 63 +-
.../devicetree/bindings/pci/pci-iommu.txt | 171 ++++
arch/arm64/mm/dma-mapping.c | 2 +-
drivers/gpu/drm/exynos/exynos_drm_iommu.h | 2 +-
drivers/iommu/Kconfig | 2 +-
drivers/iommu/arm-smmu-v3.c | 386 +++++----
drivers/iommu/arm-smmu.c | 962 ++++++++++-----------
drivers/iommu/dma-iommu.c | 161 +++-
drivers/iommu/iommu.c | 56 ++
drivers/iommu/of_iommu.c | 52 +-
drivers/irqchip/irq-gic-v2m.c | 3 +
drivers/irqchip/irq-gic-v3-its.c | 3 +
drivers/of/irq.c | 78 +-
drivers/of/of_pci.c | 102 +++
include/linux/device.h | 3 +
include/linux/dma-iommu.h | 12 +-
include/linux/iommu.h | 38 +
include/linux/of_pci.h | 10 +
19 files changed, 1323 insertions(+), 791 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/pci-iommu.txt
--
2.8.1.dirty
^ permalink raw reply
* [PATCH v3 02/17] pinctrl: dt-bindings: samsung: Update documentation with new macros
From: Rob Herring @ 2016-09-12 16:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472987060-28293-3-git-send-email-krzk@kernel.org>
On Sun, Sep 04, 2016 at 01:04:05PM +0200, Krzysztof Kozlowski wrote:
> From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
>
> Update examples in Samsung pinctrl dt-bindings with new macros coming
> from header file.
>
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
>
> ---
>
> Changes since v1:
> 1. Add Javier's reviewed-by.
> 2. Include necessary header in example (pointed by Javier).
> ---
> .../bindings/pinctrl/samsung-pinctrl.txt | 44 +++++++++++-----------
> 1 file changed, 23 insertions(+), 21 deletions(-)
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* ARM, SoC: About the use DT-defined properties by 3rd-party drivers
From: Sebastian Frias @ 2016-09-12 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160912135549.GA14165@leverpostej>
Hi Mark,
On 09/12/2016 04:01 PM, Mark Rutland wrote:
>> 3rd parties could choose to write a driver (as opposed to use say, a user-mode
>> library) if it fits their programming model better, if they think they would
>> have better performance, or other reasons.
>
> A vendor can always choose to "add value" in this manner. The general
> expectation of *some* driver being upstreamed remains.
Yes, that's the idea.
>>
>> That may be true, but so far we are not discussing changing DT's API so it
>> should not have big ramifications.
>
> You're not changing the code, but you are creating a binding. Bindings
> are intended to be stable (i.e. a working DTB from today should continue
> to work in future), and thus there are ramifications.
Ok, but who is responsible for such guarantee?
How is it enforced and verified?
>
> Few devices these says are entirely independent, and most devices can be
> instantiated multiple times (even if there happens to only be a single
> instance in practice). For the example of a userspace driver there are
> very real ABI concerns, such as how the device(s) are discovered, how
> any related components like regulators and clocks are controlled, etc.
>
> There are ramifications here, and it's a dangerous over simplification
> to say that this doesn't matter because we're not changing kernel code.
>
>> Besides, what "makes sense now" may "not make sense tomorrow" depending on
>> how the HW is modified.
>
> That's always the case when a new generation of hardware comes out, so I
> don't think that's relevant to the topic at hand.
Exactly, that's why to I'm having trouble to understand why there is so much
insistence on "getting the DT 100% right", since a HW change could imply
that what made 100% sense yesterday, does not today.
Since that is a possibility we have to live with, then the "100% right" goal
is most likely unachievable.
That's different from "backwards compatibility" for which some technique,
like alternate descriptions, can be put in place.
Maybe I will get a better understanding of this once my previous question
about who and how guarantees the stability of a given DT blob.
>>
>> Actually, I think it would encourage more SoC manufacturers to use DT as a way
>> to document their HW, which is a good thing.
>
> Writing and reviewing bindings is a very tricky topic, as it can require
> fairly intimate knowledge of a piece of hardware. I've repeatedly found
> that binding descriptions did not match the realities of the hardware,
> and I've only managed to do so by looking at accompanying driver code.
>
> Given that manuals and other information on devices are often not freely
> available (if they exist at all), the proposal effectively limits myself
> and others to spot common (anti)patterns, which is far less than ideal,
> and will result in more mistakes.
>
> As it stands, the proposal asks for effort for the community (in terms
> of review and maintenance of bindings), with no benefit to the kernel
> community, and a number of pitfalls that we would rather avoid.
Could you be more precise on those two issues? Namely:
"the effort" and the "lack of benefit for the community"?
I can understand the effort it takes to review a binding and some
driver, but if there's no driver, why would it matter if the DT binding is
100% right? Hence, why would it take more effort?
Furthermore, if there's no driver, there's no backward compatibility to
guarantee. Shouldn't it require less effort?
Also, what sort of "benefits" does the community expects or requires?
Because the idea behind the proposal is to put the HW description in DT, so
basically the HW would be documented. Maybe there wouldn't be a driver right
away, but the HW description would allow for drivers to exist.
>
> In an ideal world, writing and reviewing bindings would be a simple
> affair, and this could happen separately from work on any particular OS.
> In practice, things are sufficiently complicated that you need *some*
> demonstration that a binding is suitable, which is what I'm personally
> after when I ask for a Linux driver.
>
>>>> However, after discussing over IRC, it looks like there was no guidance on
>>>> this. Some people think submitting DT properties/nodes without a corresponding
>>>> Linux driver is frowned upon, while others thought it was an odd limitation
>>>> and suggested asking here.
>>>
>>> Unfortunately, I think that the area is sufficiently vague that there
>>> simply is no clear and general answer.
>>>
>>> For the sake of discussion, an example of a particular block, along with
>>> what you expect/need to describe would be helpful.
>>
>> I don't have a more concrete example now.
>
> For this discussion to go somewhere, we need an example. Otherwise we're
> all coming at this with differing implicit assumptions and no clear
> evidence for any assertions.
Ok, I'll try to come up with some example.
>> But if I understood correctly your comment, you are basically saying that
>> without an example is hard to say.
>> Since the question seems understood, do you have an example of other SoC's
>> doing something similar?
>
> I do not have an example. I know that others are using DT for data
> beyond what Linux or another OS requires, but it's my understanding that
> that is typically in a separate DTB.
>
I see, although I don't understand how accepting such solution (i.e.: having the
information in a different DT) benefits the open-source community, since it
basically means that the open-source community settles for less information.
Best regards,
Sebastian
^ permalink raw reply
* [PATCH] ARM: dts: meson-gxbb: Add support for the Nexbox A95X Board
From: Andreas Färber @ 2016-09-12 15:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1471951370-29269-1-git-send-email-narmstrong@baylibre.com>
Hi,
ARM64 for consistency? amlogic vs. meson-gxbb?
Am 23.08.2016 um 13:22 schrieb Neil Armstrong:
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> arch/arm64/boot/dts/amlogic/Makefile | 1 +
> .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts | 79 ++++++++++++++++++++++
> 2 files changed, 80 insertions(+)
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
>
> diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
> index 47ec703..2c50439 100644
> --- a/arch/arm64/boot/dts/amlogic/Makefile
> +++ b/arch/arm64/boot/dts/amlogic/Makefile
> @@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-p201.dtb
> dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-pro.dtb
> dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb
> dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb
> +dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb
>
> always := $(dtb-y)
> subdir-y := $(dts-dirs)
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> new file mode 100644
> index 0000000..c418bd7
> --- /dev/null
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (c) 2016 Andreas F?rber
Here I have not really contributed (don't have access to a Nexbox) so
you are free to drop my copyright line (I assume you adopted it from
Vega S95 - nodes are still trivial though).
Looks fine otherwise, except for ...
> + * Copyright (c) 2016 BayLibre, Inc.
> + * Author: Neil Armstrong <narmstrong@kernel.org>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/dts-v1/;
> +
> +#include "meson-gxbb.dtsi"
> +#include <dt-bindings/gpio/gpio.h>
> +
> +/ {
> + compatible = "nexbox,a95x", "amlogic,meson-gxbb";
> + model = "NEXBOX A95X";
> +
> + aliases {
> + serial0 = &uart_AO;
> + };
> +
> + chosen {
> + stdout-path = "serial0:115200n8";
> + };
> +
> + memory at 0 {
> + device_type = "memory";
> + reg = <0x0 0x0 0x0 0x40000000>;
> + };
> +};
> +
> +&uart_AO {
> + status = "okay";
> + pinctrl-0 = <&uart_ao_a_pins>;
> + pinctrl-names = "default";
> +};
> +
> +ðmac {
> + status = "okay";
> + pinctrl-0 = <ð_pins>;
> + pinctrl-names = "default";
> +};
> +
Trailing white line.
Cheers,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
^ permalink raw reply
* [PATCH v10 0/4] ACPI: parse the SPCR table
From: Aleksey Makarov @ 2016-09-12 15:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160905123617.18775-1-aleksey.makarov@linaro.org>
On 09/05/2016 03:36 PM, Aleksey Makarov wrote:
> 'ARM Server Base Boot Requirements' [1] mentions SPCR (Serial Port Console
> Redirection Table) [2] as a mandatory ACPI table that specifies the
> configuration of serial console.
Hi Rafael,
Could you pull these patches please?
Each of them is ACKed now.
Thank you
Aleksey Makarov
> Move "earlycon" early_param handling to earlycon.c to parse this option once
>
> Parse SPCR table, setup earlycon and register specified console.
>
> Enable parsing this table on ARM64. Earlycon should be set up as early as
> possible. ACPI boot tables are mapped in
> arch/arm64/kernel/acpi.c:acpi_boot_table_init() called from setup_arch() and
> that's where we parse spcr. So it has to be opted-in per-arch. When
> ACPI_SPCR_TABLE is defined initialization of DT earlycon is deferred until the
> DT/ACPI decision is done.
>
> Implement console_match() for pl011.
>
> Based on the work by Leif Lindholm [3]
> Thanks to Peter Hurley for explaining how this should work.
>
> Should be applied to v4.8-rc5
> Tested on QEMU and ThunderX.
> SPCR support is included in QEMU's ARM64 mach-virt since 2.4 release.
>
> v10:
> - rebase to v4.8-rc5
> - fix the issue with comparing the console name in pl011_console_match()
> (Russell King)
> - fix build on sh arch (kbuild test robot)
> - add Acked-by: Russell King <rmk+kernel@armlinux.org.uk> for 4/4
> - add Tested-by: Christopher Covington <cov@codeaurora.org>
>
> v9:
> https://lkml.kernel.org/g/20160811153152.755-1-aleksey.makarov at linaro.org
> - rebase to v4.8-rc1
> - fix compilation for !CONFIG_SERIAL_EARLYCON case
> - add Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> for ACPI part
> - move constant check out of loop (Yury Norov)
> - add '\n' to info message
>
> v8:
> https://lkml.kernel.org/g/1463749405-11640-1-git-send-email-aleksey.makarov at linaro.org
> - rebase to next-20160520
> - remove the patch "ACPICA: Headers: Add new constants for the DBG2 ACPI table"
> as it have got to linux-next
> - add Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Reviewed-by:
> Peter Hurley <peter@hurleysoftware.com> (but see below)
> - fix the patch "serial: pl011: add console matching function". The patch by
> Christopher Covington [4] specifies that SBSA uart does 32-bit access to
> registers and this breaks the match function. In this series the function
> was changed to match when SPCR specifies both mmio32 and mmio access.
> I removed Acked-by: Greg from this patch because of these changes.
>
> v7:
> https://lkml.kernel.org/g/1459431629-27934-1-git-send-email-aleksey.makarov at linaro.org
> - add Acked-by: Rob Herring for "of/serial: move earlycon early_param handling
> to serial"
> - call DT earlycon initialization from the arch ACPI code, not from parse_spcr()
> (Rafael J. Wysocki)
> - fix a few minor issues (Rafael J. Wysocki)
>
> v6:
> https://lkml.kernel.org/g/1458823925-19560-1-git-send-email-aleksey.makarov at linaro.org
> - add documentation for parse_spcr() functioin (Yury Norov)
> - don't initialize err variable (Yury Norov)
> - add __initdata for the earlycon_init_is_deferred flag variable
> - rename the function exported in "of/serial: move earlycon early_param handling
> to serial" to avoid clash with the function from arch/microblaze/kernel/prom.c
> - defer initialization of DT earlycon until DT/ACPI decision is made
> (Rob Herring, Peter Hurley)
> - use snprintf instead of sprintf (Andy Shevchenko)
> - drop patch that adds EARLYCON_DECLARE for pl011 as EARLYCON_DECLARE is
> equivalent to OF_EARLYCON_DECLARE for 4.6+ (Peter Hurley). This means that
> SPCR earlycon will not work on the kernels before 4.6
>
> v5:
> https://lkml.kernel.org/g/1458643595-14719-1-git-send-email-aleksey.makarov at linaro.org
> - drop patch "serial: pl011: use ACPI SPCR to setup 32-bit access" because
> it is ugly. Also because Christopher Covington came with a better solution [4]
> - remove error message when the table is not provided by ACPI (Andy Shevchenko)
> - rewrite spcr.c following the suggestions by Peter Hurley
> - add console_match() for pl011 in a separate patch
> - add EARLYCON_DECLARE for pl011 in a separate patch
> - add patch "of/serial: move earlycon early_param handling to serial" from
> the GDB2 series
>
> v4:
> https://lkml.kernel.org/g/1456747355-15692-1-git-send-email-aleksey.makarov at linaro.org
> - drop patch "ACPI: change __init to __ref for early_acpi_os_unmap_memory()"
> ACPI developers work on a new API and asked not to do that.
> Instead, use acpi_get_table_with_size()/early_acpi_os_unmap_memory() once
> and cache the result. (Lv Zheng)
> - fix some style issues (Yury Norov)
>
> v3:
> https://lkml.kernel.org/g/1455559532-8305-1-git-send-email-aleksey.makarov at linaro.org
>
> Greg Kroah-Hartman did not like v2 so I have rewritten this patchset:
>
> - drop acpi_match() member of struct console
> - drop implementations of this member for pl011 and 8250
> - drop the patch that renames some vars in printk.c as it is not needed anymore
> - drop patch that introduces system wide acpi_table_parse2().
> Instead introduce a custom acpi_table_parse_spcr() in spcr.c
>
> Instead of introducing a new match_acpi() member of struct console,
> this patchset introduces a new function acpi_console_check().
> This function is called when a new uart is registered at serial_core.c
> the same way OF code checks for console. If the registered uart is the
> console specified by SPCR table, this function calls add_preferred_console()
>
> The restrictions of this approach are:
>
> - only serial consoles can be set up
> - only consoles specified by the memory/io address can be set up
> (SPCR can specify devices by PCI id/PCI address)
>
> v2:
> https://lkml.kernel.org/g/1455299022-11641-1-git-send-email-aleksey.makarov at linaro.org
> - don't use SPCR if user specified console in command line
> - fix initialization order of newcon->index = 0
> - rename some variables at printk.c (Joe Perches, Peter Hurley)
> - enable ACPI_SPCR_TABLE in a separate patch (Andy Shevchenko)
> - remove the retry loop for console registering (Peter Hurley).
> Instead, obtain SPCR with acpi_get_table(). That works after
> call to acpi_early_init() i. e. in any *_initcall()
> - describe design decision behind introducing acpi_match() (Peter Hurley)
> - fix compilation for x86 + ACPI (Graeme Gregory)
> - introduce DBG2 constants in a separate patch (Andy Shevchenko)
> - fix a typo in DBG2 constants (Andy Shevchenko)
> - add ACPI_DBG2_ARM_SBSA_32BIT constant (Christopher Covington)
> - add support for ACPI_DBG2_ARM_SBSA_* consoles (Christopher Covington)
> - add documentation for functions
> - add a patch that uses SPCR to find if SBSA serial driver should use 32-bit
> accessor functions (Christopher Covington)
> - change __init to __ref for early_acpi_os_unmap_memory() in a separate patch
> - introduce acpi_table_parse2() in a separate patch
> - fix fetching the SPCR table early (Mark Salter)
> - add a patch from Mark Salter that introduces support for matching 8250-based
> consoles
>
> v1:
> https://lkml.kernel.org/g/1453722324-22407-1-git-send-email-aleksey.makarov at linaro.org
>
> [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0044a/index.html
> [2] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> [3] https://lkml.kernel.org/g/1441716217-23786-1-git-send-email-leif.lindholm at linaro.org
> [4] https://lkml.kernel.org/g/1457415800-8799-1-git-send-email-cov at codeaurora.org
>
> Aleksey Makarov (3):
> ACPI: parse SPCR and enable matching console
> ARM64: ACPI: enable ACPI_SPCR_TABLE
> serial: pl011: add console matching function
>
> Leif Lindholm (1):
> of/serial: move earlycon early_param handling to serial
>
> arch/arm64/Kconfig | 1 +
> arch/arm64/kernel/acpi.c | 11 +++-
> drivers/acpi/Kconfig | 3 ++
> drivers/acpi/Makefile | 1 +
> drivers/acpi/spcr.c | 111 ++++++++++++++++++++++++++++++++++++++++
> drivers/of/fdt.c | 11 +---
> drivers/tty/serial/amba-pl011.c | 55 ++++++++++++++++++++
> drivers/tty/serial/earlycon.c | 19 ++++++-
> include/linux/acpi.h | 6 +++
> include/linux/of_fdt.h | 3 ++
> include/linux/serial_core.h | 9 +++-
> 11 files changed, 216 insertions(+), 14 deletions(-)
> create mode 100644 drivers/acpi/spcr.c
>
^ permalink raw reply
* [PATCH] arm64: mm: move zero page from .bss to right before swapper_pg_dir
From: Ard Biesheuvel @ 2016-09-12 15:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160912153858.GD14165@leverpostej>
On 12 September 2016 at 16:40, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Sep 12, 2016 at 04:12:19PM +0100, Ard Biesheuvel wrote:
>> On 12 September 2016 at 15:59, Mark Rutland <mark.rutland@arm.com> wrote:
>> > On Mon, Sep 12, 2016 at 03:16:24PM +0100, Ard Biesheuvel wrote:
>> >> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
>> >> index 4e7e7067afdb..44e94e234ba0 100644
>> >> --- a/arch/arm64/include/asm/sections.h
>> >> +++ b/arch/arm64/include/asm/sections.h
>> >> @@ -26,5 +26,6 @@ extern char __hyp_text_start[], __hyp_text_end[];
>> >> extern char __idmap_text_start[], __idmap_text_end[];
>> >> extern char __irqentry_text_start[], __irqentry_text_end[];
>> >> extern char __mmuoff_data_start[], __mmuoff_data_end[];
>> >> +extern char __robss_start[], __robss_end[];
>> >>
>> >> #endif /* __ASM_SECTIONS_H */
>> >> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
>> >> index 5ce9b2929e0d..eae5036dc725 100644
>> >> --- a/arch/arm64/kernel/vmlinux.lds.S
>> >> +++ b/arch/arm64/kernel/vmlinux.lds.S
>> >> @@ -209,9 +209,19 @@ SECTIONS
>> >>
>> >> BSS_SECTION(0, 0, 0)
>> >>
>> >> - . = ALIGN(PAGE_SIZE);
>> >> + . = ALIGN(SEGMENT_ALIGN);
>> >> + __robss_start = .;
>> >> idmap_pg_dir = .;
>> >> - . += IDMAP_DIR_SIZE;
>> >> + . = ALIGN(. + IDMAP_DIR_SIZE + PAGE_SIZE, SEGMENT_ALIGN);
>> >> + __robss_end = .;
>> >
>> > Is it really worth aligning this beyond PAGE_SIZE?
>> >
>> > We shouldn't be poking these very often, the padding is always larger
>> > than the number of used pages, and the swapper dir is relegated to page
>> > mappings regardless.
>>
>> The segment alignment is intended to take advantage of PTE_CONT
>> mappings (support for which still hasn't landed, afaict). I don't care
>> deeply either way ...
>
> I understood that; my concern was that there was little gain relative to
> the cost of the padding:
>
> * With the above .robss will contain 5 pages that we care about, but
> could be padded to 16 or 512 pages (assuming 4K pages with or without
> DEBUG_RODATA_ALIGN). I think we can put those pages to better use.
>
Yes, I realised that. DEBUG_RODATA_ALIGN generally wastes a lot of
memory on padding, and this case is no different.
> * We don't frequently need to poke the idmap, so in practice I suspect
> TLB pressure for it doesn't matter too much.
>
Does that apply to empty_zero_page as well?
> * As we don't align _end, swapper (which we're more likely to access
> frequently) is mapped with a non-contiguous mapping regardless.
>
Indeed. However, we could defer the r/o mapping of this segment to
mark_rodata_ro(), which allows us to move other stuff in there as
well, such as bm_pmd/bm_pud (from fixmap), and actually, anything that
would qualify for __ro_after_init but is not statically initialized to
non-zero value.
> [...]
>
>> >> /*
>> >> - * Map the linear alias of the [_text, __init_begin) interval as
>> >> - * read-only/non-executable. This makes the contents of the
>> >> - * region accessible to subsystems such as hibernate, but
>> >> - * protects it from inadvertent modification or execution.
>> >> + * Map the linear alias of the intervals [_text, __init_begin) and
>> >> + * [robss_start, robss_end) as read-only/non-executable. This makes
>> >> + * the contents of these regions accessible to subsystems such
>> >> + * as hibernate, but protects them from inadvertent modification or
>> >> + * execution.
>> >
>> > For completeness, it may also be worth stating that we're mapping the
>> > gap between those as usual, since this will be freed.
>> >
>> > Then again, maybe not. ;)
>>
>> Well, there is a tacit assumption here that a memblock that covers any
>> part of the kernel covers all of it, but I think this is reasonable,
>> given that the memblock layer merges adjacent entries, and we could
>> not have holes.
>
> By "the gap between those", I meant the linear alias of the init memory
> that we explicitly mapped with a call to __create_pgd_mapping after the
> comment. As taht falls between the start of text and end of robss it
> would not have been mapped prior to this.
>
I don't think the code maps any more or less that it did before. The
only difference is that anything after __init_begin is now no longer
mapped by the conditional 'if (kernel_end < end)' call to
__create_pgd_mapping() above but by the second to last one below.
> Trivially, the comment above mentioned two mappings we create, when
> there are three calls to __create_pgd_mapping.
>
> Not a big deal, either way.
>
>> Re freeing, I don't get your point: all of these mappings are permanent.
>
> Please ignore this, it was irrelevant. ;)
>
OK.
^ permalink raw reply
* [GIT PULL] ARM: mediatek: soc updates for v4.9
From: Matthias Brugger @ 2016-09-12 15:52 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
Please pull the following change.
Thanks,
Matthias
----
The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:
Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)
are available in the git repository at:
https://github.com/mbgg/linux-mediatek.git tags/v4.8-next-soc
for you to fetch changes up to e180f887ba40a916153e29e6ad48c34d28966740:
soc: mediatek: PMIC wrap: Extend the waiting time to 10ms.
(2016-08-22 19:31:36 +0200)
----------------------------------------------------------------
- extent the waiting time of the pmic wrapper to 10 ms which
reduces the failure rate on the data transfer between pmic and
pmic wrapper.
----------------------------------------------------------------
Henry Chen (1):
soc: mediatek: PMIC wrap: Extend the waiting time to 10ms.
drivers/soc/mediatek/mtk-pmic-wrap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
^ permalink raw reply
* [GIT PULL] ARM: mediatek: dts64 updates for v4.9
From: Matthias Brugger @ 2016-09-12 15:51 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
Please pull the following changes.
Thanks,
Matthias
----
The following changes since commit 29b4817d4018df78086157ea3a55c1d9424a7cfc:
Linux 4.8-rc1 (2016-08-07 18:18:00 -0700)
are available in the git repository at:
https://github.com/mbgg/linux-mediatek.git tags/v4.8-next-dts64
for you to fetch changes up to 7475e27b45554d350f6a28edc8d0bfcf13f801c4:
arm64: dts: mt8173-evb: enable HDMI output (2016-08-22 19:12:08 +0200)
----------------------------------------------------------------
- add HDMI related nodes to mt8173
- enable the HDMI output on mt8173-evb
----------------------------------------------------------------
CK Hu (1):
arm64: dts: mt8173: Add HDMI related nodes
Philipp Zabel (1):
arm64: dts: mt8173-evb: enable HDMI output
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 38 ++++++++++++++
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 77
+++++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
^ permalink raw reply
* [PATCH 1/3] ARM64: dts: amlogic: Add Meson GX dtsi from GXBB
From: Andreas Färber @ 2016-09-12 15:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160903082227.30559-2-narmstrong@baylibre.com>
Am 03.09.2016 um 10:22 schrieb Neil Armstrong:
> Move all non-gxbb specific nodes to a common GX dtsi.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 181 ++++++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 320 +++++++++-------------------
> 2 files changed, 280 insertions(+), 221 deletions(-)
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gx.dtsi
>
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> new file mode 100644
> index 0000000..fb393e9
> --- /dev/null
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> @@ -0,0 +1,181 @@
> +/*
> + * Copyright (c) 2016 BayLibre, SAS.
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + *
> + * Copyright (c) 2016 Endless Computers, Inc.
> + * Author: Carlo Caione <carlo@endlessm.com>
This seems to be lacking my copyright as initial contributor of gxbb.
Regards,
Andreas
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + * a) This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + * b) Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or
> + * sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
[...]
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> index 2ea7bbd..ff20932 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
/*
* Copyright (c) 2016 Andreas F?rber
*
* This file is dual-licensed: you can use it either under the terms
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)
^ permalink raw reply
* [PATCH 3/3] ARM64: dts: amlogic: Add basic support for Amlogic S905D
From: Rob Herring @ 2016-09-12 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160903082227.30559-4-narmstrong@baylibre.com>
On Sat, Sep 03, 2016 at 10:22:26AM +0200, Neil Armstrong wrote:
> This patch introduces the basic support for the Amlogic S905D (MesonGXL)
> and for the Amlogic evaluation boards P230 and P231.
> No documentation has been released yet for this SoC, so for now only the
> bare minimum has been added in the DT.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> Documentation/devicetree/bindings/arm/amlogic.txt | 3 +
> arch/arm64/boot/dts/amlogic/Makefile | 2 +
> .../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 51 +++++++++++++++++
> .../boot/dts/amlogic/meson-gxl-s905d-p231.dts | 51 +++++++++++++++++
> .../boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi | 64 ++++++++++++++++++++++
> arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi | 48 ++++++++++++++++
> 6 files changed, 219 insertions(+)
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p231.dts
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p23x.dtsi
> create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d.dtsi
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH] arm64: mm: move zero page from .bss to right before swapper_pg_dir
From: Mark Rutland @ 2016-09-12 15:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKv+Gu9pfBt5n58vUy7P-VytJ1xRiETO8vqxkPqQ3tF6WtXJaQ@mail.gmail.com>
On Mon, Sep 12, 2016 at 04:12:19PM +0100, Ard Biesheuvel wrote:
> On 12 September 2016 at 15:59, Mark Rutland <mark.rutland@arm.com> wrote:
> > On Mon, Sep 12, 2016 at 03:16:24PM +0100, Ard Biesheuvel wrote:
> >> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
> >> index 4e7e7067afdb..44e94e234ba0 100644
> >> --- a/arch/arm64/include/asm/sections.h
> >> +++ b/arch/arm64/include/asm/sections.h
> >> @@ -26,5 +26,6 @@ extern char __hyp_text_start[], __hyp_text_end[];
> >> extern char __idmap_text_start[], __idmap_text_end[];
> >> extern char __irqentry_text_start[], __irqentry_text_end[];
> >> extern char __mmuoff_data_start[], __mmuoff_data_end[];
> >> +extern char __robss_start[], __robss_end[];
> >>
> >> #endif /* __ASM_SECTIONS_H */
> >> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> >> index 5ce9b2929e0d..eae5036dc725 100644
> >> --- a/arch/arm64/kernel/vmlinux.lds.S
> >> +++ b/arch/arm64/kernel/vmlinux.lds.S
> >> @@ -209,9 +209,19 @@ SECTIONS
> >>
> >> BSS_SECTION(0, 0, 0)
> >>
> >> - . = ALIGN(PAGE_SIZE);
> >> + . = ALIGN(SEGMENT_ALIGN);
> >> + __robss_start = .;
> >> idmap_pg_dir = .;
> >> - . += IDMAP_DIR_SIZE;
> >> + . = ALIGN(. + IDMAP_DIR_SIZE + PAGE_SIZE, SEGMENT_ALIGN);
> >> + __robss_end = .;
> >
> > Is it really worth aligning this beyond PAGE_SIZE?
> >
> > We shouldn't be poking these very often, the padding is always larger
> > than the number of used pages, and the swapper dir is relegated to page
> > mappings regardless.
>
> The segment alignment is intended to take advantage of PTE_CONT
> mappings (support for which still hasn't landed, afaict). I don't care
> deeply either way ...
I understood that; my concern was that there was little gain relative to
the cost of the padding:
* With the above .robss will contain 5 pages that we care about, but
could be padded to 16 or 512 pages (assuming 4K pages with or without
DEBUG_RODATA_ALIGN). I think we can put those pages to better use.
* We don't frequently need to poke the idmap, so in practice I suspect
TLB pressure for it doesn't matter too much.
* As we don't align _end, swapper (which we're more likely to access
frequently) is mapped with a non-contiguous mapping regardless.
[...]
> >> /*
> >> - * Map the linear alias of the [_text, __init_begin) interval as
> >> - * read-only/non-executable. This makes the contents of the
> >> - * region accessible to subsystems such as hibernate, but
> >> - * protects it from inadvertent modification or execution.
> >> + * Map the linear alias of the intervals [_text, __init_begin) and
> >> + * [robss_start, robss_end) as read-only/non-executable. This makes
> >> + * the contents of these regions accessible to subsystems such
> >> + * as hibernate, but protects them from inadvertent modification or
> >> + * execution.
> >
> > For completeness, it may also be worth stating that we're mapping the
> > gap between those as usual, since this will be freed.
> >
> > Then again, maybe not. ;)
>
> Well, there is a tacit assumption here that a memblock that covers any
> part of the kernel covers all of it, but I think this is reasonable,
> given that the memblock layer merges adjacent entries, and we could
> not have holes.
By "the gap between those", I meant the linear alias of the init memory
that we explicitly mapped with a call to __create_pgd_mapping after the
comment. As taht falls between the start of text and end of robss it
would not have been mapped prior to this.
Trivially, the comment above mentioned two mappings we create, when
there are three calls to __create_pgd_mapping.
Not a big deal, either way.
> Re freeing, I don't get your point: all of these mappings are permanent.
Please ignore this, it was irrelevant. ;)
Thanks,
Mark.
^ permalink raw reply
* [PATCH v2 1/3] Documentation: dtb: xgene: Add PMD clock binding
From: Rob Herring @ 2016-09-12 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472863255-32337-2-git-send-email-hotran@apm.com>
On Fri, Sep 02, 2016 at 05:40:53PM -0700, Hoan Tran wrote:
> Add APM X-Gene clock binding documentation for PMD clock.
>
> Signed-off-by: Hoan Tran <hotran@apm.com>
> ---
> Documentation/devicetree/bindings/clock/xgene.txt | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/xgene.txt b/Documentation/devicetree/bindings/clock/xgene.txt
> index 82f9638..e6e12ae 100644
> --- a/Documentation/devicetree/bindings/clock/xgene.txt
> +++ b/Documentation/devicetree/bindings/clock/xgene.txt
> @@ -8,6 +8,7 @@ Required properties:
> - compatible : shall be one of the following:
> "apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock
> "apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock
> + "apm,xgene-pmd-clock" - for a X-Gene PMD clock
> "apm,xgene-device-clock" - for a X-Gene device clock
> "apm,xgene-socpll-v2-clock" - for a X-Gene SoC PLL v2 clock
> "apm,xgene-pcppll-v2-clock" - for a X-Gene PCP PLL v2 clock
> @@ -22,6 +23,15 @@ Required properties for SoC or PCP PLL clocks:
> Optional properties for PLL clocks:
> - clock-names : shall be the name of the PLL. If missing, use the device name.
>
> +Required properties for PMD clocks:
> +- reg : shall be the physical register address for the pmd clock.
> +- clocks : shall be the input parent clock phandle for the clock.
> +- #clock-cells : shall be set to 1.
> +- clock-output-names : shall be the name of the clock referenced by derive
> + clock.
> +Optional properties for PLL clocks:
> +- clock-names : shall be the name of the clock. If missing, use the device name.
> +
> Required properties for device clocks:
> - reg : shall be a list of address and length pairs describing the CSR
> reset and/or the divider. Either may be omitted, but at least
> @@ -59,6 +69,14 @@ For example:
> type = <0>;
> };
>
> + pmd0clk: pmd0clk {
Needs a unit address.
> + compatible = "apm,xgene-pmd-clock";
> + #clock-cells = <1>;
> + clocks = <&pmdpll 0>;
> + reg = <0x0 0x7E200200 0x0 0x10>;
Lowercase hex please.
With those,
Acked-by: Rob Herring <robh@kernel.org>
> + clock-output-names = "pmd0clk";
> + };
> +
> socpll: socpll at 17000120 {
> compatible = "apm,xgene-socpll-clock";
> #clock-cells = <1>;
> --
> 1.9.1
>
^ permalink raw reply
* About enet_out clk on i.MX28, i.MX6 and i.MX7
From: Uwe Kleine-König @ 2016-09-12 15:36 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
to operate the MDIO bus a clk is required. On some i.MX SoCs it can be
configured if that clk is provided by the CPU or not (i.e. something
else provides it).
The devicetree abstraction for that is (e.g. on i.MX28):
mac0: ethernet at 800f0000 {
compatible = "fsl,imx28-fec";
...
clocks = <&clks 57>, <&clks 57>, <&clks 64>;
clock-names = "ipg", "ahb", "enet_out";
...
};
and the driver does:
/* enet_out is optional, depends on board */
fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
if (IS_ERR(fep->clk_enet_out))
fep->clk_enet_out = NULL;
. IMHO this is clumsy and wrong. See for example
arch/arm/boot/dts/imx28-m28evk.dts which has:
ethernet at 800f0000 {
...
clocks = <&clks 57>, <&clks 57>;
clock-names = "ipg", "ahb";
}
to get rid of this entry. Moreover enet_out isn't a clock for the fec
instance but for the mdio bus, so the better binding would be:
mac0: ethernet at 800f0000 {
compatible = "fsl,imx28-fec";
clocks = <&clks 57>, <&clks 57>;
clock-names = "ipg", "ahb";
mdio {
clocks = <&clks 64>;
...
};
};
This better matches reality and is easier to overwrite per board without
repeating stuff from imx28.dtsi as it is now.
What do you think? Compatibility isn't a big concern, the fec driver
could just keep handling "enet_out" as is and learn about the optional
mdio/clocks.
This would handle old dtbs just fine.
Slightly related: Some machines (bluegiga,apx4devkit, karo,tx28) still
enable enet_out clk in arch/arm/mach-mxs/mach-mxs.c. I think this can be
dropped, right? (Unless recent kernels should still handle dtbs that
don't have enet_out in the fec node. That affects dtbs built between
v3.6-rc1~144^2~7^2~11 = 3143bbb42b3d ("ARM: mxs: convert apx4devkit board to device tree")
and
v3.10-rc1~63^2~10^2~20 = f231a9fe7f80 ("ARM: dts: mxs: add enet_out clock to devicetree")
.)
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH v5 1/4] nvmem: rockchip-efuse: update compatible strings for Rockchip efuse
From: Rob Herring @ 2016-09-12 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472786217-52214-2-git-send-email-finley.xiao@rock-chips.com>
On Thu, Sep 01, 2016 at 08:16:54PM -0700, Finley Xiao wrote:
> Rk3399-efuse is organized as 32bits by 32 one-time programmable electrical
> fuses. The efuse of earlier SoCs are organized as 32bits by 8 one-time
> programmable electrical fuses with random access interface.
>
> Add different device tree compatible string for different SoCs to be able
> to differentiate between the two. The old binding is of course preserved,
> though deprecated.
>
> Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>
> ---
> Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt | 13 +++++++++++--
> 1 file changed, 11 insertions(+), 2 deletions(-)
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [RFC PATCH 0/5] arm64: Signal context expansion
From: Dave Martin @ 2016-09-12 15:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57D6C33D.9020003@arm.com>
On Mon, Sep 12, 2016 at 04:01:17PM +0100, Szabolcs Nagy wrote:
> On 12/09/16 12:17, Dave Martin wrote:
[...]
> >> On 09/09/2016 05:21 PM, Dave Martin wrote:
[...]
> >>> I wonder whether we should make the signal stack size runtime
> >>> discoverable through sysconf() instead...
> >
> > I will likely suggest this for the future, but of course it doesn't help
> > for current binaries.
> >
> >
> > Note that MINSIGSTKSZ stared life wrong for arm64, and has since gone
> > through a few ABI breaking changes. I don't condone this, but we have
> > form in this area :/
> >
> > sigaltstack() already fails with ENOMEM for software that passes
> > ss_size = MINSIGSTKSZ, and is built against glibc<2.22 [1], [2], running
> > on linux>=4.3 [3], which is an ABI break in case where sigaltstack() is
> > otherwise guaranteed to succeed.
> >
>
> yes, this was abi breaking change.
>
> if glibc does not care about existing binaries
> that use sigaltstack with MINSIGSTKSZ then it can
> increase the size, but i think the kernel should
> not change the abi (there are other libcs and libc
> independent runtime systems on linux for aarch64
> with their own sigaltstack setup, not all of them
> may care about SVE).
>
> i assume the kernel can avoid saving SVE regs when
> they are not used by the process.
I can (and do), in my patches (not posted yet).
The real issue here is that a recently updated shared library might be
optimised to use SVE, where the program using it is an older, SVE-
unaware binary.
(think of an optimised math library using some new fancy SVE-based
number crunching internally).
>
> >
> > The bottom line here is that the sigaltstack() API is broken with regard
> > to extensibility, so we cannot extend the amount of signal state without
> > breaking something.
> >
>
> extending signal state can break things independently
> of sigaltstack.
>
> binaries with strict guarantees about worst case stack
> usage can change behaviour.
Indeed, but this is not a new issue. Software must run with enough
stack in order to be portable, but there is no portable way to determine
how much stack is needed.
> fortunately glibc PTHREAD_STACK_MIN is huge on aarch64
> so applications using it are unlikely to break because
> of the increased signal state.
> (this also means it's impossible to have threads with
> tiny stacks on glibc, so large amount of threads means
> large amount of commit charge.)
Again, not a new problem.
[...]
Cheers
---Dave
^ permalink raw reply
* [PATCH] BUG: atmel_serial: Interrupts not disabled on close
From: Nicolas Ferre @ 2016-09-12 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160912133441.14597-1-richard.genoud@gmail.com>
Le 12/09/2016 ? 15:34, Richard Genoud a ?crit :
> Since commit 18dfef9c7f87 ("serial: atmel: convert to irq handling
> provided mctrl-gpio"), interrupts from GPIOs are not disabled any more
> when the serial port is closed, leading to an oops when the one of the
> input pin is toggled (CTS/DSR/DCD/RNG).
>
> This is only the case if those pins are used as GPIOs, i.e. declared
> like that:
> usart1: serial at f8020000 {
> /* CTS and DTS will be handled by GPIO */
> status = "okay";
> rts-gpios = <&pioB 17 GPIO_ACTIVE_LOW>;
> cts-gpios = <&pioB 16 GPIO_ACTIVE_LOW>;
> dtr-gpios = <&pioB 14 GPIO_ACTIVE_LOW>;
> dsr-gpios = <&pioC 31 GPIO_ACTIVE_LOW>;
> rng-gpios = <&pioB 12 GPIO_ACTIVE_LOW>;
> dcd-gpios = <&pioB 15 GPIO_ACTIVE_LOW>;
> };
>
> That's because modem interrupts used to be freed in atmel_shutdown().
> After commit 18dfef9c7f87 ("serial: atmel: convert to irq handling
> provided mctrl-gpio"), this code was just removed.
> Calling atmel_disable_ms() disables the interrupts and everything works
> fine again.
>
> Tested on at91sam9g35-cm
>
> (This patch doesn't apply on -stable kernels, fixes for 4.4 and 4.7 will
> be sent after this one is applied.)
>
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> Fixes: 18dfef9c7f87 ("serial: atmel: convert to irq handling provided mctrl-gpio")
I thinks it's a bit late for "4.8-fixes".
Greg, tell me if you want that I add the Cc: stable tag to this patch
(as advised by Uwe) and re-send?
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Thanks Richard!
Best regards,
> ---
> drivers/tty/serial/atmel_serial.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 2eaa18ddef61..8bbde52db376 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -1929,6 +1929,9 @@ static void atmel_shutdown(struct uart_port *port)
> {
> struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>
> + /* Disable modem control lines interrupts */
> + atmel_disable_ms(port);
> +
> /* Disable interrupts at device level */
> atmel_uart_writel(port, ATMEL_US_IDR, -1);
>
> @@ -1979,8 +1982,6 @@ static void atmel_shutdown(struct uart_port *port)
> */
> free_irq(port->irq, port);
>
> - atmel_port->ms_irq_enabled = false;
> -
> atmel_flush_buffer(port);
> }
>
>
--
Nicolas Ferre
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox