linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support
@ 2016-08-15 15:23 Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
                   ` (15 more replies)
  0 siblings, 16 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Marc Zyngier, Robin Murphy,
	Joerg Roedel, Rafael J. Wysocki, Tomasz Nowicki, Hanjun Guo,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

This patch series is v4 of a previous posting:

https://lkml.org/lkml/2016/7/20/248

v3 -> v4
	- Added single mapping API (for IORT named components)
	- Fixed arm_smmu_iort_xlate() return value
	- Reworked fwnode registration and platform device creation
	  ordering to fix probe ordering dependencies
	- Added code to keep device_node ref count with new iommu
	  fwspec API
	- Added patch to make iommu_fwspec arch agnostic
	- Dropped RFC status
	- Rebased against v4.8-rc2

v2 -> v3
	- Rebased on top of dependencies series [1][2][3](v4.7-rc3)
	- Added back reliance on ACPI early probing infrastructure
	- Patch[1-3] merged through other dependent series
	- Added back IOMMU fwnode generalization
	- Move SMMU v3 static functions configuration to IORT code
	- Implemented generic IOMMU fwspec API
	- Added code to implement fwnode platform device look-up

v1 -> v2:
	- Rebased on top of dependencies series [1][2][3](v4.7-rc1)
	- Removed IOMMU fwnode generalization
	- Implemented ARM SMMU v3 ACPI probing instead of ARM SMMU v2
	  owing to patch series dependencies [1]
	- Moved platform device creation logic to IORT code to
	  generalize its usage for ARM SMMU v1-v2-v3 components
	- Removed reliance on ACPI early device probing
	- Created IORT specific iommu_xlate() translation hook leaving
	  OF code unchanged according to v1 reviews

The ACPI IORT table provides information that allows instantiating
ARM SMMU devices and carrying out id mappings between components on
ARM based systems (devices, IOMMUs, interrupt controllers).

http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf

Building on basic IORT support, available through [2],
this patchset enables ARM SMMU v3 support on ACPI systems.

Most of the code is aimed at building the required generic ACPI
infrastructure to create and enable IOMMU components and to bring
the IOMMU infrastructure for ACPI on par with DT, which is going to
make future ARM SMMU components easier to integrate.

PATCH (1) adds a FWNODE_IOMMU type to the struct fwnode_handle type.
          It is required to attach a fwnode identifier to platform
          devices allocated/detected through IORT tables entries;
          IOMMU devices have to have an identifier to look them up
          eg IOMMU core layer carrying out id translation. This can be
          done through a fwnode_handle (ie IOMMU platform devices created
          out of IORT tables are not ACPI devices hence they can't be
          allocated as such, otherwise they would have a fwnode_handle of
          type FWNODE_ACPI).

PATCH (2) Add kernel infrastructure to make the struct iommu_fwspec
          handling arch agnostic and generic.

PATCH (3) makes use of the ACPI early probing API to add a linker script
          section for probing devices via IORT ACPI kernel code.

PATCH (4) provides IORT support for registering IOMMU IORT node through
          their fwnode handle.

PATCH (5) implements core code fwnode based platform devices look-up.

PATCH (6) extends iommu_fwspec so that it can be used on ACPI based
          system by creating a generic IOMMU fwspec kernel layer.

PATCH (7) implements the of_dma_configure() API in ACPI world -
          acpi_dma_configure() - and patches PCI and ACPI core code to
          start making use of it.

PATCH (8) provides an IORT function to detect existence of specific type
          of IORT components.

PATCH (9) creates the kernel infrastructure required to create ARM SMMU
          platform devices for IORT nodes.

PATCH (10) refactors the ARM SMMU v3 driver so that the init functions are
           split in a way that groups together code that probes through DT
           and code that carries out HW registers FW agnostic probing, in
           preparation for adding the ACPI probing path.

PATCH (11) rework ARM SMMU v3 platform driver registration to make it work
           on ACPI systems.

PATCH (12) Building on patch (9), it adds ARM SMMU v3 IORT IOMMU
           operations to create and probe ARM SMMU v3 components.

PATCH (13) Extend the IORT iort_node_map_rid() to work on a type mask
           instead of a single type so that the translation API can
           be used on a range of components.

PATCH (14) Add IORT API to carry out id mappings for components that do
           do not have an input identifier/RIDs (ie named components).

PATCH (15) provides IORT infrastructure to carry out IOMMU configuration
           for devices and hook it up to the previously introduced ACPI
           DMA configure API.

This patchset is built on top and depends on these two patch series:

[1] R.Murphy "Generic DT bindings for PCI and ARM SMMU v3" v4
    https://marc.info/?l=devicetree&m=146739193215518&w=2

[2] T.Nowicki "Introduce ACPI world to ITS irqchip" v8
    https://marc.info/?l=linux-kernel&m=147091000919640&w=2

and is provided for early review/testing purposes here:

git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git acpi/iort-smmu-v4

Tested on FVP models for ARM SMMU v3 probing path.

Lorenzo Pieralisi (15):
  drivers: iommu: add FWNODE_IOMMU fwnode type
  drivers: iommu: implement arch_{set/get}_iommu_fwspec API
  drivers: acpi: iort: introduce linker section for IORT entries probing
  drivers: acpi: iort: add support for IOMMU fwnode registration
  drivers: platform: add fwnode base platform devices retrieval
  drivers: iommu: make iommu_fwspec OF agnostic
  drivers: acpi: implement acpi_dma_configure
  drivers: acpi: iort: add node match function
  drivers: acpi: iort: add support for ARM SMMU platform devices
    creation
  drivers: iommu: arm-smmu-v3: split probe functions into DT/generic
    portions
  drivers: iommu: arm-smmu-v3: enable ACPI driver initialization
  drivers: iommu: arm-smmu-v3: add IORT configuration
  drivers: acpi: iort: replace rid map type with type mask
  drivers: acpi: iort: add single mapping function
  drivers: acpi: iort: introduce iort_iommu_configure

 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/acpi/arm64/iort.c             | 481 +++++++++++++++++++++++++++++++++-
 drivers/acpi/glue.c                   |   4 +-
 drivers/acpi/scan.c                   |  29 ++
 drivers/base/platform.c               |  23 ++
 drivers/iommu/Kconfig                 |   7 +
 drivers/iommu/Makefile                |   1 +
 drivers/iommu/arm-smmu-v3.c           | 150 +++++++++--
 drivers/iommu/iommu-fwspec.c          | 126 +++++++++
 drivers/iommu/of_iommu.c              |  91 -------
 drivers/pci/probe.c                   |   3 +-
 include/acpi/acpi_bus.h               |   2 +
 include/asm-generic/vmlinux.lds.h     |   1 +
 include/linux/acpi.h                  |   5 +
 include/linux/fwnode.h                |   1 +
 include/linux/iommu-fwspec.h          |  70 +++++
 include/linux/iommu.h                 |  25 ++
 include/linux/iort.h                  |  18 ++
 include/linux/of_iommu.h              |  28 +-
 include/linux/platform_device.h       |   3 +
 23 files changed, 995 insertions(+), 135 deletions(-)
 create mode 100644 arch/arm/include/asm/iommu-fwspec.h
 create mode 100644 arch/arm64/include/asm/iommu-fwspec.h
 create mode 100644 drivers/iommu/iommu-fwspec.c
 create mode 100644 include/linux/iommu-fwspec.h

-- 
2.6.4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-23 13:49   ` Lorenzo Pieralisi
  2016-09-05 11:11   ` Hanjun Guo
  2016-08-15 15:23 ` [PATCH v4 02/15] drivers: iommu: implement arch_{set/get}_iommu_fwspec API Lorenzo Pieralisi
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Joerg Roedel, Rafael J. Wysocki, Will Deacon,
	Marc Zyngier, Robin Murphy, Tomasz Nowicki, Hanjun Guo,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 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..6f703cb 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_ATOMIC);
+	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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 02/15] drivers: iommu: implement arch_{set/get}_iommu_fwspec API
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Rob Herring, Robin Murphy,
	Joerg Roedel, Rafael J. Wysocki, Marc Zyngier, Tomasz Nowicki,
	Hanjun Guo, Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen,
	linux-acpi, linux-pci, linux-kernel, linux-arm-kernel

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@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 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              | 12 ++++++------
 include/linux/of_iommu.h              | 10 ++++++++++
 7 files changed, 81 insertions(+), 6 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 bec51eb..e30f860 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -222,7 +222,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;
@@ -233,13 +233,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);
@@ -249,7 +249,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;
 
 	if (!fwspec)
@@ -263,11 +263,11 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
 	while (num_ids--)
 		fwspec->ids[fwspec->num_ids++] = *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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 02/15] drivers: iommu: implement arch_{set/get}_iommu_fwspec API Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-09-05 11:42   ` Hanjun Guo
  2016-08-15 15:23 ` [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Tomasz Nowicki, Rafael J. Wysocki,
	Marc Zyngier, Will Deacon, Robin Murphy, Joerg Roedel,
	Hanjun Guo, Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen,
	linux-acpi, linux-pci, linux-kernel, linux-arm-kernel

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@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/acpi/arm64/iort.c         | 2 ++
 include/asm-generic/vmlinux.lds.h | 1 +
 include/linux/iort.h              | 3 +++
 3 files changed, 6 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 2543f60..cad7d1d 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -383,4 +383,6 @@ void __init iort_table_detect(void)
 		const char *msg = acpi_format_exception(status);
 		pr_err("Failed to get table, %s\n", msg);
 	}
+
+	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/iort.h b/include/linux/iort.h
index d7daba1..9bb30c5 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -38,4 +38,7 @@ static inline struct irq_domain *
 iort_get_device_domain(struct device *dev, u32 req_id) { return NULL; }
 #endif
 
+#define IORT_ACPI_DECLARE(name, table_id, fn)		\
+	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
+
 #endif /* __IORT_H__ */
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (2 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-09-05 13:00   ` Hanjun Guo
  2016-08-15 15:23 ` [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval Lorenzo Pieralisi
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@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 | 65 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iort.h      |  8 ++++++
 2 files changed, 73 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index cad7d1d..01a5258 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -20,7 +20,9 @@
 
 #include <linux/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/iort.h b/include/linux/iort.h
index 9bb30c5..666a3de 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -30,12 +30,20 @@ struct fwnode_handle *iort_find_domain_token(int trans_id);
 void iort_table_detect(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 iort_table_detect(void) { }
 static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 { return 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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (3 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-09-05 13:19   ` Hanjun Guo
  2016-08-15 15:23 ` [PATCH v4 06/15] drivers: iommu: make iommu_fwspec OF agnostic Lorenzo Pieralisi
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Greg Kroah-Hartman, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Tomasz Nowicki, Hanjun Guo, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

The platform device kernel API does not provide functions to
retrieve a platform device through the corresponding struct
device fwnode pointer.

Implement the fwnode platform_device look-up in drivers core
code by using the bus_find_device() API and a corresponding
matching function. The OF equivalent (eg of_find_device_by_node())
will reuse the newly introduced function when OF code will
take care of setting up the device->fwnode value that is
currently left dangling for platform devices instantiated out
of device tree nodes.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
 drivers/base/platform.c         | 23 +++++++++++++++++++++++
 include/linux/platform_device.h |  3 +++
 2 files changed, 26 insertions(+)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 6482d47..3ef150d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -760,6 +760,29 @@ err_out:
 }
 EXPORT_SYMBOL_GPL(__platform_create_bundle);
 
+static int fwnode_dev_match(struct device *dev, void *data)
+{
+	return dev->fwnode == data;
+}
+
+/**
+ * platform_find_device_by_fwnode() - Find the platform_device associated
+ *				      with a fwnode
+ * @fwnode: Pointer to firmware node
+ *
+ * Returns platform_device pointer, or NULL if not found
+ */
+struct platform_device *
+platform_find_device_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&platform_bus_type, NULL, fwnode,
+			      fwnode_dev_match);
+	return dev ? to_platform_device(dev) : NULL;
+}
+EXPORT_SYMBOL(platform_find_device_by_fwnode);
+
 /**
  * __platform_register_drivers - register an array of platform drivers
  * @drivers: an array of drivers to register
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 98c2a7c..01a3eb2 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -276,6 +276,9 @@ extern struct platform_device *__platform_create_bundle(
 	struct resource *res, unsigned int n_res,
 	const void *data, size_t size, struct module *module);
 
+extern struct platform_device *
+platform_find_device_by_fwnode(struct fwnode_handle *fwnode);
+
 int __platform_register_drivers(struct platform_driver * const *drivers,
 				unsigned int count, struct module *owner);
 void platform_unregister_drivers(struct platform_driver * const *drivers,
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 06/15] drivers: iommu: make iommu_fwspec OF agnostic
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (4 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 07/15] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Hanjun Guo, Robin Murphy,
	Joerg Roedel, Marc Zyngier, Rafael J. Wysocki, Tomasz Nowicki,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
 drivers/iommu/Kconfig        |   4 ++
 drivers/iommu/Makefile       |   1 +
 drivers/iommu/arm-smmu-v3.c  |  13 +++--
 drivers/iommu/iommu-fwspec.c | 126 +++++++++++++++++++++++++++++++++++++++++++
 drivers/iommu/of_iommu.c     |  91 -------------------------------
 include/linux/iommu-fwspec.h |  70 ++++++++++++++++++++++++
 include/linux/of_iommu.h     |  38 ++++---------
 7 files changed, 221 insertions(+), 122 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 7bf99af..6b68232 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>
@@ -1734,9 +1735,13 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
 	return ret;
 }
 
-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 *handle)
 {
-	struct platform_device *smmu_pdev = of_find_device_by_node(np);
+	struct platform_device *smmu_pdev = NULL;
+
+	if (is_of_node(handle))
+		smmu_pdev = of_find_device_by_node(to_of_node(handle));
 
 	if (!smmu_pdev)
 		return NULL;
@@ -1775,7 +1780,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);
@@ -1887,7 +1892,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/iommu-fwspec.c b/drivers/iommu/iommu-fwspec.c
new file mode 100644
index 0000000..13644c8
--- /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(dev->archdata.iommu, 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 e30f860..e429492 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;
@@ -219,55 +180,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;
-
-	if (!fwspec)
-		return -EINVAL;
-
-	size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
-	fwspec = krealloc(dev->archdata.iommu, 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/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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 07/15] drivers: acpi: implement acpi_dma_configure
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (5 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 06/15] drivers: iommu: make iommu_fwspec OF agnostic Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 08/15] drivers: acpi: iort: add node match function Lorenzo Pieralisi
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Bjorn Helgaas, Robin Murphy, Tomasz Nowicki,
	Joerg Roedel, Rafael J. Wysocki, Will Deacon, Marc Zyngier,
	Hanjun Guo, Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen,
	linux-acpi, linux-pci, linux-kernel, linux-arm-kernel

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 ad9fc84..0bdc98e 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 4d8452c..b347782 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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 08/15] drivers: acpi: iort: add node match function
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (6 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 07/15] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

Device drivers (eg ARM SMMU) need to know if a specific component
is part of the IORT table, so that kernel data structures are not
initialized at initcalls time if the respective component is not
part of the IORT table.

To this end, this patch adds a trivial function that allows detecting
if a given IORT node type is present or not in the ACPI table, providing
an ACPI IORT equivalent for of_find_matching_node().

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 | 15 +++++++++++++++
 include/linux/iort.h      |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 01a5258..f6db3d8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -205,6 +205,21 @@ iort_scan_node(enum acpi_iort_node_type type,
 }
 
 static acpi_status
+iort_match_callback(struct acpi_iort_node *node, void *context)
+{
+	return AE_OK;
+}
+
+bool iort_node_match(u8 type)
+{
+	struct acpi_iort_node *node;
+
+	node = iort_scan_node(type, iort_match_callback, NULL);
+
+	return node != NULL;
+}
+
+static acpi_status
 iort_match_node_callback(struct acpi_iort_node *node, void *context)
 {
 	struct device *dev = context;
diff --git a/include/linux/iort.h b/include/linux/iort.h
index 666a3de..bf37aaf 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -27,6 +27,7 @@ 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);
 #ifdef CONFIG_IORT_TABLE
+bool iort_node_match(u8 type);
 void iort_table_detect(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);
@@ -34,6 +35,7 @@ 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 bool iort_node_match(u8 type) { return false; }
 static inline void iort_table_detect(void) { }
 static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 { return req_id; }
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (7 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 08/15] drivers: acpi: iort: add node match function Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-18 10:50   ` Dennis Chen
  2016-08-15 15:23 ` [PATCH v4 10/15] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions Lorenzo Pieralisi
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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 | 153 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index f6db3d8..4043071 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 {
@@ -454,6 +455,157 @@ 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 const struct iort_iommu_config * __init
+iort_get_iommu_config(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_config(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 void __init iort_smmu_init(void)
+{
+	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 *)iort_table;
+
+	/* Get the first IORT node */
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				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;
+		}
+
+		if (iort_node->type == ACPI_IORT_NODE_SMMU ||
+		    iort_node->type == ACPI_IORT_NODE_SMMU_V3) {
+			fwnode = iort_get_fwnode(iort_node);
+
+			if (!fwnode)
+				continue;
+
+			ret = iort_add_smmu_platform_device(fwnode,
+							    iort_node);
+			if (ret) {
+				pr_err("Error in platform device creation\n");
+				return;
+			}
+		}
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+}
+
 void __init iort_table_detect(void)
 {
 	acpi_status status;
@@ -465,4 +617,5 @@ void __init iort_table_detect(void)
 	}
 
 	acpi_probe_device_table(iort);
+	iort_smmu_init();
 }
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 10/15] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (8 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 11/15] drivers: iommu: arm-smmu-v3: enable ACPI driver initialization Lorenzo Pieralisi
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Hanjun Guo, Robin Murphy,
	Joerg Roedel, Marc Zyngier, Rafael J. Wysocki, Tomasz Nowicki,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
 drivers/iommu/arm-smmu-v3.c | 63 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 52 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 6b68232..91a7600 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -20,6 +20,7 @@
  * This driver is powered by bad coffee and bombay mix.
  */
 
+#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/dma-iommu.h>
 #include <linux/err.h>
@@ -27,6 +28,7 @@
 #include <linux/iommu.h>
 #include <linux/iommu-fwspec.h>
 #include <linux/iopoll.h>
+#include <linux/iort.h>
 #include <linux/module.h>
 #include <linux/msi.h>
 #include <linux/of.h>
@@ -2373,10 +2375,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);
@@ -2428,13 +2430,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");
@@ -2555,7 +2553,44 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+#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)
+{
+	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;
@@ -2597,10 +2632,16 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 	if (irq > 0)
 		smmu->gerr_irq = irq;
 
-	parse_driver_options(smmu);
+	if (acpi_disabled)
+		ret = arm_smmu_device_dt_probe(pdev, smmu);
+	else
+		ret = arm_smmu_device_acpi_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;
 
@@ -2635,7 +2676,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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 11/15] drivers: iommu: arm-smmu-v3: enable ACPI driver initialization
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (9 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 10/15] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 12/15] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Robin Murphy, Joerg Roedel,
	Marc Zyngier, Rafael J. Wysocki, Tomasz Nowicki, Hanjun Guo,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

On systems booting with ACPI that enable the ARM SMMU components
in the kernel config options, the ARM SMMU v3 init function
(ie arm_smmu_init(), that registers the driver and sets-up bus
iommu operations) does not run only because the device tree interface
(of_find_matching_node()) fails to find the respective device tree
nodes for ARM SMMU devices.

This works as long as there are no ARM SMMU devices to be probed
with ACPI. If ARM SMMU v3 components are part of the IORT tables,
for them to be instantiated and probed the function registering
the ARM SMMU v3 driver must be able to register the driver and
initialize the bus IOMMU operations accordingly.

This patch changes the logic in arm-smmu-v3 init call to allow
for it to be probed in ACPI systems.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
 drivers/iommu/arm-smmu-v3.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 91a7600..75b78f9 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2689,11 +2689,16 @@ static int __init arm_smmu_init(void)
 	if (registered)
 		return 0;
 
-	np = of_find_matching_node(NULL, arm_smmu_of_match);
-	if (!np)
-		return 0;
+	if (acpi_disabled) {
+		np = of_find_matching_node(NULL, arm_smmu_of_match);
+		if (!np)
+			return 0;
 
-	of_node_put(np);
+		of_node_put(np);
+	} else {
+		if (!iort_node_match(ACPI_IORT_NODE_SMMU_V3))
+			return 0;
+	}
 
 	ret = platform_driver_register(&arm_smmu_driver);
 	if (ret)
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 12/15] drivers: iommu: arm-smmu-v3: add IORT configuration
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (10 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 11/15] drivers: iommu: arm-smmu-v3: enable ACPI driver initialization Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 13/15] drivers: acpi: iort: replace rid map type with type mask Lorenzo Pieralisi
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Will Deacon, Robin Murphy, Joerg Roedel,
	Marc Zyngier, Rafael J. Wysocki, Tomasz Nowicki, Hanjun Guo,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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 |  61 ++++++++++++++++++++++++++
 2 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4043071..f42cff8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -455,6 +455,95 @@ 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);
@@ -464,10 +553,22 @@ struct iort_iommu_config {
 				     struct acpi_iort_node *node);
 };
 
+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 const struct iort_iommu_config * __init
 iort_get_iommu_config(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 75b78f9..197e78f 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1744,6 +1744,8 @@ arm_smmu_get_by_fwnode(struct fwnode_handle *handle)
 
 	if (is_of_node(handle))
 		smmu_pdev = of_find_device_by_node(to_of_node(handle));
+	else if (is_fwnode_iommu(handle))
+		smmu_pdev = platform_find_device_by_fwnode(handle);
 
 	if (!smmu_pdev)
 		return NULL;
@@ -1766,6 +1768,7 @@ static struct iommu_ops arm_smmu_ops;
 static int arm_smmu_add_device(struct device *dev)
 {
 	int i, ret;
+
 	struct arm_smmu_device *smmu;
 	struct arm_smmu_master_data *master;
 	struct iommu_fwspec *fwspec = dev_iommu_fwspec(dev);
@@ -2744,6 +2747,64 @@ 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;
+
+			fwspec_iommu_set_ops(fwnode, &arm_smmu_ops);
+		}
+
+		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");
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 13/15] drivers: acpi: iort: replace rid map type with type mask
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (11 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 12/15] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 14/15] drivers: acpi: iort: add single mapping function Lorenzo Pieralisi
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@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 | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index f42cff8..a04a1d2 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;
@@ -299,7 +302,7 @@ iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, u32 *rid_out)
 
 static struct acpi_iort_node *
 iort_node_map_rid(struct acpi_iort_node *node, u32 rid_in,
-		  u32 *rid_out, u8 type)
+		  u32 *rid_out, u8 type_mask)
 {
 	u32 rid = rid_in;
 
@@ -308,7 +311,7 @@ iort_node_map_rid(struct acpi_iort_node *node, u32 rid_in,
 		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;
@@ -386,7 +389,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 		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;
 }
 
@@ -411,7 +414,7 @@ iort_dev_find_its_id(struct device *dev, u32 req_id, unsigned int idx,
 		return -ENXIO;
 	}
 
-	node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+	node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
 	if (!node) {
 		dev_err(dev, "can't find related ITS node\n");
 		return -ENXIO;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 14/15] drivers: acpi: iort: add single mapping function
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (12 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 13/15] drivers: acpi: iort: replace rid map type with type mask Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-08-15 15:23 ` [PATCH v4 15/15] drivers: acpi: iort: introduce iort_iommu_configure Lorenzo Pieralisi
  2016-09-05  9:41 ` [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Hanjun Guo
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

The current IORT id mapping API requires components to provide
an input requester ID (a Bus-Device-Function (BDF) identifier for
PCI devices) to translate an input identifier to an output
identifier through an IORT range mapping.

Named components do not have an identifiable source ID therefore
their respective input/output mapping can only be defined in
IORT tables through single mappings, that provide a translation
that does not require any input identifier.

Current IORT interface for requester id mappings (iort_node_map_rid())
is not suitable for components that do not provide a requester id,
so it cannot be used for IORT named components.

Add an interface to the IORT API to enable retrieval of id
by allowing an indexed walk of the single mappings array for
a given component, therefore completing the IORT mapping API.

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 | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a04a1d2..e68ed2c 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -301,6 +301,44 @@ iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, u32 *rid_out)
 }
 
 static struct acpi_iort_node *
+iort_node_get_id(struct acpi_iort_node *node, u32 *id_out,
+		 u8 type_mask, int index)
+{
+	struct acpi_iort_node *parent;
+	struct acpi_iort_id_mapping *map;
+
+	if (!node->mapping_offset || !node->mapping_count ||
+				     index >= node->mapping_count)
+		return NULL;
+
+	map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+			   node->mapping_offset);
+
+	/* Firmware bug! */
+	if (!map->output_reference) {
+		pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+		       node, node->type);
+		return NULL;
+	}
+
+	parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+			       map->output_reference);
+
+	if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+		return NULL;
+
+	if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*id_out = map[index].output_base;
+			return parent;
+		}
+	}
+
+	return NULL;
+}
+
+static struct acpi_iort_node *
 iort_node_map_rid(struct acpi_iort_node *node, u32 rid_in,
 		  u32 *rid_out, u8 type_mask)
 {
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 15/15] drivers: acpi: iort: introduce iort_iommu_configure
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (13 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 14/15] drivers: acpi: iort: add single mapping function Lorenzo Pieralisi
@ 2016-08-15 15:23 ` Lorenzo Pieralisi
  2016-09-05  9:41 ` [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Hanjun Guo
  15 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-15 15:23 UTC (permalink / raw)
  To: iommu
  Cc: Lorenzo Pieralisi, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

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@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 | 96 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/scan.c       |  7 +++-
 include/linux/iort.h      |  5 +++
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index e68ed2c..c231629 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -18,6 +18,7 @@
 
 #define pr_fmt(fmt)	"ACPI: IORT: " fmt
 
+#include <linux/iommu-fwspec.h>
 #include <linux/iort.h>
 #include <linux/kernel.h>
 #include <linux/list.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;
@@ -496,6 +499,99 @@ 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 0bdc98e..e875537 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/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/iort.h b/include/linux/iort.h
index bf37aaf..1b6c50d 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -34,6 +34,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 bool iort_node_match(u8 type) { return false; }
 static inline void iort_table_detect(void) { }
@@ -46,6 +48,9 @@ static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
 { return -ENODEV; }
 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.6.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation
  2016-08-15 15:23 ` [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
@ 2016-08-18 10:50   ` Dennis Chen
  2016-08-18 10:55     ` Lorenzo Pieralisi
  0 siblings, 1 reply; 26+ messages in thread
From: Dennis Chen @ 2016-08-18 10:50 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, Sinan Kaya, Nate Watterson, linux-acpi, linux-pci,
	linux-kernel, linux-arm-kernel, nd

Hi Lorenzo,

On Mon, Aug 15, 2016 at 04:23:34PM +0100, 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 | 153 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 153 insertions(+)
> 
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index f6db3d8..4043071 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 {
> @@ -454,6 +455,157 @@ 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 const struct iort_iommu_config * __init
> +iort_get_iommu_config(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_config(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 void __init iort_smmu_init(void)
> +{
> +	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 *)iort_table;
>
If the firmware of a platform happens to miss the IORT table, then iort_table here
will be a NULL pointer, in this case 'NULL pointer dereference' kernel panic will occur, 
if this is not an expected behavior then we can add a sanity check here to avoid this. 
IORT missing is a fatal error? I don't think so.

Thanks,
Dennis
> +
> +	/* Get the first IORT node */
> +	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
> +				 iort->node_offset);
> +	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
> +				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;
> +		}
> +
> +		if (iort_node->type == ACPI_IORT_NODE_SMMU ||
> +		    iort_node->type == ACPI_IORT_NODE_SMMU_V3) {
> +			fwnode = iort_get_fwnode(iort_node);
> +
> +			if (!fwnode)
> +				continue;
> +
> +			ret = iort_add_smmu_platform_device(fwnode,
> +							    iort_node);
> +			if (ret) {
> +				pr_err("Error in platform device creation\n");
> +				return;
> +			}
> +		}
> +
> +		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
> +					 iort_node->length);
> +	}
> +}
> +
>  void __init iort_table_detect(void)
>  {
>  	acpi_status status;
> @@ -465,4 +617,5 @@ void __init iort_table_detect(void)
>  	}
>  
>  	acpi_probe_device_table(iort);
> +	iort_smmu_init();
>  }
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation
  2016-08-18 10:50   ` Dennis Chen
@ 2016-08-18 10:55     ` Lorenzo Pieralisi
  0 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-18 10:55 UTC (permalink / raw)
  To: Dennis Chen
  Cc: iommu, Hanjun Guo, Tomasz Nowicki, Rafael J. Wysocki,
	Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Jon Masters, Sinan Kaya, Nate Watterson, linux-acpi, linux-pci,
	linux-kernel, linux-arm-kernel, nd

On Thu, Aug 18, 2016 at 06:50:07PM +0800, Dennis Chen wrote:

[...]

> > +static void __init iort_smmu_init(void)
> > +{
> > +	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 *)iort_table;
> >
> If the firmware of a platform happens to miss the IORT table, then
> iort_table here will be a NULL pointer, in this case 'NULL pointer
> dereference' kernel panic will occur, if this is not an expected
> behavior then we can add a sanity check here to avoid this.  IORT
> missing is a fatal error? I don't think so.

Yes, I've already fixed it, thanks for pointing that out.

Lorenzo

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type
  2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
@ 2016-08-23 13:49   ` Lorenzo Pieralisi
  2016-09-05 11:11   ` Hanjun Guo
  1 sibling, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-08-23 13:49 UTC (permalink / raw)
  To: iommu, rjw
  Cc: Joerg Roedel, Will Deacon, Marc Zyngier, Robin Murphy,
	Tomasz Nowicki, Hanjun Guo, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

Hi Rafael,

On Mon, Aug 15, 2016 at 04:23:26PM +0100, Lorenzo Pieralisi wrote:
> 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@arm.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
>  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,
>  };

Are you ok with this fwnode usage ? It is quite key to the rest
of this series and I would need to know in order to make progress
on it please.

Platform devices created out of IORT tables are not ACPI devices
(I could create fake ones as we do for FADT power button, I do not
see any particular reason to prefer that approach over this one) and
in order to identify the device through a fwnode_handle (that, as for
IRQCHIP is nothing but a token used for look-up) that's what I came
up with.

Any feedback on the rest of the series is very welcome and needed
too, thanks.

Lorenzo

>  struct fwnode_handle {
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index a35fb8b..6f703cb 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_ATOMIC);
> +	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.6.4
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support
  2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
                   ` (14 preceding siblings ...)
  2016-08-15 15:23 ` [PATCH v4 15/15] drivers: acpi: iort: introduce iort_iommu_configure Lorenzo Pieralisi
@ 2016-09-05  9:41 ` Hanjun Guo
  15 siblings, 0 replies; 26+ messages in thread
From: Hanjun Guo @ 2016-09-05  9:41 UTC (permalink / raw)
  To: Lorenzo Pieralisi, iommu
  Cc: Will Deacon, Marc Zyngier, Robin Murphy, Joerg Roedel,
	Rafael J. Wysocki, Tomasz Nowicki, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> This patch series is v4 of a previous posting:
>
> https://lkml.org/lkml/2016/7/20/248
>
> v3 -> v4
> 	- Added single mapping API (for IORT named components)

Thanks, and it works for my platform msi patch set too :)

> 	- Fixed arm_smmu_iort_xlate() return value
> 	- Reworked fwnode registration and platform device creation
> 	  ordering to fix probe ordering dependencies
> 	- Added code to keep device_node ref count with new iommu
> 	  fwspec API
> 	- Added patch to make iommu_fwspec arch agnostic
> 	- Dropped RFC status
> 	- Rebased against v4.8-rc2
>

[...]
>
> The ACPI IORT table provides information that allows instantiating
> ARM SMMU devices and carrying out id mappings between components on
> ARM based systems (devices, IOMMUs, interrupt controllers).
>
> http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf
>
> Building on basic IORT support, available through [2],
> this patchset enables ARM SMMU v3 support on ACPI systems.
>
> Most of the code is aimed at building the required generic ACPI
> infrastructure to create and enable IOMMU components and to bring
> the IOMMU infrastructure for ACPI on par with DT, which is going to
> make future ARM SMMU components easier to integrate.

[...]
>
> This patchset is built on top and depends on these two patch series:
>
> [1] R.Murphy "Generic DT bindings for PCI and ARM SMMU v3" v4
>     https://marc.info/?l=devicetree&m=146739193215518&w=2
>
> [2] T.Nowicki "Introduce ACPI world to ITS irqchip" v8
>     https://marc.info/?l=linux-kernel&m=147091000919640&w=2
>
> and is provided for early review/testing purposes here:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git acpi/iort-smmu-v4
>
> Tested on FVP models for ARM SMMU v3 probing path.

I tested this patch set on Hisilicon D03 board, with the ehci platform
driver loaded, on D03, ehci is using stream id 0x40080 when SMMU is
enabled, here is the IORT table entries I used:

[0004]                          Signature : "IORT"    [IO Remapping Table]
[0004]                       Table Length : 0000029e
[0001]                           Revision : 00
[0001]                           Checksum : BC
[0006]                             Oem ID : "HISI "
[0008]                       Oem Table ID : "HISI1610"
[0004]                       Oem Revision : 00000000
[0004]                    Asl Compiler ID : "INTL"
[0004]              Asl Compiler Revision : 20151124

[0004]                         Node Count : 00000008
[0004]                        Node Offset : 00000034
[0004]                           Reserved : 00000000
[0004]                   Optional Padding : 00 00 00 00

/* ITS 0, for dsa */
[0001]                               Type : 00
[0002]                             Length : 0018
[0001]                           Revision : 00
[0004]                           Reserved : 00000000
[0004]                      Mapping Count : 00000000
[0004]                     Mapping Offset : 00000000

[0004]                           ItsCount : 00000001
[0004]                        Identifiers : 00000000

/* SMMU PCIE */
[0001]                               Type : 04
[0002]                             Length : 003C
[0001]                           Revision : 00
[0004]                           Reserved : 00000000
[0004]                      Mapping Count : 00000001
[0004]                     Mapping Offset : 0000003C

[0008]                       Base Address : A0040000
[0004]              Flags (decoded below) : 00000001
                           COHACC Override : 1
                             HTTU Override : 0
[0004]                           Reserved : 00000000
[0008]                      VATOS Address : 0
[0004]                              Model : 00000000
[0004]                    Event Interrupt : 00000000
[0004]                      PRI Interrupt : 00000000
[0004]                     GERR Interrupt : 00000000
[0004]                     Sync Interrupt : 00000000

[...]

/* usb named component */
[0001]                               Type : 01
[0002]                             Length : 0046
[0001]                           Revision : 00
[0004]                           Reserved : 00000000
[0004]                      Mapping Count : 00000001
[0004]                     Mapping Offset : 00000032

[0004]                         Node Flags : 00000000
[0008]                  Memory Properties : [IORT Memory Access Properties]
[0004]                    Cache Coherency : 00000000
[0001]              Hints (decoded below) : 00
                                 Transient : 0
                            Write Allocate : 0
                             Read Allocate : 0
                                  Override : 0
[0002]                           Reserved : 0000
[0001]       Memory Flags (decoded below) : 00
                                 Coherency : 0
                          Device Attribute : 0
[0001]                  Memory Size Limit : 00
[0016]                        Device Name : "\_SB_.USB0"
[0004]                            Padding : 00 00 00 00

[0004]                         Input base : 00000000
[0004]                           ID Count : 00000001
[0004]                        Output Base : 00040080
[0004]                   Output Reference : 0000004C /* point to smmu 
pcie */
[0004]              Flags (decoded below) : 00000001
                            Single Mapping : 1

I mounted a USB storage and copy the data (should trigger the DMA :)),
and it works fine (if the wrong stream id is configured, I can't
find the USB storage). So with this patch set:

Tested-by: Hanjun Guo <hanjun.guo@linaro.org>

I think I also test Robin's SMMUv3 patchset for supporting no-pci
devices.

Thanks
Hanjun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type
  2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
  2016-08-23 13:49   ` Lorenzo Pieralisi
@ 2016-09-05 11:11   ` Hanjun Guo
  1 sibling, 0 replies; 26+ messages in thread
From: Hanjun Guo @ 2016-09-05 11:11 UTC (permalink / raw)
  To: Lorenzo Pieralisi, iommu
  Cc: Joerg Roedel, Rafael J. Wysocki, Will Deacon, Marc Zyngier,
	Robin Murphy, Tomasz Nowicki, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> 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@arm.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
>  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..6f703cb 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_ATOMIC);
> +	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 */
>

This is the similar mechanism as FWNODE_IRQCHIP as mentioned in
change log,

Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>

Thanks
Hanjun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing
  2016-08-15 15:23 ` [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
@ 2016-09-05 11:42   ` Hanjun Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Hanjun Guo @ 2016-09-05 11:42 UTC (permalink / raw)
  To: Lorenzo Pieralisi, iommu
  Cc: Tomasz Nowicki, Rafael J. Wysocki, Marc Zyngier, Will Deacon,
	Robin Murphy, Joerg Roedel, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> 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@arm.com>
> Cc: Tomasz Nowicki <tn@semihalf.com>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  drivers/acpi/arm64/iort.c         | 2 ++
>  include/asm-generic/vmlinux.lds.h | 1 +
>  include/linux/iort.h              | 3 +++
>  3 files changed, 6 insertions(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 2543f60..cad7d1d 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -383,4 +383,6 @@ void __init iort_table_detect(void)
>  		const char *msg = acpi_format_exception(status);
>  		pr_err("Failed to get table, %s\n", msg);
>  	}
> +
> +	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/iort.h b/include/linux/iort.h
> index d7daba1..9bb30c5 100644
> --- a/include/linux/iort.h
> +++ b/include/linux/iort.h
> @@ -38,4 +38,7 @@ static inline struct irq_domain *
>  iort_get_device_domain(struct device *dev, u32 req_id) { return NULL; }
>  #endif
>
> +#define IORT_ACPI_DECLARE(name, table_id, fn)		\
> +	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> +
>  #endif /* __IORT_H__ */

Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>

Thanks
Hanjun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration
  2016-08-15 15:23 ` [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
@ 2016-09-05 13:00   ` Hanjun Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Hanjun Guo @ 2016-09-05 13:00 UTC (permalink / raw)
  To: Lorenzo Pieralisi, iommu
  Cc: Tomasz Nowicki, Rafael J. Wysocki, Will Deacon, Marc Zyngier,
	Robin Murphy, Joerg Roedel, Jon Masters, Sinan Kaya,
	Nate Watterson, Dennis Chen, linux-acpi, linux-pci, linux-kernel,
	linux-arm-kernel

On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> 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@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 | 65 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/iort.h      |  8 ++++++
>  2 files changed, 73 insertions(+)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index cad7d1d..01a5258 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -20,7 +20,9 @@
>
>  #include <linux/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/iort.h b/include/linux/iort.h
> index 9bb30c5..666a3de 100644
> --- a/include/linux/iort.h
> +++ b/include/linux/iort.h
> @@ -30,12 +30,20 @@ struct fwnode_handle *iort_find_domain_token(int trans_id);
>  void iort_table_detect(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 iort_table_detect(void) { }
>  static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>  { return 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)		\

Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>

Thanks
Hanjun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval
  2016-08-15 15:23 ` [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval Lorenzo Pieralisi
@ 2016-09-05 13:19   ` Hanjun Guo
  2016-09-05 14:57     ` Lorenzo Pieralisi
  0 siblings, 1 reply; 26+ messages in thread
From: Hanjun Guo @ 2016-09-05 13:19 UTC (permalink / raw)
  To: Lorenzo Pieralisi, iommu
  Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Will Deacon, Marc Zyngier,
	Robin Murphy, Joerg Roedel, Tomasz Nowicki, Jon Masters,
	Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi, linux-pci,
	linux-kernel, linux-arm-kernel

On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> The platform device kernel API does not provide functions to
> retrieve a platform device through the corresponding struct
> device fwnode pointer.
>
> Implement the fwnode platform_device look-up in drivers core
> code by using the bus_find_device() API and a corresponding
> matching function. The OF equivalent (eg of_find_device_by_node())
> will reuse the newly introduced function when OF code will
> take care of setting up the device->fwnode value that is
> currently left dangling for platform devices instantiated out
> of device tree nodes.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> ---
>  drivers/base/platform.c         | 23 +++++++++++++++++++++++
>  include/linux/platform_device.h |  3 +++
>  2 files changed, 26 insertions(+)
>
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index 6482d47..3ef150d 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -760,6 +760,29 @@ err_out:
>  }
>  EXPORT_SYMBOL_GPL(__platform_create_bundle);
>
> +static int fwnode_dev_match(struct device *dev, void *data)
> +{
> +	return dev->fwnode == data;
> +}
> +
> +/**
> + * platform_find_device_by_fwnode() - Find the platform_device associated
> + *				      with a fwnode
> + * @fwnode: Pointer to firmware node
> + *
> + * Returns platform_device pointer, or NULL if not found
> + */
> +struct platform_device *
> +platform_find_device_by_fwnode(struct fwnode_handle *fwnode)
> +{
> +	struct device *dev;
> +
> +	dev = bus_find_device(&platform_bus_type, NULL, fwnode,
> +			      fwnode_dev_match);
> +	return dev ? to_platform_device(dev) : NULL;
> +}
> +EXPORT_SYMBOL(platform_find_device_by_fwnode);

As SMMU is registered as platform devices, I think we need such
API to retrieve the platform device with fwnode handle, actually
Kefeng introduced a similar patch [1], but your patch is more
generic, so this patch make sense to me,

Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>

Thanks
Hanjun

[1]: https://patchwork.kernel.org/patch/7743661/

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval
  2016-09-05 13:19   ` Hanjun Guo
@ 2016-09-05 14:57     ` Lorenzo Pieralisi
  2016-09-06 12:08       ` Hanjun Guo
  0 siblings, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2016-09-05 14:57 UTC (permalink / raw)
  To: Hanjun Guo
  Cc: iommu, Greg Kroah-Hartman, Rafael J. Wysocki, Will Deacon,
	Marc Zyngier, Robin Murphy, Joerg Roedel, Tomasz Nowicki,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

On Mon, Sep 05, 2016 at 09:19:43PM +0800, Hanjun Guo wrote:
> On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
> >The platform device kernel API does not provide functions to
> >retrieve a platform device through the corresponding struct
> >device fwnode pointer.
> >
> >Implement the fwnode platform_device look-up in drivers core
> >code by using the bus_find_device() API and a corresponding
> >matching function. The OF equivalent (eg of_find_device_by_node())
> >will reuse the newly introduced function when OF code will
> >take care of setting up the device->fwnode value that is
> >currently left dangling for platform devices instantiated out
> >of device tree nodes.
> >
> >Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> >Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> >---
> > drivers/base/platform.c         | 23 +++++++++++++++++++++++
> > include/linux/platform_device.h |  3 +++
> > 2 files changed, 26 insertions(+)
> >
> >diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> >index 6482d47..3ef150d 100644
> >--- a/drivers/base/platform.c
> >+++ b/drivers/base/platform.c
> >@@ -760,6 +760,29 @@ err_out:
> > }
> > EXPORT_SYMBOL_GPL(__platform_create_bundle);
> >
> >+static int fwnode_dev_match(struct device *dev, void *data)
> >+{
> >+	return dev->fwnode == data;
> >+}
> >+
> >+/**
> >+ * platform_find_device_by_fwnode() - Find the platform_device associated
> >+ *				      with a fwnode
> >+ * @fwnode: Pointer to firmware node
> >+ *
> >+ * Returns platform_device pointer, or NULL if not found
> >+ */
> >+struct platform_device *
> >+platform_find_device_by_fwnode(struct fwnode_handle *fwnode)
> >+{
> >+	struct device *dev;
> >+
> >+	dev = bus_find_device(&platform_bus_type, NULL, fwnode,
> >+			      fwnode_dev_match);
> >+	return dev ? to_platform_device(dev) : NULL;
> >+}
> >+EXPORT_SYMBOL(platform_find_device_by_fwnode);
> 
> As SMMU is registered as platform devices, I think we need such
> API to retrieve the platform device with fwnode handle, actually
> Kefeng introduced a similar patch [1], but your patch is more
> generic, so this patch make sense to me,
> 
> Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>

Thanks ! Strictly speaking, with Robin's new series:

https://lists.linuxfoundation.org/pipermail/iommu/2016-August/018230.html


(and corresponding v5 of this one that I have rebased on top of it) we
do not need this patch any longer and it is not really that generic
keeping in mind that it can't be used for DT matching (because in DT
dev->fwnode is dangling); I will see if I keep this patch according
to dependencies.

Side note: I have a problem with [1], since that code is there to
implement DT phandles in ACPI IIUC and we must really prevent that :)

Thanks !
Lorenzo

> Thanks
> Hanjun
> 
> [1]: https://patchwork.kernel.org/patch/7743661/
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval
  2016-09-05 14:57     ` Lorenzo Pieralisi
@ 2016-09-06 12:08       ` Hanjun Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Hanjun Guo @ 2016-09-06 12:08 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: iommu, Greg Kroah-Hartman, Rafael J. Wysocki, Will Deacon,
	Marc Zyngier, Robin Murphy, Joerg Roedel, Tomasz Nowicki,
	Jon Masters, Sinan Kaya, Nate Watterson, Dennis Chen, linux-acpi,
	linux-pci, linux-kernel, linux-arm-kernel

On 2016/9/5 22:57, Lorenzo Pieralisi wrote:
> On Mon, Sep 05, 2016 at 09:19:43PM +0800, Hanjun Guo wrote:
>> On 2016/8/15 23:23, Lorenzo Pieralisi wrote:
>>> The platform device kernel API does not provide functions to
>>> retrieve a platform device through the corresponding struct
>>> device fwnode pointer.
>>>
>>> Implement the fwnode platform_device look-up in drivers core
>>> code by using the bus_find_device() API and a corresponding
>>> matching function. The OF equivalent (eg of_find_device_by_node())
>>> will reuse the newly introduced function when OF code will
>>> take care of setting up the device->fwnode value that is
>>> currently left dangling for platform devices instantiated out
>>> of device tree nodes.
>>>
>>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
>>> ---
>>> drivers/base/platform.c         | 23 +++++++++++++++++++++++
>>> include/linux/platform_device.h |  3 +++
>>> 2 files changed, 26 insertions(+)
>>>
>>> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
>>> index 6482d47..3ef150d 100644
>>> --- a/drivers/base/platform.c
>>> +++ b/drivers/base/platform.c
>>> @@ -760,6 +760,29 @@ err_out:
>>> }
>>> EXPORT_SYMBOL_GPL(__platform_create_bundle);
>>>
>>> +static int fwnode_dev_match(struct device *dev, void *data)
>>> +{
>>> +	return dev->fwnode == data;
>>> +}
>>> +
>>> +/**
>>> + * platform_find_device_by_fwnode() - Find the platform_device associated
>>> + *				      with a fwnode
>>> + * @fwnode: Pointer to firmware node
>>> + *
>>> + * Returns platform_device pointer, or NULL if not found
>>> + */
>>> +struct platform_device *
>>> +platform_find_device_by_fwnode(struct fwnode_handle *fwnode)
>>> +{
>>> +	struct device *dev;
>>> +
>>> +	dev = bus_find_device(&platform_bus_type, NULL, fwnode,
>>> +			      fwnode_dev_match);
>>> +	return dev ? to_platform_device(dev) : NULL;
>>> +}
>>> +EXPORT_SYMBOL(platform_find_device_by_fwnode);
>>
>> As SMMU is registered as platform devices, I think we need such
>> API to retrieve the platform device with fwnode handle, actually
>> Kefeng introduced a similar patch [1], but your patch is more
>> generic, so this patch make sense to me,
>>
>> Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
>
> Thanks ! Strictly speaking, with Robin's new series:
>
> https://lists.linuxfoundation.org/pipermail/iommu/2016-August/018230.html
>
>
> (and corresponding v5 of this one that I have rebased on top of it) we
> do not need this patch any longer and it is not really that generic
> keeping in mind that it can't be used for DT matching (because in DT
> dev->fwnode is dangling); I will see if I keep this patch according
> to dependencies.

OK, I think I will wait for your new version, then try another test
and review it, does it make sense?

>
> Side note: I have a problem with [1], since that code is there to
> implement DT phandles in ACPI IIUC and we must really prevent that :)

Agreed :)

Thanks
Hanjun

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-09-06 12:08 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-15 15:23 [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 01/15] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi
2016-08-23 13:49   ` Lorenzo Pieralisi
2016-09-05 11:11   ` Hanjun Guo
2016-08-15 15:23 ` [PATCH v4 02/15] drivers: iommu: implement arch_{set/get}_iommu_fwspec API Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 03/15] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi
2016-09-05 11:42   ` Hanjun Guo
2016-08-15 15:23 ` [PATCH v4 04/15] drivers: acpi: iort: add support for IOMMU fwnode registration Lorenzo Pieralisi
2016-09-05 13:00   ` Hanjun Guo
2016-08-15 15:23 ` [PATCH v4 05/15] drivers: platform: add fwnode base platform devices retrieval Lorenzo Pieralisi
2016-09-05 13:19   ` Hanjun Guo
2016-09-05 14:57     ` Lorenzo Pieralisi
2016-09-06 12:08       ` Hanjun Guo
2016-08-15 15:23 ` [PATCH v4 06/15] drivers: iommu: make iommu_fwspec OF agnostic Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 07/15] drivers: acpi: implement acpi_dma_configure Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 08/15] drivers: acpi: iort: add node match function Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 09/15] drivers: acpi: iort: add support for ARM SMMU platform devices creation Lorenzo Pieralisi
2016-08-18 10:50   ` Dennis Chen
2016-08-18 10:55     ` Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 10/15] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 11/15] drivers: iommu: arm-smmu-v3: enable ACPI driver initialization Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 12/15] drivers: iommu: arm-smmu-v3: add IORT configuration Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 13/15] drivers: acpi: iort: replace rid map type with type mask Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 14/15] drivers: acpi: iort: add single mapping function Lorenzo Pieralisi
2016-08-15 15:23 ` [PATCH v4 15/15] drivers: acpi: iort: introduce iort_iommu_configure Lorenzo Pieralisi
2016-09-05  9:41 ` [PATCH v4 00/15] ACPI IORT ARM SMMU v3 support Hanjun Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).