Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1379134 > unrolled thread

[RFC PATCH 00/11] ACPI IORT ARM SMMU support

Started byLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
First post2016-04-14 19:30 +0200
Last post2016-04-14 19:30 +0200
Articles 6 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [RFC PATCH 00/11] ACPI IORT ARM SMMU support Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200
    [RFC PATCH 10/11] drivers: iommu: arm-smmu: implement ACPI probing Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200
    [RFC PATCH 08/11] drivers: acpi: iort: enhance mapping API Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200
    [RFC PATCH 06/11] drivers: iommu: make of_xlate() interface DT agnostic Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200
    [RFC PATCH 04/11] drivers: acpi: iort: introduce linker section for IORT entries probing Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200
    [RFC PATCH 03/11] drivers: iommu: add FWNODE_IOMMU fwnode type Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - 2016-04-14 19:30 +0200

#1379134 — [RFC PATCH 00/11] ACPI IORT ARM SMMU support

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 00/11] ACPI IORT ARM SMMU support
Message-ID<rnTfz-5zn-3@gated-at.bofh.it>
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 this posting:

https://marc.info/?l=linux-acpi&m=145976009630179&w=2

this patchset enables ARM SMMU 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 ARM SMMUv3 and future IOMMU components easier to integrate.

PATCH [1] fixes a warning caused by a missing forward structure
          declaration.

PATCH [2] provides IORT support for registering IOMMU components.

PATCH [3] 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). This patch requires discussion and it is key
          to the RFC.

PATCH [4] makes use of the ACPI early probing API to add a linker script
          section for probing devices via IORT ACPI kernel code.

PATCH [5] refactors the ARM SMMU 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 [6] makes the of_xlate() interface for IOMMUs DT agnostic by
          changing its API and making it work on ACPI systems too
          through the introduction of a generic IOMMU FW translation
          specifier.

PATCH [7] implements ARM SMMU streamid mapping based on the previously
          introduced infrastructure.

PATCH [8] enhances IORT kernel code to implement the full set of mappings
          allowed through the ACPI IORT table.

PATCH [9] 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 [10] implements and enables code for probing the ARM SMMU with ACPI,
           building on top of the previously introduced generic infrastructure.

PATCH [11] is a mechanical conversion of IRQ domain infrastructure to
           generalize its translation capabilities for other kernel
           subsystems, and it is there to prove that the approach taken
           to implement IOMMU translation in a DT agnostic way would lead
           to structure data duplication that may be deemed unnecessary
           and can therefore be avoided.

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

R.Murphy "Generic DT bindings for PCI and ARM SMMU"
https://marc.info/?l=linux-arm-kernel&m=145675372917701&w=2

T.Nowicki "Introduce ACPI world to ITS irqchip"
https://marc.info/?l=linux-acpi&m=145976009630179&w=2

Tested on Juno-r2 board with both DT and ACPI probing paths.

Lorenzo Pieralisi (11):
  drivers: acpi: iort: fix struct pci_dev compiler warnings
  drivers: acpi: iort: add support for IOMMU registration
  drivers: iommu: add FWNODE_IOMMU fwnode type
  drivers: acpi: iort: introduce linker section for IORT entries probing
  drivers: iommu: arm-smmu: split probe functions into DT/generic
    portions
  drivers: iommu: make of_xlate() interface DT agnostic
  drivers: iommu: arm-smmu: allow ACPI based streamid translation
  drivers: acpi: iort: enhance mapping API
  drivers: acpi: implement acpi_dma_configure
  drivers: iommu: arm-smmu: implement ACPI probing
  drivers: irqchip: make struct irq_fwspec generic

 Documentation/IRQ-domain.txt         |   2 +-
 arch/arm/mach-exynos/suspend.c       |   6 +-
 arch/arm/mach-imx/gpc.c              |   6 +-
 arch/arm/mach-omap2/omap-wakeupgen.c |   6 +-
 drivers/acpi/glue.c                  |   4 +-
 drivers/acpi/gsi.c                   |   2 +-
 drivers/acpi/iort.c                  | 188 ++++++++++++++++++-
 drivers/acpi/scan.c                  |  29 +++
 drivers/gpio/gpio-xgene-sb.c         |   8 +-
 drivers/iommu/arm-smmu.c             | 346 ++++++++++++++++++++++++++++++-----
 drivers/iommu/exynos-iommu.c         |  11 +-
 drivers/iommu/mtk_iommu.c            |  13 +-
 drivers/iommu/of_iommu.c             |   8 +-
 drivers/irqchip/irq-alpine-msi.c     |   2 +-
 drivers/irqchip/irq-crossbar.c       |   6 +-
 drivers/irqchip/irq-gic-v2m.c        |   2 +-
 drivers/irqchip/irq-gic-v3-its.c     |   2 +-
 drivers/irqchip/irq-gic-v3.c         |   4 +-
 drivers/irqchip/irq-gic.c            |   4 +-
 drivers/irqchip/irq-imx-gpcv2.c      |   6 +-
 drivers/irqchip/irq-mbigen.c         |   4 +-
 drivers/irqchip/irq-mips-gic.c       |   2 +-
 drivers/irqchip/irq-mtk-sysirq.c     |   6 +-
 drivers/irqchip/irq-mvebu-odmi.c     |   2 +-
 drivers/irqchip/irq-nvic.c           |   4 +-
 drivers/irqchip/irq-tegra.c          |   6 +-
 drivers/irqchip/irq-vf610-mscm-ir.c  |   6 +-
 drivers/of/base.c                    |  24 +++
 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               |  21 +++
 include/linux/iommu.h                |  31 +++-
 include/linux/iort.h                 |  18 ++
 include/linux/irqdomain.h            |  22 +--
 include/linux/of.h                   |   7 +
 kernel/irq/irqdomain.c               |  17 +-
 38 files changed, 692 insertions(+), 144 deletions(-)

-- 
2.6.4

[toc] | [next] | [standalone]


#1379137 — [RFC PATCH 10/11] drivers: iommu: arm-smmu: implement ACPI probing

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 10/11] drivers: iommu: arm-smmu: implement ACPI probing
Message-ID<rnTfA-5zn-23@gated-at.bofh.it>
In reply to#1379134
In ACPI world ARM SMMU components are described through IORT table
entries, that contain SMMU parameters and provide the kernel with
data to create the corresponding kernel abstractions and allow
SMMU probing and initialization.

Currently, the arm-smmu driver probe routines are DT based, hence,
to enable the driver to probe through ACPI they should be augmented
so that the DT and ACPI probing paths can actually share the common
code that probes and initializes the ARM SMMU allowing them to co-exist
seamlessly.

This patch refactors the ARM SMMU probing path to introduce ACPI
probing effectively enabling the ARM SMMU on ACPI based systems.

To create the required platform devices representing ARM SMMU components
and initialize them with the required data, this patch also implements
ARM SMMU ACPI probing by adding a hook into the ACPI IORT linker section,
that is executed automatically by the kernel on boot and allows
to detect and configure the ARM SMMU devices present in the system.

Based on prior work by Hanjun Guo <hanjun.guo@linaro.org>.

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: Tomasz Nowicki <tn@semihalf.com>
---
 drivers/iommu/arm-smmu.c | 240 +++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/iort.h     |   3 +
 2 files changed, 233 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 0f1e784..85ab4b7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,7 @@
 
 #define pr_fmt(fmt) "arm-smmu: " fmt
 
+#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/dma-iommu.h>
 #include <linux/dma-mapping.h>
@@ -36,6 +37,7 @@
 #include <linux/io.h>
 #include <linux/iommu.h>
 #include <linux/iopoll.h>
+#include <linux/iort.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -1729,6 +1731,103 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
 	return 0;
 }
 
+#ifdef CONFIG_ACPI
+static int __init acpi_smmu_version(u32 model, u32 *version)
+{
+	switch (model) {
+	case ACPI_IORT_SMMU_V1:
+	case ACPI_IORT_SMMU_CORELINK_MMU400:
+		*version = ARM_SMMU_V1;
+		return 0;
+	case ACPI_IORT_SMMU_V2:
+	case ACPI_IORT_SMMU_CORELINK_MMU500:
+		*version = ARM_SMMU_V2;
+		return 0;
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int __init arm_smmu_acpi_probe(struct platform_device *pdev,
+				      struct arm_smmu_device *smmu)
+{
+	struct device *dev = smmu->dev;
+	struct acpi_iort_node *node =
+		*(struct acpi_iort_node **)dev_get_platdata(dev);
+	struct acpi_iort_smmu *iort_smmu;
+	int num_irqs, i, err, trigger, ret, irq_idx;
+	u64 *ctx_irq, *glb_irq;
+
+	/* Retrieve SMMU1/2 specific data */
+	iort_smmu = (struct acpi_iort_smmu *)node->node_data;
+
+	ret = acpi_smmu_version(iort_smmu->model, &smmu->version);
+	if (ret < 0)
+		return ret;
+
+	glb_irq = ACPI_ADD_PTR(u64, node, iort_smmu->global_interrupt_offset);
+	if (!IORT_IRQ_MASK(glb_irq[1]))	/* 0 means not implemented */
+		smmu->num_global_irqs = 1;
+	else
+		smmu->num_global_irqs = 2;
+
+	smmu->num_context_irqs = iort_smmu->context_interrupt_count;
+	num_irqs = smmu->num_context_irqs + smmu->num_global_irqs;
+
+	if (!smmu->num_context_irqs) {
+		dev_err(dev, "found %d interrupts but expected at least %d\n",
+			num_irqs, smmu->num_global_irqs + 1);
+		return -ENODEV;
+	}
+
+	smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs,
+				  GFP_KERNEL);
+	if (!smmu->irqs) {
+		dev_err(dev, "failed to allocate %d irqs\n", num_irqs);
+		return -ENOMEM;
+	}
+
+	/* Global IRQs */
+	for (i = irq_idx = 0; i < smmu->num_global_irqs; i++, irq_idx++) {
+		int hw_irq = IORT_IRQ_MASK(glb_irq[i]);
+
+		trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[i]);
+		smmu->irqs[irq_idx] = acpi_register_gsi(NULL, hw_irq, trigger,
+							ACPI_ACTIVE_HIGH);
+	}
+
+	/* Context IRQs */
+	ctx_irq = ACPI_ADD_PTR(u64, node, iort_smmu->context_interrupt_offset);
+	for (i = 0; i < smmu->num_context_irqs; i++, irq_idx++) {
+		int hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+
+		trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+		smmu->irqs[irq_idx] = acpi_register_gsi(NULL, hw_irq, trigger,
+							ACPI_ACTIVE_HIGH);
+	}
+
+	if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
+		smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+	err = arm_smmu_device_cfg_probe(smmu);
+	if (err)
+		return err;
+
+	iort_iommu_set_node(&arm_smmu_ops, node, pdev->dev.fwnode);
+
+	return 0;
+}
+
+#else
+static inline int arm_smmu_acpi_probe(struct platform_device *pdev,
+				      struct arm_smmu_device *smmu)
+{
+	return -ENODEV;
+}
+#endif
+
 static const struct of_device_id arm_smmu_of_match[] = {
 	{ .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 },
 	{ .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 },
@@ -1933,7 +2032,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		return PTR_ERR(smmu->base);
 	smmu->size = resource_size(res);
 
-	err = arm_smmu_dt_probe(pdev, smmu);
+	if (acpi_disabled)
+		err = arm_smmu_dt_probe(pdev, smmu);
+	else
+		err = arm_smmu_acpi_probe(pdev, smmu);
 
 	if (err)
 		return err;
@@ -2007,16 +2109,20 @@ static int __init arm_smmu_init(void)
 
 	if (done)
 		return 0;
-	/*
-	 * Play nice with systems that don't have an ARM SMMU by checking that
-	 * an ARM SMMU exists in the system before proceeding with the driver
-	 * and IOMMU bus operation registration.
-	 */
-	np = of_find_matching_node(NULL, arm_smmu_of_match);
-	if (!np)
-		return 0;
 
-	of_node_put(np);
+	if (acpi_disabled) {
+		/*
+		 * Play nice with systems that don't have an ARM SMMU by
+		 * checking that an ARM SMMU exists in the system before
+		 * proceeding with the driver and IOMMU bus operation
+		 * registration.
+		 */
+		np = of_find_matching_node(NULL, arm_smmu_of_match);
+		if (!np)
+			return 0;
+
+		of_node_put(np);
+	}
 
 	ret = platform_driver_register(&arm_smmu_driver);
 	if (ret)
@@ -2048,6 +2154,120 @@ static void __exit arm_smmu_exit(void)
 subsys_initcall(arm_smmu_init);
 module_exit(arm_smmu_exit);
 
+#ifdef CONFIG_ACPI
+static int __init add_smmu_platform_device(struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu *smmu;
+	struct platform_device *pdev = NULL;
+	struct resource resources;
+	enum dev_dma_attr attr;
+	int ret;
+
+	/* Retrieve SMMU1/2 specific data */
+	smmu = (struct acpi_iort_smmu *)node->node_data;
+
+	memset(&resources, 0, sizeof(resources));
+	resources.start = smmu->base_address;
+	resources.end = smmu->base_address + smmu->span - 1;
+	resources.flags = IORESOURCE_MEM;
+
+	pdev = platform_device_alloc("arm-smmu", PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return PTR_ERR(pdev);
+
+	pdev->dev.fwnode = iommu_alloc_fwnode();
+
+	if (!pdev->dev.fwnode) {
+		ret = -ENOMEM;
+		goto dev_put;
+	}
+
+	ret = platform_device_add_resources(pdev, &resources, 1);
+	if (ret)
+		goto free_node;
+
+	ret = platform_device_add_data(pdev, &node, sizeof(node));
+	if (ret)
+		goto free_node;
+
+	pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+	if (!pdev->dev.dma_mask) {
+		ret = -ENOMEM;
+		goto free_node;
+	}
+
+	/*
+	 * 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 = smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK ?
+			     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);
+free_node:
+	iommu_free_fwnode(pdev->dev.fwnode);
+dev_put:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	int i, ret = arm_smmu_init();
+
+	if (ret)
+		return ret;
+	/*
+	 * iort_table and iort both point to the start of IORT table, but
+	 * have different struct types
+	 */
+	iort = (struct acpi_table_iort *)table;
+
+	/* Get the first IORT node */
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (iort_node >= iort_end) {
+			pr_err("iort node pointer overflows, bad table\n");
+			return -EINVAL;
+		}
+
+		if (iort_node->type == ACPI_IORT_NODE_SMMU) {
+			ret = add_smmu_platform_device(iort_node);
+			if (ret)
+				return ret;
+		}
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+
+	return 0;
+}
+
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+#endif
+
 static int __init arm_smmu_of_init(struct device_node *np)
 {
 	struct arm_smmu_device *smmu;
diff --git a/include/linux/iort.h b/include/linux/iort.h
index 7a7af40..958b236 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -21,6 +21,9 @@
 
 #include <linux/acpi.h>
 
+#define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
+
 struct pci_dev;
 struct fwnode_handle;
 int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
-- 
2.6.4

[toc] | [prev] | [next] | [standalone]


#1379138 — [RFC PATCH 08/11] drivers: acpi: iort: enhance mapping API

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 08/11] drivers: acpi: iort: enhance mapping API
Message-ID<rnTfA-5zn-29@gated-at.bofh.it>
In reply to#1379134
The current IORT API works only for mappings that have the GIC ITS
as a sink node and does not allow mapping components other than
PCI root complexes.

This patch enhances the IORT API to allow any mapping permitted by
the IORT specifications, inclusive of IORT translations for named
components.

Based on prior work by Hanjun Guo <hanjun.guo@linaro.org>.

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/iort.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 53 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/iort.c b/drivers/acpi/iort.c
index 080888a..2b5ce65 100644
--- a/drivers/acpi/iort.c
+++ b/drivers/acpi/iort.c
@@ -182,15 +182,61 @@ iort_scan_node(enum acpi_iort_node_type type,
 	return NULL;
 }
 
+static struct acpi_iort_node *
+iort_find_parent_node(struct acpi_iort_node *node, u8 type)
+{
+	struct acpi_iort_id_mapping *id;
+
+	if (!node || !node->mapping_offset || !node->mapping_count)
+		return NULL;
+
+	id = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+			  node->mapping_offset);
+
+	if (!id->output_reference) {
+		pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+		       node, node->type);
+		return NULL;
+	}
+
+	node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+			    id->output_reference);
+
+	return node->type == type ? node : NULL;
+}
+
 static acpi_status
 iort_find_dev_callback(struct acpi_iort_node *node, void *context)
 {
-	struct acpi_iort_root_complex *pci_rc;
 	struct device *dev = context;
-	struct pci_bus *bus;
 
 	switch (node->type) {
-	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
+	case ACPI_IORT_NODE_NAMED_COMPONENT: {
+		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+		struct acpi_iort_named_component *ncomp;
+		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+
+		if (!adev)
+			break;
+
+		ncomp = (struct acpi_iort_named_component *)node->node_data;
+
+		if (ACPI_FAILURE(acpi_get_name(adev->handle,
+					       ACPI_FULL_PATHNAME, &buffer))) {
+			pr_warn("Can't get device full path name\n");
+			break;
+		}
+
+		if (!strcmp(ncomp->device_name, (char *)buffer.pointer))
+			return AE_OK;
+
+		break;
+	}
+
+	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX: {
+		struct acpi_iort_root_complex *pci_rc;
+		struct pci_bus *bus;
+
 		bus = to_pci_bus(dev);
 		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
 
@@ -204,20 +250,21 @@ iort_find_dev_callback(struct acpi_iort_node *node, void *context)
 
 		break;
 	}
+	}
 
 	return AE_NOT_FOUND;
 }
 
 static struct acpi_iort_node *
 iort_dev_map_rid(struct acpi_iort_node *node, u32 rid_in,
-			    u32 *rid_out)
+			    u32 *rid_out, u8 type)
 {
 
 	if (!node)
 		goto out;
 
 	/* Go upstream */
-	while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
+	while (node->type != type) {
 		struct acpi_iort_id_mapping *id;
 		int i, found = 0;
 
@@ -283,7 +330,7 @@ iort_its_find_node_and_map_rid(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
 		return NULL;
 	}
 
-	return iort_dev_map_rid(node, req_id, dev_id);
+	return iort_dev_map_rid(node, req_id, dev_id, ACPI_IORT_NODE_ITS_GROUP);
 }
 
 /**
-- 
2.6.4

[toc] | [prev] | [next] | [standalone]


#1379139 — [RFC PATCH 06/11] drivers: iommu: make of_xlate() interface DT agnostic

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 06/11] drivers: iommu: make of_xlate() interface DT agnostic
Message-ID<rnTfA-5zn-27@gated-at.bofh.it>
In reply to#1379134
On systems booting with ACPI, the IOMMU drivers require the same
kind of id mapping carried out with a DT tree through the of_xlate()
API in order to map devices identifiers to IOMMU ones.

On ACPI systems, since DT nodes are not present (ie struct
device.of_node == NULL), to identify the device requiring the translation
the struct device_node (and the structure used to pass translation
information - struct of_phandle_args - that contains a struct device_node)
cannot be used, so a generic translation structure to be used for IOMMU
mapping should be defined, based on the firmware agnostic fwnode_handle
type.

This patch mechanically refactors/renames the of_xlate API to make
it DT agnostic, by declaring a new type (struct iommu_fwspec), that
allows the kernel to pass a device identifier (fwnode - which can
represent either a DT node or an IOMMU FW node) and by changing the
of_xlate signature so that it does not take anymore the DT specific
of_phandle_args argument and replaces it with the DT agnostic
iommu_fwspec one.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/iommu/arm-smmu.c     | 12 +++++++-----
 drivers/iommu/exynos-iommu.c | 11 +++++++----
 drivers/iommu/mtk_iommu.c    | 13 ++++++++-----
 drivers/iommu/of_iommu.c     | 20 ++++++++++++++++++--
 include/linux/iommu.h        | 24 ++++++++++++++++++++----
 5 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 6c42770..84bcff7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1440,18 +1440,20 @@ out_unlock:
 	return ret;
 }
 
-static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
+static int arm_smmu_fw_xlate(struct device *dev, struct iommu_fwspec *args)
 {
 	struct arm_smmu_device *smmu;
-	struct platform_device *smmu_pdev;
+	struct platform_device *smmu_pdev = NULL;
+
+	if (is_of_node(args->fwnode))
+		smmu_pdev = of_find_device_by_node(to_of_node(args->fwnode));
 
-	smmu_pdev = of_find_device_by_node(args->np);
 	if (!smmu_pdev)
 		return -ENODEV;
 
 	smmu = platform_get_drvdata(smmu_pdev);
 
-	return arm_smmu_add_dev_streamid(smmu, dev, args->args[0]);
+	return arm_smmu_add_dev_streamid(smmu, dev, args->param[0]);
 }
 
 static struct iommu_ops arm_smmu_ops = {
@@ -1468,7 +1470,7 @@ static struct iommu_ops arm_smmu_ops = {
 	.device_group		= arm_smmu_device_group,
 	.domain_get_attr	= arm_smmu_domain_get_attr,
 	.domain_set_attr	= arm_smmu_domain_set_attr,
-	.of_xlate		= arm_smmu_of_xlate,
+	.fw_xlate		= arm_smmu_fw_xlate,
 	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
 };
 
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 5ecc86c..84ff5bb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1250,13 +1250,16 @@ static void exynos_iommu_remove_device(struct device *dev)
 	iommu_group_remove_device(dev);
 }
 
-static int exynos_iommu_of_xlate(struct device *dev,
-				 struct of_phandle_args *spec)
+static int exynos_iommu_fw_xlate(struct device *dev,
+				 struct iommu_fwspec *args)
 {
 	struct exynos_iommu_owner *owner = dev->archdata.iommu;
-	struct platform_device *sysmmu = of_find_device_by_node(spec->np);
+	struct platform_device *sysmmu = NULL;
 	struct sysmmu_drvdata *data;
 
+	if (is_of_node(args->fwnode))
+		sysmmu = of_find_device_by_node(to_of_node(args->fwnode));
+
 	if (!sysmmu)
 		return -ENODEV;
 
@@ -1290,7 +1293,7 @@ static struct iommu_ops exynos_iommu_ops = {
 	.add_device = exynos_iommu_add_device,
 	.remove_device = exynos_iommu_remove_device,
 	.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
-	.of_xlate = exynos_iommu_of_xlate,
+	.fw_xlate = exynos_iommu_fw_xlate,
 };
 
 static bool init_done;
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 929a66a..e08dc0a 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -436,20 +436,23 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev)
 	return data->m4u_group;
 }
 
-static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+static int mtk_iommu_fw_xlate(struct device *dev, struct iommu_fwspec *args)
 {
 	struct mtk_iommu_client_priv *head, *priv, *next;
 	struct platform_device *m4updev;
 
-	if (args->args_count != 1) {
+	if (!is_of_node(args->fwnode))
+		return -ENODEV;
+
+	if (args->param_count != 1) {
 		dev_err(dev, "invalid #iommu-cells(%d) property for IOMMU\n",
-			args->args_count);
+			args->param_count);
 		return -EINVAL;
 	}
 
 	if (!dev->archdata.iommu) {
 		/* Get the m4u device */
-		m4updev = of_find_device_by_node(args->np);
+		m4updev = of_find_device_by_node(to_of_node(args->fwnode));
 		of_node_put(args->np);
 		if (WARN_ON(!m4updev))
 			return -EINVAL;
@@ -469,7 +472,7 @@ static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
 	if (!priv)
 		goto err_free_mem;
 
-	priv->mtk_m4u_id = args->args[0];
+	priv->mtk_m4u_id = args->param[0];
 	list_add_tail(&priv->client, &head->client);
 
 	return 0;
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 910826c..331dd78 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -135,6 +135,18 @@ struct iommu_ops *of_iommu_get_ops(struct device_node *np)
 	return ops;
 }
 
+static void of_phandle_args_to_fwspec(struct of_phandle_args *iommu_data,
+				      struct iommu_fwspec *fwspec)
+{
+	int i;
+
+	fwspec->fwnode = iommu_data->np ? &iommu_data->np->fwnode : NULL;
+	fwspec->param_count = iommu_data->args_count;
+
+	for (i = 0; i < iommu_data->args_count; i++)
+		fwspec->param[i] = iommu_data->args[i];
+}
+
 static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
 {
 	struct of_phandle_args *iommu_spec = data;
@@ -148,6 +160,7 @@ struct iommu_ops *of_iommu_configure(struct device *dev,
 				     struct device_node *master_np)
 {
 	struct of_phandle_args iommu_spec;
+	struct iommu_fwspec fwspec;
 	struct device_node *np = NULL;
 	struct iommu_ops *ops = NULL;
 	int idx = 0;
@@ -170,8 +183,9 @@ struct iommu_ops *of_iommu_configure(struct device *dev,
 
 		iommu_spec.np = np;
 		iommu_spec.args_count = 1;
+		of_phandle_args_to_fwspec(&iommu_spec, &fwspec);
 		ops = of_iommu_get_ops(np);
-		if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec))
+		if (!ops || !ops->fw_xlate || ops->fw_xlate(dev, &fwspec))
 			goto err_put_node;
 
 		of_node_put(np);
@@ -189,7 +203,9 @@ struct iommu_ops *of_iommu_configure(struct device *dev,
 		np = iommu_spec.np;
 		ops = of_iommu_get_ops(np);
 
-		if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec))
+		of_phandle_args_to_fwspec(&iommu_spec, &fwspec);
+
+		if (!ops || !ops->fw_xlate || ops->fw_xlate(dev, &fwspec))
 			goto err_put_node;
 
 		of_node_put(np);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 0bba25e..5184d81 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -85,6 +85,24 @@ struct iommu_domain {
 	void *iova_cookie;
 };
 
+#define IOMMU_MAP_SPEC_PARAMS 16
+
+/**
+ * struct iommu_fwspec - generic IOMMU specifier structure
+ *
+ * @fwnode:		Pointer to a firmware-specific descriptor
+ * @param_count:	Number of device-specific parameters
+ * @param:		Device-specific parameters
+ *
+ * This structure, directly modeled after of_phandle_args, is used to
+ * pass a device-specific description of an IOMMU mapping.
+ */
+struct iommu_fwspec {
+	struct fwnode_handle *fwnode;
+	int param_count;
+	u32 param[IOMMU_MAP_SPEC_PARAMS];
+};
+
 enum iommu_cap {
 	IOMMU_CAP_CACHE_COHERENCY,	/* IOMMU can enforce cache coherent DMA
 					   transactions */
@@ -155,7 +173,7 @@ struct iommu_dm_region {
  * @domain_window_disable: Disable a particular window for a domain
  * @domain_set_windows: Set the number of windows for a domain
  * @domain_get_windows: Return the number of windows for a domain
- * @of_xlate: add OF master IDs to iommu grouping
+ * @fw_xlate: add FW master IDs to iommu grouping
  * @pgsize_bitmap: bitmap of supported page sizes
  * @priv: per-instance data private to the iommu driver
  */
@@ -196,9 +214,7 @@ struct iommu_ops {
 	/* Get the number of windows per domain */
 	u32 (*domain_get_windows)(struct iommu_domain *domain);
 
-#ifdef CONFIG_OF_IOMMU
-	int (*of_xlate)(struct device *dev, struct of_phandle_args *args);
-#endif
+	int (*fw_xlate)(struct device *dev, struct iommu_fwspec *args);
 
 	unsigned long pgsize_bitmap;
 	void *priv;
-- 
2.6.4

[toc] | [prev] | [next] | [standalone]


#1379140 — [RFC PATCH 04/11] drivers: acpi: iort: introduce linker section for IORT entries probing

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 04/11] drivers: acpi: iort: introduce linker section for IORT entries probing
Message-ID<rnTfA-5zn-33@gated-at.bofh.it>
In reply to#1379134
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/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/iort.c b/drivers/acpi/iort.c
index 98db580..080888a 100644
--- a/drivers/acpi/iort.c
+++ b/drivers/acpi/iort.c
@@ -372,6 +372,8 @@ static int __init iort_table_detect(void)
 		return -EINVAL;
 	}
 
+	acpi_probe_device_table(iort);
+
 	return 0;
 }
 arch_initcall(iort_table_detect);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 339125b..0aae448 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -536,6 +536,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 148d9a1..766adda 100644
--- a/include/linux/iort.h
+++ b/include/linux/iort.h
@@ -31,4 +31,7 @@ struct fwnode_handle *iort_pci_get_domain(struct pci_dev *pdev, u32 req_id);
 int iort_iommu_set_node(struct iommu_ops *ops, struct acpi_iort_node *node,
 			struct fwnode_handle *fwnode);
 
+#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

[toc] | [prev] | [next] | [standalone]


#1379143 — [RFC PATCH 03/11] drivers: iommu: add FWNODE_IOMMU fwnode type

FromLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Date2016-04-14 19:30 +0200
Subject[RFC PATCH 03/11] drivers: iommu: add FWNODE_IOMMU fwnode type
Message-ID<rnTfB-5zn-39@gated-at.bofh.it>
In reply to#1379134
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
- Identify the device in kernel functions that must be firmware
  agnostic (eg IOMMU of_xlate() callbacks)

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 a5c539f..0bba25e 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -37,6 +37,7 @@ struct bus_type;
 struct device;
 struct iommu_domain;
 struct notifier_block;
+struct fwnode_handle;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ	0x0
@@ -542,4 +543,28 @@ static inline void iommu_device_unlink(struct device *dev, struct device *link)
 
 #endif /* CONFIG_IOMMU_API */
 
+/* IOMMU fwnode handling */
+static inline bool is_fwnode_iommu(struct fwnode_handle *fwnode)
+{
+	return fwnode && fwnode->type == FWNODE_IOMMU;
+}
+
+static inline struct fwnode_handle *iommu_alloc_fwnode(void)
+{
+	struct fwnode_handle *fwnode;
+
+	fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
+	fwnode->type = FWNODE_IOMMU;
+
+	return fwnode;
+}
+
+static inline void iommu_free_fwnode(struct fwnode_handle *fwnode)
+{
+	if (WARN_ON(!is_fwnode_iommu(fwnode)))
+		return;
+
+	kfree(fwnode);
+}
+
 #endif /* __LINUX_IOMMU_H */
-- 
2.6.4

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web