2015-12-17 11:52:25

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 00/10] Introduce ACPI world to GICv3 & ITS irqchip

These patches have been part of:
[PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
https://lkml.org/lkml/2015/7/29/234

Patches base on Suravee's ACPI GICv2m support:
https://lkml.org/lkml/2015/12/10/475

The following git branch contains submitted patches along with
the useful for test patches (mainly ACPI ARM64 PCI support).
https://github.com/semihalf-nowicki-tomasz/linux.git (gicv3-its-acpi-v2)

Series has been tested on Cavium ThunderX 1 socket server.

v1 -> v2
- rebased on top of 4.4-rc4
- use pci_msi_domain_get_msi_rid for requester ID to device ID translation

Hanjun Guo (1):
irqchip / GICv3: remove gic root node in ITS

Tomasz Nowicki (9):
irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
irqchip / GICv3: Add ACPI support for GICv3+ initialization
irqchip,GICv3,ACPI: Add redistributor support via GICC structures.
irqchip, gicv3, its: Mark its_init() and its children as __init
irqchip/GICv3/ITS: Refator ITS dt init code to prepare for ACPI.
ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.
irqchip, gicv3, its: Probe ITS in the ACPI way.
acpi, gicv3, msi: Factor out code that might be reused for ACPI
equivalent.
acpi, gicv3, its: Use MADT ITS subtable to do PCI/MSI domain
initialization.

drivers/acpi/Kconfig | 3 +
drivers/acpi/Makefile | 1 +
drivers/acpi/iort.c | 326 +++++++++++++++++++++++++++++
drivers/irqchip/Kconfig | 1 +
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 85 ++++++--
drivers/irqchip/irq-gic-v3-its.c | 142 +++++++++----
drivers/irqchip/irq-gic-v3.c | 341 ++++++++++++++++++++++++++-----
drivers/pci/msi.c | 3 +
include/linux/iort.h | 38 ++++
include/linux/irqchip/arm-gic-v3.h | 2 +-
10 files changed, 841 insertions(+), 101 deletions(-)
create mode 100644 drivers/acpi/iort.c
create mode 100644 include/linux/iort.h

--
1.9.1


2015-12-17 11:52:31

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 01/10] irqchip / GICv3: Refactor gic_of_init() for GICv3 driver

Isolate hardware abstraction (FDT) code to gic_of_init().
Rest of the logic goes to gic_init_bases() and expects well
defined data to initialize GIC properly. The same solution
is used for GICv2 driver.

This is needed for ACPI initialization later.

Signed-off-by: Tomasz Nowicki <[email protected]>
Signed-off-by: Hanjun Guo <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 130 ++++++++++++++++++++++++++-----------------
1 file changed, 78 insertions(+), 52 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index d7be6dd..31205c7 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -811,59 +811,16 @@ static void gicv3_enable_quirks(void)
#endif
}

-static int __init gic_of_init(struct device_node *node, struct device_node *parent)
+static int __init gic_init_bases(void __iomem *dist_base,
+ struct redist_region *rdist_regs,
+ u32 nr_redist_regions,
+ u64 redist_stride,
+ struct fwnode_handle *handle)
{
- void __iomem *dist_base;
- struct redist_region *rdist_regs;
- u64 redist_stride;
- u32 nr_redist_regions;
+ struct device_node *node;
u32 typer;
- u32 reg;
int gic_irqs;
int err;
- int i;
-
- dist_base = of_iomap(node, 0);
- if (!dist_base) {
- pr_err("%s: unable to map gic dist registers\n",
- node->full_name);
- return -ENXIO;
- }
-
- reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
- if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
- pr_err("%s: no distributor detected, giving up\n",
- node->full_name);
- err = -ENODEV;
- goto out_unmap_dist;
- }
-
- if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
- nr_redist_regions = 1;
-
- rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
- if (!rdist_regs) {
- err = -ENOMEM;
- goto out_unmap_dist;
- }
-
- for (i = 0; i < nr_redist_regions; i++) {
- struct resource res;
- int ret;
-
- ret = of_address_to_resource(node, 1 + i, &res);
- rdist_regs[i].redist_base = of_iomap(node, 1 + i);
- if (ret || !rdist_regs[i].redist_base) {
- pr_err("%s: couldn't map region %d\n",
- node->full_name, i);
- err = -ENODEV;
- goto out_unmap_rdist;
- }
- rdist_regs[i].phys_base = res.start;
- }
-
- if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
- redist_stride = 0;

if (!is_hyp_mode_available())
static_key_slow_dec(&supports_deactivate);
@@ -889,8 +846,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
gic_irqs = 1020;
gic_data.irq_nr = gic_irqs;

- gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
- &gic_data);
+ gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
+ &gic_data);
gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));

if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
@@ -900,7 +857,9 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare

set_handle_irq(gic_handle_irq);

- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
+ node = to_of_node(handle);
+ if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
+ node) /* Temp hack to prevent ITS init for ACPI */
its_init(node, &gic_data.rdists, gic_data.domain);

gic_smp_init();
@@ -914,6 +873,73 @@ out_free:
if (gic_data.domain)
irq_domain_remove(gic_data.domain);
free_percpu(gic_data.rdists.rdist);
+ return err;
+}
+
+static int __init gic_validate_dist_version(void __iomem *dist_base)
+{
+ u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+
+ if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+ void __iomem *dist_base;
+ struct redist_region *rdist_regs;
+ u64 redist_stride;
+ u32 nr_redist_regions;
+ int err, i;
+
+ dist_base = of_iomap(node, 0);
+ if (!dist_base) {
+ pr_err("%s: unable to map gic dist registers\n",
+ node->full_name);
+ return -ENXIO;
+ }
+
+ err = gic_validate_dist_version(dist_base);
+ if (err) {
+ pr_err("%s: no distributor detected, giving up\n",
+ node->full_name);
+ goto out_unmap_dist;
+ }
+
+ if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
+ nr_redist_regions = 1;
+
+ rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
+ if (!rdist_regs) {
+ err = -ENOMEM;
+ goto out_unmap_dist;
+ }
+
+ for (i = 0; i < nr_redist_regions; i++) {
+ struct resource res;
+ int ret;
+
+ ret = of_address_to_resource(node, 1 + i, &res);
+ rdist_regs[i].redist_base = of_iomap(node, 1 + i);
+ if (ret || !rdist_regs[i].redist_base) {
+ pr_err("%s: couldn't map region %d\n",
+ node->full_name, i);
+ err = -ENODEV;
+ goto out_unmap_rdist;
+ }
+ rdist_regs[i].phys_base = res.start;
+ }
+
+ if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
+ redist_stride = 0;
+
+ err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+ redist_stride, &node->fwnode);
+ if (!err)
+ return 0;
+
out_unmap_rdist:
for (i = 0; i < nr_redist_regions; i++)
if (rdist_regs[i].redist_base)
--
1.9.1

2015-12-17 11:54:41

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 02/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization

With the refator of gic_of_init(), GICv3/4 can be initialized
by gic_init_bases() with gic distributor base address and gic
redistributor region(s).

So get the redistributor region base addresses from MADT GIC
redistributor subtable, and the distributor base address from
GICD subtable to init GICv3 irqchip in ACPI way.

Note: GIC redistributor base address may also be provided in
GICC structures on systems supporting GICv3 and above if the GIC
Redistributors are not in the always-on power domain, this
patch didn't implement such feature yet.
Also, ACPI ITS initialization will be added in the following patches.

Signed-off-by: Tomasz Nowicki <[email protected]>
Signed-off-by: Hanjun Guo <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 142 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 31205c7..c4b929c 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/cpu_pm.h>
#include <linux/delay.h>
@@ -764,6 +765,15 @@ static int gic_irq_domain_translate(struct irq_domain *d,
return 0;
}

+ if (is_fwnode_irqchip(fwspec->fwnode)) {
+ if(fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1];
+ return 0;
+ }
+
return -EINVAL;
}

@@ -951,3 +961,135 @@ out_unmap_dist:
}

IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
+
+#ifdef CONFIG_ACPI
+static struct redist_region *redist_regs __initdata;
+static u32 nr_redist_regions __initdata;
+
+static int __init
+gic_acpi_register_redist(phys_addr_t phys_base, u64 size)
+{
+ void __iomem *redist_base;
+ static int count = 0;
+
+ redist_base = ioremap(phys_base, size);
+ if (!redist_base) {
+ pr_err("Couldn't map GICR region @%llx\n", phys_base);
+ return -ENOMEM;
+ }
+
+ redist_regs[count].phys_base = phys_base;
+ redist_regs[count++].redist_base = redist_base;
+ return 0;
+}
+
+static int __init
+gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_redistributor *redist =
+ (struct acpi_madt_generic_redistributor *)header;
+
+ return gic_acpi_register_redist(redist->base_address, redist->length);
+}
+
+static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ /* Subtable presence means that redist exists, that's it */
+ return 0;
+}
+
+static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
+ struct acpi_probe_entry *ape)
+{
+ struct acpi_madt_generic_distributor *dist;
+ int count;
+
+ dist = (struct acpi_madt_generic_distributor *)header;
+ if (dist->version != ape->driver_data)
+ return false;
+
+ /* We need to do that exercise anyway, the sooner the better */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+ gic_acpi_match_gicr, 0);
+ if (count <= 0)
+ return false;
+
+ nr_redist_regions = count;
+ return true;
+}
+
+#define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
+
+static int __init
+gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
+{
+ struct acpi_madt_generic_distributor *dist;
+ struct fwnode_handle *domain_handle;
+ void __iomem *dist_base;
+ int i, err, count;
+
+ /* Get distributor base address */
+ dist = (struct acpi_madt_generic_distributor *)header;
+ dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
+ if (!dist_base) {
+ pr_err("Unable to map GICD registers\n");
+ return -ENOMEM;
+ }
+
+ err = gic_validate_dist_version(dist_base);
+ if (err) {
+ pr_err("No distributor detected at @%p, giving up", dist_base);
+ goto out_dist_unmap;
+ }
+
+ redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions,
+ GFP_KERNEL);
+ if (!redist_regs) {
+ err = -ENOMEM;
+ goto out_dist_unmap;
+ }
+
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+ gic_acpi_parse_madt_redist, 0);
+ if (count <= 0) {
+ err = -ENODEV;
+ goto out_redist_unmap;
+ }
+
+ domain_handle = irq_domain_alloc_fwnode(dist_base);
+ if (!domain_handle) {
+ err = -ENOMEM;
+ goto out_redist_unmap;
+ }
+
+ err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
+ domain_handle);
+ if (err)
+ goto out_fwhandle_free;
+
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+ return 0;
+
+out_fwhandle_free:
+ irq_domain_free_fwnode(domain_handle);
+out_redist_unmap:
+ for (i = 0; i < nr_redist_regions; i++)
+ if (redist_regs[i].redist_base)
+ iounmap(redist_regs[i].redist_base);
+ kfree(redist_regs);
+out_dist_unmap:
+ iounmap(dist_base);
+ return err;
+}
+IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
+ gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v3_maybe, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
+ gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
+ gic_acpi_init);
+#endif
--
1.9.1

2015-12-17 11:52:36

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 03/10] irqchip,GICv3,ACPI: Add redistributor support via GICC structures.

On systems supporting GICv3 and above, in MADT GICC structures, the
field of GICR Base Address holds the 64-bit physical address of the
associated Redistributor if the GIC Redistributors are not in the
always-on power domain, so instead of init GICR regions via GIC
redistributor structure(s), init it with GICR base address in GICC
structures in that case.

Signed-off-by: Hanjun Guo <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3.c | 98 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 89 insertions(+), 9 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index c4b929c..0528e82 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -39,6 +39,7 @@
struct redist_region {
void __iomem *redist_base;
phys_addr_t phys_base;
+ bool single_redist;
};

struct gic_chip_data {
@@ -435,6 +436,9 @@ static int gic_populate_rdist(void)
return 0;
}

+ if (gic_data.redist_regions[i].single_redist)
+ break;
+
if (gic_data.redist_stride) {
ptr += gic_data.redist_stride;
} else {
@@ -965,6 +969,7 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
#ifdef CONFIG_ACPI
static struct redist_region *redist_regs __initdata;
static u32 nr_redist_regions __initdata;
+static bool single_redist;

static int __init
gic_acpi_register_redist(phys_addr_t phys_base, u64 size)
@@ -979,7 +984,8 @@ gic_acpi_register_redist(phys_addr_t phys_base, u64 size)
}

redist_regs[count].phys_base = phys_base;
- redist_regs[count++].redist_base = redist_base;
+ redist_regs[count].redist_base = redist_base;
+ redist_regs[count++].single_redist = single_redist;
return 0;
}

@@ -993,6 +999,48 @@ gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
return gic_acpi_register_redist(redist->base_address, redist->length);
}

+static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *gicc;
+ void __iomem *redist_base;
+ u64 typer;
+ u32 size;
+
+ gicc = (struct acpi_madt_generic_interrupt *)header;
+ redist_base = ioremap(gicc->gicr_base_address, SZ_64K * 2);
+ if (!redist_base)
+ return -ENOMEM;
+
+ typer = readq_relaxed(redist_base + GICR_TYPER);
+ /* don't map reserved page as it's buggy to access it */
+ size = (typer & GICR_TYPER_VLPIS) ? SZ_64K * 3 : SZ_64K * 2;
+ iounmap(redist_base);
+ return gic_acpi_register_redist(gicc->gicr_base_address, size);
+}
+
+static int __init gic_acpi_collect_gicr_base(void)
+{
+ acpi_tbl_entry_handler redist_parser;
+ enum acpi_madt_type type;
+
+ if (single_redist) {
+ type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
+ redist_parser = gic_acpi_parse_madt_gicc;
+ } else {
+ type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
+ redist_parser = gic_acpi_parse_madt_redist;
+ }
+
+ /* Collect redistributor base addresses in GICR entries */
+ if (acpi_table_parse_madt(type, redist_parser, 0) > 0)
+ return 0;
+
+ pr_info("No valid GICR entries exist\n");
+ return -ENODEV;
+}
+
static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
const unsigned long end)
{
@@ -1000,6 +1048,42 @@ static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
return 0;
}

+static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *gicc =
+ (struct acpi_madt_generic_interrupt *)header;
+
+ /*
+ * If GICC is enabled and has valid gicr base address, then it means
+ * GICR base is presented via GICC
+ */
+ if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
+ return 0;
+
+ return -ENODEV;
+}
+
+static int __init gic_acpi_count_gicr_regions(void)
+{
+ int count;
+
+ /* Count how many redistributor regions we have */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+ gic_acpi_match_gicr, 0);
+ if (count > 0) {
+ single_redist = false;
+ return count;
+ }
+
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+ gic_acpi_match_gicc, 0);
+ if (count > 0)
+ single_redist = true;
+
+ return count;
+}
+
static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
struct acpi_probe_entry *ape)
{
@@ -1011,8 +1095,7 @@ static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
return false;

/* We need to do that exercise anyway, the sooner the better */
- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
- gic_acpi_match_gicr, 0);
+ count = gic_acpi_count_gicr_regions();
if (count <= 0)
return false;

@@ -1028,7 +1111,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
struct acpi_madt_generic_distributor *dist;
struct fwnode_handle *domain_handle;
void __iomem *dist_base;
- int i, err, count;
+ int i, err;

/* Get distributor base address */
dist = (struct acpi_madt_generic_distributor *)header;
@@ -1051,12 +1134,9 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
goto out_dist_unmap;
}

- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
- gic_acpi_parse_madt_redist, 0);
- if (count <= 0) {
- err = -ENODEV;
+ err = gic_acpi_collect_gicr_base();
+ if (err)
goto out_redist_unmap;
- }

domain_handle = irq_domain_alloc_fwnode(dist_base);
if (!domain_handle) {
--
1.9.1

2015-12-17 11:54:38

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 04/10] irqchip / GICv3: remove gic root node in ITS

From: Hanjun Guo <[email protected]>

The gic_root_node defined in ITS driver is not actually
used, and the ITS driver seems will not use it in the
future, so just remove it.

Signed-off-by: Hanjun Guo <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index e23d1d1..7ca7f9a 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -97,7 +97,6 @@ struct its_device {

static LIST_HEAD(its_nodes);
static DEFINE_SPINLOCK(its_lock);
-static struct device_node *gic_root_node;
static struct rdists *gic_rdists;

#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist))
@@ -1602,8 +1601,6 @@ int its_init(struct device_node *node, struct rdists *rdists,
}

gic_rdists = rdists;
- gic_root_node = node;
-
its_alloc_lpi_tables();
its_lpi_init(rdists->id_bits);

--
1.9.1

2015-12-17 11:52:40

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 05/10] irqchip, gicv3, its: Mark its_init() and its children as __init

gicv3_init_bases() is the only caller for its_init(),
also it is a __init function, so mark its_init() as __init too,
then recursively mark the functions called as __init.

This will help to introduce ITS initialization using ACPI tables as
we will use acpi_table_parse_entries family functions there which
belong to __init section as well.

Signed-off-by: Hanjun Guo <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 7ca7f9a..2bbed18 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -669,7 +669,7 @@ static int its_chunk_to_lpi(int chunk)
return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
}

-static int its_lpi_init(u32 id_bits)
+static int __init its_lpi_init(u32 id_bits)
{
lpi_chunks = its_lpi_to_chunk(1UL << id_bits);

@@ -1424,7 +1424,8 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}

-static int its_probe(struct device_node *node, struct irq_domain *parent)
+static int __init its_probe(struct device_node *node,
+ struct irq_domain *parent)
{
struct resource res;
struct its_node *its;
@@ -1585,7 +1586,7 @@ static struct of_device_id its_device_id[] = {
{},
};

-int its_init(struct device_node *node, struct rdists *rdists,
+int __init its_init(struct device_node *node, struct rdists *rdists,
struct irq_domain *parent_domain)
{
struct device_node *np;
--
1.9.1

2015-12-17 11:53:59

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 06/10] irqchip/GICv3/ITS: Refator ITS dt init code to prepare for ACPI.

Signed-off-by: Hanjun Guo <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 82 +++++++++++++++++++++++---------------
drivers/irqchip/irq-gic-v3.c | 6 +--
include/linux/irqchip/arm-gic-v3.h | 2 +-
3 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2bbed18..fecb7a6 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -813,7 +813,7 @@ static void its_free_tables(struct its_node *its)
}
}

-static int its_alloc_tables(const char *node_name, struct its_node *its)
+static int its_alloc_tables(struct its_node *its)
{
int err;
int i;
@@ -868,8 +868,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
order);
if (order >= MAX_ORDER) {
order = MAX_ORDER - 1;
- pr_warn("%s: Device Table too large, reduce its page order to %u\n",
- node_name, order);
+ pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u\n",
+ its->phys_base, order);
}
}

@@ -878,8 +878,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
if (alloc_pages > GITS_BASER_PAGES_MAX) {
alloc_pages = GITS_BASER_PAGES_MAX;
order = get_order(GITS_BASER_PAGES_MAX * psz);
- pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n",
- node_name, order, alloc_pages);
+ pr_warn("ITS@0x%lx: Device Table too large, reduce its page order to %u (%u pages)\n",
+ its->phys_base, order, alloc_pages);
}

base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
@@ -948,8 +948,8 @@ retry_baser:
}

if (val != tmp) {
- pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
- node_name, i,
+ pr_err("ITS@0x%lx: GITS_BASER%d doesn't stick: %lx %lx\n",
+ its->phys_base, i,
(unsigned long) val, (unsigned long) tmp);
err = -ENXIO;
goto out_free;
@@ -1424,10 +1424,11 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}

-static int __init its_probe(struct device_node *node,
- struct irq_domain *parent)
+static int __init its_probe_one(phys_addr_t phys_base, unsigned long size,
+ struct irq_domain *parent,
+ bool is_msi_controller,
+ struct fwnode_handle *handler)
{
- struct resource res;
struct its_node *its;
void __iomem *its_base;
struct irq_domain *inner_domain;
@@ -1435,33 +1436,26 @@ static int __init its_probe(struct device_node *node,
u64 baser, tmp;
int err;

- err = of_address_to_resource(node, 0, &res);
- if (err) {
- pr_warn("%s: no regs?\n", node->full_name);
- return -ENXIO;
- }
-
- its_base = ioremap(res.start, resource_size(&res));
+ its_base = ioremap(phys_base, size);
if (!its_base) {
- pr_warn("%s: unable to map registers\n", node->full_name);
+ pr_warn("Unable to map ITS registers\n");
return -ENOMEM;
}

val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
if (val != 0x30 && val != 0x40) {
- pr_warn("%s: no ITS detected, giving up\n", node->full_name);
+ pr_warn("No ITS detected, giving up\n");
err = -ENODEV;
goto out_unmap;
}

err = its_force_quiescent(its_base);
if (err) {
- pr_warn("%s: failed to quiesce, giving up\n",
- node->full_name);
+ pr_warn("Failed to quiesce, giving up\n");
goto out_unmap;
}

- pr_info("ITS: %s\n", node->full_name);
+ pr_info("ITS@0x%lx\n", (long)phys_base);

its = kzalloc(sizeof(*its), GFP_KERNEL);
if (!its) {
@@ -1473,7 +1467,7 @@ static int __init its_probe(struct device_node *node,
INIT_LIST_HEAD(&its->entry);
INIT_LIST_HEAD(&its->its_device_list);
its->base = its_base;
- its->phys_base = res.start;
+ its->phys_base = phys_base;
its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;

its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
@@ -1485,7 +1479,7 @@ static int __init its_probe(struct device_node *node,

its_enable_quirks(its);

- err = its_alloc_tables(node->full_name, its);
+ err = its_alloc_tables(its);
if (err)
goto out_free_cmd;

@@ -1521,7 +1515,7 @@ static int __init its_probe(struct device_node *node,
writeq_relaxed(0, its->base + GITS_CWRITER);
writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);

- if (of_property_read_bool(node, "msi-controller")) {
+ if (is_msi_controller) {
struct msi_domain_info *info;

info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -1530,7 +1524,8 @@ static int __init its_probe(struct device_node *node,
goto out_free_tables;
}

- inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+ inner_domain = irq_domain_create_tree(handler, &its_domain_ops,
+ its);
if (!inner_domain) {
err = -ENOMEM;
kfree(info);
@@ -1558,10 +1553,28 @@ out_free_its:
kfree(its);
out_unmap:
iounmap(its_base);
- pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+ pr_err("ITS@0x%lx: failed probing (%d)\n", (long)phys_base, err);
return err;
}

+static int __init
+its_of_probe(struct device_node *node, struct irq_domain *parent)
+{
+ struct resource res;
+ bool is_msi_controller = false;
+
+ if (of_address_to_resource(node, 0, &res)) {
+ pr_warn("%s: no regs?\n", node->full_name);
+ return -ENXIO;
+ }
+
+ if (of_property_read_bool(node, "msi-controller"))
+ is_msi_controller = true;
+
+ return its_probe_one(res.start, resource_size(&res), parent,
+ is_msi_controller, &node->fwnode);
+}
+
static bool gic_rdists_supports_plpis(void)
{
return !!(readl_relaxed(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
@@ -1586,14 +1599,17 @@ static struct of_device_id its_device_id[] = {
{},
};

-int __init its_init(struct device_node *node, struct rdists *rdists,
- struct irq_domain *parent_domain)
+int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
+ struct irq_domain *parent_domain)
{
- struct device_node *np;
+ struct device_node *np, *of_node;

- for (np = of_find_matching_node(node, its_device_id); np;
- np = of_find_matching_node(np, its_device_id)) {
- its_probe(np, parent_domain);
+ of_node = to_of_node(handle);
+ if (of_node) {
+ for (np = of_find_matching_node(of_node, its_device_id); np;
+ np = of_find_matching_node(np, its_device_id)) {
+ its_of_probe(np, parent_domain);
+ }
}

if (list_empty(&its_nodes)) {
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 0528e82..1f3d761 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -831,7 +831,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
u64 redist_stride,
struct fwnode_handle *handle)
{
- struct device_node *node;
u32 typer;
int gic_irqs;
int err;
@@ -871,10 +870,9 @@ static int __init gic_init_bases(void __iomem *dist_base,

set_handle_irq(gic_handle_irq);

- node = to_of_node(handle);
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
- node) /* Temp hack to prevent ITS init for ACPI */
- its_init(node, &gic_data.rdists, gic_data.domain);
+ to_of_node(handle)) /* Temp hack to prevent ITS init for ACPI */
+ its_init(handle, &gic_data.rdists, gic_data.domain);

gic_smp_init();
gic_dist_init();
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c9ae0c6..6739fd3 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -331,7 +331,7 @@ struct rdists {

struct irq_domain;
int its_cpu_init(void);
-int its_init(struct device_node *node, struct rdists *rdists,
+int its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *domain);

static inline bool gic_enable_sre(void)
--
1.9.1

2015-12-17 11:52:45

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 07/10] ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.

IORT shows representation of IO topology for ARM based systems.
It describes how various components are connected together on
parent-child basis e.g. PCI RC -> SMMU -> ITS.

Initial support allows to:
- register ITS MSI chip along with ITS translation ID and domain token
- find registered domain token based on ITS translation ID
- find registered domain token corresponding to given PCI device
- find PCI device DeviceID based on its RequesterID

Additional features like:
- devices to SMMU binding
- finding platform device DeviceID based on its RequesterID
will be added in next series.

Signed-off-by: Tomasz Nowicki <[email protected]>

Conflicts:
drivers/acpi/Kconfig
---
drivers/acpi/Kconfig | 3 +
drivers/acpi/Makefile | 1 +
drivers/acpi/iort.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/irqchip/Kconfig | 1 +
include/linux/iort.h | 38 ++++++
5 files changed, 369 insertions(+)
create mode 100644 drivers/acpi/iort.c
create mode 100644 include/linux/iort.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5eef4cb..c3664be 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
config ACPI_CCA_REQUIRED
bool

+config IORT_TABLE
+ bool
+
config ACPI_DEBUGGER
bool "AML debugger interface (EXPERIMENTAL)"
select ACPI_DEBUG
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 675eaf3..96b3183 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
+obj-$(CONFIG_IORT_TABLE) += iort.o

# processor has its own "processor." module_param namespace
processor-y := processor_driver.o
diff --git a/drivers/acpi/iort.c b/drivers/acpi/iort.c
new file mode 100644
index 0000000..13efc5f
--- /dev/null
+++ b/drivers/acpi/iort.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2015, Linaro Ltd.
+ * Author: Tomasz Nowicki <[email protected]>
+ *
+ * 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.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt) "ACPI: IORT: " fmt
+
+#include <linux/export.h>
+#include <linux/iort.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+struct iort_its_msi_chip {
+ struct list_head list;
+ struct fwnode_handle *fw_node;
+ u32 translation_id;
+};
+
+typedef acpi_status (*iort_find_node_callback)
+ (struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * to the list from where we can get it back
+ * later on.
+ * @translation_id: ITS ID
+ * @token: domain token
+ *
+ * Returns: 0 on success, -ENOMEM if not memory when allocating list element.
+ */
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+{
+ struct iort_its_msi_chip *its_msi_chip;
+
+ its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
+ if (!its_msi_chip)
+ return -ENOMEM;
+
+ its_msi_chip->fw_node = fw_node;
+ its_msi_chip->translation_id = trans_id;
+
+ list_add(&its_msi_chip->list, &iort_msi_chip_list);
+ return 0;
+}
+
+/**
+ * iort_find_its_domain_token() - find domain token based on given ITS ID.
+ * @translation_id: ITS ID
+ *
+ * Returns: domain token when find on the list, NULL otherwise.
+ */
+struct fwnode_handle *iort_find_its_domain_token(int trans_id)
+{
+ struct iort_its_msi_chip *its_msi_chip;
+
+ list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+ if (its_msi_chip->translation_id == trans_id)
+ return its_msi_chip->fw_node;
+ }
+
+ return NULL;
+}
+
+static struct acpi_iort_node *
+iort_scan_node(enum acpi_iort_node_type type,
+ iort_find_node_callback callback, void *context)
+{
+ struct acpi_iort_node *iort_node, *iort_end;
+ struct acpi_table_iort *iort;
+ int i;
+
+ if (!iort_table)
+ return NULL;
+
+ /*
+ * iort_table and iort 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,
+ 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 NULL;
+ }
+
+ if (iort_node->type == type) {
+ if (ACPI_SUCCESS(callback(iort_node, context)))
+ return iort_node;
+ }
+
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+ iort_node->length);
+ }
+
+ return NULL;
+}
+
+static struct acpi_iort_node *iort_find_parent_node(struct acpi_iort_node *node)
+{
+ 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);
+ /* Firmware bug! */
+ 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;
+}
+
+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:
+ bus = to_pci_bus(dev);
+ pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+ /*
+ * It is assumed that PCI segment numbers have a one-to-one
+ * mapping with root complexes. Each segment number can
+ * represent only one root complex.
+ */
+ if (pci_rc->pci_segment_number == pci_domain_nr(bus))
+ return AE_OK;
+
+ break;
+ }
+
+ return AE_NOT_FOUND;
+}
+
+/**
+ * iort_pci_find_its_id() - find the ITS identifier based on specified device.
+ * @dev: device
+ * @idx: index of the ITS identifier list
+ * @its_id: ITS identifier
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int
+iort_pci_find_its_id(struct device *dev, unsigned int idx, int *its_id)
+{
+ struct acpi_iort_its_group *its;
+ struct acpi_iort_node *node;
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_find_dev_callback, dev);
+ if (!node) {
+ pr_err("can't find node related to %s device\n", dev_name(dev));
+ return -ENXIO;
+ }
+
+ /* Go upstream until find its parent ITS node */
+ while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
+ node = iort_find_parent_node(node);
+ if (!node)
+ return -ENXIO;
+ }
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)node->node_data;
+ if (idx > its->its_count) {
+ pr_err("requested ITS ID index [%d] is greater than available ITS count [%d]\n",
+ idx, its->its_count);
+ return -ENXIO;
+ }
+
+ *its_id = its->identifiers[idx];
+ return 0;
+}
+
+
+/**
+ * iort_find_pci_domain_token() - find registered domain token related to
+ * PCI device
+ * @dev: device
+ *
+ * Returns: domain token on success, NULL otherwise
+ */
+struct fwnode_handle *iort_find_pci_domain_token(struct device *dev)
+{
+ static struct fwnode_handle *domain_handle;
+ int its_id;
+
+ if (iort_pci_find_its_id(dev, 0, &its_id))
+ return NULL;
+
+ domain_handle = iort_find_its_domain_token(its_id);
+ if (!domain_handle)
+ return NULL;
+
+ return domain_handle;
+}
+
+static int
+iort_translate_dev_to_devid(struct acpi_iort_node *node, u32 req_id,
+ u32 *dev_id)
+{
+ u32 curr_id = req_id;
+
+ if (!node)
+ return -EINVAL;
+
+ /* Go upstream */
+ while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
+ struct acpi_iort_id_mapping *id;
+ int i, found = 0;
+
+ /* Exit when no mapping array */
+ if (!node->mapping_offset || !node->mapping_count)
+ return -EINVAL;
+
+ id = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
+
+ for (i = 0, found = 0; i < node->mapping_count; i++, id++) {
+ /*
+ * Single mapping is not translation rule,
+ * lets move on for this case
+ */
+ if (id->flags & ACPI_IORT_ID_SINGLE_MAPPING)
+ continue;
+
+ if (curr_id < id->input_base ||
+ (curr_id > id->input_base + id->id_count))
+ continue;
+
+ curr_id = id->output_base + (curr_id - id->input_base);
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ return -ENXIO;
+
+ node = iort_find_parent_node(node);
+ if (!node)
+ return -ENXIO;
+ }
+
+ *dev_id = curr_id;
+ return 0;
+}
+
+/**
+ * iort_find_pci_id() - find PCI device ID based on requester ID
+ * @dev: device
+ * @req_id: requester ID
+ * @dev_id: device ID
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+int iort_find_pci_id(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
+{
+ struct pci_bus *bus = pdev->bus;
+ struct acpi_iort_node *node;
+ int err;
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_find_dev_callback, &bus->dev);
+ if (!node) {
+ pr_err("can't find node related to %s device\n",
+ dev_name(&pdev->dev));
+ return -ENXIO;
+ }
+
+ err = iort_translate_dev_to_devid(node, req_id, dev_id);
+ return err;
+}
+
+static int __init iort_table_detect(void)
+{
+ acpi_status status;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+ if (ACPI_FAILURE(status)) {
+ const char *msg = acpi_format_exception(status);
+ pr_err("Failed to get table, %s\n", msg);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+arch_initcall(iort_table_detect);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..90f00b1 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -26,6 +26,7 @@ config ARM_GIC_V3
config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
+ select IORT_TABLE if ACPI

config ARM_NVIC
bool
diff --git a/include/linux/iort.h b/include/linux/iort.h
new file mode 100644
index 0000000..783e8d6
--- /dev/null
+++ b/include/linux/iort.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015, Linaro Ltd.
+ * Author: Tomasz Nowicki <[email protected]>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __IORT_H__
+#define __IORT_H__
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI
+
+struct fwnode_handle;
+
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+struct fwnode_handle *iort_find_its_domain_token(int trans_id);
+struct fwnode_handle *iort_find_pci_domain_token(struct device *dev);
+int iort_find_pci_id(struct pci_dev *pdev, u32 req_id, u32 *dev_id);
+#else /* CONFIG_ACPI */
+static inline int
+iort_find_pci_id(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
+{ return -ENXIO; }
+#endif /* CONFIG_ACPI */
+
+#endif /* __IORT_H__ */
--
1.9.1

2015-12-17 11:53:40

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 08/10] irqchip, gicv3, its: Probe ITS in the ACPI way.

Since we prepared ITS for being initialized different that via DT,
it is now possible to parse MADT and pass mandatory info to
firmware-agnostic ITS init call.

Note that we are using here IORT lib to keep track of allocated
domain handler which will be used to build PCI MSI domain on top
in the later patches.

Signed-off-by: Tomasz Nowicki <[email protected]>
Signed-off-by: Hanjun Guo <[email protected]>
---
drivers/irqchip/irq-gic-v3-its.c | 56 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index fecb7a6..2adb220 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,10 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

+#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
@@ -1272,6 +1274,11 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain,
fwspec.param[0] = GIC_IRQ_TYPE_LPI;
fwspec.param[1] = hwirq;
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+ } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
} else {
return -EINVAL;
}
@@ -1594,6 +1601,52 @@ int its_cpu_init(void)
return 0;
}

+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV3_ITS_MEM_SIZE (2 * SZ_64K)
+
+static struct irq_domain *its_parent __initdata;
+
+static int __init
+gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ int err;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ domain_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
+ if (!domain_handle) {
+ pr_err("Unable to allocate GICv2m domain token\n");
+ return -ENOMEM;
+ }
+
+ /* ITS works as msi controller in ACPI case */
+ err = its_probe_one(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE,
+ its_parent, true, domain_handle);
+ if (err) {
+ irq_domain_free_fwnode(domain_handle);
+ return err;
+ }
+ iort_register_domain_token(its_entry->translation_id, domain_handle);
+ return 0;
+}
+
+void __init its_acpi_probe(struct irq_domain *parent_domain)
+{
+ int count;
+
+ its_parent = parent_domain;
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ gic_acpi_parse_madt_its, 0);
+ if (count <= 0)
+ pr_info("No valid GIC ITS entries exist\n");
+}
+#else
+static inline void __init its_acpi_probe(struct irq_domain *parent_domain) { }
+#endif
+
static struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
@@ -1610,7 +1663,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
np = of_find_matching_node(np, its_device_id)) {
its_of_probe(np, parent_domain);
}
- }
+ } else
+ its_acpi_probe(parent_domain);

if (list_empty(&its_nodes)) {
pr_warn("ITS: No ITS available, not enabling LPIs\n");
--
1.9.1

2015-12-17 11:52:50

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 09/10] acpi, gicv3, msi: Factor out code that might be reused for ACPI equivalent.

Firmware agnostic code lands in separate function which do necessary
domain initialization based on unique domain handler.

Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 43 +++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index aee60ed..06165cb 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -106,34 +106,47 @@ static struct of_device_id its_device_id[] = {
{},
};

-static int __init its_pci_msi_init(void)
+static int __init its_pci_msi_init_one(struct fwnode_handle *handle)
{
- struct device_node *np;
struct irq_domain *parent;

+ parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ pr_err("Unable to locate ITS domain\n");
+ return -ENXIO;
+ }
+
+ if (!pci_msi_create_irq_domain(handle, &its_pci_msi_domain_info,
+ parent)) {
+ pr_err("Unable to create PCI domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __init its_pci_of_msi_init(void)
+{
+ struct device_node *np;
+
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;

- parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
- if (!parent || !msi_get_domain_info(parent)) {
- pr_err("%s: unable to locate ITS domain\n",
- np->full_name);
+ if (its_pci_msi_init_one(of_node_to_fwnode(np)))
continue;
- }
-
- if (!pci_msi_create_irq_domain(of_node_to_fwnode(np),
- &its_pci_msi_domain_info,
- parent)) {
- pr_err("%s: unable to create PCI domain\n",
- np->full_name);
- continue;
- }

pr_info("PCI/MSI: %s domain created\n", np->full_name);
}

return 0;
}
+
+static int __init its_pci_msi_init(void)
+{
+ its_pci_of_msi_init();
+ return 0;
+}
+
early_initcall(its_pci_msi_init);
--
1.9.1

2015-12-17 11:53:05

by Tomasz Nowicki

[permalink] [raw]
Subject: [PATCH V2 10/10] acpi, gicv3, its: Use MADT ITS subtable to do PCI/MSI domain initialization.

After refactoring DT code, we let ACPI to build ITS PCI MSI domain
and do requester ID to device ID translation using IORT table.

We have now full PCI MSI domain stack, thus we can enable ITS initialization
from GICv3 core driver for ACPI scenario.

Signed-off-by: Tomasz Nowicki <[email protected]>
---
drivers/irqchip/irq-gic-v3-its-pci-msi.c | 44 +++++++++++++++++++++++++++++++-
drivers/irqchip/irq-gic-v3.c | 3 +--
drivers/pci/msi.c | 3 +++
3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index 06165cb..7f0a958 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

+#include <linux/acpi.h>
+#include <linux/iort.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -143,10 +145,50 @@ static int __init its_pci_of_msi_init(void)
return 0;
}

+#ifdef CONFIG_ACPI
+
+static int __init
+its_pci_msi_parse_madt(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ domain_handle = iort_find_its_domain_token(its_entry->translation_id);
+ if (!domain_handle) {
+ pr_err("ITS@0x%lx: Unable to locate ITS domain handle\n",
+ (long)its_entry->base_address);
+ return 0;
+ }
+
+ if (its_pci_msi_init_one(domain_handle))
+ return 0;
+
+ pci_msi_register_fwnode_provider(&iort_find_pci_domain_token);
+ pr_info("PCI/MSI: ITS@0x%lx domain created\n",
+ (long)its_entry->base_address);
+ return 0;
+}
+
+static int __init its_pci_acpi_msi_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ its_pci_msi_parse_madt, 0);
+ return 0;
+}
+#else
+inline static int __init its_pci_acpi_msi_init(void)
+{
+ return 0;
+}
+#endif
+
static int __init its_pci_msi_init(void)
{
its_pci_of_msi_init();
+ its_pci_acpi_msi_init();
+
return 0;
}
-
early_initcall(its_pci_msi_init);
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 1f3d761..1c9cd5c 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -870,8 +870,7 @@ static int __init gic_init_bases(void __iomem *dist_base,

set_handle_irq(gic_handle_irq);

- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
- to_of_node(handle)) /* Temp hack to prevent ITS init for ACPI */
+ if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
its_init(handle, &gic_data.rdists, gic_data.domain);

gic_smp_init();
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 53e4632..0393114 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -18,6 +18,7 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/iort.h>
#include <linux/slab.h>
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
@@ -1366,6 +1367,8 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
of_node = irq_domain_get_of_node(domain);
if (of_node)
rid = of_msi_map_rid(&pdev->dev, of_node, rid);
+ else
+ iort_find_pci_id(pdev, rid, &rid);

return rid;
}
--
1.9.1

2015-12-17 12:44:57

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH V2 10/10] acpi, gicv3, its: Use MADT ITS subtable to do PCI/MSI domain initialization.

Hi Tomasz,

[auto build test ERROR on v4.4-rc4]
[also build test ERROR on next-20151217]
[cannot apply to tip/irq/core v4.4-rc5]

url: https://github.com/0day-ci/linux/commits/Tomasz-Nowicki/Introduce-ACPI-world-to-GICv3-ITS-irqchip/20151217-195910
config: i386-randconfig-s1-12171706 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

drivers/built-in.o: In function `pci_msi_domain_get_msi_rid':
>> (.text+0x3175d): undefined reference to `iort_find_pci_id'

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (729.00 B)
.config.gz (24.06 kB)
Download all attachments

2015-12-17 13:25:58

by Tomasz Nowicki

[permalink] [raw]
Subject: Re: [PATCH V2 07/10] ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.

On 17.12.2015 12:52, Tomasz Nowicki wrote:
> IORT shows representation of IO topology for ARM based systems.
> It describes how various components are connected together on
> parent-child basis e.g. PCI RC -> SMMU -> ITS.
>
> Initial support allows to:
> - register ITS MSI chip along with ITS translation ID and domain token
> - find registered domain token based on ITS translation ID
> - find registered domain token corresponding to given PCI device
> - find PCI device DeviceID based on its RequesterID
>
> Additional features like:
> - devices to SMMU binding
> - finding platform device DeviceID based on its RequesterID
> will be added in next series.
>
> Signed-off-by: Tomasz Nowicki <[email protected]>
>
> Conflicts:
> drivers/acpi/Kconfig

Sorry for ^^^^ git rebase leftover.

> ---
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/iort.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/irqchip/Kconfig | 1 +
> include/linux/iort.h | 38 ++++++
> 5 files changed, 369 insertions(+)
> create mode 100644 drivers/acpi/iort.c
> create mode 100644 include/linux/iort.h
>

[...]

> diff --git a/include/linux/iort.h b/include/linux/iort.h
> new file mode 100644
> index 0000000..783e8d6
> --- /dev/null
> +++ b/include/linux/iort.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright (C) 2015, Linaro Ltd.
> + * Author: Tomasz Nowicki <[email protected]>
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
> + * Place - Suite 330, Boston, MA 02111-1307 USA.
> + */
> +
> +#ifndef __IORT_H__
> +#define __IORT_H__
> +
> +#include <linux/acpi.h>
> +
> +#ifdef CONFIG_ACPI
> +

As per kbuild test report, this has to be:
#ifdef CONFIG_IORT_TABLE

Will be fixed in the next version.

Regards,
Tomasz

2015-12-17 13:45:32

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH V2 02/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization

Hi Tomasz,

[auto build test ERROR on v4.4-rc4]
[also build test ERROR on next-20151217]
[cannot apply to tip/irq/core v4.4-rc5]

url: https://github.com/0day-ci/linux/commits/Tomasz-Nowicki/Introduce-ACPI-world-to-GICv3-ITS-irqchip/20151217-195910
config: arm-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm

All errors (new ones prefixed by >>):

drivers/irqchip/irq-gic-v3.c: In function 'gic_irq_domain_translate':
>> drivers/irqchip/irq-gic-v3.c:768:2: error: implicit declaration of function 'is_fwnode_irqchip' [-Werror=implicit-function-declaration]
if (is_fwnode_irqchip(fwspec->fwnode)) {
^
cc1: some warnings being treated as errors

vim +/is_fwnode_irqchip +768 drivers/irqchip/irq-gic-v3.c

762 }
763
764 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
765 return 0;
766 }
767
> 768 if (is_fwnode_irqchip(fwspec->fwnode)) {
769 if(fwspec->param_count != 2)
770 return -EINVAL;
771

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.32 kB)
.config.gz (52.71 kB)
Download all attachments

2015-12-17 15:14:29

by Tomasz Nowicki

[permalink] [raw]
Subject: Re: [PATCH V2 02/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization

On 17.12.2015 14:44, kbuild test robot wrote:
> Hi Tomasz,
>
> [auto build test ERROR on v4.4-rc4]
> [also build test ERROR on next-20151217]
> [cannot apply to tip/irq/core v4.4-rc5]
>
> url: https://github.com/0day-ci/linux/commits/Tomasz-Nowicki/Introduce-ACPI-world-to-GICv3-ITS-irqchip/20151217-195910
> config: arm-allyesconfig (attached as .config)
> reproduce:
> wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm
>
> All errors (new ones prefixed by >>):
>
> drivers/irqchip/irq-gic-v3.c: In function 'gic_irq_domain_translate':
>>> drivers/irqchip/irq-gic-v3.c:768:2: error: implicit declaration of function 'is_fwnode_irqchip' [-Werror=implicit-function-declaration]
> if (is_fwnode_irqchip(fwspec->fwnode)) {
> ^
> cc1: some warnings being treated as errors
>
> vim +/is_fwnode_irqchip +768 drivers/irqchip/irq-gic-v3.c
>
> 762 }
> 763
> 764 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> 765 return 0;
> 766 }
> 767
> > 768 if (is_fwnode_irqchip(fwspec->fwnode)) {
> 769 if(fwspec->param_count != 2)
> 770 return -EINVAL;
> 771
>

It is because I missed irqdomain.h header for irq-gic-v3.c and
irq-gic-v3-its.c files. Fixed in version 3.

Tomasz

2015-12-18 10:57:35

by Hanjun Guo

[permalink] [raw]
Subject: Re: [PATCH V2 06/10] irqchip/GICv3/ITS: Refator ITS dt init code to prepare for ACPI.

On 2015/12/17 19:52, Tomasz Nowicki wrote:
> Signed-off-by: Hanjun Guo <[email protected]>
> Signed-off-by: Tomasz Nowicki <[email protected]>

Missing change log here?

Thanks
Hanjun

2015-12-18 11:16:14

by Tomasz Nowicki

[permalink] [raw]
Subject: Re: [PATCH V2 06/10] irqchip/GICv3/ITS: Refator ITS dt init code to prepare for ACPI.

On 18.12.2015 11:57, Hanjun Guo wrote:
> On 2015/12/17 19:52, Tomasz Nowicki wrote:
>> Signed-off-by: Hanjun Guo <[email protected]>
>> Signed-off-by: Tomasz Nowicki <[email protected]>
>
> Missing change log here?
>
I think that subject explains patch changes, if not I will add more
detailed description, let me know.

Tomasz

2015-12-18 11:27:32

by Hanjun Guo

[permalink] [raw]
Subject: Re: [PATCH V2 07/10] ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.

On 2015/12/17 19:52, Tomasz Nowicki wrote:
> +++ b/include/linux/iort.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright (C) 2015, Linaro Ltd.
> + * Author: Tomasz Nowicki <[email protected]>
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
> + * Place - Suite 330, Boston, MA 02111-1307 USA.
> + */
> +
> +#ifndef __IORT_H__
> +#define __IORT_H__
> +
> +#include <linux/acpi.h>
> +
> +#ifdef CONFIG_ACPI

I think we need use CONFIG_IORT_TABLE here, or the code will be compiled
error on no-ARM64 platform, and it will lead to undefined function, just as
the kbuild test robot pointed out:

All errors (new ones prefixed by >>):

drivers/built-in.o: In function `pci_msi_domain_get_msi_rid':

>> (.text+0x3175d): undefined reference to `iort_find_pci_id'


Thanks
Hanjun
> +
> +struct fwnode_handle;
> +
> +int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
> +struct fwnode_handle *iort_find_its_domain_token(int trans_id);
> +struct fwnode_handle *iort_find_pci_domain_token(struct device *dev);
> +int iort_find_pci_id(struct pci_dev *pdev, u32 req_id, u32 *dev_id);
> +#else /* CONFIG_ACPI */
> +static inline int
> +iort_find_pci_id(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
> +{ return -ENXIO; }
> +#endif /* CONFIG_ACPI */
> +
> +#endif /* __IORT_H__ */

2015-12-18 12:28:52

by Hanjun Guo

[permalink] [raw]
Subject: Re: [PATCH V2 07/10] ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.

On 2015/12/17 21:24, Tomasz Nowicki wrote:
> On 17.12.2015 12:52, Tomasz Nowicki wrote:
>> IORT shows representation of IO topology for ARM based systems.
>> It describes how various components are connected together on
>> parent-child basis e.g. PCI RC -> SMMU -> ITS.
>>
>> Initial support allows to:
>> - register ITS MSI chip along with ITS translation ID and domain token
>> - find registered domain token based on ITS translation ID
>> - find registered domain token corresponding to given PCI device
>> - find PCI device DeviceID based on its RequesterID
>>
>> Additional features like:
>> - devices to SMMU binding
>> - finding platform device DeviceID based on its RequesterID
>> will be added in next series.
>>
>> Signed-off-by: Tomasz Nowicki <[email protected]>
>>
>> Conflicts:
>> drivers/acpi/Kconfig
>
> Sorry for ^^^^ git rebase leftover.
>
>> ---
>> drivers/acpi/Kconfig | 3 +
>> drivers/acpi/Makefile | 1 +
>> drivers/acpi/iort.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++
>> drivers/irqchip/Kconfig | 1 +
>> include/linux/iort.h | 38 ++++++
>> 5 files changed, 369 insertions(+)
>> create mode 100644 drivers/acpi/iort.c
>> create mode 100644 include/linux/iort.h
>>
>
> [...]
>
>> diff --git a/include/linux/iort.h b/include/linux/iort.h
>> new file mode 100644
>> index 0000000..783e8d6
>> --- /dev/null
>> +++ b/include/linux/iort.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Copyright (C) 2015, Linaro Ltd.
>> + * Author: Tomasz Nowicki <[email protected]>
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>> + * Place - Suite 330, Boston, MA 02111-1307 USA.
>> + */
>> +
>> +#ifndef __IORT_H__
>> +#define __IORT_H__
>> +
>> +#include <linux/acpi.h>
>> +
>> +#ifdef CONFIG_ACPI
>> +
>
> As per kbuild test report, this has to be:
> #ifdef CONFIG_IORT_TABLE
>
> Will be fixed in the next version.

Sorry, I should notice this email before I comment on this patch
as you already find the way to fix it.

Thanks
Hanjun