* [PATCH v5 01/14] drivers: iommu: add FWNODE_IOMMU fwnode type
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
[not found] ` <20160909142343.13314-2-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
2016-09-09 14:23 ` [PATCH v5 02/14] drivers: iommu: implement arch_{set/get}_iommu_fwspec API Lorenzo Pieralisi
` (11 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
On systems booting with a device tree, every struct device is
associated with a struct device_node, that represents its DT
representation. The device node can be used in generic kernel
contexts (eg IRQ translation, IOMMU streamid mapping), to
retrieve the properties associated with the device and carry
out kernel operation accordingly. Owing to the 1:1 relationship
between the device and its device_node, the device_node can also
be used as a look-up token for the device (eg looking up a device
through its device_node), to retrieve the device in kernel paths
where the device_node is available.
On systems booting with ACPI, the same abstraction provided by
the device_node is required to provide look-up functionality.
Therefore, mirroring the approach implemented in the IRQ domain
kernel layer, this patch adds an additional fwnode type FWNODE_IOMMU.
This patch also implements a glue kernel layer that allows to
allocate/free FWNODE_IOMMU fwnode_handle structures and associate
them with IOMMU devices.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Reviewed-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
include/linux/fwnode.h | 1 +
include/linux/iommu.h | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 8516717..6e10050 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -19,6 +19,7 @@ enum fwnode_type {
FWNODE_ACPI_DATA,
FWNODE_PDATA,
FWNODE_IRQCHIP,
+ FWNODE_IOMMU,
};
struct fwnode_handle {
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a35fb8b..6456528 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -38,6 +38,7 @@ struct bus_type;
struct device;
struct iommu_domain;
struct notifier_block;
+struct fwnode_handle;
/* iommu fault flags */
#define IOMMU_FAULT_READ 0x0
@@ -543,4 +544,28 @@ static inline void iommu_device_unlink(struct device *dev, struct device *link)
#endif /* CONFIG_IOMMU_API */
+/* IOMMU fwnode handling */
+static inline bool is_fwnode_iommu(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_IOMMU;
+}
+
+static inline struct fwnode_handle *iommu_alloc_fwnode(void)
+{
+ struct fwnode_handle *fwnode;
+
+ fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
+ fwnode->type = FWNODE_IOMMU;
+
+ return fwnode;
+}
+
+static inline void iommu_free_fwnode(struct fwnode_handle *fwnode)
+{
+ if (WARN_ON(!is_fwnode_iommu(fwnode)))
+ return;
+
+ kfree(fwnode);
+}
+
#endif /* __LINUX_IOMMU_H */
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 02/14] drivers: iommu: implement arch_{set/get}_iommu_fwspec API
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
2016-09-09 14:23 ` [PATCH v5 01/14] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 03/14] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
` (10 subsequent siblings)
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Dennis Chen,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Rob Herring,
Tomasz Nowicki, Prem Mallappa, Jon Masters
The iommu fwspec configuration mechanism currently relies on
the arch specific struct dev_archdata.iommu member to stash
the struct iommu_fwspec pointer set-up for streamid translation.
The struct dev_archdata.iommu member is arch specific and is not present
on all arches that make use of the struct iommu_fwspec infrastructure,
hence an arch specific kernel API is required to set-up and retrieve
struct iommu_fwspec pointers safely from generic iommu code, hiding
the arch specific details.
Implement the arch_{set/get}_iommu_fwspec() generic kernel infrastructure
and add the ARM/ARM64 back-end implementations.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/iommu-fwspec.h | 30 ++++++++++++++++++++++++++++++
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/iommu-fwspec.h | 30 ++++++++++++++++++++++++++++++
drivers/iommu/Kconfig | 3 +++
drivers/iommu/of_iommu.c | 14 +++++++-------
include/linux/of_iommu.h | 10 ++++++++++
7 files changed, 82 insertions(+), 7 deletions(-)
create mode 100644 arch/arm/include/asm/iommu-fwspec.h
create mode 100644 arch/arm64/include/asm/iommu-fwspec.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a9c4e48..e84f62e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -59,6 +59,7 @@ config ARM
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_IDE if PCI || ISA || PCMCIA
+ select HAVE_IOMMU_FWSPEC if IOMMU_API
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
diff --git a/arch/arm/include/asm/iommu-fwspec.h b/arch/arm/include/asm/iommu-fwspec.h
new file mode 100644
index 0000000..2e87d8b
--- /dev/null
+++ b/arch/arm/include/asm/iommu-fwspec.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_IOMMU_FWSPEC_H
+#define __ASM_IOMMU_FWSPEC_H
+
+static inline void arch_set_iommu_fwspec(struct device *dev,
+ struct iommu_fwspec *fwspec)
+{
+ dev->archdata.iommu = fwspec;
+}
+
+static inline struct iommu_fwspec *arch_get_iommu_fwspec(struct device *dev)
+{
+ return dev->archdata.iommu;
+}
+#endif
+
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index bc3f00f..10c9b3d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -83,6 +83,7 @@ config ARM64
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if PERF_EVENTS
+ select HAVE_IOMMU_FWSPEC if IOMMU_API
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP if NUMA
diff --git a/arch/arm64/include/asm/iommu-fwspec.h b/arch/arm64/include/asm/iommu-fwspec.h
new file mode 100644
index 0000000..2e87d8b
--- /dev/null
+++ b/arch/arm64/include/asm/iommu-fwspec.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_IOMMU_FWSPEC_H
+#define __ASM_IOMMU_FWSPEC_H
+
+static inline void arch_set_iommu_fwspec(struct device *dev,
+ struct iommu_fwspec *fwspec)
+{
+ dev->archdata.iommu = fwspec;
+}
+
+static inline struct iommu_fwspec *arch_get_iommu_fwspec(struct device *dev)
+{
+ return dev->archdata.iommu;
+}
+#endif
+
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 8ee54d7..101cb17 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -67,6 +67,9 @@ config OF_IOMMU
def_bool y
depends on OF && IOMMU_API
+config HAVE_IOMMU_FWSPEC
+ bool
+
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
bool
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 04d616d..38669b8 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -229,7 +229,7 @@ postcore_initcall_sync(of_iommu_init);
int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np)
{
- struct iommu_fwspec *fwspec = dev->archdata.iommu;
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
if (fwspec)
return 0;
@@ -240,13 +240,13 @@ int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np)
fwspec->iommu_np = of_node_get(iommu_np);
fwspec->iommu_ops = of_iommu_get_ops(iommu_np);
- dev->archdata.iommu = fwspec;
+ arch_set_iommu_fwspec(dev, fwspec);
return 0;
}
void iommu_fwspec_free(struct device *dev)
{
- struct iommu_fwspec *fwspec = dev->archdata.iommu;
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
if (fwspec) {
of_node_put(fwspec->iommu_np);
@@ -256,7 +256,7 @@ void iommu_fwspec_free(struct device *dev)
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
{
- struct iommu_fwspec *fwspec = dev->archdata.iommu;
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
size_t size;
int i;
@@ -264,7 +264,7 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
return -EINVAL;
size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
- fwspec = krealloc(dev->archdata.iommu, size, GFP_KERNEL);
+ fwspec = krealloc(fwspec, size, GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
@@ -272,11 +272,11 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
fwspec->ids[fwspec->num_ids + i] = ids[i];
fwspec->num_ids += num_ids;
- dev->archdata.iommu = fwspec;
+ arch_set_iommu_fwspec(dev, fwspec);
return 0;
}
inline struct iommu_fwspec *dev_iommu_fwspec(struct device *dev)
{
- return dev->archdata.iommu;
+ return arch_get_iommu_fwspec(dev);
}
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index accdc05..358db49 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -46,6 +46,16 @@ void iommu_fwspec_free(struct device *dev);
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
struct iommu_fwspec *dev_iommu_fwspec(struct device *dev);
+#ifdef CONFIG_HAVE_IOMMU_FWSPEC
+#include <asm/iommu-fwspec.h>
+#else /* !CONFIG_HAVE_IOMMU_FWSPEC */
+static inline void arch_set_iommu_fwspec(struct device *dev,
+ struct iommu_fwspec *fwspec) {}
+
+static inline struct iommu_fwspec *
+arch_get_iommu_fwspec(struct device *dev) { return NULL; }
+#endif
+
void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops);
const struct iommu_ops *of_iommu_get_ops(struct device_node *np);
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 03/14] drivers: acpi: iort: introduce linker section for IORT entries probing
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
2016-09-09 14:23 ` [PATCH v5 01/14] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 02/14] drivers: iommu: implement arch_{set/get}_iommu_fwspec API Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 04/14] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
` (9 subsequent siblings)
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
Since commit e647b532275b ("ACPI: Add early device probing
infrastructure") the kernel has gained the infrastructure that allows
adding linker script section entries to execute ACPI driver callbacks
(ie probe routines) for all subsystems that register a table entry
in the respective kernel section (eg clocksource, irqchip).
Since ARM IOMMU devices data is described through IORT tables when
booting with ACPI, the ARM IOMMU drivers must be made able to hook ACPI
callback routines that are called to probe IORT entries and initialize
the respective IOMMU devices.
To avoid adding driver specific hooks into IORT table initialization
code (breaking therefore code modularity - ie ACPI IORT code must be made
aware of ARM SMMU drivers ACPI init callbacks), this patch adds code
that allows ARM SMMU drivers to take advantage of the ACPI early probing
infrastructure, so that they can add linker script section entries
containing drivers callback to be executed on IORT tables detection.
Since IORT nodes are differentiated by a type, the callback routines
can easily parse the IORT table entries, check the IORT nodes and
carry out some actions whenever the IORT node type associated with
the driver specific callback is matched.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Reviewed-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
Cc: Marc Zyngier <marc.zyngier-5wv7dgnIgG8@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 3 +++
include/asm-generic/vmlinux.lds.h | 1 +
include/linux/acpi_iort.h | 3 +++
3 files changed, 7 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a6fba4d..4cbeb707 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -367,5 +367,8 @@ void __init acpi_iort_init(void)
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
const char *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
+ return;
}
+
+ acpi_probe_device_table(iort);
}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 2456397..7ee4e0c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -546,6 +546,7 @@
IRQCHIP_OF_MATCH_TABLE() \
ACPI_PROBE_TABLE(irqchip) \
ACPI_PROBE_TABLE(clksrc) \
+ ACPI_PROBE_TABLE(iort) \
EARLYCON_TABLE()
#define INIT_TEXT \
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 0e32dac..d16fdda 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -39,4 +39,7 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
{ return NULL; }
#endif
+#define IORT_ACPI_DECLARE(name, table_id, fn) \
+ ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
+
#endif /* __ACPI_IORT_H__ */
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 04/14] drivers: acpi: iort: add support for IOMMU fwnode registration
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (2 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 03/14] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 05/14] drivers: iommu: make iommu_fwspec OF agnostic Lorenzo Pieralisi
` (8 subsequent siblings)
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
The ACPI IORT table provide entries for IOMMU (aka SMMU in ARM world)
components that allow creating the kernel data structures required to
probe and initialize the IOMMU devices.
This patch provides support in the IORT kernel code to register IOMMU
components and their respective fwnode.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Reviewed-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi_iort.h | 9 +++++++
2 files changed, 74 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4cbeb707..b89b3d3 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -20,7 +20,9 @@
#include <linux/acpi_iort.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/slab.h>
struct iort_its_msi_chip {
struct list_head list;
@@ -28,6 +30,69 @@ struct iort_its_msi_chip {
u32 translation_id;
};
+struct iort_fwnode {
+ struct list_head list;
+ struct acpi_iort_node *iort_node;
+ struct fwnode_handle *fwnode;
+};
+static LIST_HEAD(iort_fwnode_list);
+static DEFINE_SPINLOCK(iort_fwnode_lock);
+
+/**
+ * iort_set_fwnode() - Create iort_fwnode and use it to register
+ * iommu data in the iort_fwnode_list
+ *
+ * @node: IORT table node associated with the IOMMU
+ * @fwnode: fwnode associated with the IORT node
+ *
+ * Returns: 0 on success
+ * <0 on failure
+ */
+int iort_set_fwnode(struct acpi_iort_node *iort_node,
+ struct fwnode_handle *fwnode)
+{
+ struct iort_fwnode *np;
+
+ np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
+
+ if (WARN_ON(!np))
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&np->list);
+ np->iort_node = iort_node;
+ np->fwnode = fwnode;
+
+ spin_lock(&iort_fwnode_lock);
+ list_add_tail(&np->list, &iort_fwnode_list);
+ spin_unlock(&iort_fwnode_lock);
+
+ return 0;
+}
+
+/**
+ * iort_get_fwnode() - Retrieve fwnode associated with an IORT node
+ *
+ * @node: IORT table node to be looked-up
+ *
+ * Returns: fwnode_handle pointer on success, NULL on failure
+*/
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
+{
+ struct iort_fwnode *curr;
+ struct fwnode_handle *fwnode = NULL;
+
+ spin_lock(&iort_fwnode_lock);
+ list_for_each_entry(curr, &iort_fwnode_list, list) {
+ if (curr->iort_node == node) {
+ fwnode = curr->fwnode;
+ break;
+ }
+ }
+ spin_unlock(&iort_fwnode_lock);
+
+ return fwnode;
+}
+
typedef acpi_status (*iort_find_node_callback)
(struct acpi_iort_node *node, void *context);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index d16fdda..c851646 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -30,6 +30,9 @@ struct fwnode_handle *iort_find_domain_token(int trans_id);
void acpi_iort_init(void);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+int iort_set_fwnode(struct acpi_iort_node *iort_node,
+ struct fwnode_handle *fwnode);
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node);
#else
static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
@@ -37,6 +40,12 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
+ struct fwnode_handle *fwnode)
+{ return -ENODEV; }
+static inline
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
+{ return NULL; }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 05/14] drivers: iommu: make iommu_fwspec OF agnostic
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (3 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 04/14] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
[not found] ` <20160909142343.13314-6-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
2016-09-09 14:23 ` [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
` (7 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
The iommu_fwspec structure, used to hold per device iommu configuration
data is not OF specific and therefore can be moved to a generic
and OF independent compilation unit.
In particular, the iommu_fwspec handling hinges on the device_node
pointer to identify the IOMMU device associated with the iommu_fwspec
structure, that is easily converted to a more generic fwnode_handle
pointer that can cater for OF and non-OF (ie ACPI) systems.
Create the files and related Kconfig entry to decouple iommu_fwspec
structure from the OF iommu kernel layer.
Given that the current iommu_fwspec implementation relies on
the arch specific struct device.archdata.iommu field in its
implementation, by making the code standalone and independent
of the OF layer this patch makes sure that the iommu_fwspec
kernel code can be selected only on arches implementing the
struct device.archdata.iommu field by adding an explicit
arch dependency in its config entry.
Current drivers using the iommu_fwspec for streamid translation
are converted to the new iommu_fwspec API by simply converting
the device_node to its fwnode_handle pointer.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
drivers/iommu/Kconfig | 4 ++
drivers/iommu/Makefile | 1 +
drivers/iommu/arm-smmu-v3.c | 16 ++++--
drivers/iommu/arm-smmu.c | 17 +++---
drivers/iommu/iommu-fwspec.c | 126 +++++++++++++++++++++++++++++++++++++++++++
drivers/iommu/of_iommu.c | 93 --------------------------------
include/linux/iommu-fwspec.h | 70 ++++++++++++++++++++++++
include/linux/of_iommu.h | 38 ++++---------
8 files changed, 234 insertions(+), 131 deletions(-)
create mode 100644 drivers/iommu/iommu-fwspec.c
create mode 100644 include/linux/iommu-fwspec.h
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 101cb17..873bd41 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -70,6 +70,10 @@ config OF_IOMMU
config HAVE_IOMMU_FWSPEC
bool
+config IOMMU_FWSPEC
+ def_bool y
+ depends on IOMMU_API
+
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
bool
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 195f7b9..bbbc6d6 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o
obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
obj-$(CONFIG_IOMMU_IOVA) += iova.o
+obj-$(CONFIG_IOMMU_FWSPEC) += iommu-fwspec.o
obj-$(CONFIG_OF_IOMMU) += of_iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index be293b5..a7e9de9 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
+#include <linux/iommu-fwspec.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/msi.h>
@@ -1720,13 +1721,18 @@ static struct platform_driver arm_smmu_driver;
static int arm_smmu_match_node(struct device *dev, void *data)
{
- return dev->of_node == data;
+ struct fwnode_handle *fwnode;
+
+ fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
+
+ return fwnode == data;
}
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static struct arm_smmu_device *
+arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
{
struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
- np, arm_smmu_match_node);
+ fwnode, arm_smmu_match_node);
put_device(dev);
return dev ? dev_get_drvdata(dev) : NULL;
}
@@ -1762,7 +1768,7 @@ static int arm_smmu_add_device(struct device *dev)
master = fwspec->iommu_priv;
smmu = master->smmu;
} else {
- smmu = arm_smmu_get_by_node(fwspec->iommu_np);
+ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
if (!smmu)
return -ENODEV;
master = kzalloc(sizeof(*master), GFP_KERNEL);
@@ -1874,7 +1880,7 @@ out_unlock:
static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
{
- int ret = iommu_fwspec_init(dev, args->np);
+ int ret = iommu_fwspec_init(dev, &args->np->fwnode);
if (!ret)
ret = iommu_fwspec_add_ids(dev, &args->args[0], 1);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 2e20cdc..d453c55 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -517,7 +517,7 @@ static int arm_smmu_register_legacy_master(struct device *dev,
it.cur_count = 1;
}
- err = iommu_fwspec_init(dev, smmu_dev->of_node);
+ err = iommu_fwspec_init(dev, &smmu_dev->of_node->fwnode);
if (err)
return err;
@@ -1368,13 +1368,18 @@ static bool arm_smmu_capable(enum iommu_cap cap)
static int arm_smmu_match_node(struct device *dev, void *data)
{
- return dev->of_node == data;
+ struct fwnode_handle *fwnode;
+
+ fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
+
+ return fwnode == data;
}
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static struct arm_smmu_device *
+arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
{
struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
- np, arm_smmu_match_node);
+ fwnode, arm_smmu_match_node);
put_device(dev);
return dev ? dev_get_drvdata(dev) : NULL;
}
@@ -1392,7 +1397,7 @@ static int arm_smmu_add_device(struct device *dev)
if (ret)
goto out_free;
} else if (fwspec) {
- smmu = arm_smmu_get_by_node(fwspec->iommu_np);
+ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
} else {
return -ENODEV;
}
@@ -1524,7 +1529,7 @@ out_unlock:
static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
{
u32 fwid = 0;
- int ret = iommu_fwspec_init(dev, args->np);
+ int ret = iommu_fwspec_init(dev, &args->np->fwnode);
if (ret)
return ret;
diff --git a/drivers/iommu/iommu-fwspec.c b/drivers/iommu/iommu-fwspec.c
new file mode 100644
index 0000000..be19102
--- /dev/null
+++ b/drivers/iommu/iommu-fwspec.c
@@ -0,0 +1,126 @@
+/*
+ * Firmware handling helpers for IOMMU
+ *
+ * Copyright (c) 2016 ARM Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#include <linux/iommu.h>
+#include <linux/iommu-fwspec.h>
+#include <linux/of_iommu.h>
+#include <linux/slab.h>
+
+struct fwspec_iommu_node {
+ struct list_head list;
+ struct fwnode_handle *fwnode;
+ const struct iommu_ops *ops;
+};
+static LIST_HEAD(fwnode_iommu_list);
+static DEFINE_SPINLOCK(fwspec_iommu_lock);
+
+void fwspec_iommu_set_ops(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ struct fwspec_iommu_node *iommu =
+ kzalloc(sizeof(*iommu), GFP_KERNEL);
+
+ if (WARN_ON(!iommu))
+ return;
+
+ if (is_of_node(fwnode))
+ of_node_get(to_of_node(fwnode));
+
+ INIT_LIST_HEAD(&iommu->list);
+ iommu->fwnode = fwnode;
+ iommu->ops = ops;
+ spin_lock(&fwspec_iommu_lock);
+ list_add_tail(&iommu->list, &fwnode_iommu_list);
+ spin_unlock(&fwspec_iommu_lock);
+}
+
+const struct iommu_ops *fwspec_iommu_get_ops(struct fwnode_handle *fwnode)
+{
+ struct fwspec_iommu_node *node;
+ const struct iommu_ops *ops = NULL;
+
+ spin_lock(&fwspec_iommu_lock);
+ list_for_each_entry(node, &fwnode_iommu_list, list)
+ if (node->fwnode == fwnode) {
+ ops = node->ops;
+ break;
+ }
+ spin_unlock(&fwspec_iommu_lock);
+ return ops;
+}
+
+int iommu_fwspec_init(struct device *dev,
+ struct fwnode_handle *iommu_fwnode)
+{
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
+ const struct iommu_ops *ops;
+
+ if (fwspec)
+ return 0;
+
+ fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
+ if (!fwspec)
+ return -ENOMEM;
+
+ if (is_of_node(iommu_fwnode)) {
+ ops = of_iommu_get_ops(to_of_node(iommu_fwnode));
+ of_node_get(to_of_node(iommu_fwnode));
+ } else {
+ ops = fwspec_iommu_get_ops(iommu_fwnode);
+ }
+
+ fwspec->iommu_fwnode = iommu_fwnode;
+ fwspec->iommu_ops = ops;
+
+ arch_set_iommu_fwspec(dev, fwspec);
+ return 0;
+}
+
+void iommu_fwspec_free(struct device *dev)
+{
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
+
+ if (fwspec) {
+ if (is_of_node(fwspec->iommu_fwnode))
+ of_node_put(to_of_node(fwspec->iommu_fwnode));
+
+ kfree(fwspec);
+ }
+}
+
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
+{
+ struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
+ size_t size;
+
+ if (!fwspec)
+ return -EINVAL;
+
+ size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + 1]);
+ fwspec = krealloc(fwspec, size, GFP_KERNEL);
+ if (!fwspec)
+ return -ENOMEM;
+
+ while (num_ids--)
+ fwspec->ids[fwspec->num_ids++] = *ids++;
+
+ arch_set_iommu_fwspec(dev, fwspec);
+ return 0;
+}
+
+inline struct iommu_fwspec *dev_iommu_fwspec(struct device *dev)
+{
+ return arch_get_iommu_fwspec(dev);
+}
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 38669b8..ab3c069 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -96,45 +96,6 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
}
EXPORT_SYMBOL_GPL(of_get_dma_window);
-struct of_iommu_node {
- struct list_head list;
- struct device_node *np;
- const struct iommu_ops *ops;
-};
-static LIST_HEAD(of_iommu_list);
-static DEFINE_SPINLOCK(of_iommu_lock);
-
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops)
-{
- struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
-
- if (WARN_ON(!iommu))
- return;
-
- of_node_get(np);
- INIT_LIST_HEAD(&iommu->list);
- iommu->np = np;
- iommu->ops = ops;
- spin_lock(&of_iommu_lock);
- list_add_tail(&iommu->list, &of_iommu_list);
- spin_unlock(&of_iommu_lock);
-}
-
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
-{
- struct of_iommu_node *node;
- const struct iommu_ops *ops = NULL;
-
- spin_lock(&of_iommu_lock);
- list_for_each_entry(node, &of_iommu_list, list)
- if (node->np == np) {
- ops = node->ops;
- break;
- }
- spin_unlock(&of_iommu_lock);
- return ops;
-}
-
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
struct of_phandle_args *iommu_spec = data;
@@ -226,57 +187,3 @@ static int __init of_iommu_init(void)
return 0;
}
postcore_initcall_sync(of_iommu_init);
-
-int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np)
-{
- struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
-
- if (fwspec)
- return 0;
-
- fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
- if (!fwspec)
- return -ENOMEM;
-
- fwspec->iommu_np = of_node_get(iommu_np);
- fwspec->iommu_ops = of_iommu_get_ops(iommu_np);
- arch_set_iommu_fwspec(dev, fwspec);
- return 0;
-}
-
-void iommu_fwspec_free(struct device *dev)
-{
- struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
-
- if (fwspec) {
- of_node_put(fwspec->iommu_np);
- kfree(fwspec);
- }
-}
-
-int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
-{
- struct iommu_fwspec *fwspec = arch_get_iommu_fwspec(dev);
- size_t size;
- int i;
-
- if (!fwspec)
- return -EINVAL;
-
- size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
- fwspec = krealloc(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;
- arch_set_iommu_fwspec(dev, fwspec);
- return 0;
-}
-
-inline struct iommu_fwspec *dev_iommu_fwspec(struct device *dev)
-{
- return arch_get_iommu_fwspec(dev);
-}
diff --git a/include/linux/iommu-fwspec.h b/include/linux/iommu-fwspec.h
new file mode 100644
index 0000000..f88b635
--- /dev/null
+++ b/include/linux/iommu-fwspec.h
@@ -0,0 +1,70 @@
+#ifndef __IOMMU_FWSPEC_H
+#define __IOMMU_FWSPEC_H
+
+#include <linux/device.h>
+#include <linux/iommu.h>
+
+struct iommu_fwspec {
+ const struct iommu_ops *iommu_ops;
+ struct fwnode_handle *iommu_fwnode;
+ void *iommu_priv;
+ unsigned int num_ids;
+ u32 ids[];
+};
+
+#ifdef CONFIG_IOMMU_FWSPEC
+int iommu_fwspec_init(struct device *dev,
+ struct fwnode_handle *iommu_fwnode);
+void iommu_fwspec_free(struct device *dev);
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+struct iommu_fwspec *dev_iommu_fwspec(struct device *dev);
+
+void fwspec_iommu_set_ops(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops);
+const struct iommu_ops *fwspec_iommu_get_ops(struct fwnode_handle *fwnode);
+
+#ifdef CONFIG_HAVE_IOMMU_FWSPEC
+#include <asm/iommu-fwspec.h>
+#else /* !CONFIG_HAVE_IOMMU_FWSPEC */
+static inline void arch_set_iommu_fwspec(struct device *dev,
+ struct iommu_fwspec *fwspec) {}
+
+static inline struct iommu_fwspec *
+arch_get_iommu_fwspec(struct device *dev) { return NULL; }
+#endif
+#else /* CONFIG_IOMMU_FWSPEC */
+static inline int iommu_fwspec_init(struct device *dev,
+ struct fwnode_handle *iommu_fwnode)
+{
+ return -ENODEV;
+}
+
+static inline void iommu_fwspec_free(struct device *dev)
+{
+}
+
+static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
+ int num_ids)
+{
+ return -ENODEV;
+}
+
+static inline struct iommu_fwspec *dev_iommu_fwspec(struct device *dev)
+{
+ return NULL;
+}
+
+static inline void fwspec_iommu_set_ops(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+}
+
+static inline const struct iommu_ops *
+fwspec_iommu_get_ops(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_IOMMU_FWSPEC */
+
+#endif /* __IOMMU_FWSPEC_H */
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 358db49..4b02861 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -3,6 +3,7 @@
#include <linux/device.h>
#include <linux/iommu.h>
+#include <linux/iommu-fwspec.h>
#include <linux/of.h>
#ifdef CONFIG_OF_IOMMU
@@ -14,14 +15,6 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix,
extern const struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np);
-struct iommu_fwspec {
- const struct iommu_ops *iommu_ops;
- struct device_node *iommu_np;
- void *iommu_priv;
- unsigned int num_ids;
- u32 ids[];
-};
-
#else
static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -36,28 +29,19 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
{
return NULL;
}
-
-struct iommu_fwspec;
-
#endif /* CONFIG_OF_IOMMU */
-int iommu_fwspec_init(struct device *dev, struct device_node *iommu_np);
-void iommu_fwspec_free(struct device *dev);
-int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
-struct iommu_fwspec *dev_iommu_fwspec(struct device *dev);
-
-#ifdef CONFIG_HAVE_IOMMU_FWSPEC
-#include <asm/iommu-fwspec.h>
-#else /* !CONFIG_HAVE_IOMMU_FWSPEC */
-static inline void arch_set_iommu_fwspec(struct device *dev,
- struct iommu_fwspec *fwspec) {}
-
-static inline struct iommu_fwspec *
-arch_get_iommu_fwspec(struct device *dev) { return NULL; }
-#endif
+static inline void of_iommu_set_ops(struct device_node *np,
+ const struct iommu_ops *ops)
+{
+ fwspec_iommu_set_ops(&np->fwnode, ops);
+}
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops);
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np);
+static inline const struct iommu_ops *
+of_iommu_get_ops(struct device_node *np)
+{
+ return fwspec_iommu_get_ops(&np->fwnode);
+}
extern struct of_device_id __iommu_of_table;
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (4 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 05/14] drivers: iommu: make iommu_fwspec OF agnostic Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-13 14:41 ` Robin Murphy
2016-09-09 14:23 ` [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
` (6 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Bjorn Helgaas, Dennis Chen, Prem Mallappa
On DT based systems, the of_dma_configure() API implements DMA
configuration for a given device. On ACPI systems an API equivalent to
of_dma_configure() is missing which implies that it is currently not
possible to set-up DMA operations for devices through the ACPI generic
kernel layer.
This patch fills the gap by introducing acpi_dma_configure/deconfigure()
calls that for now are just wrappers around arch_setup_dma_ops() and
arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.
The DMA range size passed to arch_setup_dma_ops() is sized according
to the device coherent_dma_mask (starting at address 0x0), mirroring the
DT probing path behaviour when a dma-ranges property is not provided
for the device being probed; this changes the current arch_setup_dma_ops()
call parameters in the ACPI probing case, but since arch_setup_dma_ops()
is a NOP on all architectures but ARM/ARM64 this patch does not change
the current kernel behaviour on them.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Acked-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> [pci]
Cc: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/glue.c | 4 ++--
drivers/acpi/scan.c | 24 ++++++++++++++++++++++++
drivers/pci/probe.c | 3 +--
include/acpi/acpi_bus.h | 2 ++
include/linux/acpi.h | 5 +++++
5 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 5ea5dc2..f8d6564 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
attr = acpi_get_dma_attr(acpi_dev);
if (attr != DEV_DMA_NOT_SUPPORTED)
- arch_setup_dma_ops(dev, 0, 0, NULL,
- attr == DEV_DMA_COHERENT);
+ acpi_dma_configure(dev, attr);
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
return 0;
err:
+ acpi_dma_deconfigure(dev);
ACPI_COMPANION_SET(dev, NULL);
put_device(dev);
put_device(&acpi_dev->dev);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e878fc7..9614232 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1370,6 +1370,30 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NON_COHERENT;
}
+/**
+ * acpi_dma_configure - Set-up DMA configuration for the device.
+ * @dev: The pointer to the device
+ * @attr: device dma attributes
+ */
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
+{
+ /*
+ * Assume dma valid range starts at 0 and covers the whole
+ * coherent_dma_mask.
+ */
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ attr == DEV_DMA_COHERENT);
+}
+
+/**
+ * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
+ * @dev: The pointer to the device
+ */
+void acpi_dma_deconfigure(struct device *dev)
+{
+ arch_teardown_dma_ops(dev);
+}
+
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 93f280d..e96d482 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1734,8 +1734,7 @@ static void pci_dma_configure(struct pci_dev *dev)
if (attr == DEV_DMA_NOT_SUPPORTED)
dev_warn(&dev->dev, "DMA not supported.\n");
else
- arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
- attr == DEV_DMA_COHERENT);
+ acpi_dma_configure(&dev->dev, attr);
}
pci_put_host_bridge_device(bridge);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c1a524d..4242c31 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -573,6 +573,8 @@ struct acpi_pci_root {
bool acpi_dma_supported(struct acpi_device *adev);
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
+void acpi_dma_deconfigure(struct device *dev);
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
u64 address, bool check_children);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index c5eaf2f..05d4e48 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -729,6 +729,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NOT_SUPPORTED;
}
+static inline void acpi_dma_configure(struct device *dev,
+ enum dev_dma_attr attr) { }
+
+static inline void acpi_dma_deconfigure(struct device *dev) { }
+
#define ACPI_PTR(_ptr) (NULL)
static inline void acpi_device_set_enumerated(struct acpi_device *adev)
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure
2016-09-09 14:23 ` [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
@ 2016-09-13 14:41 ` Robin Murphy
2016-09-13 16:00 ` Lorenzo Pieralisi
0 siblings, 1 reply; 35+ messages in thread
From: Robin Murphy @ 2016-09-13 14:41 UTC (permalink / raw)
To: Lorenzo Pieralisi, iommu
Cc: Bjorn Helgaas, Tomasz Nowicki, Joerg Roedel, Rafael J. Wysocki,
Will Deacon, Marc Zyngier, Hanjun Guo, Jon Masters, Eric Auger,
Sinan Kaya, Nate Watterson, Prem Mallappa, Dennis Chen,
linux-acpi, linux-pci, linux-kernel, linux-arm-kernel
On 09/09/16 15:23, Lorenzo Pieralisi wrote:
> On DT based systems, the of_dma_configure() API implements DMA
> configuration for a given device. On ACPI systems an API equivalent to
> of_dma_configure() is missing which implies that it is currently not
> possible to set-up DMA operations for devices through the ACPI generic
> kernel layer.
>
> This patch fills the gap by introducing acpi_dma_configure/deconfigure()
> calls that for now are just wrappers around arch_setup_dma_ops() and
> arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
> the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.
>
> The DMA range size passed to arch_setup_dma_ops() is sized according
> to the device coherent_dma_mask (starting at address 0x0), mirroring the
> DT probing path behaviour when a dma-ranges property is not provided
> for the device being probed; this changes the current arch_setup_dma_ops()
> call parameters in the ACPI probing case, but since arch_setup_dma_ops()
> is a NOP on all architectures but ARM/ARM64 this patch does not change
> the current kernel behaviour on them.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com> [pci]
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Cc: Tomasz Nowicki <tn@semihalf.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
> drivers/acpi/glue.c | 4 ++--
> drivers/acpi/scan.c | 24 ++++++++++++++++++++++++
> drivers/pci/probe.c | 3 +--
> include/acpi/acpi_bus.h | 2 ++
> include/linux/acpi.h | 5 +++++
> 5 files changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index 5ea5dc2..f8d6564 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>
> attr = acpi_get_dma_attr(acpi_dev);
> if (attr != DEV_DMA_NOT_SUPPORTED)
> - arch_setup_dma_ops(dev, 0, 0, NULL,
> - attr == DEV_DMA_COHERENT);
> + acpi_dma_configure(dev, attr);
>
> acpi_physnode_link_name(physical_node_name, node_id);
> retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
> @@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
> return 0;
>
> err:
> + acpi_dma_deconfigure(dev);
> ACPI_COMPANION_SET(dev, NULL);
> put_device(dev);
> put_device(&acpi_dev->dev);
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index e878fc7..9614232 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -1370,6 +1370,30 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> return DEV_DMA_NON_COHERENT;
> }
>
> +/**
> + * acpi_dma_configure - Set-up DMA configuration for the device.
> + * @dev: The pointer to the device
> + * @attr: device dma attributes
> + */
> +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
> +{
> + /*
> + * Assume dma valid range starts at 0 and covers the whole
> + * coherent_dma_mask.
> + */
> + arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
> + attr == DEV_DMA_COHERENT);
This looks a bit hairy - if we're setting up the DMA configuration at
this point can we really always rely on the device already having a
valid DMA mask? I think it would make sense to at least check, and apply
the standard default 32-bit mask if not.
> +}
> +
> +/**
> + * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
> + * @dev: The pointer to the device
> + */
> +void acpi_dma_deconfigure(struct device *dev)
> +{
> + arch_teardown_dma_ops(dev);
> +}
As touched upon in the dwc-usb3 thread, is it worth exporting these for
the benefit of modular bus/glue code, to match of_dma_configure()?
> +
> static void acpi_init_coherency(struct acpi_device *adev)
> {
> unsigned long long cca = 0;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 93f280d..e96d482 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1734,8 +1734,7 @@ static void pci_dma_configure(struct pci_dev *dev)
> if (attr == DEV_DMA_NOT_SUPPORTED)
> dev_warn(&dev->dev, "DMA not supported.\n");
> else
> - arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
> - attr == DEV_DMA_COHERENT);
> + acpi_dma_configure(&dev->dev, attr);
> }
What about non-PCI stuff? I see there's at least an
acpi_create_platform_device() which I'd also kind of expect to see as a
caller (which indeed might also tie in with the aforementioned default
mask initialisation).
Robin.
>
> pci_put_host_bridge_device(bridge);
> diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> index c1a524d..4242c31 100644
> --- a/include/acpi/acpi_bus.h
> +++ b/include/acpi/acpi_bus.h
> @@ -573,6 +573,8 @@ struct acpi_pci_root {
>
> bool acpi_dma_supported(struct acpi_device *adev);
> enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
> +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
> +void acpi_dma_deconfigure(struct device *dev);
>
> struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
> u64 address, bool check_children);
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index c5eaf2f..05d4e48 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -729,6 +729,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> return DEV_DMA_NOT_SUPPORTED;
> }
>
> +static inline void acpi_dma_configure(struct device *dev,
> + enum dev_dma_attr attr) { }
> +
> +static inline void acpi_dma_deconfigure(struct device *dev) { }
> +
> #define ACPI_PTR(_ptr) (NULL)
>
> static inline void acpi_device_set_enumerated(struct acpi_device *adev)
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure
2016-09-13 14:41 ` Robin Murphy
@ 2016-09-13 16:00 ` Lorenzo Pieralisi
0 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-13 16:00 UTC (permalink / raw)
To: Robin Murphy
Cc: iommu, Bjorn Helgaas, Tomasz Nowicki, Joerg Roedel,
Rafael J. Wysocki, Will Deacon, Marc Zyngier, Hanjun Guo,
Jon Masters, Eric Auger, Sinan Kaya, Nate Watterson,
Prem Mallappa, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
linux-arm-kernel
On Tue, Sep 13, 2016 at 03:41:06PM +0100, Robin Murphy wrote:
> On 09/09/16 15:23, Lorenzo Pieralisi wrote:
> > On DT based systems, the of_dma_configure() API implements DMA
> > configuration for a given device. On ACPI systems an API equivalent to
> > of_dma_configure() is missing which implies that it is currently not
> > possible to set-up DMA operations for devices through the ACPI generic
> > kernel layer.
> >
> > This patch fills the gap by introducing acpi_dma_configure/deconfigure()
> > calls that for now are just wrappers around arch_setup_dma_ops() and
> > arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
> > the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.
> >
> > The DMA range size passed to arch_setup_dma_ops() is sized according
> > to the device coherent_dma_mask (starting at address 0x0), mirroring the
> > DT probing path behaviour when a dma-ranges property is not provided
> > for the device being probed; this changes the current arch_setup_dma_ops()
> > call parameters in the ACPI probing case, but since arch_setup_dma_ops()
> > is a NOP on all architectures but ARM/ARM64 this patch does not change
> > the current kernel behaviour on them.
> >
> > Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> > Acked-by: Bjorn Helgaas <bhelgaas@google.com> [pci]
> > Cc: Bjorn Helgaas <bhelgaas@google.com>
> > Cc: Robin Murphy <robin.murphy@arm.com>
> > Cc: Tomasz Nowicki <tn@semihalf.com>
> > Cc: Joerg Roedel <joro@8bytes.org>
> > Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> > ---
> > drivers/acpi/glue.c | 4 ++--
> > drivers/acpi/scan.c | 24 ++++++++++++++++++++++++
> > drivers/pci/probe.c | 3 +--
> > include/acpi/acpi_bus.h | 2 ++
> > include/linux/acpi.h | 5 +++++
> > 5 files changed, 34 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> > index 5ea5dc2..f8d6564 100644
> > --- a/drivers/acpi/glue.c
> > +++ b/drivers/acpi/glue.c
> > @@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
> >
> > attr = acpi_get_dma_attr(acpi_dev);
> > if (attr != DEV_DMA_NOT_SUPPORTED)
> > - arch_setup_dma_ops(dev, 0, 0, NULL,
> > - attr == DEV_DMA_COHERENT);
> > + acpi_dma_configure(dev, attr);
Here's the call for non-PCI devices ;-)
> > acpi_physnode_link_name(physical_node_name, node_id);
> > retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
> > @@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
> > return 0;
> >
> > err:
> > + acpi_dma_deconfigure(dev);
> > ACPI_COMPANION_SET(dev, NULL);
> > put_device(dev);
> > put_device(&acpi_dev->dev);
> > diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> > index e878fc7..9614232 100644
> > --- a/drivers/acpi/scan.c
> > +++ b/drivers/acpi/scan.c
> > @@ -1370,6 +1370,30 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> > return DEV_DMA_NON_COHERENT;
> > }
> >
> > +/**
> > + * acpi_dma_configure - Set-up DMA configuration for the device.
> > + * @dev: The pointer to the device
> > + * @attr: device dma attributes
> > + */
> > +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
> > +{
> > + /*
> > + * Assume dma valid range starts at 0 and covers the whole
> > + * coherent_dma_mask.
> > + */
> > + arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
> > + attr == DEV_DMA_COHERENT);
>
> This looks a bit hairy - if we're setting up the DMA configuration at
> this point can we really always rely on the device already having a
> valid DMA mask? I think it would make sense to at least check, and apply
> the standard default 32-bit mask if not.
That's a good point, but we would be changing the x86/IA64 probing path
if we do what you suggest; so I think you are right and it should be a
safe change to make but I still need to make sure we do not break
anything in the process.
> > +}
> > +
> > +/**
> > + * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
> > + * @dev: The pointer to the device
> > + */
> > +void acpi_dma_deconfigure(struct device *dev)
> > +{
> > + arch_teardown_dma_ops(dev);
> > +}
>
> As touched upon in the dwc-usb3 thread, is it worth exporting these for
> the benefit of modular bus/glue code, to match of_dma_configure()?
I think yes, I will do.
> > static void acpi_init_coherency(struct acpi_device *adev)
> > {
> > unsigned long long cca = 0;
> > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> > index 93f280d..e96d482 100644
> > --- a/drivers/pci/probe.c
> > +++ b/drivers/pci/probe.c
> > @@ -1734,8 +1734,7 @@ static void pci_dma_configure(struct pci_dev *dev)
> > if (attr == DEV_DMA_NOT_SUPPORTED)
> > dev_warn(&dev->dev, "DMA not supported.\n");
> > else
> > - arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
> > - attr == DEV_DMA_COHERENT);
> > + acpi_dma_configure(&dev->dev, attr);
> > }
>
> What about non-PCI stuff? I see there's at least an
> acpi_create_platform_device() which I'd also kind of expect to see as a
> caller (which indeed might also tie in with the aforementioned default
> mask initialisation).
See above (acpi_bind_one()).
Thanks for having a look,
Lorenzo
>
> Robin.
>
> >
> > pci_put_host_bridge_device(bridge);
> > diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> > index c1a524d..4242c31 100644
> > --- a/include/acpi/acpi_bus.h
> > +++ b/include/acpi/acpi_bus.h
> > @@ -573,6 +573,8 @@ struct acpi_pci_root {
> >
> > bool acpi_dma_supported(struct acpi_device *adev);
> > enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
> > +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
> > +void acpi_dma_deconfigure(struct device *dev);
> >
> > struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
> > u64 address, bool check_children);
> > diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> > index c5eaf2f..05d4e48 100644
> > --- a/include/linux/acpi.h
> > +++ b/include/linux/acpi.h
> > @@ -729,6 +729,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
> > return DEV_DMA_NOT_SUPPORTED;
> > }
> >
> > +static inline void acpi_dma_configure(struct device *dev,
> > + enum dev_dma_attr attr) { }
> > +
> > +static inline void acpi_dma_deconfigure(struct device *dev) { }
> > +
> > #define ACPI_PTR(_ptr) (NULL)
> >
> > static inline void acpi_device_set_enumerated(struct acpi_device *adev)
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (5 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 06/14] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-13 7:46 ` nwatters
2016-09-13 15:25 ` Robin Murphy
2016-09-09 14:23 ` [PATCH v5 08/14] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions Lorenzo Pieralisi
` (5 subsequent siblings)
12 siblings, 2 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
In ARM ACPI systems, IOMMU components are specified through static
IORT table entries. In order to create platform devices for the
corresponding ARM SMMU components, IORT kernel code should be made
able to parse IORT table entries and create platform devices
dynamically.
This patch adds the generic IORT infrastructure required to create
platform devices for ARM SMMUs.
ARM SMMU versions have different resources requirement therefore this
patch also introduces an IORT specific structure (ie iort_iommu_config)
that contains hooks (to be defined when the corresponding ARM SMMU
driver support is added to the kernel) to be used to define the
platform devices names, init the IOMMUs, count their resources and
finally initialize them.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index b89b3d3..e0a9b16 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
struct iort_its_msi_chip {
@@ -424,6 +425,135 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+struct iort_iommu_config {
+ const char *name;
+ int (*iommu_init)(struct acpi_iort_node *node);
+ bool (*iommu_is_coherent)(struct acpi_iort_node *node);
+ int (*iommu_count_resources)(struct acpi_iort_node *node);
+ void (*iommu_init_resources)(struct resource *res,
+ struct acpi_iort_node *node);
+};
+
+static __init
+const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
+{
+ return NULL;
+}
+
+/**
+ * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
+ * @fwnode: IORT node associated fwnode handle
+ * @node: Pointer to SMMU ACPI IORT node
+ *
+ * Returns: 0 on success, <0 failure
+ */
+static int __init iort_add_smmu_platform_device(struct fwnode_handle *fwnode,
+ struct acpi_iort_node *node)
+{
+ struct platform_device *pdev;
+ struct resource *r;
+ enum dev_dma_attr attr;
+ int ret, count;
+ const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
+
+ if (!ops)
+ return -ENODEV;
+
+ pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return PTR_ERR(pdev);
+
+ count = ops->iommu_count_resources(node);
+
+ r = kcalloc(count, sizeof(*r), GFP_KERNEL);
+ if (!r) {
+ ret = -ENOMEM;
+ goto dev_put;
+ }
+
+ ops->iommu_init_resources(r, node);
+
+ ret = platform_device_add_resources(pdev, r, count);
+ /*
+ * Resources are duplicated in platform_device_add_resources,
+ * free their allocated memory
+ */
+ kfree(r);
+
+ if (ret)
+ goto dev_put;
+
+ /*
+ * Add a copy of IORT node pointer to platform_data to
+ * be used to retrieve IORT data information.
+ */
+ ret = platform_device_add_data(pdev, &node, sizeof(node));
+ if (ret)
+ goto dev_put;
+
+ pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+ if (!pdev->dev.dma_mask) {
+ ret = -ENOMEM;
+ goto dev_put;
+ }
+
+ pdev->dev.fwnode = fwnode;
+
+ /*
+ * Set default dma mask value for the table walker,
+ * to be overridden on probing with correct value.
+ */
+ *pdev->dev.dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.coherent_dma_mask = *pdev->dev.dma_mask;
+
+ attr = ops->iommu_is_coherent(node) ?
+ DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
+
+ /* Configure DMA for the page table walker */
+ acpi_dma_configure(&pdev->dev, attr);
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto dma_deconfigure;
+
+ return 0;
+
+dma_deconfigure:
+ acpi_dma_deconfigure(&pdev->dev);
+ kfree(pdev->dev.dma_mask);
+
+dev_put:
+ platform_device_put(pdev);
+
+ return ret;
+}
+
+static acpi_status __init iort_match_iommu_callback(struct acpi_iort_node *node,
+ void *context)
+{
+ int ret;
+ struct fwnode_handle *fwnode;
+
+ fwnode = iort_get_fwnode(node);
+
+ if (!fwnode)
+ return AE_NOT_FOUND;
+
+ ret = iort_add_smmu_platform_device(fwnode, node);
+ if (ret) {
+ pr_err("Error in platform device creation\n");
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+static void __init iort_smmu_init(void)
+{
+ iort_scan_node(ACPI_IORT_NODE_SMMU, iort_match_iommu_callback, NULL);
+ iort_scan_node(ACPI_IORT_NODE_SMMU_V3, iort_match_iommu_callback, NULL);
+}
+
void __init acpi_iort_init(void)
{
acpi_status status;
@@ -436,4 +566,5 @@ void __init acpi_iort_init(void)
}
acpi_probe_device_table(iort);
+ iort_smmu_init();
}
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation
2016-09-09 14:23 ` [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
@ 2016-09-13 7:46 ` nwatters
2016-09-13 8:15 ` Hanjun Guo
2016-09-13 15:25 ` Robin Murphy
1 sibling, 1 reply; 35+ messages in thread
From: nwatters @ 2016-09-13 7:46 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: iommu, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki, Will Deacon,
Marc Zyngier, Robin Murphy, Joerg Roedel, Jon Masters, Eric Auger,
Sinan Kaya, Prem Mallappa, Dennis Chen, linux-acpi, linux-pci,
linux-kernel, linux-arm-kernel
On 2016-09-09 10:23, Lorenzo Pieralisi wrote:
> In ARM ACPI systems, IOMMU components are specified through static
> IORT table entries. In order to create platform devices for the
> corresponding ARM SMMU components, IORT kernel code should be made
> able to parse IORT table entries and create platform devices
> dynamically.
>
> This patch adds the generic IORT infrastructure required to create
> platform devices for ARM SMMUs.
>
> ARM SMMU versions have different resources requirement therefore this
> patch also introduces an IORT specific structure (ie iort_iommu_config)
> that contains hooks (to be defined when the corresponding ARM SMMU
> driver support is added to the kernel) to be used to define the
> platform devices names, init the IOMMUs, count their resources and
> finally initialize them.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Hanjun Guo <hanjun.guo@linaro.org>
> Cc: Tomasz Nowicki <tn@semihalf.com>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
> drivers/acpi/arm64/iort.c | 131
> ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 131 insertions(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index b89b3d3..e0a9b16 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -22,6 +22,7 @@
> #include <linux/kernel.h>
> #include <linux/list.h>
> #include <linux/pci.h>
> +#include <linux/platform_device.h>
> #include <linux/slab.h>
>
> struct iort_its_msi_chip {
> @@ -424,6 +425,135 @@ struct irq_domain *iort_get_device_domain(struct
> device *dev, u32 req_id)
> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> }
>
> +struct iort_iommu_config {
> + const char *name;
> + int (*iommu_init)(struct acpi_iort_node *node);
> + bool (*iommu_is_coherent)(struct acpi_iort_node *node);
> + int (*iommu_count_resources)(struct acpi_iort_node *node);
> + void (*iommu_init_resources)(struct resource *res,
> + struct acpi_iort_node *node);
> +};
> +
> +static __init
> +const struct iort_iommu_config *iort_get_iommu_cfg(struct
> acpi_iort_node *node)
> +{
> + return NULL;
> +}
> +
> +/**
> + * iort_add_smmu_platform_device() - Allocate a platform device for
> SMMU
> + * @fwnode: IORT node associated fwnode handle
> + * @node: Pointer to SMMU ACPI IORT node
> + *
> + * Returns: 0 on success, <0 failure
> + */
> +static int __init iort_add_smmu_platform_device(struct fwnode_handle
> *fwnode,
> + struct acpi_iort_node *node)
> +{
> + struct platform_device *pdev;
> + struct resource *r;
> + enum dev_dma_attr attr;
> + int ret, count;
> + const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> +
> + if (!ops)
> + return -ENODEV;
> +
> + pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> + if (!pdev)
> + return PTR_ERR(pdev);
> +
> + count = ops->iommu_count_resources(node);
> +
> + r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> + if (!r) {
> + ret = -ENOMEM;
> + goto dev_put;
> + }
> +
> + ops->iommu_init_resources(r, node);
> +
> + ret = platform_device_add_resources(pdev, r, count);
> + /*
> + * Resources are duplicated in platform_device_add_resources,
> + * free their allocated memory
> + */
> + kfree(r);
> +
> + if (ret)
> + goto dev_put;
> +
> + /*
> + * Add a copy of IORT node pointer to platform_data to
> + * be used to retrieve IORT data information.
> + */
> + ret = platform_device_add_data(pdev, &node, sizeof(node));
> + if (ret)
> + goto dev_put;
> +
> + pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask),
> GFP_KERNEL);
> + if (!pdev->dev.dma_mask) {
> + ret = -ENOMEM;
> + goto dev_put;
> + }
> +
> + pdev->dev.fwnode = fwnode;
> +
> + /*
> + * Set default dma mask value for the table walker,
> + * to be overridden on probing with correct value.
> + */
> + *pdev->dev.dma_mask = DMA_BIT_MASK(32);
> + pdev->dev.coherent_dma_mask = *pdev->dev.dma_mask;
> +
> + attr = ops->iommu_is_coherent(node) ?
> + DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> +
> + /* Configure DMA for the page table walker */
> + acpi_dma_configure(&pdev->dev, attr);
> +
> + ret = platform_device_add(pdev);
> + if (ret)
> + goto dma_deconfigure;
> +
> + return 0;
> +
> +dma_deconfigure:
> + acpi_dma_deconfigure(&pdev->dev);
> + kfree(pdev->dev.dma_mask);
> +
> +dev_put:
> + platform_device_put(pdev);
> +
> + return ret;
> +}
> +
> +static acpi_status __init iort_match_iommu_callback(struct
> acpi_iort_node *node,
> + void *context)
> +{
> + int ret;
> + struct fwnode_handle *fwnode;
> +
> + fwnode = iort_get_fwnode(node);
> +
> + if (!fwnode)
> + return AE_NOT_FOUND;
> +
> + ret = iort_add_smmu_platform_device(fwnode, node);
> + if (ret) {
> + pr_err("Error in platform device creation\n");
> + return AE_ERROR;
> + }
> +
> + return AE_OK;
> +}
> +
> +static void __init iort_smmu_init(void)
> +{
> + iort_scan_node(ACPI_IORT_NODE_SMMU, iort_match_iommu_callback, NULL);
> + iort_scan_node(ACPI_IORT_NODE_SMMU_V3, iort_match_iommu_callback,
> NULL);
Since iort_scan_node() returns after the first successful match it
finds,
only the first SMMU_V3 in my IORT is being enumerated. I think you need
to go back to the "iterator" like approach you had been using or make
iort_match_iommu_callback() always return a non-AE_OK value so the scan
continues and has a chance to visit all of the SMMU_V3 nodes.
> +}
> +
> void __init acpi_iort_init(void)
> {
> acpi_status status;
> @@ -436,4 +566,5 @@ void __init acpi_iort_init(void)
> }
>
> acpi_probe_device_table(iort);
> + iort_smmu_init();
> }
--
Qualcomm Datacenter Technologies, Inc. on behalf of Qualcomm
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
Linux Foundation Collaborative Project.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation
2016-09-13 7:46 ` nwatters
@ 2016-09-13 8:15 ` Hanjun Guo
[not found] ` <fb4acfd5-b7fd-636f-53f3-13dc6fb8b713-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
0 siblings, 1 reply; 35+ messages in thread
From: Hanjun Guo @ 2016-09-13 8:15 UTC (permalink / raw)
To: nwatters, Lorenzo Pieralisi
Cc: iommu, Tomasz Nowicki, Rafael J. Wysocki, Will Deacon,
Marc Zyngier, Robin Murphy, Joerg Roedel, Jon Masters, Eric Auger,
Sinan Kaya, Prem Mallappa, Dennis Chen, linux-acpi, linux-pci,
linux-kernel, linux-arm-kernel
On 2016/9/13 15:46, nwatters@codeaurora.org wrote:
> On 2016-09-09 10:23, Lorenzo Pieralisi wrote:
>> In ARM ACPI systems, IOMMU components are specified through static
>> IORT table entries. In order to create platform devices for the
>> corresponding ARM SMMU components, IORT kernel code should be made
>> able to parse IORT table entries and create platform devices
>> dynamically.
>>
>> This patch adds the generic IORT infrastructure required to create
>> platform devices for ARM SMMUs.
>>
>> ARM SMMU versions have different resources requirement therefore this
>> patch also introduces an IORT specific structure (ie iort_iommu_config)
>> that contains hooks (to be defined when the corresponding ARM SMMU
>> driver support is added to the kernel) to be used to define the
>> platform devices names, init the IOMMUs, count their resources and
>> finally initialize them.
>>
>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Hanjun Guo <hanjun.guo@linaro.org>
>> Cc: Tomasz Nowicki <tn@semihalf.com>
>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>> ---
>> drivers/acpi/arm64/iort.c | 131
>> ++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 131 insertions(+)
>>
>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>> index b89b3d3..e0a9b16 100644
>> --- a/drivers/acpi/arm64/iort.c
>> +++ b/drivers/acpi/arm64/iort.c
>> @@ -22,6 +22,7 @@
>> #include <linux/kernel.h>
>> #include <linux/list.h>
>> #include <linux/pci.h>
>> +#include <linux/platform_device.h>
>> #include <linux/slab.h>
>>
>> struct iort_its_msi_chip {
>> @@ -424,6 +425,135 @@ struct irq_domain *iort_get_device_domain(struct
>> device *dev, u32 req_id)
>> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
>> }
>>
>> +struct iort_iommu_config {
>> + const char *name;
>> + int (*iommu_init)(struct acpi_iort_node *node);
>> + bool (*iommu_is_coherent)(struct acpi_iort_node *node);
>> + int (*iommu_count_resources)(struct acpi_iort_node *node);
>> + void (*iommu_init_resources)(struct resource *res,
>> + struct acpi_iort_node *node);
>> +};
>> +
>> +static __init
>> +const struct iort_iommu_config *iort_get_iommu_cfg(struct
>> acpi_iort_node *node)
>> +{
>> + return NULL;
>> +}
>> +
>> +/**
>> + * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>> + * @fwnode: IORT node associated fwnode handle
>> + * @node: Pointer to SMMU ACPI IORT node
>> + *
>> + * Returns: 0 on success, <0 failure
>> + */
>> +static int __init iort_add_smmu_platform_device(struct fwnode_handle
>> *fwnode,
>> + struct acpi_iort_node *node)
>> +{
>> + struct platform_device *pdev;
>> + struct resource *r;
>> + enum dev_dma_attr attr;
>> + int ret, count;
>> + const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
>> +
>> + if (!ops)
>> + return -ENODEV;
>> +
>> + pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
>> + if (!pdev)
>> + return PTR_ERR(pdev);
>> +
>> + count = ops->iommu_count_resources(node);
>> +
>> + r = kcalloc(count, sizeof(*r), GFP_KERNEL);
>> + if (!r) {
>> + ret = -ENOMEM;
>> + goto dev_put;
>> + }
>> +
>> + ops->iommu_init_resources(r, node);
>> +
>> + ret = platform_device_add_resources(pdev, r, count);
>> + /*
>> + * Resources are duplicated in platform_device_add_resources,
>> + * free their allocated memory
>> + */
>> + kfree(r);
>> +
>> + if (ret)
>> + goto dev_put;
>> +
>> + /*
>> + * Add a copy of IORT node pointer to platform_data to
>> + * be used to retrieve IORT data information.
>> + */
>> + ret = platform_device_add_data(pdev, &node, sizeof(node));
>> + if (ret)
>> + goto dev_put;
>> +
>> + pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask),
>> GFP_KERNEL);
>> + if (!pdev->dev.dma_mask) {
>> + ret = -ENOMEM;
>> + goto dev_put;
>> + }
>> +
>> + pdev->dev.fwnode = fwnode;
>> +
>> + /*
>> + * Set default dma mask value for the table walker,
>> + * to be overridden on probing with correct value.
>> + */
>> + *pdev->dev.dma_mask = DMA_BIT_MASK(32);
>> + pdev->dev.coherent_dma_mask = *pdev->dev.dma_mask;
>> +
>> + attr = ops->iommu_is_coherent(node) ?
>> + DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
>> +
>> + /* Configure DMA for the page table walker */
>> + acpi_dma_configure(&pdev->dev, attr);
>> +
>> + ret = platform_device_add(pdev);
>> + if (ret)
>> + goto dma_deconfigure;
>> +
>> + return 0;
>> +
>> +dma_deconfigure:
>> + acpi_dma_deconfigure(&pdev->dev);
>> + kfree(pdev->dev.dma_mask);
>> +
>> +dev_put:
>> + platform_device_put(pdev);
>> +
>> + return ret;
>> +}
>> +
>> +static acpi_status __init iort_match_iommu_callback(struct
>> acpi_iort_node *node,
>> + void *context)
>> +{
>> + int ret;
>> + struct fwnode_handle *fwnode;
>> +
>> + fwnode = iort_get_fwnode(node);
>> +
>> + if (!fwnode)
>> + return AE_NOT_FOUND;
>> +
>> + ret = iort_add_smmu_platform_device(fwnode, node);
>> + if (ret) {
>> + pr_err("Error in platform device creation\n");
>> + return AE_ERROR;
>> + }
>> +
>> + return AE_OK;
>> +}
>> +
>> +static void __init iort_smmu_init(void)
>> +{
>> + iort_scan_node(ACPI_IORT_NODE_SMMU, iort_match_iommu_callback,
>> NULL);
>> + iort_scan_node(ACPI_IORT_NODE_SMMU_V3, iort_match_iommu_callback,
>> NULL);
>
> Since iort_scan_node() returns after the first successful match it finds,
> only the first SMMU_V3 in my IORT is being enumerated. I think you need
> to go back to the "iterator" like approach you had been using or make
> iort_match_iommu_callback() always return a non-AE_OK value so the scan
> continues and has a chance to visit all of the SMMU_V3 nodes.
Please use the updated version of IORT patch (aka Tomasz's v11)
then things will work fine.
Thanks
Hanjun
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation
2016-09-09 14:23 ` [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
2016-09-13 7:46 ` nwatters
@ 2016-09-13 15:25 ` Robin Murphy
2016-09-13 16:29 ` Lorenzo Pieralisi
1 sibling, 1 reply; 35+ messages in thread
From: Robin Murphy @ 2016-09-13 15:25 UTC (permalink / raw)
To: Lorenzo Pieralisi, iommu
Cc: Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki, Will Deacon,
Marc Zyngier, Joerg Roedel, Jon Masters, Eric Auger, Sinan Kaya,
Nate Watterson, Prem Mallappa, Dennis Chen, linux-acpi, linux-pci,
linux-kernel, linux-arm-kernel
On 09/09/16 15:23, Lorenzo Pieralisi wrote:
> In ARM ACPI systems, IOMMU components are specified through static
> IORT table entries. In order to create platform devices for the
> corresponding ARM SMMU components, IORT kernel code should be made
> able to parse IORT table entries and create platform devices
> dynamically.
>
> This patch adds the generic IORT infrastructure required to create
> platform devices for ARM SMMUs.
>
> ARM SMMU versions have different resources requirement therefore this
> patch also introduces an IORT specific structure (ie iort_iommu_config)
> that contains hooks (to be defined when the corresponding ARM SMMU
> driver support is added to the kernel) to be used to define the
> platform devices names, init the IOMMUs, count their resources and
> finally initialize them.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Hanjun Guo <hanjun.guo@linaro.org>
> Cc: Tomasz Nowicki <tn@semihalf.com>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
> drivers/acpi/arm64/iort.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 131 insertions(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index b89b3d3..e0a9b16 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -22,6 +22,7 @@
> #include <linux/kernel.h>
> #include <linux/list.h>
> #include <linux/pci.h>
> +#include <linux/platform_device.h>
> #include <linux/slab.h>
>
> struct iort_its_msi_chip {
> @@ -424,6 +425,135 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> }
>
> +struct iort_iommu_config {
> + const char *name;
> + int (*iommu_init)(struct acpi_iort_node *node);
> + bool (*iommu_is_coherent)(struct acpi_iort_node *node);
> + int (*iommu_count_resources)(struct acpi_iort_node *node);
> + void (*iommu_init_resources)(struct resource *res,
> + struct acpi_iort_node *node);
> +};
> +
> +static __init
> +const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
> +{
> + return NULL;
> +}
> +
> +/**
> + * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
> + * @fwnode: IORT node associated fwnode handle
> + * @node: Pointer to SMMU ACPI IORT node
> + *
> + * Returns: 0 on success, <0 failure
> + */
> +static int __init iort_add_smmu_platform_device(struct fwnode_handle *fwnode,
> + struct acpi_iort_node *node)
> +{
> + struct platform_device *pdev;
> + struct resource *r;
> + enum dev_dma_attr attr;
> + int ret, count;
> + const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> +
> + if (!ops)
> + return -ENODEV;
> +
> + pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> + if (!pdev)
> + return PTR_ERR(pdev);
> +
> + count = ops->iommu_count_resources(node);
> +
> + r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> + if (!r) {
> + ret = -ENOMEM;
> + goto dev_put;
> + }
> +
> + ops->iommu_init_resources(r, node);
> +
> + ret = platform_device_add_resources(pdev, r, count);
> + /*
> + * Resources are duplicated in platform_device_add_resources,
> + * free their allocated memory
> + */
> + kfree(r);
> +
> + if (ret)
> + goto dev_put;
> +
> + /*
> + * Add a copy of IORT node pointer to platform_data to
> + * be used to retrieve IORT data information.
> + */
> + ret = platform_device_add_data(pdev, &node, sizeof(node));
> + if (ret)
> + goto dev_put;
> +
> + pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
> + if (!pdev->dev.dma_mask) {
> + ret = -ENOMEM;
> + goto dev_put;
> + }
Since this is exclusively for creating SMMUs, and we know they should
never have weird shenanigans going on requiring different masks, I'd be
inclined to just point dev.dma_mask at dev.coherent_dma_mask and be done
with it.
> +
> + pdev->dev.fwnode = fwnode;
> +
> + /*
> + * Set default dma mask value for the table walker,
> + * to be overridden on probing with correct value.
> + */
> + *pdev->dev.dma_mask = DMA_BIT_MASK(32);
> + pdev->dev.coherent_dma_mask = *pdev->dev.dma_mask;
> +
> + attr = ops->iommu_is_coherent(node) ?
> + DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> +
> + /* Configure DMA for the page table walker */
> + acpi_dma_configure(&pdev->dev, attr);
Oh look, some more code which would be simpler if acpi_dma_configure()
set the default mask itself ;)
Robin.
> +
> + ret = platform_device_add(pdev);
> + if (ret)
> + goto dma_deconfigure;
> +
> + return 0;
> +
> +dma_deconfigure:
> + acpi_dma_deconfigure(&pdev->dev);
> + kfree(pdev->dev.dma_mask);
> +
> +dev_put:
> + platform_device_put(pdev);
> +
> + return ret;
> +}
> +
> +static acpi_status __init iort_match_iommu_callback(struct acpi_iort_node *node,
> + void *context)
> +{
> + int ret;
> + struct fwnode_handle *fwnode;
> +
> + fwnode = iort_get_fwnode(node);
> +
> + if (!fwnode)
> + return AE_NOT_FOUND;
> +
> + ret = iort_add_smmu_platform_device(fwnode, node);
> + if (ret) {
> + pr_err("Error in platform device creation\n");
> + return AE_ERROR;
> + }
> +
> + return AE_OK;
> +}
> +
> +static void __init iort_smmu_init(void)
> +{
> + iort_scan_node(ACPI_IORT_NODE_SMMU, iort_match_iommu_callback, NULL);
> + iort_scan_node(ACPI_IORT_NODE_SMMU_V3, iort_match_iommu_callback, NULL);
> +}
> +
> void __init acpi_iort_init(void)
> {
> acpi_status status;
> @@ -436,4 +566,5 @@ void __init acpi_iort_init(void)
> }
>
> acpi_probe_device_table(iort);
> + iort_smmu_init();
> }
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation
2016-09-13 15:25 ` Robin Murphy
@ 2016-09-13 16:29 ` Lorenzo Pieralisi
0 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-13 16:29 UTC (permalink / raw)
To: Robin Murphy
Cc: iommu, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki, Will Deacon,
Marc Zyngier, Joerg Roedel, Jon Masters, Eric Auger, Sinan Kaya,
Nate Watterson, Prem Mallappa, Dennis Chen, linux-acpi, linux-pci,
linux-kernel, linux-arm-kernel
On Tue, Sep 13, 2016 at 04:25:55PM +0100, Robin Murphy wrote:
[...]
> > +/**
> > + * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
> > + * @fwnode: IORT node associated fwnode handle
> > + * @node: Pointer to SMMU ACPI IORT node
> > + *
> > + * Returns: 0 on success, <0 failure
> > + */
> > +static int __init iort_add_smmu_platform_device(struct fwnode_handle *fwnode,
> > + struct acpi_iort_node *node)
> > +{
> > + struct platform_device *pdev;
> > + struct resource *r;
> > + enum dev_dma_attr attr;
> > + int ret, count;
> > + const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> > +
> > + if (!ops)
> > + return -ENODEV;
> > +
> > + pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> > + if (!pdev)
> > + return PTR_ERR(pdev);
> > +
> > + count = ops->iommu_count_resources(node);
> > +
> > + r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> > + if (!r) {
> > + ret = -ENOMEM;
> > + goto dev_put;
> > + }
> > +
> > + ops->iommu_init_resources(r, node);
> > +
> > + ret = platform_device_add_resources(pdev, r, count);
> > + /*
> > + * Resources are duplicated in platform_device_add_resources,
> > + * free their allocated memory
> > + */
> > + kfree(r);
> > +
> > + if (ret)
> > + goto dev_put;
> > +
> > + /*
> > + * Add a copy of IORT node pointer to platform_data to
> > + * be used to retrieve IORT data information.
> > + */
> > + ret = platform_device_add_data(pdev, &node, sizeof(node));
> > + if (ret)
> > + goto dev_put;
> > +
> > + pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
> > + if (!pdev->dev.dma_mask) {
> > + ret = -ENOMEM;
> > + goto dev_put;
> > + }
>
> Since this is exclusively for creating SMMUs, and we know they should
> never have weird shenanigans going on requiring different masks, I'd be
> inclined to just point dev.dma_mask at dev.coherent_dma_mask and be done
> with it.
That sounds reasonable yes, I will do.
> > +
> > + pdev->dev.fwnode = fwnode;
> > +
> > + /*
> > + * Set default dma mask value for the table walker,
> > + * to be overridden on probing with correct value.
> > + */
> > + *pdev->dev.dma_mask = DMA_BIT_MASK(32);
> > + pdev->dev.coherent_dma_mask = *pdev->dev.dma_mask;
> > +
> > + attr = ops->iommu_is_coherent(node) ?
> > + DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> > +
> > + /* Configure DMA for the page table walker */
> > + acpi_dma_configure(&pdev->dev, attr);
>
> Oh look, some more code which would be simpler if acpi_dma_configure()
> set the default mask itself ;)
Eheh I have no objections, apart from the effect that change can
have on non-ARM probing paths, it could also help remove some code
from ACPI core while at it.
Thanks !
Lorenzo
>
> Robin.
>
> > +
> > + ret = platform_device_add(pdev);
> > + if (ret)
> > + goto dma_deconfigure;
> > +
> > + return 0;
> > +
> > +dma_deconfigure:
> > + acpi_dma_deconfigure(&pdev->dev);
> > + kfree(pdev->dev.dma_mask);
> > +
> > +dev_put:
> > + platform_device_put(pdev);
> > +
> > + return ret;
> > +}
> > +
> > +static acpi_status __init iort_match_iommu_callback(struct acpi_iort_node *node,
> > + void *context)
> > +{
> > + int ret;
> > + struct fwnode_handle *fwnode;
> > +
> > + fwnode = iort_get_fwnode(node);
> > +
> > + if (!fwnode)
> > + return AE_NOT_FOUND;
> > +
> > + ret = iort_add_smmu_platform_device(fwnode, node);
> > + if (ret) {
> > + pr_err("Error in platform device creation\n");
> > + return AE_ERROR;
> > + }
> > +
> > + return AE_OK;
> > +}
> > +
> > +static void __init iort_smmu_init(void)
> > +{
> > + iort_scan_node(ACPI_IORT_NODE_SMMU, iort_match_iommu_callback, NULL);
> > + iort_scan_node(ACPI_IORT_NODE_SMMU_V3, iort_match_iommu_callback, NULL);
> > +}
> > +
> > void __init acpi_iort_init(void)
> > {
> > acpi_status status;
> > @@ -436,4 +566,5 @@ void __init acpi_iort_init(void)
> > }
> >
> > acpi_probe_device_table(iort);
> > + iort_smmu_init();
> > }
> >
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v5 08/14] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (6 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 07/14] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 09/14] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
` (4 subsequent siblings)
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
Current ARM SMMUv3 probe functions intermingle HW and DT probing in the
initialization functions to detect and programme the ARM SMMU v3 driver
features. In order to allow probing the ARM SMMUv3 with other firmwares
than DT, this patch splits the ARM SMMUv3 init functions into DT and HW
specific portions so that other FW interfaces (ie ACPI) can reuse the HW
probing functions and skip the DT portion accordingly.
This patch implements no functional change, only code reshuffling.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Acked-by: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
drivers/iommu/arm-smmu-v3.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index a7e9de9..dbc21e3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2361,10 +2361,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
return 0;
}
-static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
+static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
{
u32 reg;
- bool coherent;
+ bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
/* IDR0 */
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
@@ -2416,13 +2416,9 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
smmu->features |= ARM_SMMU_FEAT_HYP;
/*
- * The dma-coherent property is used in preference to the ID
+ * The coherency feature as set by FW is used in preference to the ID
* register, but warn on mismatch.
*/
- coherent = of_dma_is_coherent(smmu->dev->of_node);
- if (coherent)
- smmu->features |= ARM_SMMU_FEAT_COHERENCY;
-
if (!!(reg & IDR0_COHACC) != coherent)
dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n",
coherent ? "true" : "false");
@@ -2543,7 +2539,18 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
return 0;
}
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ parse_driver_options(smmu);
+
+ if (of_dma_is_coherent(smmu->dev->of_node))
+ smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+ return 0;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
{
int irq, ret;
struct resource *res;
@@ -2585,10 +2592,13 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (irq > 0)
smmu->gerr_irq = irq;
- parse_driver_options(smmu);
+ ret = arm_smmu_device_dt_probe(pdev, smmu);
+
+ if (ret)
+ return ret;
/* Probe the h/w */
- ret = arm_smmu_device_probe(smmu);
+ ret = arm_smmu_device_hw_probe(smmu);
if (ret)
return ret;
@@ -2606,7 +2616,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return ret;
/* And we're up. Go go go! */
- of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+ fwspec_iommu_set_ops(&dev->of_node->fwnode, &arm_smmu_ops);
#ifdef CONFIG_PCI
pci_request_acs();
ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
@@ -2640,7 +2650,7 @@ static struct platform_driver arm_smmu_driver = {
.name = "arm-smmu-v3",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 09/14] drivers: iommu: arm-smmu-v3: add IORT configuration
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (7 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 08/14] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-13 17:30 ` Robin Murphy
2016-09-09 14:23 ` [PATCH v5 10/14] drivers: iommu: arm-smmu: split probe functions into DT/generic portions Lorenzo Pieralisi
` (3 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU v3 components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU v3 components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU v3 components, so that the ARM SMMU v3 driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 103 +++++++++++++++++++++++++++++++++++++++++++-
drivers/iommu/arm-smmu-v3.c | 95 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index e0a9b16..a2ad102 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -425,6 +425,95 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static void __init acpi_iort_register_irq(int hwirq, const char *name,
+ int trigger,
+ struct resource *res)
+{
+ int irq = acpi_register_gsi(NULL, hwirq, trigger,
+ ACPI_ACTIVE_HIGH);
+
+ if (irq < 0) {
+ pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
+ name);
+ return;
+ }
+
+ res->start = irq;
+ res->end = irq;
+ res->flags = IORESOURCE_IRQ;
+ res->name = name;
+}
+
+static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+ /* Always present mem resource */
+ int num_res = 1;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ if (smmu->event_gsiv)
+ num_res++;
+
+ if (smmu->pri_gsiv)
+ num_res++;
+
+ if (smmu->gerr_gsiv)
+ num_res++;
+
+ if (smmu->sync_gsiv)
+ num_res++;
+
+ return num_res;
+}
+
+static void __init arm_smmu_v3_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+ int num_res = 0;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + SZ_128K - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+
+ num_res++;
+
+ if (smmu->event_gsiv)
+ acpi_iort_register_irq(smmu->event_gsiv, "eventq",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->pri_gsiv)
+ acpi_iort_register_irq(smmu->pri_gsiv, "priq",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->gerr_gsiv)
+ acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->sync_gsiv)
+ acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+}
+
+static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -434,10 +523,22 @@ struct iort_iommu_config {
struct acpi_iort_node *node);
};
+static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
+ .name = "arm-smmu-v3",
+ .iommu_is_coherent = arm_smmu_v3_is_coherent,
+ .iommu_count_resources = arm_smmu_v3_count_resources,
+ .iommu_init_resources = arm_smmu_v3_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
- return NULL;
+ switch (node->type) {
+ case ACPI_IORT_NODE_SMMU_V3:
+ return &iort_arm_smmu_v3_cfg;
+ default:
+ return NULL;
+ }
}
/**
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index dbc21e3..9463f3f 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -20,6 +20,8 @@
* This driver is powered by bad coffee and bombay mix.
*/
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
#include <linux/err.h>
@@ -2539,6 +2541,32 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
return 0;
}
+#ifdef CONFIG_ACPI
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ struct acpi_iort_smmu_v3 *iort_smmu;
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node;
+
+ node = *(struct acpi_iort_node **)dev_get_platdata(dev);
+
+ /* Retrieve SMMUv3 specific data */
+ iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE)
+ smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+ return 0;
+}
+#else
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
@@ -2556,6 +2584,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
struct resource *res;
struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
+ struct fwnode_handle *fwnode;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
@@ -2592,7 +2621,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (irq > 0)
smmu->gerr_irq = irq;
- ret = arm_smmu_device_dt_probe(pdev, smmu);
+ if (dev->of_node)
+ ret = arm_smmu_device_dt_probe(pdev, smmu);
+ else
+ ret = arm_smmu_device_acpi_probe(pdev, smmu);
if (ret)
return ret;
@@ -2615,8 +2647,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* FIXME: DT code path does not set up dev->fwnode pointer */
+ fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
+
/* And we're up. Go go go! */
- fwspec_iommu_set_ops(&dev->of_node->fwnode, &arm_smmu_ops);
+ fwspec_iommu_set_ops(fwnode, &arm_smmu_ops);
+
#ifdef CONFIG_PCI
pci_request_acs();
ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
@@ -2688,6 +2724,61 @@ static int __init arm_smmu_of_init(struct device_node *np)
}
IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
+{
+ struct acpi_iort_node *iort_node, *iort_end;
+ struct acpi_table_iort *iort;
+ struct fwnode_handle *fwnode;
+ int i, ret;
+
+ /*
+ * table and iort will both point to the start of IORT table, but
+ * have different struct types
+ */
+ iort = (struct acpi_table_iort *)table;
+
+ /* Get the first IORT node */
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, table,
+ iort->node_offset);
+ iort_end = ACPI_ADD_PTR(struct acpi_iort_node, table,
+ table->length);
+
+ for (i = 0; i < iort->node_count; i++) {
+
+ if (iort_node >= iort_end) {
+ pr_err("iort node pointer overflows, bad table\n");
+ return -EINVAL;
+ }
+
+ if (iort_node->type == ACPI_IORT_NODE_SMMU_V3) {
+ ret = arm_smmu_init();
+ if (ret)
+ return ret;
+
+ fwnode = iommu_alloc_fwnode();
+
+ if (!fwnode)
+ return -ENOMEM;
+
+ ret = iort_set_fwnode(iort_node, fwnode);
+ if (ret)
+ goto free;
+ }
+
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+ iort_node->length);
+ }
+
+ return 0;
+free:
+ iommu_free_fwnode(fwnode);
+ return ret;
+
+}
+IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
MODULE_AUTHOR("Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>");
MODULE_LICENSE("GPL v2");
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v5 09/14] drivers: iommu: arm-smmu-v3: add IORT configuration
2016-09-09 14:23 ` [PATCH v5 09/14] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
@ 2016-09-13 17:30 ` Robin Murphy
0 siblings, 0 replies; 35+ messages in thread
From: Robin Murphy @ 2016-09-13 17:30 UTC (permalink / raw)
To: Lorenzo Pieralisi, iommu
Cc: Will Deacon, Joerg Roedel, Marc Zyngier, Rafael J. Wysocki,
Tomasz Nowicki, Hanjun Guo, Jon Masters, Eric Auger, Sinan Kaya,
Nate Watterson, Prem Mallappa, Dennis Chen, linux-acpi, linux-pci,
linux-kernel, linux-arm-kernel
On 09/09/16 15:23, Lorenzo Pieralisi wrote:
> In ACPI bases systems, in order to be able to create platform
> devices and initialize them for ARM SMMU v3 components, the IORT
> kernel implementation requires a set of static functions to be
> used by the IORT kernel layer to configure platform devices for
> ARM SMMU v3 components.
>
> Add static configuration functions to the IORT kernel layer for
> the ARM SMMU v3 components, so that the ARM SMMU v3 driver can
> initialize its respective platform device by relying on the IORT
> kernel infrastructure and by adding a corresponding ACPI device
> early probe section entry.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> ---
> drivers/acpi/arm64/iort.c | 103 +++++++++++++++++++++++++++++++++++++++++++-
> drivers/iommu/arm-smmu-v3.c | 95 +++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 195 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index e0a9b16..a2ad102 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -425,6 +425,95 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
> return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
> }
>
> +static void __init acpi_iort_register_irq(int hwirq, const char *name,
> + int trigger,
> + struct resource *res)
> +{
> + int irq = acpi_register_gsi(NULL, hwirq, trigger,
> + ACPI_ACTIVE_HIGH);
> +
> + if (irq < 0) {
irq <= 0 ?
> + pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
> + name);
> + return;
> + }
> +
> + res->start = irq;
> + res->end = irq;
> + res->flags = IORESOURCE_IRQ;
> + res->name = name;
> +}
> +
> +static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
> +{
> + struct acpi_iort_smmu_v3 *smmu;
> + /* Always present mem resource */
> + int num_res = 1;
> +
> + /* Retrieve SMMUv3 specific data */
> + smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
> +
> + if (smmu->event_gsiv)
> + num_res++;
> +
> + if (smmu->pri_gsiv)
> + num_res++;
> +
> + if (smmu->gerr_gsiv)
> + num_res++;
> +
> + if (smmu->sync_gsiv)
> + num_res++;
> +
> + return num_res;
> +}
> +
> +static void __init arm_smmu_v3_init_resources(struct resource *res,
> + struct acpi_iort_node *node)
> +{
> + struct acpi_iort_smmu_v3 *smmu;
> + int num_res = 0;
> +
> + /* Retrieve SMMUv3 specific data */
> + smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
> +
> + res[num_res].start = smmu->base_address;
> + res[num_res].end = smmu->base_address + SZ_128K - 1;
> + res[num_res].flags = IORESOURCE_MEM;
> +
> + num_res++;
> +
> + if (smmu->event_gsiv)
> + acpi_iort_register_irq(smmu->event_gsiv, "eventq",
> + ACPI_EDGE_SENSITIVE,
> + &res[num_res++]);
> +
> + if (smmu->pri_gsiv)
> + acpi_iort_register_irq(smmu->pri_gsiv, "priq",
> + ACPI_EDGE_SENSITIVE,
> + &res[num_res++]);
> +
> + if (smmu->gerr_gsiv)
> + acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
> + ACPI_EDGE_SENSITIVE,
> + &res[num_res++]);
> +
> + if (smmu->sync_gsiv)
> + acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
> + ACPI_EDGE_SENSITIVE,
> + &res[num_res++]);
> +}
> +
> +static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
> +{
> + struct acpi_iort_smmu_v3 *smmu;
> +
> + /* Retrieve SMMUv3 specific data */
> + smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
> +
> + return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
> +}
> +
> struct iort_iommu_config {
> const char *name;
> int (*iommu_init)(struct acpi_iort_node *node);
> @@ -434,10 +523,22 @@ struct iort_iommu_config {
> struct acpi_iort_node *node);
> };
>
> +static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
> + .name = "arm-smmu-v3",
> + .iommu_is_coherent = arm_smmu_v3_is_coherent,
> + .iommu_count_resources = arm_smmu_v3_count_resources,
> + .iommu_init_resources = arm_smmu_v3_init_resources
> +};
> +
> static __init
> const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
> {
> - return NULL;
> + switch (node->type) {
> + case ACPI_IORT_NODE_SMMU_V3:
> + return &iort_arm_smmu_v3_cfg;
> + default:
> + return NULL;
> + }
> }
>
> /**
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index dbc21e3..9463f3f 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -20,6 +20,8 @@
> * This driver is powered by bad coffee and bombay mix.
> */
>
> +#include <linux/acpi.h>
> +#include <linux/acpi_iort.h>
> #include <linux/delay.h>
> #include <linux/dma-iommu.h>
> #include <linux/err.h>
> @@ -2539,6 +2541,32 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
> + struct arm_smmu_device *smmu)
> +{
> + struct acpi_iort_smmu_v3 *iort_smmu;
> + struct device *dev = smmu->dev;
> + struct acpi_iort_node *node;
> +
> + node = *(struct acpi_iort_node **)dev_get_platdata(dev);
> +
> + /* Retrieve SMMUv3 specific data */
> + iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
> +
> + if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE)
> + smmu->features |= ARM_SMMU_FEAT_COHERENCY;
> +
> + return 0;
> +}
> +#else
> +static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
> + struct arm_smmu_device *smmu)
> +{
> + return -ENODEV;
> +}
> +#endif
> +
> static int arm_smmu_device_dt_probe(struct platform_device *pdev,
> struct arm_smmu_device *smmu)
> {
> @@ -2556,6 +2584,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
> struct resource *res;
> struct arm_smmu_device *smmu;
> struct device *dev = &pdev->dev;
> + struct fwnode_handle *fwnode;
>
> smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
> if (!smmu) {
> @@ -2592,7 +2621,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
> if (irq > 0)
> smmu->gerr_irq = irq;
>
> - ret = arm_smmu_device_dt_probe(pdev, smmu);
> + if (dev->of_node)
> + ret = arm_smmu_device_dt_probe(pdev, smmu);
> + else
> + ret = arm_smmu_device_acpi_probe(pdev, smmu);
>
> if (ret)
> return ret;
> @@ -2615,8 +2647,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> + /* FIXME: DT code path does not set up dev->fwnode pointer */
> + fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
> +
You're right, this is getting annoying. For a sample of n=1, I've just
booted a Juno with the below and nothing blew up - I'll do a bit more
homework and probably spin it into a proper patch:
---8<---
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index f39ccd5aa701..f811d2796437 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -142,6 +142,7 @@ struct platform_device *of_device_alloc(struct
device_node *np,
}
dev->dev.of_node = of_node_get(np);
+ dev->dev.fwnode = &np->fwnode;
dev->dev.parent = parent ? : &platform_bus;
if (bus_id)
@@ -241,6 +242,7 @@ static struct amba_device
*of_amba_device_create(struct device_node *node,
/* setup generic device info */
dev->dev.of_node = of_node_get(node);
+ dev->dev.fwnode = &node->fwnode;
dev->dev.parent = parent ? : &platform_bus;
dev->dev.platform_data = platform_data;
if (bus_id)
--->8---
Robin.
> /* And we're up. Go go go! */
> - fwspec_iommu_set_ops(&dev->of_node->fwnode, &arm_smmu_ops);
> + fwspec_iommu_set_ops(fwnode, &arm_smmu_ops);
> +
> #ifdef CONFIG_PCI
> pci_request_acs();
> ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
> @@ -2688,6 +2724,61 @@ static int __init arm_smmu_of_init(struct device_node *np)
> }
> IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
>
> +#ifdef CONFIG_ACPI
> +static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
> +{
> + struct acpi_iort_node *iort_node, *iort_end;
> + struct acpi_table_iort *iort;
> + struct fwnode_handle *fwnode;
> + int i, ret;
> +
> + /*
> + * table and iort will both point to the start of IORT table, but
> + * have different struct types
> + */
> + iort = (struct acpi_table_iort *)table;
> +
> + /* Get the first IORT node */
> + iort_node = ACPI_ADD_PTR(struct acpi_iort_node, table,
> + iort->node_offset);
> + iort_end = ACPI_ADD_PTR(struct acpi_iort_node, table,
> + table->length);
> +
> + for (i = 0; i < iort->node_count; i++) {
> +
> + if (iort_node >= iort_end) {
> + pr_err("iort node pointer overflows, bad table\n");
> + return -EINVAL;
> + }
> +
> + if (iort_node->type == ACPI_IORT_NODE_SMMU_V3) {
> + ret = arm_smmu_init();
> + if (ret)
> + return ret;
> +
> + fwnode = iommu_alloc_fwnode();
> +
> + if (!fwnode)
> + return -ENOMEM;
> +
> + ret = iort_set_fwnode(iort_node, fwnode);
> + if (ret)
> + goto free;
> + }
> +
> + iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
> + iort_node->length);
> + }
> +
> + return 0;
> +free:
> + iommu_free_fwnode(fwnode);
> + return ret;
> +
> +}
> +IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init);
> +#endif
> +
> MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
> MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
> MODULE_LICENSE("GPL v2");
>
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 10/14] drivers: iommu: arm-smmu: split probe functions into DT/generic portions
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (8 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 09/14] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 11/14] drivers: iommu: arm-smmu: add IORT configuration Lorenzo Pieralisi
` (2 subsequent siblings)
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
Current ARM SMMU probe functions intermingle HW and DT probing
in the initialization functions to detect and programme the ARM SMMU
driver features. In order to allow probing the ARM SMMU with other
firmwares than DT, this patch splits the ARM SMMU init functions into
DT and HW specific portions so that other FW interfaces (ie ACPI) can
reuse the HW probing functions and skip the DT portion accordingly.
This patch implements no functional change, only code reshuffling.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
---
drivers/iommu/arm-smmu.c | 65 +++++++++++++++++++++++++++++-------------------
1 file changed, 39 insertions(+), 26 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index d453c55..bdb4e26 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1665,7 +1665,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
unsigned long size;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
u32 id;
- bool cttw_dt, cttw_reg;
+ bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
int i;
dev_notice(smmu->dev, "probing hardware configuration...\n");
@@ -1710,20 +1710,17 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
/*
* In order for DMA API calls to work properly, we must defer to what
- * the DT says about coherency, regardless of what the hardware claims.
+ * the FW says about coherency, regardless of what the hardware claims.
* Fortunately, this also opens up a workaround for systems where the
* ID register value has ended up configured incorrectly.
*/
- cttw_dt = of_dma_is_coherent(smmu->dev->of_node);
cttw_reg = !!(id & ID0_CTTW);
- if (cttw_dt)
- smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
- if (cttw_dt || cttw_reg)
+ if (cttw_fw || cttw_reg)
dev_notice(smmu->dev, "\t%scoherent table walk\n",
- cttw_dt ? "" : "non-");
- if (cttw_dt != cttw_reg)
+ cttw_fw ? "" : "non-");
+ if (cttw_fw != cttw_reg)
dev_notice(smmu->dev,
- "\t(IDR0.CTTW overridden by dma-coherent property)\n");
+ "\t(IDR0.CTTW overridden by FW configuration)\n");
/* Max. number of entries we have for stream matching/indexing */
size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK);
@@ -1904,15 +1901,25 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
{
const struct arm_smmu_match_data *data;
- struct resource *res;
- struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
- int num_irqs, i, err;
bool legacy_binding;
+ if (of_property_read_u32(dev->of_node, "#global-interrupts",
+ &smmu->num_global_irqs)) {
+ dev_err(dev, "missing #global-interrupts property\n");
+ return -ENODEV;
+ }
+
+ data = of_device_get_match_data(dev);
+ smmu->version = data->version;
+ smmu->model = data->model;
+
+ parse_driver_options(smmu);
+
legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL);
if (legacy_binding && !using_generic_binding) {
pr_notice("deprecated \"mmu-masters\" DT property in use; DMA API support unavailable\n");
@@ -1924,6 +1931,19 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (of_dma_is_coherent(smmu->dev->of_node))
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device *dev = &pdev->dev;
+ int num_irqs, i, err;
+
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate arm_smmu_device\n");
@@ -1931,9 +1951,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- data = of_device_get_match_data(dev);
- smmu->version = data->version;
- smmu->model = data->model;
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+
+ if (err)
+ return err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
smmu->base = devm_ioremap_resource(dev, res);
@@ -1941,12 +1962,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return PTR_ERR(smmu->base);
smmu->size = resource_size(res);
- if (of_property_read_u32(dev->of_node, "#global-interrupts",
- &smmu->num_global_irqs)) {
- dev_err(dev, "missing #global-interrupts property\n");
- return -ENODEV;
- }
-
num_irqs = 0;
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
num_irqs++;
@@ -1981,8 +1996,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err)
return err;
- parse_driver_options(smmu);
-
if (smmu->version == ARM_SMMU_V2 &&
smmu->num_context_banks != smmu->num_context_irqs) {
dev_err(dev,
@@ -2004,7 +2017,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
}
- of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+ fwspec_iommu_set_ops(&dev->of_node->fwnode, &arm_smmu_ops);
platform_set_drvdata(pdev, smmu);
arm_smmu_device_reset(smmu);
@@ -2044,7 +2057,7 @@ static struct platform_driver arm_smmu_driver = {
.name = "arm-smmu",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 11/14] drivers: iommu: arm-smmu: add IORT configuration
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (9 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 10/14] drivers: iommu: arm-smmu: split probe functions into DT/generic portions Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 12/14] drivers: acpi: iort: replace rid map type with type mask Lorenzo Pieralisi
2016-09-09 14:23 ` [PATCH v5 14/14] drivers: acpi: iort: introduce iort_iommu_configure Lorenzo Pieralisi
12 siblings, 0 replies; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier,
Rafael J. Wysocki, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Sinan Kaya, Dennis Chen,
Tomasz Nowicki, Prem Mallappa, Jon Masters
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU components, so that the ARM SMMU driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
Cc: Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 81 ++++++++++++++++++++++++++++
drivers/iommu/arm-smmu.c | 131 +++++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_iort.h | 3 ++
3 files changed, 213 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a2ad102..a12dda9 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -514,6 +514,78 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}
+static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int num_irqs;
+ u64 *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ num_irqs = 1;
+ else
+ num_irqs = 2;
+
+ num_irqs += smmu->context_interrupt_count;
+
+ return num_irqs + 1;
+}
+
+static void __init arm_smmu_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int i, hw_irq, trigger, num_res = 0;
+ u64 *ctx_irq, *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + smmu->span - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+ num_res++;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[0]);
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[1]);
+ if (hw_irq) {
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[1]);
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+ }
+
+ /* Context IRQs */
+ ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
+ for (i = 0; i < smmu->context_interrupt_count; i++) {
+ hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+ trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
+ &res[num_res++]);
+ }
+}
+
+static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -530,12 +602,21 @@ static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.iommu_init_resources = arm_smmu_v3_init_resources
};
+static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
+ .name = "arm-smmu",
+ .iommu_is_coherent = arm_smmu_is_coherent,
+ .iommu_count_resources = arm_smmu_count_resources,
+ .iommu_init_resources = arm_smmu_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
switch (node->type) {
case ACPI_IORT_NODE_SMMU_V3:
return &iort_arm_smmu_v3_cfg;
+ case ACPI_IORT_NODE_SMMU:
+ return &iort_arm_smmu_cfg;
default:
return NULL;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index bdb4e26..a4d3030 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,8 @@
#define pr_fmt(fmt) "arm-smmu: " fmt
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
@@ -1901,6 +1903,71 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#ifdef CONFIG_ACPI
+static int acpi_smmu_get_data(u32 model, u32 *version, u32 *impl)
+{
+ int ret = 0;
+
+ switch (model) {
+ case ACPI_IORT_SMMU_V1:
+ case ACPI_IORT_SMMU_CORELINK_MMU400:
+ *version = ARM_SMMU_V1;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_V2:
+ *version = ARM_SMMU_V2;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_CORELINK_MMU500:
+ *version = ARM_SMMU_V2;
+ *impl = ARM_MMU500;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node =
+ *(struct acpi_iort_node **)dev_get_platdata(dev);
+ struct acpi_iort_smmu *iort_smmu;
+ u64 *glb_irq;
+ int ret;
+
+ /* Retrieve SMMU1/2 specific data */
+ iort_smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ ret = acpi_smmu_get_data(iort_smmu->model, &smmu->version,
+ &smmu->model);
+ if (ret < 0)
+ return ret;
+
+ glb_irq = ACPI_ADD_PTR(u64, iort_smmu,
+ iort_smmu->global_interrupt_offset);
+
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ smmu->num_global_irqs = 1;
+ else
+ smmu->num_global_irqs = 2;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
@@ -1943,6 +2010,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
int num_irqs, i, err;
+ struct fwnode_handle *fwnode;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
@@ -1951,7 +2019,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (dev->of_node)
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ else
+ err = arm_smmu_device_acpi_probe(pdev, smmu);
if (err)
return err;
@@ -2016,8 +2087,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
return err;
}
}
+ /* FIXME: DT code path does not set up dev->fwnode pointer */
+ fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
- fwspec_iommu_set_ops(&dev->of_node->fwnode, &arm_smmu_ops);
+ fwspec_iommu_set_ops(fwnode, &arm_smmu_ops);
platform_set_drvdata(pdev, smmu);
arm_smmu_device_reset(smmu);
@@ -2100,6 +2173,60 @@ IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
+{
+ struct acpi_iort_node *iort_node, *iort_end;
+ struct acpi_table_iort *iort;
+ struct fwnode_handle *fwnode;
+ int i, ret;
+
+ /*
+ * iort_table and iort both point to the start of IORT table, but
+ * have different struct types
+ */
+ iort = (struct acpi_table_iort *)table;
+
+ /* Get the first IORT node */
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+ iort->node_offset);
+ iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+ table->length);
+
+ for (i = 0; i < iort->node_count; i++) {
+ if (iort_node >= iort_end) {
+ pr_err("iort node pointer overflows, bad table\n");
+ return -EINVAL;
+ }
+
+ if (iort_node->type == ACPI_IORT_NODE_SMMU) {
+ ret = arm_smmu_init();
+ if (ret)
+ return ret;
+
+ fwnode = iommu_alloc_fwnode();
+
+ if (!fwnode)
+ return -ENOMEM;
+
+ ret = iort_set_fwnode(iort_node, fwnode);
+ if (ret)
+ goto free;
+ }
+
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+ iort_node->length);
+ }
+
+ return 0;
+free:
+ iommu_free_fwnode(fwnode);
+ return ret;
+}
+
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index c851646..1ed4f8f 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -23,6 +23,9 @@
#include <linux/fwnode.h>
#include <linux/irqdomain.h>
+#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
+
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 12/14] drivers: acpi: iort: replace rid map type with type mask
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (10 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 11/14] drivers: iommu: arm-smmu: add IORT configuration Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
[not found] ` <20160909142343.13314-13-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
2016-09-09 14:23 ` [PATCH v5 14/14] drivers: acpi: iort: introduce iort_iommu_configure Lorenzo Pieralisi
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
IORT tables provide data that allow the kernel to carry out
device ID mappings between endpoints and system components
(eg interrupt controllers, IOMMUs). When the mapping for a
given device ID is carried out, the translation mechanism
is done on a per-subsystem basis rather than a component
subtype (ie the IOMMU kernel layer will look for mappings
from a device to all IORT node types corresponding to IOMMU
components), therefore the corresponding mapping API should
work on a range (ie mask) of IORT node types corresponding
to a common set of components (eg IOMMUs) rather than a
specific node type.
Upgrade the IORT iort_node_map_rid() API to work with a
type mask instead of a single node type so that it can
be used for mappings that span multiple components types
(ie IOMMUs).
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a12dda9..36ea93e 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -25,6 +25,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#define IORT_TYPE_MASK(type) (1 << (type))
+#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+
struct iort_its_msi_chip {
struct list_head list;
struct fwnode_handle *fw_node;
@@ -283,7 +286,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
- u8 type)
+ u8 type_mask)
{
u32 rid = rid_in;
@@ -292,7 +295,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
struct acpi_iort_id_mapping *map;
int i;
- if (node->type == type) {
+ if (IORT_TYPE_MASK(node->type) & type_mask) {
if (rid_out)
*rid_out = rid;
return node;
@@ -365,7 +368,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
if (!node)
return req_id;
- iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+ iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
return dev_id;
}
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v5 14/14] drivers: acpi: iort: introduce iort_iommu_configure
[not found] ` <20160909142343.13314-1-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
` (11 preceding siblings ...)
2016-09-09 14:23 ` [PATCH v5 12/14] drivers: acpi: iort: replace rid map type with type mask Lorenzo Pieralisi
@ 2016-09-09 14:23 ` Lorenzo Pieralisi
[not found] ` <20160909142343.13314-15-lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
12 siblings, 1 reply; 35+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-09 14:23 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-acpi-u79uwXL29TY76Z2rM5mHXA, Marc Zyngier, Tomasz Nowicki,
Rafael J. Wysocki, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Will Deacon, Sinan Kaya, linux-pci-u79uwXL29TY76Z2rM5mHXA,
Jon Masters, Dennis Chen, Prem Mallappa
DT based systems have a generic kernel API to configure IOMMUs
for devices (ie of_iommu_configure()).
On ARM based ACPI systems, the of_iommu_configure() equivalent can
be implemented atop ACPI IORT kernel API, with the corresponding
functions to map device identifiers to IOMMUs and retrieve the
corresponding IOMMU operations necessary for DMA operations set-up.
By relying on the iommu_fwspec generic kernel infrastructure,
implement the IORT based IOMMU configuration for ARM ACPI systems
and hook it up in the ACPI kernel layer that implements DMA
configuration for a device.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
Cc: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Tomasz Nowicki <tn-nYOzD4b6Jr9Wk0Htik3J/w@public.gmane.org>
Cc: "Rafael J. Wysocki" <rjw-LthD3rsA81gm4RdzfppkhA@public.gmane.org>
---
drivers/acpi/arm64/iort.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 7 +++-
include/linux/acpi_iort.h | 6 +++
3 files changed, 108 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 7c68eb4..55a4ae9 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -19,6 +19,7 @@
#define pr_fmt(fmt) "ACPI: IORT: " fmt
#include <linux/acpi_iort.h>
+#include <linux/iommu-fwspec.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -27,6 +28,8 @@
#define IORT_TYPE_MASK(type) (1 << (type))
#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
+ (1 << ACPI_IORT_NODE_SMMU_V3))
struct iort_its_msi_chip {
struct list_head list;
@@ -467,6 +470,99 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+ u32 *rid = data;
+
+ *rid = alias;
+ return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+ struct fwnode_handle *fwnode)
+{
+ int ret = iommu_fwspec_init(dev, fwnode);
+
+ if (!ret)
+ ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+ return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+ struct acpi_iort_node *node,
+ u32 streamid)
+{
+ struct fwnode_handle *iort_fwnode = NULL;
+ int ret;
+
+ if (node) {
+ iort_fwnode = iort_get_fwnode(node);
+ if (!iort_fwnode)
+ return NULL;
+
+ ret = arm_smmu_iort_xlate(dev, streamid,
+ iort_fwnode);
+ if (!ret)
+ return fwspec_iommu_get_ops(iort_fwnode);
+ }
+
+ return NULL;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ * NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+ struct acpi_iort_node *node, *parent;
+ const struct iommu_ops *ops = NULL;
+ u32 streamid = 0;
+
+ if (dev_is_pci(dev)) {
+ struct pci_bus *bus = to_pci_dev(dev)->bus;
+ u32 rid;
+
+ pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+ &rid);
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_match_node_callback, &bus->dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_map_rid(node, rid, &streamid,
+ IORT_IOMMU_TYPE);
+
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ } else {
+ int i = 0;
+
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+
+ while (parent) {
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+ }
+ }
+
+ return ops;
+}
+
static void __init acpi_iort_register_irq(int hwirq, const char *name,
int trigger,
struct resource *res)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 9614232..7e56a85 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -1377,11 +1378,15 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
*/
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
+ const struct iommu_ops *iommu;
+
+ iommu = iort_iommu_configure(dev);
+
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
- arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
}
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 1ed4f8f..167649a 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -36,6 +36,8 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode);
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node);
+/* IOMMU interface */
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
@@ -49,6 +51,10 @@ static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
static inline
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
{ return NULL; }
+/* IOMMU interface */
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
--
2.10.0
^ permalink raw reply related [flat|nested] 35+ messages in thread