All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-07-29 10:08 ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

When ACPI core patches were merged into mainline, there were two TODOs for
ACPI based GIC init, one is the Self-probing for GIC, the other one is to
support stacked irq domain, also the feature of GICv2m and GICv3 is missing
in that patch set.

For ACPI Self-probing for GIC, thanks to the GIC version which is introduced
in ACPI 6.0, we can match the GIC version and GIC driver, based on that,
we introduce the self-probe infrastructure similar as IRQCHIP_DECLARE(),
please see patch 1~3.

The stacked domain thing is more complicated, Marc introduced a patchset
to slove this problem (great thanks!) - Making the generic ACPI GSI layer
irqdomain aware, which is avaiable at:

git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git irq/gsi-irq-domain-v2

so we reworked the GICv2m and GICv3 support on top of it, and combined
them as a single patch set for review.

Note: this patchset has no ITS support for GICv3/4, it will be implmented
in the IORT patchset, which had a draft version but needs to rework it
on top of Marc's Per-device MSI domain & platform MSI patchset.

Tested on GICv2 based FVP base model and AMD Seattle platform, both wired
interrupt and MSI (with some PCI patches) work fine.

Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
at:

git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain

Comments are warmly welcomed.

>From v3:
  - Rework GICv3 patches on top of Marc's tree
  - Add gicV2m support

Hanjun Guo (5):
  irqchip / GIC: Add GIC version support in ACPI MADT
  ACPI / irqchip: Add self-probe infrastructure to initialize IRQ
    controller
  irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init
    code
  irqchip / GICv3: remove the useless comparision of device node in
    xlate
  irqchip / GICv3 / ACPI: Add GICR support via GICC structures

Suravee Suthikulpanit (3):
  ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for
    for GIC MSI and ITS
  PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  irqchip / gicv2m: Introducing gicv2m_acpi_init()

Tomasz Nowicki (2):
  irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
  irqchip / GICv3: Add ACPI support for GICv3+ initialization

 arch/arm64/Kconfig                   |   1 +
 arch/arm64/include/asm/irq.h         |  13 --
 arch/arm64/kernel/acpi.c             |  25 --
 drivers/acpi/Makefile                |   1 +
 drivers/acpi/acpi_gic.c              | 234 +++++++++++++++++++
 drivers/irqchip/Kconfig              |   3 +
 drivers/irqchip/Makefile             |   1 +
 drivers/irqchip/irq-gic-acpi.c       | 175 ++++++++++++++
 drivers/irqchip/irq-gic-v2m.c        | 111 +++++++--
 drivers/irqchip/irq-gic-v3.c         | 438 +++++++++++++++++++++++++++++++----
 drivers/irqchip/irq-gic.c            |   6 +-
 drivers/pci/pci-acpi.c               |  18 ++
 drivers/pci/probe.c                  |   3 +
 include/acpi/acpi_gic.h              |  23 ++
 include/asm-generic/vmlinux.lds.h    |  13 ++
 include/linux/acpi.h                 |  17 ++
 include/linux/acpi_irq.h             |   4 +-
 include/linux/irqchip.h              |  13 ++
 include/linux/irqchip/arm-gic-acpi.h |  10 +-
 include/linux/irqchip/arm-gic.h      |   7 +
 include/linux/mod_devicetable.h      |   8 +
 include/linux/pci-acpi.h             |   4 +
 22 files changed, 1009 insertions(+), 119 deletions(-)
 create mode 100644 drivers/acpi/acpi_gic.c
 create mode 100644 drivers/irqchip/irq-gic-acpi.c
 create mode 100644 include/acpi/acpi_gic.h

-- 
1.9.1


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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-07-29 10:08 ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

When ACPI core patches were merged into mainline, there were two TODOs for
ACPI based GIC init, one is the Self-probing for GIC, the other one is to
support stacked irq domain, also the feature of GICv2m and GICv3 is missing
in that patch set.

For ACPI Self-probing for GIC, thanks to the GIC version which is introduced
in ACPI 6.0, we can match the GIC version and GIC driver, based on that,
we introduce the self-probe infrastructure similar as IRQCHIP_DECLARE(),
please see patch 1~3.

The stacked domain thing is more complicated, Marc introduced a patchset
to slove this problem (great thanks!) - Making the generic ACPI GSI layer
irqdomain aware, which is avaiable at:

git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git irq/gsi-irq-domain-v2

so we reworked the GICv2m and GICv3 support on top of it, and combined
them as a single patch set for review.

Note: this patchset has no ITS support for GICv3/4, it will be implmented
in the IORT patchset, which had a draft version but needs to rework it
on top of Marc's Per-device MSI domain & platform MSI patchset.

Tested on GICv2 based FVP base model and AMD Seattle platform, both wired
interrupt and MSI (with some PCI patches) work fine.

Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
at:

git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain

Comments are warmly welcomed.

>From v3:
  - Rework GICv3 patches on top of Marc's tree
  - Add gicV2m support

Hanjun Guo (5):
  irqchip / GIC: Add GIC version support in ACPI MADT
  ACPI / irqchip: Add self-probe infrastructure to initialize IRQ
    controller
  irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init
    code
  irqchip / GICv3: remove the useless comparision of device node in
    xlate
  irqchip / GICv3 / ACPI: Add GICR support via GICC structures

Suravee Suthikulpanit (3):
  ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for
    for GIC MSI and ITS
  PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  irqchip / gicv2m: Introducing gicv2m_acpi_init()

Tomasz Nowicki (2):
  irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
  irqchip / GICv3: Add ACPI support for GICv3+ initialization

 arch/arm64/Kconfig                   |   1 +
 arch/arm64/include/asm/irq.h         |  13 --
 arch/arm64/kernel/acpi.c             |  25 --
 drivers/acpi/Makefile                |   1 +
 drivers/acpi/acpi_gic.c              | 234 +++++++++++++++++++
 drivers/irqchip/Kconfig              |   3 +
 drivers/irqchip/Makefile             |   1 +
 drivers/irqchip/irq-gic-acpi.c       | 175 ++++++++++++++
 drivers/irqchip/irq-gic-v2m.c        | 111 +++++++--
 drivers/irqchip/irq-gic-v3.c         | 438 +++++++++++++++++++++++++++++++----
 drivers/irqchip/irq-gic.c            |   6 +-
 drivers/pci/pci-acpi.c               |  18 ++
 drivers/pci/probe.c                  |   3 +
 include/acpi/acpi_gic.h              |  23 ++
 include/asm-generic/vmlinux.lds.h    |  13 ++
 include/linux/acpi.h                 |  17 ++
 include/linux/acpi_irq.h             |   4 +-
 include/linux/irqchip.h              |  13 ++
 include/linux/irqchip/arm-gic-acpi.h |  10 +-
 include/linux/irqchip/arm-gic.h      |   7 +
 include/linux/mod_devicetable.h      |   8 +
 include/linux/pci-acpi.h             |   4 +
 22 files changed, 1009 insertions(+), 119 deletions(-)
 create mode 100644 drivers/acpi/acpi_gic.c
 create mode 100644 drivers/irqchip/irq-gic-acpi.c
 create mode 100644 include/acpi/acpi_gic.h

-- 
1.9.1

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

There is a field added in ACPI 6.0 MADT table to indicate the
GIC version, so parse the table to get its value for later use.

If GIC version presented in MADT is 0, we need to fallback to
hardware discovery to get the GIC version.

In ACPI MADT table there is no compatible strings to indicate
various irqchips and also ACPI doesn't support irqchips which
are not compatible with ARM GIC spec, so GIC version can be used
to load different GIC drivers which is needed for the later patch.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 arch/arm64/Kconfig                   |   1 +
 drivers/irqchip/Kconfig              |   3 +
 drivers/irqchip/Makefile             |   1 +
 drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-acpi.h |   1 +
 5 files changed, 115 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-acpi.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 318175f..f2ff61f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -16,6 +16,7 @@ config ARM64
 	select ARM_AMBA
 	select ARM_ARCH_TIMER
 	select ARM_GIC
+	select ARM_GIC_ACPI if ACPI
 	select AUDIT_ARCH_COMPAT_GENERIC
 	select ARM_GIC_V2M if PCI_MSI
 	select ARM_GIC_V3
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 120d815..557ec2f 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -47,6 +47,9 @@ config ARM_VIC_NR
 	  The maximum number of VICs available in the system, for
 	  power management.
 
+config ARM_GIC_ACPI
+	bool
+
 config ATMEL_AIC_IRQ
 	bool
 	select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 11d08c9..383f421 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
new file mode 100644
index 0000000..6537b43
--- /dev/null
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -0,0 +1,109 @@
+/*
+ * ACPI based support for ARM GIC init
+ *
+ * Copyright (C) 2015, Linaro Ltd.
+ * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "ACPI: GIC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/irqchip/arm-gic-acpi.h>
+#include <linux/irqchip/arm-gic-v3.h>
+
+/* GIC version presented in MADT GIC distributor structure */
+static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
+
+static phys_addr_t dist_phy_base __initdata;
+
+static int __init
+acpi_gic_parse_distributor(struct acpi_subtable_header *header,
+			   const unsigned long end)
+{
+	struct acpi_madt_generic_distributor *dist;
+
+	dist = (struct acpi_madt_generic_distributor *)header;
+
+	if (BAD_MADT_ENTRY(dist, end))
+		return -EINVAL;
+
+	gic_version = dist->version;
+	dist_phy_base = dist->base_address;
+	return 0;
+}
+
+static int __init
+match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
+{
+	return 0;
+}
+
+static bool __init acpi_gic_redist_is_present(void)
+{
+	int count;
+
+	/* scan MADT table to find if we have redistributor entries */
+	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+					match_gic_redist, 0);
+
+	/* that's true if we have at least one GIC redistributor entry */
+	return count > 0;
+}
+
+static int __init acpi_gic_version_init(void)
+{
+	int count;
+	u32 reg;
+	void __iomem *dist_base;
+
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+				      acpi_gic_parse_distributor, 0);
+
+	if (count <= 0) {
+		pr_err("No valid GIC distributor entry exists\n");
+		return -ENODEV;
+	}
+
+	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
+		pr_err("Invalid GIC version %d in MADT\n", gic_version);
+		return -EINVAL;
+	}
+
+	/*
+	 * when the GIC version is 0, we fallback to hardware discovery.
+	 * this is also needed to keep compatiable with ACPI 5.1,
+	 * which has no gic_version field in distributor structure and
+	 * reserved as 0.
+	 *
+	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
+	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
+	 * for GICv3/4), so we need to handle it separately.
+	 */
+	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
+		/* it's GICv3/v4 if redistributor is present */
+		if (acpi_gic_redist_is_present()) {
+			dist_base = ioremap(dist_phy_base,
+					    ACPI_GICV3_DIST_MEM_SIZE);
+			if (!dist_base)
+				return -ENOMEM;
+
+			reg = readl_relaxed(dist_base + GICD_PIDR2) &
+					    GIC_PIDR2_ARCH_MASK;
+			if (reg == GIC_PIDR2_ARCH_GICv3)
+				gic_version = ACPI_MADT_GIC_VERSION_V3;
+			else
+				gic_version = ACPI_MADT_GIC_VERSION_V4;
+
+			iounmap(dist_base);
+		} else {
+			gic_version = ACPI_MADT_GIC_VERSION_V2;
+		}
+	}
+
+	return 0;
+}
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index de3419e..13bc676 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -19,6 +19,7 @@
  */
 #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
+#define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
 struct acpi_table_header;
 
-- 
1.9.1

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

There is a field added in ACPI 6.0 MADT table to indicate the
GIC version, so parse the table to get its value for later use.

If GIC version presented in MADT is 0, we need to fallback to
hardware discovery to get the GIC version.

In ACPI MADT table there is no compatible strings to indicate
various irqchips and also ACPI doesn't support irqchips which
are not compatible with ARM GIC spec, so GIC version can be used
to load different GIC drivers which is needed for the later patch.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 arch/arm64/Kconfig                   |   1 +
 drivers/irqchip/Kconfig              |   3 +
 drivers/irqchip/Makefile             |   1 +
 drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-acpi.h |   1 +
 5 files changed, 115 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-acpi.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 318175f..f2ff61f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -16,6 +16,7 @@ config ARM64
 	select ARM_AMBA
 	select ARM_ARCH_TIMER
 	select ARM_GIC
+	select ARM_GIC_ACPI if ACPI
 	select AUDIT_ARCH_COMPAT_GENERIC
 	select ARM_GIC_V2M if PCI_MSI
 	select ARM_GIC_V3
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 120d815..557ec2f 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -47,6 +47,9 @@ config ARM_VIC_NR
 	  The maximum number of VICs available in the system, for
 	  power management.
 
+config ARM_GIC_ACPI
+	bool
+
 config ATMEL_AIC_IRQ
 	bool
 	select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 11d08c9..383f421 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
 obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
new file mode 100644
index 0000000..6537b43
--- /dev/null
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -0,0 +1,109 @@
+/*
+ * ACPI based support for ARM GIC init
+ *
+ * Copyright (C) 2015, Linaro Ltd.
+ * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "ACPI: GIC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/irqchip/arm-gic-acpi.h>
+#include <linux/irqchip/arm-gic-v3.h>
+
+/* GIC version presented in MADT GIC distributor structure */
+static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
+
+static phys_addr_t dist_phy_base __initdata;
+
+static int __init
+acpi_gic_parse_distributor(struct acpi_subtable_header *header,
+			   const unsigned long end)
+{
+	struct acpi_madt_generic_distributor *dist;
+
+	dist = (struct acpi_madt_generic_distributor *)header;
+
+	if (BAD_MADT_ENTRY(dist, end))
+		return -EINVAL;
+
+	gic_version = dist->version;
+	dist_phy_base = dist->base_address;
+	return 0;
+}
+
+static int __init
+match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
+{
+	return 0;
+}
+
+static bool __init acpi_gic_redist_is_present(void)
+{
+	int count;
+
+	/* scan MADT table to find if we have redistributor entries */
+	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+					match_gic_redist, 0);
+
+	/* that's true if we have at least one GIC redistributor entry */
+	return count > 0;
+}
+
+static int __init acpi_gic_version_init(void)
+{
+	int count;
+	u32 reg;
+	void __iomem *dist_base;
+
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+				      acpi_gic_parse_distributor, 0);
+
+	if (count <= 0) {
+		pr_err("No valid GIC distributor entry exists\n");
+		return -ENODEV;
+	}
+
+	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
+		pr_err("Invalid GIC version %d in MADT\n", gic_version);
+		return -EINVAL;
+	}
+
+	/*
+	 * when the GIC version is 0, we fallback to hardware discovery.
+	 * this is also needed to keep compatiable with ACPI 5.1,
+	 * which has no gic_version field in distributor structure and
+	 * reserved as 0.
+	 *
+	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
+	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
+	 * for GICv3/4), so we need to handle it separately.
+	 */
+	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
+		/* it's GICv3/v4 if redistributor is present */
+		if (acpi_gic_redist_is_present()) {
+			dist_base = ioremap(dist_phy_base,
+					    ACPI_GICV3_DIST_MEM_SIZE);
+			if (!dist_base)
+				return -ENOMEM;
+
+			reg = readl_relaxed(dist_base + GICD_PIDR2) &
+					    GIC_PIDR2_ARCH_MASK;
+			if (reg == GIC_PIDR2_ARCH_GICv3)
+				gic_version = ACPI_MADT_GIC_VERSION_V3;
+			else
+				gic_version = ACPI_MADT_GIC_VERSION_V4;
+
+			iounmap(dist_base);
+		} else {
+			gic_version = ACPI_MADT_GIC_VERSION_V2;
+		}
+	}
+
+	return 0;
+}
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index de3419e..13bc676 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -19,6 +19,7 @@
  */
 #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
+#define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
 struct acpi_table_header;
 
-- 
1.9.1

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

* [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

This self-probe infrastructure works in the similar way as OF,
but there is some different in the mechanism:

For DT, the init fn will be called once it finds compatible strings
in DT,  but for ACPI, we init irqchips by static tables, and in
static ACPI tables, there are no compatible strings to indicate
irqchips, but thanks to the GIC version presented in ACPI table,
we can call the corresponding GIC drivers matching the GIC version
with this framework.

This mechanism can also be used for clock declare and may also works
on x86 for some table parsing too.

This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
work.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
 include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
 include/linux/acpi.h              | 16 ++++++++++++++++
 include/linux/irqchip.h           | 13 +++++++++++++
 include/linux/mod_devicetable.h   |  8 ++++++++
 5 files changed, 83 insertions(+)

diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 6537b43..011468d 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
 
 	return 0;
 }
+
+/*
+ * This special acpi_table_id is the sentinel at the end of the
+ * acpi_table_id[] array of all irqchips. It is automatically placed at
+ * the end of the array by the linker, thanks to being part of a
+ * special section.
+ */
+static const struct acpi_table_id
+irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
+
+extern struct acpi_table_id __irqchip_acpi_table[];
+
+void __init acpi_irqchip_init(void)
+{
+	struct acpi_table_id *id;
+
+	if (acpi_disabled)
+		return;
+
+	if (acpi_gic_version_init())
+		return;
+
+	/* scan the irqchip table to match the GIC version and its driver */
+	for (id = __irqchip_acpi_table; id->id[0]; id++) {
+		if (gic_version == (u8)id->driver_data) {
+			acpi_table_parse(id->id,
+					 (acpi_tbl_table_handler)id->handler);
+			return;
+		}
+	}
+
+	pr_err("No matched driver GIC version %d\n", gic_version);
+}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8bd374d..625776c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -181,6 +181,18 @@
 #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
 #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
 
+#ifdef CONFIG_ACPI
+#define ACPI_TABLE(name)						\
+	. = ALIGN(8);							\
+	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
+	*(__##name##_acpi_table)					\
+	*(__##name##_acpi_table_end)
+
+#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
+#else
+#define IRQCHIP_ACPI_MATCH_TABLE()
+#endif
+
 #define KERNEL_DTB()							\
 	STRUCT_ALIGN();							\
 	VMLINUX_SYMBOL(__dtb_start) = .;				\
@@ -516,6 +528,7 @@
 	CPUIDLE_METHOD_OF_TABLES()					\
 	KERNEL_DTB()							\
 	IRQCHIP_OF_MATCH_TABLE()					\
+	IRQCHIP_ACPI_MATCH_TABLE()					\
 	EARLYCON_TABLE()						\
 	EARLYCON_OF_TABLES()
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 0820cb1..04dd0bb 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
 
 #endif
 
+#ifdef CONFIG_ACPI
+#define ACPI_DECLARE(table, name, table_id, data, fn)			\
+	static const struct acpi_table_id __acpi_table_##name		\
+		__used __section(__##table##_acpi_table)		\
+		 = { .id = table_id,					\
+		     .handler = (void *)fn,				\
+		     .driver_data = data }
+#else
+#define ACPI_DECLARE(table, name, table_id, data, fn)			\
+	static const struct acpi_table_id __acpi_table_##name		\
+		__attribute__((unused))					\
+		 = { .id = table_id,					\
+		     .handler = (void *)fn,				\
+		     .driver_data = data }
+#endif
+
 #endif	/*_LINUX_ACPI_H*/
diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
index 6388873..6b66d3e 100644
--- a/include/linux/irqchip.h
+++ b/include/linux/irqchip.h
@@ -11,6 +11,7 @@
 #ifndef _LINUX_IRQCHIP_H
 #define _LINUX_IRQCHIP_H
 
+#include <linux/acpi.h>
 #include <linux/of.h>
 
 /*
@@ -25,6 +26,18 @@
  */
 #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
 
+/*
+ * This macro must be used by the different ARM GIC drivers to declare
+ * the association between their version and their initialization function.
+ *
+ * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
+ * same file.
+ * @gic_version: version of GIC
+ * @fn: initialization function
+ */
+#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
+	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
+
 #ifdef CONFIG_IRQCHIP
 void irqchip_init(void);
 #else
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 34f25b7..105be1f 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -193,6 +193,14 @@ struct acpi_device_id {
 	__u32 cls_msk;
 };
 
+#define ACPI_TABLE_ID_LEN	5
+
+struct acpi_table_id {
+	__u8 id[ACPI_TABLE_ID_LEN];
+	const void *handler;
+	kernel_ulong_t driver_data;
+};
+
 #define PNP_ID_LEN	8
 #define PNP_MAX_DEVICES	8
 
-- 
1.9.1

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

* [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

This self-probe infrastructure works in the similar way as OF,
but there is some different in the mechanism:

For DT, the init fn will be called once it finds compatible strings
in DT,  but for ACPI, we init irqchips by static tables, and in
static ACPI tables, there are no compatible strings to indicate
irqchips, but thanks to the GIC version presented in ACPI table,
we can call the corresponding GIC drivers matching the GIC version
with this framework.

This mechanism can also be used for clock declare and may also works
on x86 for some table parsing too.

This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
work.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
 include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
 include/linux/acpi.h              | 16 ++++++++++++++++
 include/linux/irqchip.h           | 13 +++++++++++++
 include/linux/mod_devicetable.h   |  8 ++++++++
 5 files changed, 83 insertions(+)

diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 6537b43..011468d 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
 
 	return 0;
 }
+
+/*
+ * This special acpi_table_id is the sentinel at the end of the
+ * acpi_table_id[] array of all irqchips. It is automatically placed at
+ * the end of the array by the linker, thanks to being part of a
+ * special section.
+ */
+static const struct acpi_table_id
+irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
+
+extern struct acpi_table_id __irqchip_acpi_table[];
+
+void __init acpi_irqchip_init(void)
+{
+	struct acpi_table_id *id;
+
+	if (acpi_disabled)
+		return;
+
+	if (acpi_gic_version_init())
+		return;
+
+	/* scan the irqchip table to match the GIC version and its driver */
+	for (id = __irqchip_acpi_table; id->id[0]; id++) {
+		if (gic_version == (u8)id->driver_data) {
+			acpi_table_parse(id->id,
+					 (acpi_tbl_table_handler)id->handler);
+			return;
+		}
+	}
+
+	pr_err("No matched driver GIC version %d\n", gic_version);
+}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8bd374d..625776c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -181,6 +181,18 @@
 #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
 #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
 
+#ifdef CONFIG_ACPI
+#define ACPI_TABLE(name)						\
+	. = ALIGN(8);							\
+	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
+	*(__##name##_acpi_table)					\
+	*(__##name##_acpi_table_end)
+
+#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
+#else
+#define IRQCHIP_ACPI_MATCH_TABLE()
+#endif
+
 #define KERNEL_DTB()							\
 	STRUCT_ALIGN();							\
 	VMLINUX_SYMBOL(__dtb_start) = .;				\
@@ -516,6 +528,7 @@
 	CPUIDLE_METHOD_OF_TABLES()					\
 	KERNEL_DTB()							\
 	IRQCHIP_OF_MATCH_TABLE()					\
+	IRQCHIP_ACPI_MATCH_TABLE()					\
 	EARLYCON_TABLE()						\
 	EARLYCON_OF_TABLES()
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 0820cb1..04dd0bb 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
 
 #endif
 
+#ifdef CONFIG_ACPI
+#define ACPI_DECLARE(table, name, table_id, data, fn)			\
+	static const struct acpi_table_id __acpi_table_##name		\
+		__used __section(__##table##_acpi_table)		\
+		 = { .id = table_id,					\
+		     .handler = (void *)fn,				\
+		     .driver_data = data }
+#else
+#define ACPI_DECLARE(table, name, table_id, data, fn)			\
+	static const struct acpi_table_id __acpi_table_##name		\
+		__attribute__((unused))					\
+		 = { .id = table_id,					\
+		     .handler = (void *)fn,				\
+		     .driver_data = data }
+#endif
+
 #endif	/*_LINUX_ACPI_H*/
diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
index 6388873..6b66d3e 100644
--- a/include/linux/irqchip.h
+++ b/include/linux/irqchip.h
@@ -11,6 +11,7 @@
 #ifndef _LINUX_IRQCHIP_H
 #define _LINUX_IRQCHIP_H
 
+#include <linux/acpi.h>
 #include <linux/of.h>
 
 /*
@@ -25,6 +26,18 @@
  */
 #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
 
+/*
+ * This macro must be used by the different ARM GIC drivers to declare
+ * the association between their version and their initialization function.
+ *
+ * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
+ * same file.
+ * @gic_version: version of GIC
+ * @fn: initialization function
+ */
+#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
+	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
+
 #ifdef CONFIG_IRQCHIP
 void irqchip_init(void);
 #else
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 34f25b7..105be1f 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -193,6 +193,14 @@ struct acpi_device_id {
 	__u32 cls_msk;
 };
 
+#define ACPI_TABLE_ID_LEN	5
+
+struct acpi_table_id {
+	__u8 id[ACPI_TABLE_ID_LEN];
+	const void *handler;
+	kernel_ulong_t driver_data;
+};
+
 #define PNP_ID_LEN	8
 #define PNP_MAX_DEVICES	8
 
-- 
1.9.1

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

* [PATCH v4 03/10] irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code
  2015-07-29 10:08 ` Hanjun Guo
  (?)
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Wei Huang, Lorenzo Pieralisi, linux-acpi, Timur Tabi,
	linaro-acpi, linux-kernel, Tomasz Nowicki, Grant Likely,
	Mark Brown, Hanjun Guo, Suravee Suthikulpanit, Bjorn Helgaas,
	Thomas Gleixner, Jiang Liu, linux-arm-kernel

As the ACPI self-probe infrastructure for irqchip is ready,
we use the infrastructure to simplify GICv2 init code.

acpi_irqchip_init() is renamed as acpi_irq_init() to replace
the previous hardcode version of acpi_irq_init() in asm/irq.h,
also cleanup the code which previously calling the GIC driver
manually in arch/arm64/kernel/acpi.c.

>From now on, GIC init calls reside in their drivers only.
This means the code becomes cleaner and it is not spread
outside irqchip driver.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 arch/arm64/include/asm/irq.h         | 13 -------------
 arch/arm64/kernel/acpi.c             | 25 -------------------------
 drivers/irqchip/irq-gic-acpi.c       |  2 +-
 drivers/irqchip/irq-gic.c            |  3 ++-
 include/linux/acpi_irq.h             |  4 +++-
 include/linux/irqchip/arm-gic-acpi.h |  9 +--------
 6 files changed, 7 insertions(+), 49 deletions(-)

diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index bbb251b..94c5367 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -1,8 +1,6 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
-#include <linux/irqchip/arm-gic-acpi.h>
-
 #include <asm-generic/irq.h>
 
 struct pt_regs;
@@ -10,15 +8,4 @@ struct pt_regs;
 extern void migrate_irqs(void);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
-static inline void acpi_irq_init(void)
-{
-	/*
-	 * Hardcode ACPI IRQ chip initialization to GICv2 for now.
-	 * Proper irqchip infrastructure will be implemented along with
-	 * incoming  GICv2m|GICv3|ITS bits.
-	 */
-	acpi_gic_init();
-}
-#define acpi_irq_init acpi_irq_init
-
 #endif
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 19de753..d6463bb 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -205,28 +205,3 @@ void __init acpi_boot_table_init(void)
 			disable_acpi();
 	}
 }
-
-void __init acpi_gic_init(void)
-{
-	struct acpi_table_header *table;
-	acpi_status status;
-	acpi_size tbl_size;
-	int err;
-
-	if (acpi_disabled)
-		return;
-
-	status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
-	if (ACPI_FAILURE(status)) {
-		const char *msg = acpi_format_exception(status);
-
-		pr_err("Failed to get MADT table, %s\n", msg);
-		return;
-	}
-
-	err = gic_v2_acpi_init(table);
-	if (err)
-		pr_err("Failed to initialize GIC IRQ controller");
-
-	early_acpi_os_unmap_memory((char *)table, tbl_size);
-}
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 011468d..95454e3 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -119,7 +119,7 @@ irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
 
 extern struct acpi_table_id __irqchip_acpi_table[];
 
-void __init acpi_irqchip_init(void)
+void __init acpi_irq_init(void)
 {
 	struct acpi_table_id *id;
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ce531e6..bec6b00 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1109,7 +1109,7 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
 	return 0;
 }
 
-int __init
+static int __init
 gic_v2_acpi_init(struct acpi_table_header *table)
 {
 	void __iomem *cpu_base, *dist_base;
@@ -1163,4 +1163,5 @@ gic_v2_acpi_init(struct acpi_table_header *table)
 			   gic_acpi_gsi_desc_populate);
 	return 0;
 }
+IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_GIC_VERSION_V2, gic_v2_acpi_init);
 #endif
diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h
index f10c872..4c0e108 100644
--- a/include/linux/acpi_irq.h
+++ b/include/linux/acpi_irq.h
@@ -3,7 +3,9 @@
 
 #include <linux/irq.h>
 
-#ifndef acpi_irq_init
+#ifdef CONFIG_ACPI
+void acpi_irq_init(void);
+#else
 static inline void acpi_irq_init(void) { }
 #endif
 
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index 13bc676..56cd82c 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -21,12 +21,5 @@
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
-struct acpi_table_header;
-
-int gic_v2_acpi_init(struct acpi_table_header *table);
-void acpi_gic_init(void);
-#else
-static inline void acpi_gic_init(void) { }
-#endif
-
+#endif /* CONFIG_ACPI */
 #endif /* ARM_GIC_ACPI_H_ */
-- 
1.9.1

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

* [PATCH v4 03/10] irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

As the ACPI self-probe infrastructure for irqchip is ready,
we use the infrastructure to simplify GICv2 init code.

acpi_irqchip_init() is renamed as acpi_irq_init() to replace
the previous hardcode version of acpi_irq_init() in asm/irq.h,
also cleanup the code which previously calling the GIC driver
manually in arch/arm64/kernel/acpi.c.

>From now on, GIC init calls reside in their drivers only.
This means the code becomes cleaner and it is not spread
outside irqchip driver.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 arch/arm64/include/asm/irq.h         | 13 -------------
 arch/arm64/kernel/acpi.c             | 25 -------------------------
 drivers/irqchip/irq-gic-acpi.c       |  2 +-
 drivers/irqchip/irq-gic.c            |  3 ++-
 include/linux/acpi_irq.h             |  4 +++-
 include/linux/irqchip/arm-gic-acpi.h |  9 +--------
 6 files changed, 7 insertions(+), 49 deletions(-)

diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index bbb251b..94c5367 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -1,8 +1,6 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
-#include <linux/irqchip/arm-gic-acpi.h>
-
 #include <asm-generic/irq.h>
 
 struct pt_regs;
@@ -10,15 +8,4 @@ struct pt_regs;
 extern void migrate_irqs(void);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
-static inline void acpi_irq_init(void)
-{
-	/*
-	 * Hardcode ACPI IRQ chip initialization to GICv2 for now.
-	 * Proper irqchip infrastructure will be implemented along with
-	 * incoming  GICv2m|GICv3|ITS bits.
-	 */
-	acpi_gic_init();
-}
-#define acpi_irq_init acpi_irq_init
-
 #endif
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 19de753..d6463bb 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -205,28 +205,3 @@ void __init acpi_boot_table_init(void)
 			disable_acpi();
 	}
 }
-
-void __init acpi_gic_init(void)
-{
-	struct acpi_table_header *table;
-	acpi_status status;
-	acpi_size tbl_size;
-	int err;
-
-	if (acpi_disabled)
-		return;
-
-	status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
-	if (ACPI_FAILURE(status)) {
-		const char *msg = acpi_format_exception(status);
-
-		pr_err("Failed to get MADT table, %s\n", msg);
-		return;
-	}
-
-	err = gic_v2_acpi_init(table);
-	if (err)
-		pr_err("Failed to initialize GIC IRQ controller");
-
-	early_acpi_os_unmap_memory((char *)table, tbl_size);
-}
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 011468d..95454e3 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -119,7 +119,7 @@ irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
 
 extern struct acpi_table_id __irqchip_acpi_table[];
 
-void __init acpi_irqchip_init(void)
+void __init acpi_irq_init(void)
 {
 	struct acpi_table_id *id;
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ce531e6..bec6b00 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1109,7 +1109,7 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
 	return 0;
 }
 
-int __init
+static int __init
 gic_v2_acpi_init(struct acpi_table_header *table)
 {
 	void __iomem *cpu_base, *dist_base;
@@ -1163,4 +1163,5 @@ gic_v2_acpi_init(struct acpi_table_header *table)
 			   gic_acpi_gsi_desc_populate);
 	return 0;
 }
+IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_GIC_VERSION_V2, gic_v2_acpi_init);
 #endif
diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h
index f10c872..4c0e108 100644
--- a/include/linux/acpi_irq.h
+++ b/include/linux/acpi_irq.h
@@ -3,7 +3,9 @@
 
 #include <linux/irq.h>
 
-#ifndef acpi_irq_init
+#ifdef CONFIG_ACPI
+void acpi_irq_init(void);
+#else
 static inline void acpi_irq_init(void) { }
 #endif
 
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index 13bc676..56cd82c 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -21,12 +21,5 @@
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
-struct acpi_table_header;
-
-int gic_v2_acpi_init(struct acpi_table_header *table);
-void acpi_gic_init(void);
-#else
-static inline void acpi_gic_init(void) { }
-#endif
-
+#endif /* CONFIG_ACPI */
 #endif /* ARM_GIC_ACPI_H_ */
-- 
1.9.1


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

* [PATCH v4 03/10] irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

As the ACPI self-probe infrastructure for irqchip is ready,
we use the infrastructure to simplify GICv2 init code.

acpi_irqchip_init() is renamed as acpi_irq_init() to replace
the previous hardcode version of acpi_irq_init() in asm/irq.h,
also cleanup the code which previously calling the GIC driver
manually in arch/arm64/kernel/acpi.c.

>From now on, GIC init calls reside in their drivers only.
This means the code becomes cleaner and it is not spread
outside irqchip driver.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 arch/arm64/include/asm/irq.h         | 13 -------------
 arch/arm64/kernel/acpi.c             | 25 -------------------------
 drivers/irqchip/irq-gic-acpi.c       |  2 +-
 drivers/irqchip/irq-gic.c            |  3 ++-
 include/linux/acpi_irq.h             |  4 +++-
 include/linux/irqchip/arm-gic-acpi.h |  9 +--------
 6 files changed, 7 insertions(+), 49 deletions(-)

diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index bbb251b..94c5367 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -1,8 +1,6 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
-#include <linux/irqchip/arm-gic-acpi.h>
-
 #include <asm-generic/irq.h>
 
 struct pt_regs;
@@ -10,15 +8,4 @@ struct pt_regs;
 extern void migrate_irqs(void);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
-static inline void acpi_irq_init(void)
-{
-	/*
-	 * Hardcode ACPI IRQ chip initialization to GICv2 for now.
-	 * Proper irqchip infrastructure will be implemented along with
-	 * incoming  GICv2m|GICv3|ITS bits.
-	 */
-	acpi_gic_init();
-}
-#define acpi_irq_init acpi_irq_init
-
 #endif
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 19de753..d6463bb 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -205,28 +205,3 @@ void __init acpi_boot_table_init(void)
 			disable_acpi();
 	}
 }
-
-void __init acpi_gic_init(void)
-{
-	struct acpi_table_header *table;
-	acpi_status status;
-	acpi_size tbl_size;
-	int err;
-
-	if (acpi_disabled)
-		return;
-
-	status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
-	if (ACPI_FAILURE(status)) {
-		const char *msg = acpi_format_exception(status);
-
-		pr_err("Failed to get MADT table, %s\n", msg);
-		return;
-	}
-
-	err = gic_v2_acpi_init(table);
-	if (err)
-		pr_err("Failed to initialize GIC IRQ controller");
-
-	early_acpi_os_unmap_memory((char *)table, tbl_size);
-}
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 011468d..95454e3 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -119,7 +119,7 @@ irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
 
 extern struct acpi_table_id __irqchip_acpi_table[];
 
-void __init acpi_irqchip_init(void)
+void __init acpi_irq_init(void)
 {
 	struct acpi_table_id *id;
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ce531e6..bec6b00 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1109,7 +1109,7 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
 	return 0;
 }
 
-int __init
+static int __init
 gic_v2_acpi_init(struct acpi_table_header *table)
 {
 	void __iomem *cpu_base, *dist_base;
@@ -1163,4 +1163,5 @@ gic_v2_acpi_init(struct acpi_table_header *table)
 			   gic_acpi_gsi_desc_populate);
 	return 0;
 }
+IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_GIC_VERSION_V2, gic_v2_acpi_init);
 #endif
diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h
index f10c872..4c0e108 100644
--- a/include/linux/acpi_irq.h
+++ b/include/linux/acpi_irq.h
@@ -3,7 +3,9 @@
 
 #include <linux/irq.h>
 
-#ifndef acpi_irq_init
+#ifdef CONFIG_ACPI
+void acpi_irq_init(void);
+#else
 static inline void acpi_irq_init(void) { }
 #endif
 
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index 13bc676..56cd82c 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -21,12 +21,5 @@
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
-struct acpi_table_header;
-
-int gic_v2_acpi_init(struct acpi_table_header *table);
-void acpi_gic_init(void);
-#else
-static inline void acpi_gic_init(void) { }
-#endif
-
+#endif /* CONFIG_ACPI */
 #endif /* ARM_GIC_ACPI_H_ */
-- 
1.9.1

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

* [PATCH v4 04/10] irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

From: Tomasz Nowicki <tomasz.nowicki@linaro.org>

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 <tomasz.nowicki@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 105 +++++++++++++++++++++++++------------------
 1 file changed, 61 insertions(+), 44 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 5492f4e..19a65de 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -766,17 +766,69 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
 	.free = gic_irq_domain_free,
 };
 
+static int __init gic_init_bases(void __iomem *dist_base,
+			    struct redist_region *rdist_regs,
+			    u32 nr_redist_regions,
+			    u64 redist_stride,
+			    void *domain_token)
+{
+	u32 typer;
+	int gic_irqs;
+	int err;
+
+	gic_data.dist_base = dist_base;
+	gic_data.redist_regions = rdist_regs;
+	gic_data.nr_redist_regions = nr_redist_regions;
+	gic_data.redist_stride = redist_stride;
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+	 */
+	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
+	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
+	gic_irqs = GICD_TYPER_IRQS(typer);
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic_data.irq_nr = gic_irqs;
+
+	gic_data.domain = irq_domain_add_tree(domain_token, &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)) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	set_handle_irq(gic_handle_irq);
+
+	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
+		its_init(domain_token, &gic_data.rdists, gic_data.domain);
+
+	gic_smp_init();
+	gic_dist_init();
+	gic_cpu_init();
+	gic_cpu_pm_init();
+
+	return 0;
+
+out_free:
+	if (gic_data.domain)
+		irq_domain_remove(gic_data.domain);
+	free_percpu(gic_data.rdists.rdist);
+	return err;
+}
+
+#ifdef CONFIG_OF
 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;
-	u32 typer;
 	u32 reg;
-	int gic_irqs;
-	int err;
-	int i;
+	int err, i;
 
 	dist_base = of_iomap(node, 0);
 	if (!dist_base) {
@@ -820,47 +872,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
 		redist_stride = 0;
 
-	gic_data.dist_base = dist_base;
-	gic_data.redist_regions = rdist_regs;
-	gic_data.nr_redist_regions = nr_redist_regions;
-	gic_data.redist_stride = redist_stride;
+	err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+			     redist_stride, node);
+	if (!err)
+		return 0;
 
-	/*
-	 * Find out how many interrupts are supported.
-	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
-	 */
-	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
-	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
-	gic_irqs = GICD_TYPER_IRQS(typer);
-	if (gic_irqs > 1020)
-		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.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
-
-	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
-		err = -ENOMEM;
-		goto out_free;
-	}
-
-	set_handle_irq(gic_handle_irq);
-
-	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
-		its_init(node, &gic_data.rdists, gic_data.domain);
-
-	gic_smp_init();
-	gic_dist_init();
-	gic_cpu_init();
-	gic_cpu_pm_init();
-
-	return 0;
-
-out_free:
-	if (gic_data.domain)
-		irq_domain_remove(gic_data.domain);
-	free_percpu(gic_data.rdists.rdist);
 out_unmap_rdist:
 	for (i = 0; i < nr_redist_regions; i++)
 		if (rdist_regs[i].redist_base)
@@ -872,3 +888,4 @@ out_unmap_dist:
 }
 
 IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
+#endif
-- 
1.9.1


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

* [PATCH v4 04/10] irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tomasz Nowicki <tomasz.nowicki@linaro.org>

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 <tomasz.nowicki@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 105 +++++++++++++++++++++++++------------------
 1 file changed, 61 insertions(+), 44 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 5492f4e..19a65de 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -766,17 +766,69 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
 	.free = gic_irq_domain_free,
 };
 
+static int __init gic_init_bases(void __iomem *dist_base,
+			    struct redist_region *rdist_regs,
+			    u32 nr_redist_regions,
+			    u64 redist_stride,
+			    void *domain_token)
+{
+	u32 typer;
+	int gic_irqs;
+	int err;
+
+	gic_data.dist_base = dist_base;
+	gic_data.redist_regions = rdist_regs;
+	gic_data.nr_redist_regions = nr_redist_regions;
+	gic_data.redist_stride = redist_stride;
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+	 */
+	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
+	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
+	gic_irqs = GICD_TYPER_IRQS(typer);
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic_data.irq_nr = gic_irqs;
+
+	gic_data.domain = irq_domain_add_tree(domain_token, &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)) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	set_handle_irq(gic_handle_irq);
+
+	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
+		its_init(domain_token, &gic_data.rdists, gic_data.domain);
+
+	gic_smp_init();
+	gic_dist_init();
+	gic_cpu_init();
+	gic_cpu_pm_init();
+
+	return 0;
+
+out_free:
+	if (gic_data.domain)
+		irq_domain_remove(gic_data.domain);
+	free_percpu(gic_data.rdists.rdist);
+	return err;
+}
+
+#ifdef CONFIG_OF
 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;
-	u32 typer;
 	u32 reg;
-	int gic_irqs;
-	int err;
-	int i;
+	int err, i;
 
 	dist_base = of_iomap(node, 0);
 	if (!dist_base) {
@@ -820,47 +872,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
 		redist_stride = 0;
 
-	gic_data.dist_base = dist_base;
-	gic_data.redist_regions = rdist_regs;
-	gic_data.nr_redist_regions = nr_redist_regions;
-	gic_data.redist_stride = redist_stride;
+	err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+			     redist_stride, node);
+	if (!err)
+		return 0;
 
-	/*
-	 * Find out how many interrupts are supported.
-	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
-	 */
-	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
-	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
-	gic_irqs = GICD_TYPER_IRQS(typer);
-	if (gic_irqs > 1020)
-		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.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
-
-	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
-		err = -ENOMEM;
-		goto out_free;
-	}
-
-	set_handle_irq(gic_handle_irq);
-
-	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
-		its_init(node, &gic_data.rdists, gic_data.domain);
-
-	gic_smp_init();
-	gic_dist_init();
-	gic_cpu_init();
-	gic_cpu_pm_init();
-
-	return 0;
-
-out_free:
-	if (gic_data.domain)
-		irq_domain_remove(gic_data.domain);
-	free_percpu(gic_data.rdists.rdist);
 out_unmap_rdist:
 	for (i = 0; i < nr_redist_regions; i++)
 		if (rdist_regs[i].redist_base)
@@ -872,3 +888,4 @@ out_unmap_dist:
 }
 
 IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
+#endif
-- 
1.9.1

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

* [PATCH v4 05/10] irqchip / GICv3: remove the useless comparision of device node in xlate
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

In gic_irq_domain_xlate(), we match the domain's device node to the
controller and it turns out pretty useless, because we're always
registering the GIC domain with its device_node on DT, this is really
guaranteed to match.

Since we unify the way of matching irqdomain in DT and ACPI, this is
also a blocker of making this function usable in the context
of ACPI, so just remove it.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 19a65de..c0b96c6 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -706,8 +706,6 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
 				const u32 *intspec, unsigned int intsize,
 				unsigned long *out_hwirq, unsigned int *out_type)
 {
-	if (irq_domain_get_of_node(d) != controller)
-		return -EINVAL;
 	if (intsize < 3)
 		return -EINVAL;
 
-- 
1.9.1


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

* [PATCH v4 05/10] irqchip / GICv3: remove the useless comparision of device node in xlate
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

In gic_irq_domain_xlate(), we match the domain's device node to the
controller and it turns out pretty useless, because we're always
registering the GIC domain with its device_node on DT, this is really
guaranteed to match.

Since we unify the way of matching irqdomain in DT and ACPI, this is
also a blocker of making this function usable in the context
of ACPI, so just remove it.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 19a65de..c0b96c6 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -706,8 +706,6 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
 				const u32 *intspec, unsigned int intsize,
 				unsigned long *out_hwirq, unsigned int *out_type)
 {
-	if (irq_domain_get_of_node(d) != controller)
-		return -EINVAL;
 	if (intsize < 3)
 		return -EINVAL;
 
-- 
1.9.1

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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

From: Tomasz Nowicki <tomasz.nowicki@linaro.org>

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.

Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
[hj: Rework this patch and fix multi issues]
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 169 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index c0b96c6..ebc5604 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>
@@ -25,6 +26,7 @@
 #include <linux/percpu.h>
 #include <linux/slab.h>
 
+#include <linux/irqchip/arm-gic-acpi.h>
 #include <linux/irqchip/arm-gic-v3.h>
 
 #include <asm/cputype.h>
@@ -802,7 +804,8 @@ 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())
-		its_init(domain_token, &gic_data.rdists, gic_data.domain);
+		its_init(irq_domain_token_to_of_node(domain_token),
+			 &gic_data.rdists, gic_data.domain);
 
 	gic_smp_init();
 	gic_dist_init();
@@ -818,6 +821,16 @@ out_free:
 	return err;
 }
 
+static int __init detect_distributor(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;
+}
+
 #ifdef CONFIG_OF
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
@@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 	struct redist_region *rdist_regs;
 	u64 redist_stride;
 	u32 nr_redist_regions;
-	u32 reg;
 	int err, i;
 
 	dist_base = of_iomap(node, 0);
@@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 		return -ENXIO;
 	}
 
-	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
-	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+	err = detect_distributor(dist_base);
+	if (err) {
 		pr_err("%s: no distributor detected, giving up\n",
 			node->full_name);
-		err = -ENODEV;
 		goto out_unmap_dist;
 	}
 
@@ -887,3 +898,156 @@ out_unmap_dist:
 
 IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
 #endif
+
+#ifdef CONFIG_ACPI
+static struct redist_region *redist_regs __initdata;
+static u32 nr_redist_regions __initdata;
+static phys_addr_t dist_phys_base __initdata;
+
+static int __init
+gic_acpi_register_redist(u64 phys_base, u64 size)
+{
+	struct redist_region *redist_regs_new;
+	void __iomem *redist_base;
+
+	redist_regs_new = krealloc(redist_regs,
+				   sizeof(*redist_regs) * (nr_redist_regions + 1),
+				   GFP_KERNEL);
+	if (!redist_regs_new) {
+		pr_err("Couldn't allocate resource for GICR region\n");
+		return -ENOMEM;
+	}
+
+	redist_regs = redist_regs_new;
+
+	redist_base = ioremap(phys_base, size);
+	if (!redist_base) {
+		pr_err("Couldn't map GICR region @%llx\n", phys_base);
+		return -ENOMEM;
+	}
+
+	redist_regs[nr_redist_regions].phys_base = phys_base;
+	redist_regs[nr_redist_regions].redist_base = redist_base;
+	nr_redist_regions++;
+	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;
+
+	if (BAD_MADT_ENTRY(header, end))
+		return -EINVAL;
+
+	redist = (struct acpi_madt_generic_redistributor *)header;
+	if (!redist->base_address)
+		return -EINVAL;
+
+	return gic_acpi_register_redist(redist->base_address, redist->length);
+}
+
+static int __init
+gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
+				const unsigned long end)
+{
+	struct acpi_madt_generic_distributor *dist;
+
+	dist = (struct acpi_madt_generic_distributor *)header;
+
+	if (BAD_MADT_ENTRY(dist, end))
+		return -EINVAL;
+
+	dist_phys_base = dist->base_address;
+	return 0;
+}
+
+static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
+				      u32 gsi, unsigned int irq_type)
+{
+	/*
+	 * Encode GSI and triggering information the way the GIC likes
+	 * them.
+	 */
+	if (WARN_ON(gsi < 16))
+		return -EINVAL;
+
+	if (gsi >= 32) {
+		data->param[0] = 0;		/* SPI */
+		data->param[1] = gsi - 32;
+		data->param[2] = irq_type;
+	} else {
+		data->param[0] = 1; 		/* PPI */
+		data->param[1] = gsi - 16;
+		data->param[2] = 0xff << 4 | irq_type;
+	}
+
+	data->param_count = 3;
+
+	return 0;
+}
+
+static int __init
+gic_acpi_init(struct acpi_table_header *table)
+{
+	int count, i, err = 0;
+	void __iomem *dist_base;
+
+	/* Get distributor base address */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+				sizeof(struct acpi_table_madt),
+				gic_acpi_parse_madt_distributor, table,
+				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
+	if (count <= 0) {
+		pr_err("No valid GICD entry exist\n");
+		return -EINVAL;
+	} else if (count > 1) {
+		pr_err("More than one GICD entry detected\n");
+		return -EINVAL;
+	}
+
+	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
+	if (!dist_base) {
+		pr_err("Unable to map GICD registers\n");
+		return -ENOMEM;
+	}
+
+	err = detect_distributor(dist_base);
+	if (err) {
+		pr_err("No distributor detected at @%p, giving up", dist_base);
+		goto out_dist_unmap;
+	}
+
+	/* Collect redistributor base addresses */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_redist, table,
+			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
+	if (count <= 0) {
+		pr_info("No valid GICR entries exist\n");
+		err = -EINVAL;
+		goto out_redist_unmap;
+	}
+
+	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
+			     (void *)ACPI_IRQ_MODEL_GIC);
+	if (err)
+		goto out_redist_unmap;
+
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
+			   gic_acpi_gsi_desc_populate);
+	return 0;
+
+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_GIC_VERSION_V3, gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
+#endif
-- 
1.9.1

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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

From: Tomasz Nowicki <tomasz.nowicki@linaro.org>

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.

Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
[hj: Rework this patch and fix multi issues]
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 169 insertions(+), 5 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index c0b96c6..ebc5604 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>
@@ -25,6 +26,7 @@
 #include <linux/percpu.h>
 #include <linux/slab.h>
 
+#include <linux/irqchip/arm-gic-acpi.h>
 #include <linux/irqchip/arm-gic-v3.h>
 
 #include <asm/cputype.h>
@@ -802,7 +804,8 @@ 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())
-		its_init(domain_token, &gic_data.rdists, gic_data.domain);
+		its_init(irq_domain_token_to_of_node(domain_token),
+			 &gic_data.rdists, gic_data.domain);
 
 	gic_smp_init();
 	gic_dist_init();
@@ -818,6 +821,16 @@ out_free:
 	return err;
 }
 
+static int __init detect_distributor(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;
+}
+
 #ifdef CONFIG_OF
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
@@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 	struct redist_region *rdist_regs;
 	u64 redist_stride;
 	u32 nr_redist_regions;
-	u32 reg;
 	int err, i;
 
 	dist_base = of_iomap(node, 0);
@@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 		return -ENXIO;
 	}
 
-	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
-	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+	err = detect_distributor(dist_base);
+	if (err) {
 		pr_err("%s: no distributor detected, giving up\n",
 			node->full_name);
-		err = -ENODEV;
 		goto out_unmap_dist;
 	}
 
@@ -887,3 +898,156 @@ out_unmap_dist:
 
 IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
 #endif
+
+#ifdef CONFIG_ACPI
+static struct redist_region *redist_regs __initdata;
+static u32 nr_redist_regions __initdata;
+static phys_addr_t dist_phys_base __initdata;
+
+static int __init
+gic_acpi_register_redist(u64 phys_base, u64 size)
+{
+	struct redist_region *redist_regs_new;
+	void __iomem *redist_base;
+
+	redist_regs_new = krealloc(redist_regs,
+				   sizeof(*redist_regs) * (nr_redist_regions + 1),
+				   GFP_KERNEL);
+	if (!redist_regs_new) {
+		pr_err("Couldn't allocate resource for GICR region\n");
+		return -ENOMEM;
+	}
+
+	redist_regs = redist_regs_new;
+
+	redist_base = ioremap(phys_base, size);
+	if (!redist_base) {
+		pr_err("Couldn't map GICR region @%llx\n", phys_base);
+		return -ENOMEM;
+	}
+
+	redist_regs[nr_redist_regions].phys_base = phys_base;
+	redist_regs[nr_redist_regions].redist_base = redist_base;
+	nr_redist_regions++;
+	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;
+
+	if (BAD_MADT_ENTRY(header, end))
+		return -EINVAL;
+
+	redist = (struct acpi_madt_generic_redistributor *)header;
+	if (!redist->base_address)
+		return -EINVAL;
+
+	return gic_acpi_register_redist(redist->base_address, redist->length);
+}
+
+static int __init
+gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
+				const unsigned long end)
+{
+	struct acpi_madt_generic_distributor *dist;
+
+	dist = (struct acpi_madt_generic_distributor *)header;
+
+	if (BAD_MADT_ENTRY(dist, end))
+		return -EINVAL;
+
+	dist_phys_base = dist->base_address;
+	return 0;
+}
+
+static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
+				      u32 gsi, unsigned int irq_type)
+{
+	/*
+	 * Encode GSI and triggering information the way the GIC likes
+	 * them.
+	 */
+	if (WARN_ON(gsi < 16))
+		return -EINVAL;
+
+	if (gsi >= 32) {
+		data->param[0] = 0;		/* SPI */
+		data->param[1] = gsi - 32;
+		data->param[2] = irq_type;
+	} else {
+		data->param[0] = 1; 		/* PPI */
+		data->param[1] = gsi - 16;
+		data->param[2] = 0xff << 4 | irq_type;
+	}
+
+	data->param_count = 3;
+
+	return 0;
+}
+
+static int __init
+gic_acpi_init(struct acpi_table_header *table)
+{
+	int count, i, err = 0;
+	void __iomem *dist_base;
+
+	/* Get distributor base address */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+				sizeof(struct acpi_table_madt),
+				gic_acpi_parse_madt_distributor, table,
+				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
+	if (count <= 0) {
+		pr_err("No valid GICD entry exist\n");
+		return -EINVAL;
+	} else if (count > 1) {
+		pr_err("More than one GICD entry detected\n");
+		return -EINVAL;
+	}
+
+	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
+	if (!dist_base) {
+		pr_err("Unable to map GICD registers\n");
+		return -ENOMEM;
+	}
+
+	err = detect_distributor(dist_base);
+	if (err) {
+		pr_err("No distributor detected at @%p, giving up", dist_base);
+		goto out_dist_unmap;
+	}
+
+	/* Collect redistributor base addresses */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_redist, table,
+			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
+	if (count <= 0) {
+		pr_info("No valid GICR entries exist\n");
+		err = -EINVAL;
+		goto out_redist_unmap;
+	}
+
+	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
+			     (void *)ACPI_IRQ_MODEL_GIC);
+	if (err)
+		goto out_redist_unmap;
+
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
+			   gic_acpi_gsi_desc_populate);
+	return 0;
+
+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_GIC_VERSION_V3, gic_acpi_init);
+IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
+#endif
-- 
1.9.1

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

* [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

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.

As GICR base in MADT GICC is another way to indicate the GIC version
is 3 or 4, add its support to find out the GIC versions.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
 drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
 include/linux/irqchip/arm-gic-acpi.h |   2 +
 3 files changed, 215 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 95454e3..3e5c8f4 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
 
 static phys_addr_t dist_phy_base __initdata;
 
+u8 __init acpi_gic_version(void)
+{
+	return gic_version;
+}
+
 static int __init
 acpi_gic_parse_distributor(struct acpi_subtable_header *header,
 			   const unsigned long end)
@@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
 }
 
 static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+			 const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc;
+
+	gicc = (struct acpi_madt_generic_interrupt *)header;
+
+	if (BAD_MADT_GICC_ENTRY(gicc, end))
+		return -EINVAL;
+
+	/*
+	 * If GICC is enabled but has no valid gicr base address, then it
+	 * means GICR base is not presented via GICC
+	 */
+	if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __init
 match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
 {
 	return 0;
@@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
 	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
 					match_gic_redist, 0);
 
-	/* that's true if we have at least one GIC redistributor entry */
+	/* has at least one GIC redistributor entry */
+	if (count > 0)
+		return true;
+
+	/* else try to find GICR base in GICC entries */
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+				      gic_acpi_parse_madt_gicc, 0);
+
 	return count > 0;
 }
 
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ebc5604..b72ccbb 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
 		writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
 }
 
-static int gic_populate_rdist(void)
+static int gic_populate_rdist_with_regions(u64 mpidr)
 {
-	u64 mpidr = cpu_logical_map(smp_processor_id());
 	u64 typer;
 	u32 aff;
 	int i;
@@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
 		} while (!(typer & GICR_TYPER_LAST));
 	}
 
+	return -ENODEV;
+}
+
+#ifdef CONFIG_ACPI
+/*
+ * Populate redist when GIC redistributor address is presented in ACPI
+ * MADT GICC entries
+ */
+static int gic_populate_rdist_with_gicr_base(u64 mpidr);
+#else
+static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
+{
+	return -ENODEV;
+}
+#endif
+
+static int gic_populate_rdist(void)
+{
+	u64 mpidr = cpu_logical_map(smp_processor_id());
+
+	if (gic_data.nr_redist_regions) {
+		if (!gic_populate_rdist_with_regions(mpidr))
+			return 0;
+	} else {
+		if (!gic_populate_rdist_with_gicr_base(mpidr))
+			return 0;
+	}
+
 	/* We couldn't even deal with ourselves... */
 	WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
 	     smp_processor_id(), (unsigned long long)mpidr);
@@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
 #endif
 
 #ifdef CONFIG_ACPI
+
+struct acpi_gicc_redist {
+	struct list_head list;
+	u64 mpidr;
+	phys_addr_t phys_base;
+	void __iomem *redist_base;
+};
+
+static LIST_HEAD(redist_list);
+
 static struct redist_region *redist_regs __initdata;
 static u32 nr_redist_regions __initdata;
 static phys_addr_t dist_phys_base __initdata;
@@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
 	return 0;
 }
 
+static void __init
+gic_acpi_release_redist_regions(void)
+{
+	int i;
+
+	for (i = 0; i < nr_redist_regions; i++)
+		if (redist_regs[i].redist_base)
+			iounmap(redist_regs[i].redist_base);
+	kfree(redist_regs);
+}
+
 static int __init
 gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
 			const unsigned long end)
@@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
 }
 
 static int __init
+gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
+{
+	struct acpi_gicc_redist *redist;
+
+	redist = kzalloc(sizeof(*redist), GFP_KERNEL);
+	if (!redist)
+		return -ENOMEM;
+
+	redist->mpidr = mpidr;
+	redist->phys_base = phys_base;
+
+	if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
+		/* RD_base + SGI_base */
+		redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
+	else
+		/*
+		 * RD_base + SGI_base + VLPI_base,
+		 * we don't map reserved page as it's buggy to access it
+		 */
+		redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
+
+	if (!redist->redist_base) {
+		kfree(redist);
+		return -ENOMEM;
+	}
+
+	list_add(&redist->list, &redist_list);
+	return 0;
+}
+
+static void __init
+gic_acpi_release_gicc_redist(void)
+{
+	struct acpi_gicc_redist *redist, *t;
+
+	list_for_each_entry_safe(redist, t, &redist_list, list) {
+		list_del(&redist->list);
+		iounmap(redist->redist_base);
+		kfree(redist);
+	}
+}
+
+static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+			 const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc;
+
+	gicc = (struct acpi_madt_generic_interrupt *)header;
+
+	if (BAD_MADT_GICC_ENTRY(gicc, end))
+		return -EINVAL;
+
+	/*
+	 * just quietly ingore the disabled CPU(s) and continue
+	 * to find the enabled one(s), if we return error here,
+	 * the scanning will be stopped.
+	 */
+	if (!(gicc->flags & ACPI_MADT_ENABLED))
+		return 0;
+
+	return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
+					gicc->arm_mpidr);
+}
+
+static int gic_populate_rdist_with_gicr_base(u64 mpidr)
+{
+	struct acpi_gicc_redist *redist;
+	void __iomem *ptr;
+	u32 reg;
+
+	list_for_each_entry(redist, &redist_list, list) {
+		if (redist->mpidr != mpidr)
+			continue;
+
+		ptr = redist->redist_base;
+		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
+		if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+			pr_warn("No redistributor present @%p\n", ptr);
+			return -ENODEV;
+		}
+
+		gic_data_rdist_rd_base() = ptr;
+		gic_data_rdist()->phys_base = redist->phys_base;
+		pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
+			smp_processor_id(),
+			(unsigned long long)mpidr,
+			&gic_data_rdist()->phys_base);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int __init collect_gicr_base(struct acpi_table_header *table)
+{
+	int count;
+
+	/* Collect redistributor base addresses in GICR entries */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_redist, table,
+			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
+	if (count > 0)
+		return 0;
+
+	pr_info("No valid GICR entries exist, try GICC entries\n");
+
+	/* Collect redistributor base addresses in GICC entries */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_gicc, table,
+			ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
+	if (count > 0 && !list_empty(&redist_list))
+		return 0;
+
+	pr_info("No valid GICC entries exist for GICR base\n");
+	return -ENODEV;
+}
+
+static int __init
 gic_acpi_init(struct acpi_table_header *table)
 {
-	int count, i, err = 0;
+	int count, err = 0;
 	void __iomem *dist_base;
 
 	/* Get distributor base address */
@@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
 	}
 
 	/* Collect redistributor base addresses */
-	count = acpi_parse_entries(ACPI_SIG_MADT,
-			sizeof(struct acpi_table_madt),
-			gic_acpi_parse_madt_redist, table,
-			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
-	if (count <= 0) {
-		pr_info("No valid GICR entries exist\n");
-		err = -EINVAL;
-		goto out_redist_unmap;
-	}
+	if (collect_gicr_base(table))
+		goto out_release_redist;
 
 	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
 			     (void *)ACPI_IRQ_MODEL_GIC);
 	if (err)
-		goto out_redist_unmap;
+		goto out_release_redist;
 
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
 			   gic_acpi_gsi_desc_populate);
 	return 0;
 
-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_release_redist:
+	gic_acpi_release_redist_regions();
+	if (!list_empty(&redist_list))
+		gic_acpi_release_gicc_redist();
 out_dist_unmap:
 	iounmap(dist_base);
 	return err;
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index 56cd82c..0d43f515 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -21,5 +21,7 @@
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
+u8 acpi_gic_version(void);
+
 #endif /* CONFIG_ACPI */
 #endif /* ARM_GIC_ACPI_H_ */
-- 
1.9.1

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

* [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

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.

As GICR base in MADT GICC is another way to indicate the GIC version
is 3 or 4, add its support to find out the GIC versions.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
 drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
 include/linux/irqchip/arm-gic-acpi.h |   2 +
 3 files changed, 215 insertions(+), 19 deletions(-)

diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
index 95454e3..3e5c8f4 100644
--- a/drivers/irqchip/irq-gic-acpi.c
+++ b/drivers/irqchip/irq-gic-acpi.c
@@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
 
 static phys_addr_t dist_phy_base __initdata;
 
+u8 __init acpi_gic_version(void)
+{
+	return gic_version;
+}
+
 static int __init
 acpi_gic_parse_distributor(struct acpi_subtable_header *header,
 			   const unsigned long end)
@@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
 }
 
 static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+			 const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc;
+
+	gicc = (struct acpi_madt_generic_interrupt *)header;
+
+	if (BAD_MADT_GICC_ENTRY(gicc, end))
+		return -EINVAL;
+
+	/*
+	 * If GICC is enabled but has no valid gicr base address, then it
+	 * means GICR base is not presented via GICC
+	 */
+	if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __init
 match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
 {
 	return 0;
@@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
 	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
 					match_gic_redist, 0);
 
-	/* that's true if we have at least one GIC redistributor entry */
+	/* has at least one GIC redistributor entry */
+	if (count > 0)
+		return true;
+
+	/* else try to find GICR base in GICC entries */
+	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+				      gic_acpi_parse_madt_gicc, 0);
+
 	return count > 0;
 }
 
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ebc5604..b72ccbb 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
 		writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
 }
 
-static int gic_populate_rdist(void)
+static int gic_populate_rdist_with_regions(u64 mpidr)
 {
-	u64 mpidr = cpu_logical_map(smp_processor_id());
 	u64 typer;
 	u32 aff;
 	int i;
@@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
 		} while (!(typer & GICR_TYPER_LAST));
 	}
 
+	return -ENODEV;
+}
+
+#ifdef CONFIG_ACPI
+/*
+ * Populate redist when GIC redistributor address is presented in ACPI
+ * MADT GICC entries
+ */
+static int gic_populate_rdist_with_gicr_base(u64 mpidr);
+#else
+static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
+{
+	return -ENODEV;
+}
+#endif
+
+static int gic_populate_rdist(void)
+{
+	u64 mpidr = cpu_logical_map(smp_processor_id());
+
+	if (gic_data.nr_redist_regions) {
+		if (!gic_populate_rdist_with_regions(mpidr))
+			return 0;
+	} else {
+		if (!gic_populate_rdist_with_gicr_base(mpidr))
+			return 0;
+	}
+
 	/* We couldn't even deal with ourselves... */
 	WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
 	     smp_processor_id(), (unsigned long long)mpidr);
@@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
 #endif
 
 #ifdef CONFIG_ACPI
+
+struct acpi_gicc_redist {
+	struct list_head list;
+	u64 mpidr;
+	phys_addr_t phys_base;
+	void __iomem *redist_base;
+};
+
+static LIST_HEAD(redist_list);
+
 static struct redist_region *redist_regs __initdata;
 static u32 nr_redist_regions __initdata;
 static phys_addr_t dist_phys_base __initdata;
@@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
 	return 0;
 }
 
+static void __init
+gic_acpi_release_redist_regions(void)
+{
+	int i;
+
+	for (i = 0; i < nr_redist_regions; i++)
+		if (redist_regs[i].redist_base)
+			iounmap(redist_regs[i].redist_base);
+	kfree(redist_regs);
+}
+
 static int __init
 gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
 			const unsigned long end)
@@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
 }
 
 static int __init
+gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
+{
+	struct acpi_gicc_redist *redist;
+
+	redist = kzalloc(sizeof(*redist), GFP_KERNEL);
+	if (!redist)
+		return -ENOMEM;
+
+	redist->mpidr = mpidr;
+	redist->phys_base = phys_base;
+
+	if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
+		/* RD_base + SGI_base */
+		redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
+	else
+		/*
+		 * RD_base + SGI_base + VLPI_base,
+		 * we don't map reserved page as it's buggy to access it
+		 */
+		redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
+
+	if (!redist->redist_base) {
+		kfree(redist);
+		return -ENOMEM;
+	}
+
+	list_add(&redist->list, &redist_list);
+	return 0;
+}
+
+static void __init
+gic_acpi_release_gicc_redist(void)
+{
+	struct acpi_gicc_redist *redist, *t;
+
+	list_for_each_entry_safe(redist, t, &redist_list, list) {
+		list_del(&redist->list);
+		iounmap(redist->redist_base);
+		kfree(redist);
+	}
+}
+
+static int __init
+gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
+			 const unsigned long end)
+{
+	struct acpi_madt_generic_interrupt *gicc;
+
+	gicc = (struct acpi_madt_generic_interrupt *)header;
+
+	if (BAD_MADT_GICC_ENTRY(gicc, end))
+		return -EINVAL;
+
+	/*
+	 * just quietly ingore the disabled CPU(s) and continue
+	 * to find the enabled one(s), if we return error here,
+	 * the scanning will be stopped.
+	 */
+	if (!(gicc->flags & ACPI_MADT_ENABLED))
+		return 0;
+
+	return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
+					gicc->arm_mpidr);
+}
+
+static int gic_populate_rdist_with_gicr_base(u64 mpidr)
+{
+	struct acpi_gicc_redist *redist;
+	void __iomem *ptr;
+	u32 reg;
+
+	list_for_each_entry(redist, &redist_list, list) {
+		if (redist->mpidr != mpidr)
+			continue;
+
+		ptr = redist->redist_base;
+		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
+		if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
+			pr_warn("No redistributor present @%p\n", ptr);
+			return -ENODEV;
+		}
+
+		gic_data_rdist_rd_base() = ptr;
+		gic_data_rdist()->phys_base = redist->phys_base;
+		pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
+			smp_processor_id(),
+			(unsigned long long)mpidr,
+			&gic_data_rdist()->phys_base);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int __init collect_gicr_base(struct acpi_table_header *table)
+{
+	int count;
+
+	/* Collect redistributor base addresses in GICR entries */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_redist, table,
+			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
+	if (count > 0)
+		return 0;
+
+	pr_info("No valid GICR entries exist, try GICC entries\n");
+
+	/* Collect redistributor base addresses in GICC entries */
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+			sizeof(struct acpi_table_madt),
+			gic_acpi_parse_madt_gicc, table,
+			ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
+	if (count > 0 && !list_empty(&redist_list))
+		return 0;
+
+	pr_info("No valid GICC entries exist for GICR base\n");
+	return -ENODEV;
+}
+
+static int __init
 gic_acpi_init(struct acpi_table_header *table)
 {
-	int count, i, err = 0;
+	int count, err = 0;
 	void __iomem *dist_base;
 
 	/* Get distributor base address */
@@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
 	}
 
 	/* Collect redistributor base addresses */
-	count = acpi_parse_entries(ACPI_SIG_MADT,
-			sizeof(struct acpi_table_madt),
-			gic_acpi_parse_madt_redist, table,
-			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
-	if (count <= 0) {
-		pr_info("No valid GICR entries exist\n");
-		err = -EINVAL;
-		goto out_redist_unmap;
-	}
+	if (collect_gicr_base(table))
+		goto out_release_redist;
 
 	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
 			     (void *)ACPI_IRQ_MODEL_GIC);
 	if (err)
-		goto out_redist_unmap;
+		goto out_release_redist;
 
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
 			   gic_acpi_gsi_desc_populate);
 	return 0;
 
-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_release_redist:
+	gic_acpi_release_redist_regions();
+	if (!list_empty(&redist_list))
+		gic_acpi_release_gicc_redist();
 out_dist_unmap:
 	iounmap(dist_base);
 	return err;
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
index 56cd82c..0d43f515 100644
--- a/include/linux/irqchip/arm-gic-acpi.h
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -21,5 +21,7 @@
 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
 
+u8 acpi_gic_version(void);
+
 #endif /* CONFIG_ACPI */
 #endif /* ARM_GIC_ACPI_H_ */
-- 
1.9.1

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

* [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
token that can be used to look up MSI doamin of a device.
In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
or GIC ITS structure is used as a token for MSI domain.

In addition, this patch also provides low-level helper functions to parse
and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
a copy of the structure for use in subsequent queries to avoid having
to map and parse MADT multiple times.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/acpi/Makefile   |   1 +
 drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_gic.h |  23 +++++
 include/linux/acpi.h    |   1 +
 4 files changed, 259 insertions(+)
 create mode 100644 drivers/acpi/acpi_gic.c
 create mode 100644 include/acpi/acpi_gic.h

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8321430..def54b9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
+acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
 
 # These are (potentially) separate modules
 
diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
new file mode 100644
index 0000000..11ee4eb
--- /dev/null
+++ b/drivers/acpi/acpi_gic.c
@@ -0,0 +1,234 @@
+/*
+ * File: acpi_gic.c
+ *
+ * ACPI helper functions for ARM GIC
+ *
+ * Copyright (C) 2015 Advanced Micro Devices, Inc.
+ * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+
+/*
+ * GIC MSI Frame data structures
+ */
+struct gic_msi_frame_handle {
+	struct list_head list;
+	struct acpi_madt_generic_msi_frame frame;
+};
+
+static LIST_HEAD(msi_frame_list);
+
+static int acpi_num_msi;
+
+/*
+ * GIC ITS data structures
+ */
+struct gic_its_handle {
+	struct list_head list;
+	struct acpi_madt_generic_translator trans;
+};
+
+static LIST_HEAD(its_list);
+
+static int acpi_num_its;
+
+/*
+ * GIC MSI Frame parsing stuff
+ */
+inline int acpi_gic_get_num_msi_frame(void)
+{
+	return acpi_num_msi;
+}
+
+static int __init
+acpi_parse_madt_msi(struct acpi_subtable_header *header,
+		    const unsigned long end)
+{
+	struct gic_msi_frame_handle *h;
+	struct acpi_madt_generic_msi_frame *frame;
+
+	frame = (struct acpi_madt_generic_msi_frame *)header;
+	if (BAD_MADT_ENTRY(frame, end))
+		return -EINVAL;
+
+	h = kzalloc(sizeof(struct gic_msi_frame_handle *), GFP_KERNEL);
+	if (!h)
+		return -ENOMEM;
+
+	/** Note:
+	 * We make a copy of this structure since this code is called
+	 * prior to acpi_early_init(), which sets the acpi_gbl_permanent_mmap.
+	 * Therefore, we could not keep just the pointer sincce the memory
+	 * could be unmapped.
+	 */
+	memcpy(&h->frame, frame, sizeof(struct acpi_madt_generic_msi_frame));
+
+	list_add(&h->list, &msi_frame_list);
+
+	return 0;
+}
+
+int __init acpi_gic_msi_init(struct acpi_table_header *table)
+{
+	int ret = 0;
+
+	if (acpi_num_msi > 0)
+		return ret;
+
+	ret = acpi_parse_entries(ACPI_SIG_MADT,
+				 sizeof(struct acpi_table_madt),
+				 acpi_parse_madt_msi, table,
+				 ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
+	if (ret == 0) {
+		pr_debug("No valid ACPI GIC MSI FRAME exist\n");
+		return ret;
+	}
+
+	acpi_num_msi = ret;
+	return 0;
+}
+
+int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p)
+{
+	int i = 0;
+	struct gic_msi_frame_handle *m;
+
+	if (index >= acpi_num_msi)
+		return -EINVAL;
+
+	list_for_each_entry(m, &msi_frame_list, list) {
+		if (i == index)
+			break;
+		i++;
+	}
+
+	if (i == acpi_num_msi)
+		return -EINVAL;
+
+	*p = &(m->frame);
+	return  0;
+}
+
+/*
+ * GIC ITS parsing stuff
+ */
+inline int acpi_gic_get_num_its(void)
+{
+	return acpi_num_its;
+}
+
+static int __init
+acpi_parse_madt_its(struct acpi_subtable_header *header,
+		    const unsigned long end)
+{
+	struct gic_its_handle *h;
+	struct acpi_madt_generic_translator *trans;
+
+	trans = (struct acpi_madt_generic_translator *)header;
+	if (BAD_MADT_ENTRY(trans, end))
+		return -EINVAL;
+
+	h = kzalloc(sizeof(struct gic_its_handle *), GFP_KERNEL);
+	if (!h)
+		return -ENOMEM;
+
+	memcpy(&h->trans, trans, sizeof(struct acpi_madt_generic_translator));
+
+	list_add(&h->list, &its_list);
+
+	return 0;
+}
+
+int __init acpi_gic_madt_gic_its_init(struct acpi_table_header *table)
+{
+	int ret = 0;
+
+	if (acpi_num_its > 0)
+		return ret;
+
+	ret = acpi_parse_entries(ACPI_SIG_MADT,
+				 sizeof(struct acpi_table_madt),
+				 acpi_parse_madt_its, table,
+				 ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 0);
+	if (ret == 0) {
+		pr_debug("No valid ACPI GIC ITS exist\n");
+		return ret;
+	}
+
+	acpi_num_its = ret;
+	return 0;
+}
+
+int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p)
+{
+	int i = 0;
+	struct gic_its_handle *m;
+
+	if (index >= acpi_num_its)
+		return -EINVAL;
+
+	list_for_each_entry(m, &its_list, list) {
+		if (i == index)
+			break;
+		i++;
+	}
+
+	if (i == acpi_num_its)
+		return -EINVAL;
+
+	*p = &(m->trans);
+	return  0;
+}
+
+static void *acpi_gic_msi_token(struct device *dev)
+{
+	int err;
+	struct acpi_madt_generic_msi_frame *msi;
+
+	/**
+	* Since ACPI 5.1 currently does not define
+	* a way to associate MSI frame ID to a device,
+	* we can only support single MSI frame (index 0)
+	* at the moment.
+	*/
+	err = acpi_gic_get_msi_frame(0, &msi);
+	if (err)
+		return NULL;
+
+	return (void *) msi->base_address;
+}
+
+static void *acpi_gic_its_token(struct device *dev)
+{
+	int err;
+	struct acpi_madt_generic_translator *trans;
+	int its_id = 0;
+
+	/**
+	 * TODO: We need a way to retrieve GIC ITS ID from
+	 * struct device pointer (in this case, the device
+	 * would be the PCI host controller.
+	 *
+	 * This would be done by the IORT-related code.
+	 *
+	 * its_id = get_its_id(dev);
+	 */
+
+	err = acpi_gic_get_its(its_id, &trans);
+	if (err)
+		return NULL;
+
+	return (void *) trans->base_address;
+}
+
+void *acpi_gic_get_msi_token(struct device *dev)
+{
+	void *token = acpi_gic_msi_token(dev);
+
+	if (!token)
+		token = acpi_gic_its_token(dev);
+
+	return token;
+}
diff --git a/include/acpi/acpi_gic.h b/include/acpi/acpi_gic.h
new file mode 100644
index 0000000..34fa475
--- /dev/null
+++ b/include/acpi/acpi_gic.h
@@ -0,0 +1,23 @@
+/*
+ *  include/acpi/acpi_gic.h
+ *
+ * Copyright (C) 2015 Advanced Micro Devices, Inc.
+ * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ */
+
+#ifndef __ACPI_GIC_H__
+#define __ACPI_GIC_H__
+
+#ifdef CONFIG_ACPI
+int acpi_gic_get_num_msi_frame(void);
+int acpi_gic_msi_init(struct acpi_table_header *table);
+int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p);
+
+int acpi_gic_get_num_its(void);
+int acpi_gic_its_init(struct acpi_table_header *table);
+int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p);
+
+void *acpi_gic_get_msi_token(struct device *dev);
+#endif
+
+#endif /*__ACPI_GIC_H__*/
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 04dd0bb..5d58b61 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -44,6 +44,7 @@
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <acpi/acpi_gic.h>
 #include <acpi/acpi_numa.h>
 #include <acpi/acpi_io.h>
 #include <asm/acpi.h>
-- 
1.9.1


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

* [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
token that can be used to look up MSI doamin of a device.
In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
or GIC ITS structure is used as a token for MSI domain.

In addition, this patch also provides low-level helper functions to parse
and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
a copy of the structure for use in subsequent queries to avoid having
to map and parse MADT multiple times.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/acpi/Makefile   |   1 +
 drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_gic.h |  23 +++++
 include/linux/acpi.h    |   1 +
 4 files changed, 259 insertions(+)
 create mode 100644 drivers/acpi/acpi_gic.c
 create mode 100644 include/acpi/acpi_gic.h

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8321430..def54b9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y				+= acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
+acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
 
 # These are (potentially) separate modules
 
diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
new file mode 100644
index 0000000..11ee4eb
--- /dev/null
+++ b/drivers/acpi/acpi_gic.c
@@ -0,0 +1,234 @@
+/*
+ * File: acpi_gic.c
+ *
+ * ACPI helper functions for ARM GIC
+ *
+ * Copyright (C) 2015 Advanced Micro Devices, Inc.
+ * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+
+/*
+ * GIC MSI Frame data structures
+ */
+struct gic_msi_frame_handle {
+	struct list_head list;
+	struct acpi_madt_generic_msi_frame frame;
+};
+
+static LIST_HEAD(msi_frame_list);
+
+static int acpi_num_msi;
+
+/*
+ * GIC ITS data structures
+ */
+struct gic_its_handle {
+	struct list_head list;
+	struct acpi_madt_generic_translator trans;
+};
+
+static LIST_HEAD(its_list);
+
+static int acpi_num_its;
+
+/*
+ * GIC MSI Frame parsing stuff
+ */
+inline int acpi_gic_get_num_msi_frame(void)
+{
+	return acpi_num_msi;
+}
+
+static int __init
+acpi_parse_madt_msi(struct acpi_subtable_header *header,
+		    const unsigned long end)
+{
+	struct gic_msi_frame_handle *h;
+	struct acpi_madt_generic_msi_frame *frame;
+
+	frame = (struct acpi_madt_generic_msi_frame *)header;
+	if (BAD_MADT_ENTRY(frame, end))
+		return -EINVAL;
+
+	h = kzalloc(sizeof(struct gic_msi_frame_handle *), GFP_KERNEL);
+	if (!h)
+		return -ENOMEM;
+
+	/** Note:
+	 * We make a copy of this structure since this code is called
+	 * prior to acpi_early_init(), which sets the acpi_gbl_permanent_mmap.
+	 * Therefore, we could not keep just the pointer sincce the memory
+	 * could be unmapped.
+	 */
+	memcpy(&h->frame, frame, sizeof(struct acpi_madt_generic_msi_frame));
+
+	list_add(&h->list, &msi_frame_list);
+
+	return 0;
+}
+
+int __init acpi_gic_msi_init(struct acpi_table_header *table)
+{
+	int ret = 0;
+
+	if (acpi_num_msi > 0)
+		return ret;
+
+	ret = acpi_parse_entries(ACPI_SIG_MADT,
+				 sizeof(struct acpi_table_madt),
+				 acpi_parse_madt_msi, table,
+				 ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
+	if (ret == 0) {
+		pr_debug("No valid ACPI GIC MSI FRAME exist\n");
+		return ret;
+	}
+
+	acpi_num_msi = ret;
+	return 0;
+}
+
+int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p)
+{
+	int i = 0;
+	struct gic_msi_frame_handle *m;
+
+	if (index >= acpi_num_msi)
+		return -EINVAL;
+
+	list_for_each_entry(m, &msi_frame_list, list) {
+		if (i == index)
+			break;
+		i++;
+	}
+
+	if (i == acpi_num_msi)
+		return -EINVAL;
+
+	*p = &(m->frame);
+	return  0;
+}
+
+/*
+ * GIC ITS parsing stuff
+ */
+inline int acpi_gic_get_num_its(void)
+{
+	return acpi_num_its;
+}
+
+static int __init
+acpi_parse_madt_its(struct acpi_subtable_header *header,
+		    const unsigned long end)
+{
+	struct gic_its_handle *h;
+	struct acpi_madt_generic_translator *trans;
+
+	trans = (struct acpi_madt_generic_translator *)header;
+	if (BAD_MADT_ENTRY(trans, end))
+		return -EINVAL;
+
+	h = kzalloc(sizeof(struct gic_its_handle *), GFP_KERNEL);
+	if (!h)
+		return -ENOMEM;
+
+	memcpy(&h->trans, trans, sizeof(struct acpi_madt_generic_translator));
+
+	list_add(&h->list, &its_list);
+
+	return 0;
+}
+
+int __init acpi_gic_madt_gic_its_init(struct acpi_table_header *table)
+{
+	int ret = 0;
+
+	if (acpi_num_its > 0)
+		return ret;
+
+	ret = acpi_parse_entries(ACPI_SIG_MADT,
+				 sizeof(struct acpi_table_madt),
+				 acpi_parse_madt_its, table,
+				 ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 0);
+	if (ret == 0) {
+		pr_debug("No valid ACPI GIC ITS exist\n");
+		return ret;
+	}
+
+	acpi_num_its = ret;
+	return 0;
+}
+
+int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p)
+{
+	int i = 0;
+	struct gic_its_handle *m;
+
+	if (index >= acpi_num_its)
+		return -EINVAL;
+
+	list_for_each_entry(m, &its_list, list) {
+		if (i == index)
+			break;
+		i++;
+	}
+
+	if (i == acpi_num_its)
+		return -EINVAL;
+
+	*p = &(m->trans);
+	return  0;
+}
+
+static void *acpi_gic_msi_token(struct device *dev)
+{
+	int err;
+	struct acpi_madt_generic_msi_frame *msi;
+
+	/**
+	* Since ACPI 5.1 currently does not define
+	* a way to associate MSI frame ID to a device,
+	* we can only support single MSI frame (index 0)
+	* at the moment.
+	*/
+	err = acpi_gic_get_msi_frame(0, &msi);
+	if (err)
+		return NULL;
+
+	return (void *) msi->base_address;
+}
+
+static void *acpi_gic_its_token(struct device *dev)
+{
+	int err;
+	struct acpi_madt_generic_translator *trans;
+	int its_id = 0;
+
+	/**
+	 * TODO: We need a way to retrieve GIC ITS ID from
+	 * struct device pointer (in this case, the device
+	 * would be the PCI host controller.
+	 *
+	 * This would be done by the IORT-related code.
+	 *
+	 * its_id = get_its_id(dev);
+	 */
+
+	err = acpi_gic_get_its(its_id, &trans);
+	if (err)
+		return NULL;
+
+	return (void *) trans->base_address;
+}
+
+void *acpi_gic_get_msi_token(struct device *dev)
+{
+	void *token = acpi_gic_msi_token(dev);
+
+	if (!token)
+		token = acpi_gic_its_token(dev);
+
+	return token;
+}
diff --git a/include/acpi/acpi_gic.h b/include/acpi/acpi_gic.h
new file mode 100644
index 0000000..34fa475
--- /dev/null
+++ b/include/acpi/acpi_gic.h
@@ -0,0 +1,23 @@
+/*
+ *  include/acpi/acpi_gic.h
+ *
+ * Copyright (C) 2015 Advanced Micro Devices, Inc.
+ * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+ */
+
+#ifndef __ACPI_GIC_H__
+#define __ACPI_GIC_H__
+
+#ifdef CONFIG_ACPI
+int acpi_gic_get_num_msi_frame(void);
+int acpi_gic_msi_init(struct acpi_table_header *table);
+int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p);
+
+int acpi_gic_get_num_its(void);
+int acpi_gic_its_init(struct acpi_table_header *table);
+int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p);
+
+void *acpi_gic_get_msi_token(struct device *dev);
+#endif
+
+#endif /*__ACPI_GIC_H__*/
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 04dd0bb..5d58b61 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -44,6 +44,7 @@
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <acpi/acpi_gic.h>
 #include <acpi/acpi_numa.h>
 #include <acpi/acpi_io.h>
 #include <asm/acpi.h>
-- 
1.9.1

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
a GIC MSI irq-domain token and use it to retrieve an irq_domain with
DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
 drivers/pci/probe.c      |  3 +++
 include/linux/pci-acpi.h |  4 ++++
 3 files changed, 25 insertions(+)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 314a625..5f11653 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -9,6 +9,7 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
@@ -16,6 +17,7 @@
 #include <linux/pci-acpi.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_qos.h>
+#include <acpi/acpi_gic.h>
 #include "pci.h"
 
 /*
@@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
 	return dev_is_pci(dev);
 }
 
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
+{
+	struct irq_domain *d = NULL;
+	void *token = acpi_gic_get_msi_token(&bus->dev);
+
+	if (token)
+		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
+
+	if (!d)
+		pr_debug("Fail to find domain for MSI\n");
+
+	return d;
+}
+#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
+
 static struct acpi_bus_type acpi_pci_bus = {
 	.name = "PCI",
 	.match = pci_acpi_bus_match,
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a7afeac..8c1204c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
@@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
 	 * should be called from here.
 	 */
 	d = pci_host_bridge_of_msi_domain(bus);
+	if (!d)
+		d = pci_host_bridge_acpi_msi_domain(bus);
 
 	return d;
 }
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index a965efa..766d045 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
 #endif
 
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
+
 extern const u8 pci_acpi_dsm_uuid[];
 #define DEVICE_LABEL_DSM	0x07
 #define RESET_DELAY_DSM		0x08
@@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+static inline struct irq_domain *
+pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
 #endif	/* CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI_APEI
-- 
1.9.1


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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
a GIC MSI irq-domain token and use it to retrieve an irq_domain with
DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
 drivers/pci/probe.c      |  3 +++
 include/linux/pci-acpi.h |  4 ++++
 3 files changed, 25 insertions(+)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 314a625..5f11653 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -9,6 +9,7 @@
 
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/module.h>
@@ -16,6 +17,7 @@
 #include <linux/pci-acpi.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_qos.h>
+#include <acpi/acpi_gic.h>
 #include "pci.h"
 
 /*
@@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
 	return dev_is_pci(dev);
 }
 
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
+{
+	struct irq_domain *d = NULL;
+	void *token = acpi_gic_get_msi_token(&bus->dev);
+
+	if (token)
+		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
+
+	if (!d)
+		pr_debug("Fail to find domain for MSI\n");
+
+	return d;
+}
+#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
+
 static struct acpi_bus_type acpi_pci_bus = {
 	.name = "PCI",
 	.match = pci_acpi_bus_match,
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a7afeac..8c1204c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
@@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
 	 * should be called from here.
 	 */
 	d = pci_host_bridge_of_msi_domain(bus);
+	if (!d)
+		d = pci_host_bridge_acpi_msi_domain(bus);
 
 	return d;
 }
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index a965efa..766d045 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
 #endif
 
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
+
 extern const u8 pci_acpi_dsm_uuid[];
 #define DEVICE_LABEL_DSM	0x07
 #define RESET_DELAY_DSM		0x08
@@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+static inline struct irq_domain *
+pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
 #endif	/* CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI_APEI
-- 
1.9.1

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

* [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-07-29 10:08   ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Tomasz Nowicki, Grant Likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi, Hanjun Guo

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces gicv2m_acpi_init(), which uses information
in MADT GIC MSI frames structure to initialize GICv2m driver.
It also refactors gicv2m_init_one() to handle both DT and ACPI
initialization path.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
 drivers/irqchip/irq-gic.c       |   3 ++
 include/linux/irqchip/arm-gic.h |   7 +++
 3 files changed, 98 insertions(+), 23 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index d0fcbf8..c491a08 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -15,6 +15,7 @@
 
 #define pr_fmt(fmt) "GICv2m: " fmt
 
+#include <linux/acpi.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
@@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
 	return true;
 }
 
+char gicv2m_domain_name[] = "GICV2M";
+char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
+char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
+
 static struct irq_chip gicv2m_pmsi_irq_chip = {
 	.name			= "pMSI",
 };
@@ -224,8 +229,9 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
 	.chip	= &gicv2m_pmsi_irq_chip,
 };
 
-static int __init gicv2m_init_one(struct device_node *node,
-				  struct irq_domain *parent)
+static int __init gicv2m_init_one(struct irq_domain *parent,
+				  u32 *spi_start, u32 *nr_spis,
+				  struct resource *res, void *token)
 {
 	int ret;
 	struct v2m_data *v2m;
@@ -237,28 +243,22 @@ static int __init gicv2m_init_one(struct device_node *node,
 		return -ENOMEM;
 	}
 
-	ret = of_address_to_resource(node, 0, &v2m->res);
-	if (ret) {
-		pr_err("Failed to allocate v2m resource.\n");
-		goto err_free_v2m;
-	}
-
-	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
+	v2m->base = ioremap(res->start, resource_size(res));
 	if (!v2m->base) {
 		pr_err("Failed to map GICv2m resource\n");
 		ret = -ENOMEM;
 		goto err_free_v2m;
 	}
+	memcpy(&v2m->res, res, sizeof(struct resource));
 
-	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
-	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
-		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
-			v2m->spi_start, v2m->nr_spis);
+	if (*spi_start && *nr_spis) {
+		v2m->spi_start = *spi_start;
+		v2m->nr_spis = *nr_spis;
 	} else {
 		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
 
-		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
-		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
+		v2m->spi_start = *spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
+		v2m->nr_spis = *nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
 	}
 
 	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
@@ -273,7 +273,7 @@ static int __init gicv2m_init_one(struct device_node *node,
 		goto err_iounmap;
 	}
 
-	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
+	inner_domain = irq_domain_add_tree(token, &gicv2m_domain_ops, v2m);
 	if (!inner_domain) {
 		pr_err("Failed to create GICv2m domain\n");
 		ret = -ENOMEM;
@@ -282,9 +282,11 @@ static int __init gicv2m_init_one(struct device_node *node,
 
 	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 	inner_domain->parent = parent;
-	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
+	inner_domain->name = gicv2m_domain_name;
+
+	pci_domain = pci_msi_create_irq_domain(token, &gicv2m_msi_domain_info,
 					       inner_domain);
-	plat_domain = platform_msi_create_irq_domain(node,
+	plat_domain = platform_msi_create_irq_domain(token,
 						     &gicv2m_pmsi_domain_info,
 						     inner_domain);
 	if (!pci_domain || !plat_domain) {
@@ -293,11 +295,10 @@ static int __init gicv2m_init_one(struct device_node *node,
 		goto err_free_domains;
 	}
 
-	spin_lock_init(&v2m->msi_cnt_lock);
+	pci_domain->name = gicv2m_pci_msi_domain_name;
+	plat_domain->name = gicv2m_plat_msi_domain_name;
 
-	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
-		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
-		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
+	spin_lock_init(&v2m->msi_cnt_lock);
 
 	return 0;
 
@@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
 
 	for (child = of_find_matching_node(node, gicv2m_device_id); child;
 	     child = of_find_matching_node(child, gicv2m_device_id)) {
+		u32 spi_start = 0, nr_spis = 0;
+		struct resource res;
+
 		if (!of_find_property(child, "msi-controller", NULL))
 			continue;
 
-		ret = gicv2m_init_one(child, parent);
+		ret = of_address_to_resource(child, 0, &res);
+		if (ret) {
+			pr_err("Failed to allocate v2m resource.\n");
+			break;
+		}
+
+		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
+		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+				spi_start, nr_spis);
+
+		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+				      child);
 		if (ret) {
 			of_node_put(node);
 			break;
 		}
+
+		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
+			(unsigned long)res.start, (unsigned long)res.end,
+			spi_start, (spi_start + nr_spis));
 	}
 
 	return ret;
 }
+
+#ifdef CONFIG_ACPI
+int __init gicv2m_acpi_init(struct acpi_table_header *table,
+			    struct irq_domain *parent)
+{
+	int i, ret;
+
+	ret = acpi_gic_msi_init(table);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
+		struct resource res;
+		u32 spi_start = 0, nr_spis = 0;
+		struct acpi_madt_generic_msi_frame *m;
+
+		ret = acpi_gic_get_msi_frame(i, &m);
+		if (ret)
+			return ret;
+
+		res.start = m->base_address;
+		res.end = m->base_address + 0x1000;
+
+		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+			spi_start = m->spi_base;
+			nr_spis = m->spi_count;
+
+			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+				spi_start, nr_spis);
+		}
+
+		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+				      (void *)(m->base_address));
+		if (ret)
+			break;
+
+		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
+			m->msi_frame_id,
+			(unsigned long)res.start, (unsigned long)res.end,
+			spi_start, (spi_start + nr_spis));
+	}
+	return ret;
+}
+
+#endif /* CONFIG_ACPI */
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bec6b00..531ebbc 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
 	 */
 	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
 
+	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+		gicv2m_acpi_init(table, gic_data[0].domain);
+
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
 			   gic_acpi_gsi_desc_populate);
 	return 0;
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 97799b7..27d8196 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
 
 int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
 
+#ifdef CONFIG_ACPI
+struct acpi_table_header;
+
+int gicv2m_acpi_init(struct acpi_table_header *table,
+		     struct irq_domain *parent);
+#endif
+
 void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
 int gic_get_cpu_id(unsigned int cpu);
 void gic_migrate_target(unsigned int new_cpu_id);
-- 
1.9.1

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

* [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
@ 2015-07-29 10:08   ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-07-29 10:08 UTC (permalink / raw)
  To: linux-arm-kernel

From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>

This patch introduces gicv2m_acpi_init(), which uses information
in MADT GIC MSI frames structure to initialize GICv2m driver.
It also refactors gicv2m_init_one() to handle both DT and ACPI
initialization path.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
 drivers/irqchip/irq-gic.c       |   3 ++
 include/linux/irqchip/arm-gic.h |   7 +++
 3 files changed, 98 insertions(+), 23 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index d0fcbf8..c491a08 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -15,6 +15,7 @@
 
 #define pr_fmt(fmt) "GICv2m: " fmt
 
+#include <linux/acpi.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
@@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
 	return true;
 }
 
+char gicv2m_domain_name[] = "GICV2M";
+char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
+char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
+
 static struct irq_chip gicv2m_pmsi_irq_chip = {
 	.name			= "pMSI",
 };
@@ -224,8 +229,9 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
 	.chip	= &gicv2m_pmsi_irq_chip,
 };
 
-static int __init gicv2m_init_one(struct device_node *node,
-				  struct irq_domain *parent)
+static int __init gicv2m_init_one(struct irq_domain *parent,
+				  u32 *spi_start, u32 *nr_spis,
+				  struct resource *res, void *token)
 {
 	int ret;
 	struct v2m_data *v2m;
@@ -237,28 +243,22 @@ static int __init gicv2m_init_one(struct device_node *node,
 		return -ENOMEM;
 	}
 
-	ret = of_address_to_resource(node, 0, &v2m->res);
-	if (ret) {
-		pr_err("Failed to allocate v2m resource.\n");
-		goto err_free_v2m;
-	}
-
-	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
+	v2m->base = ioremap(res->start, resource_size(res));
 	if (!v2m->base) {
 		pr_err("Failed to map GICv2m resource\n");
 		ret = -ENOMEM;
 		goto err_free_v2m;
 	}
+	memcpy(&v2m->res, res, sizeof(struct resource));
 
-	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
-	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
-		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
-			v2m->spi_start, v2m->nr_spis);
+	if (*spi_start && *nr_spis) {
+		v2m->spi_start = *spi_start;
+		v2m->nr_spis = *nr_spis;
 	} else {
 		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
 
-		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
-		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
+		v2m->spi_start = *spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
+		v2m->nr_spis = *nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
 	}
 
 	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
@@ -273,7 +273,7 @@ static int __init gicv2m_init_one(struct device_node *node,
 		goto err_iounmap;
 	}
 
-	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
+	inner_domain = irq_domain_add_tree(token, &gicv2m_domain_ops, v2m);
 	if (!inner_domain) {
 		pr_err("Failed to create GICv2m domain\n");
 		ret = -ENOMEM;
@@ -282,9 +282,11 @@ static int __init gicv2m_init_one(struct device_node *node,
 
 	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 	inner_domain->parent = parent;
-	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
+	inner_domain->name = gicv2m_domain_name;
+
+	pci_domain = pci_msi_create_irq_domain(token, &gicv2m_msi_domain_info,
 					       inner_domain);
-	plat_domain = platform_msi_create_irq_domain(node,
+	plat_domain = platform_msi_create_irq_domain(token,
 						     &gicv2m_pmsi_domain_info,
 						     inner_domain);
 	if (!pci_domain || !plat_domain) {
@@ -293,11 +295,10 @@ static int __init gicv2m_init_one(struct device_node *node,
 		goto err_free_domains;
 	}
 
-	spin_lock_init(&v2m->msi_cnt_lock);
+	pci_domain->name = gicv2m_pci_msi_domain_name;
+	plat_domain->name = gicv2m_plat_msi_domain_name;
 
-	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
-		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
-		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
+	spin_lock_init(&v2m->msi_cnt_lock);
 
 	return 0;
 
@@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
 
 	for (child = of_find_matching_node(node, gicv2m_device_id); child;
 	     child = of_find_matching_node(child, gicv2m_device_id)) {
+		u32 spi_start = 0, nr_spis = 0;
+		struct resource res;
+
 		if (!of_find_property(child, "msi-controller", NULL))
 			continue;
 
-		ret = gicv2m_init_one(child, parent);
+		ret = of_address_to_resource(child, 0, &res);
+		if (ret) {
+			pr_err("Failed to allocate v2m resource.\n");
+			break;
+		}
+
+		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
+		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+				spi_start, nr_spis);
+
+		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+				      child);
 		if (ret) {
 			of_node_put(node);
 			break;
 		}
+
+		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
+			(unsigned long)res.start, (unsigned long)res.end,
+			spi_start, (spi_start + nr_spis));
 	}
 
 	return ret;
 }
+
+#ifdef CONFIG_ACPI
+int __init gicv2m_acpi_init(struct acpi_table_header *table,
+			    struct irq_domain *parent)
+{
+	int i, ret;
+
+	ret = acpi_gic_msi_init(table);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
+		struct resource res;
+		u32 spi_start = 0, nr_spis = 0;
+		struct acpi_madt_generic_msi_frame *m;
+
+		ret = acpi_gic_get_msi_frame(i, &m);
+		if (ret)
+			return ret;
+
+		res.start = m->base_address;
+		res.end = m->base_address + 0x1000;
+
+		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+			spi_start = m->spi_base;
+			nr_spis = m->spi_count;
+
+			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+				spi_start, nr_spis);
+		}
+
+		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
+				      (void *)(m->base_address));
+		if (ret)
+			break;
+
+		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
+			m->msi_frame_id,
+			(unsigned long)res.start, (unsigned long)res.end,
+			spi_start, (spi_start + nr_spis));
+	}
+	return ret;
+}
+
+#endif /* CONFIG_ACPI */
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index bec6b00..531ebbc 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
 	 */
 	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
 
+	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+		gicv2m_acpi_init(table, gic_data[0].domain);
+
 	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
 			   gic_acpi_gsi_desc_populate);
 	return 0;
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 97799b7..27d8196 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
 
 int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
 
+#ifdef CONFIG_ACPI
+struct acpi_table_header;
+
+int gicv2m_acpi_init(struct acpi_table_header *table,
+		     struct irq_domain *parent);
+#endif
+
 void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
 int gic_get_cpu_id(unsigned int cpu);
 void gic_migrate_target(unsigned int new_cpu_id);
-- 
1.9.1

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 12:06     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:06 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> There is a field added in ACPI 6.0 MADT table to indicate the
> GIC version, so parse the table to get its value for later use.
> 
> If GIC version presented in MADT is 0, we need to fallback to
> hardware discovery to get the GIC version.
> 
> In ACPI MADT table there is no compatible strings to indicate
> various irqchips and also ACPI doesn't support irqchips which
> are not compatible with ARM GIC spec, so GIC version can be used
> to load different GIC drivers which is needed for the later patch.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  arch/arm64/Kconfig                   |   1 +
>  drivers/irqchip/Kconfig              |   3 +
>  drivers/irqchip/Makefile             |   1 +
>  drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>  include/linux/irqchip/arm-gic-acpi.h |   1 +
>  5 files changed, 115 insertions(+)
>  create mode 100644 drivers/irqchip/irq-gic-acpi.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 318175f..f2ff61f 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -16,6 +16,7 @@ config ARM64
>  	select ARM_AMBA
>  	select ARM_ARCH_TIMER
>  	select ARM_GIC
> +	select ARM_GIC_ACPI if ACPI
>  	select AUDIT_ARCH_COMPAT_GENERIC
>  	select ARM_GIC_V2M if PCI_MSI
>  	select ARM_GIC_V3
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 120d815..557ec2f 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>  	  The maximum number of VICs available in the system, for
>  	  power management.
>  
> +config ARM_GIC_ACPI
> +	bool
> +
>  config ATMEL_AIC_IRQ
>  	bool
>  	select GENERIC_IRQ_CHIP
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 11d08c9..383f421 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>  obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>  obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>  obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>  obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> new file mode 100644
> index 0000000..6537b43
> --- /dev/null
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -0,0 +1,109 @@
> +/*
> + * ACPI based support for ARM GIC init
> + *
> + * Copyright (C) 2015, Linaro Ltd.
> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +#include <linux/irqchip/arm-gic-acpi.h>
> +#include <linux/irqchip/arm-gic-v3.h>
> +
> +/* GIC version presented in MADT GIC distributor structure */
> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> +
> +static phys_addr_t dist_phy_base __initdata;
> +
> +static int __init
> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
> +			   const unsigned long end)
> +{
> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	gic_version = dist->version;
> +	dist_phy_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int __init
> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
> +{
> +	return 0;
> +}
> +
> +static bool __init acpi_gic_redist_is_present(void)
> +{
> +	int count;
> +
> +	/* scan MADT table to find if we have redistributor entries */
> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
> +					match_gic_redist, 0);
> +
> +	/* that's true if we have at least one GIC redistributor entry */
> +	return count > 0;
> +}
> +
> +static int __init acpi_gic_version_init(void)
> +{
> +	int count;
> +	u32 reg;
> +	void __iomem *dist_base;
> +
> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
> +				      acpi_gic_parse_distributor, 0);
> +
> +	if (count <= 0) {
> +		pr_err("No valid GIC distributor entry exists\n");
> +		return -ENODEV;
> +	}
> +
> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * when the GIC version is 0, we fallback to hardware discovery.
> +	 * this is also needed to keep compatiable with ACPI 5.1,
> +	 * which has no gic_version field in distributor structure and
> +	 * reserved as 0.
> +	 *
> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
> +	 * for GICv3/4), so we need to handle it separately.
> +	 */
> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
> +		/* it's GICv3/v4 if redistributor is present */
> +		if (acpi_gic_redist_is_present()) {
> +			dist_base = ioremap(dist_phy_base,
> +					    ACPI_GICV3_DIST_MEM_SIZE);
> +			if (!dist_base)
> +				return -ENOMEM;
> +
> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
> +					    GIC_PIDR2_ARCH_MASK;
> +			if (reg == GIC_PIDR2_ARCH_GICv3)
> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
> +			else
> +				gic_version = ACPI_MADT_GIC_VERSION_V4;

Frankly, why should we care? If there is no redistributor, this is a V2.
If there are redistributors, then it is a V3/V4, and it shouldn't matter
which one this is as the GICv3 driver can find out all by itself. Also,
the GICv4 feature only matter for KVM, which can probe this on its own.

> +
> +			iounmap(dist_base);
> +		} else {
> +			gic_version = ACPI_MADT_GIC_VERSION_V2;
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index de3419e..13bc676 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -19,6 +19,7 @@
>   */
>  #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
>  #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
> +#define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
>  
>  struct acpi_table_header;
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-04 12:06     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:06 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> There is a field added in ACPI 6.0 MADT table to indicate the
> GIC version, so parse the table to get its value for later use.
> 
> If GIC version presented in MADT is 0, we need to fallback to
> hardware discovery to get the GIC version.
> 
> In ACPI MADT table there is no compatible strings to indicate
> various irqchips and also ACPI doesn't support irqchips which
> are not compatible with ARM GIC spec, so GIC version can be used
> to load different GIC drivers which is needed for the later patch.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  arch/arm64/Kconfig                   |   1 +
>  drivers/irqchip/Kconfig              |   3 +
>  drivers/irqchip/Makefile             |   1 +
>  drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>  include/linux/irqchip/arm-gic-acpi.h |   1 +
>  5 files changed, 115 insertions(+)
>  create mode 100644 drivers/irqchip/irq-gic-acpi.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 318175f..f2ff61f 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -16,6 +16,7 @@ config ARM64
>  	select ARM_AMBA
>  	select ARM_ARCH_TIMER
>  	select ARM_GIC
> +	select ARM_GIC_ACPI if ACPI
>  	select AUDIT_ARCH_COMPAT_GENERIC
>  	select ARM_GIC_V2M if PCI_MSI
>  	select ARM_GIC_V3
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 120d815..557ec2f 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>  	  The maximum number of VICs available in the system, for
>  	  power management.
>  
> +config ARM_GIC_ACPI
> +	bool
> +
>  config ATMEL_AIC_IRQ
>  	bool
>  	select GENERIC_IRQ_CHIP
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 11d08c9..383f421 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>  obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>  obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>  obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>  obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> new file mode 100644
> index 0000000..6537b43
> --- /dev/null
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -0,0 +1,109 @@
> +/*
> + * ACPI based support for ARM GIC init
> + *
> + * Copyright (C) 2015, Linaro Ltd.
> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +#include <linux/irqchip/arm-gic-acpi.h>
> +#include <linux/irqchip/arm-gic-v3.h>
> +
> +/* GIC version presented in MADT GIC distributor structure */
> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> +
> +static phys_addr_t dist_phy_base __initdata;
> +
> +static int __init
> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
> +			   const unsigned long end)
> +{
> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	gic_version = dist->version;
> +	dist_phy_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int __init
> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
> +{
> +	return 0;
> +}
> +
> +static bool __init acpi_gic_redist_is_present(void)
> +{
> +	int count;
> +
> +	/* scan MADT table to find if we have redistributor entries */
> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
> +					match_gic_redist, 0);
> +
> +	/* that's true if we have at least one GIC redistributor entry */
> +	return count > 0;
> +}
> +
> +static int __init acpi_gic_version_init(void)
> +{
> +	int count;
> +	u32 reg;
> +	void __iomem *dist_base;
> +
> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
> +				      acpi_gic_parse_distributor, 0);
> +
> +	if (count <= 0) {
> +		pr_err("No valid GIC distributor entry exists\n");
> +		return -ENODEV;
> +	}
> +
> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * when the GIC version is 0, we fallback to hardware discovery.
> +	 * this is also needed to keep compatiable with ACPI 5.1,
> +	 * which has no gic_version field in distributor structure and
> +	 * reserved as 0.
> +	 *
> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
> +	 * for GICv3/4), so we need to handle it separately.
> +	 */
> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
> +		/* it's GICv3/v4 if redistributor is present */
> +		if (acpi_gic_redist_is_present()) {
> +			dist_base = ioremap(dist_phy_base,
> +					    ACPI_GICV3_DIST_MEM_SIZE);
> +			if (!dist_base)
> +				return -ENOMEM;
> +
> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
> +					    GIC_PIDR2_ARCH_MASK;
> +			if (reg == GIC_PIDR2_ARCH_GICv3)
> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
> +			else
> +				gic_version = ACPI_MADT_GIC_VERSION_V4;

Frankly, why should we care? If there is no redistributor, this is a V2.
If there are redistributors, then it is a V3/V4, and it shouldn't matter
which one this is as the GICv3 driver can find out all by itself. Also,
the GICv4 feature only matter for KVM, which can probe this on its own.

> +
> +			iounmap(dist_base);
> +		} else {
> +			gic_version = ACPI_MADT_GIC_VERSION_V2;
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index de3419e..13bc676 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -19,6 +19,7 @@
>   */
>  #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
>  #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
> +#define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
>  
>  struct acpi_table_header;
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-04 12:06     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> There is a field added in ACPI 6.0 MADT table to indicate the
> GIC version, so parse the table to get its value for later use.
> 
> If GIC version presented in MADT is 0, we need to fallback to
> hardware discovery to get the GIC version.
> 
> In ACPI MADT table there is no compatible strings to indicate
> various irqchips and also ACPI doesn't support irqchips which
> are not compatible with ARM GIC spec, so GIC version can be used
> to load different GIC drivers which is needed for the later patch.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  arch/arm64/Kconfig                   |   1 +
>  drivers/irqchip/Kconfig              |   3 +
>  drivers/irqchip/Makefile             |   1 +
>  drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>  include/linux/irqchip/arm-gic-acpi.h |   1 +
>  5 files changed, 115 insertions(+)
>  create mode 100644 drivers/irqchip/irq-gic-acpi.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 318175f..f2ff61f 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -16,6 +16,7 @@ config ARM64
>  	select ARM_AMBA
>  	select ARM_ARCH_TIMER
>  	select ARM_GIC
> +	select ARM_GIC_ACPI if ACPI
>  	select AUDIT_ARCH_COMPAT_GENERIC
>  	select ARM_GIC_V2M if PCI_MSI
>  	select ARM_GIC_V3
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 120d815..557ec2f 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>  	  The maximum number of VICs available in the system, for
>  	  power management.
>  
> +config ARM_GIC_ACPI
> +	bool
> +
>  config ATMEL_AIC_IRQ
>  	bool
>  	select GENERIC_IRQ_CHIP
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 11d08c9..383f421 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>  obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>  obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>  obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>  obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>  obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> new file mode 100644
> index 0000000..6537b43
> --- /dev/null
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -0,0 +1,109 @@
> +/*
> + * ACPI based support for ARM GIC init
> + *
> + * Copyright (C) 2015, Linaro Ltd.
> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +#include <linux/irqchip/arm-gic-acpi.h>
> +#include <linux/irqchip/arm-gic-v3.h>
> +
> +/* GIC version presented in MADT GIC distributor structure */
> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> +
> +static phys_addr_t dist_phy_base __initdata;
> +
> +static int __init
> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
> +			   const unsigned long end)
> +{
> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	gic_version = dist->version;
> +	dist_phy_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int __init
> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
> +{
> +	return 0;
> +}
> +
> +static bool __init acpi_gic_redist_is_present(void)
> +{
> +	int count;
> +
> +	/* scan MADT table to find if we have redistributor entries */
> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
> +					match_gic_redist, 0);
> +
> +	/* that's true if we have at least one GIC redistributor entry */
> +	return count > 0;
> +}
> +
> +static int __init acpi_gic_version_init(void)
> +{
> +	int count;
> +	u32 reg;
> +	void __iomem *dist_base;
> +
> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
> +				      acpi_gic_parse_distributor, 0);
> +
> +	if (count <= 0) {
> +		pr_err("No valid GIC distributor entry exists\n");
> +		return -ENODEV;
> +	}
> +
> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * when the GIC version is 0, we fallback to hardware discovery.
> +	 * this is also needed to keep compatiable with ACPI 5.1,
> +	 * which has no gic_version field in distributor structure and
> +	 * reserved as 0.
> +	 *
> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
> +	 * for GICv3/4), so we need to handle it separately.
> +	 */
> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
> +		/* it's GICv3/v4 if redistributor is present */
> +		if (acpi_gic_redist_is_present()) {
> +			dist_base = ioremap(dist_phy_base,
> +					    ACPI_GICV3_DIST_MEM_SIZE);
> +			if (!dist_base)
> +				return -ENOMEM;
> +
> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
> +					    GIC_PIDR2_ARCH_MASK;
> +			if (reg == GIC_PIDR2_ARCH_GICv3)
> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
> +			else
> +				gic_version = ACPI_MADT_GIC_VERSION_V4;

Frankly, why should we care? If there is no redistributor, this is a V2.
If there are redistributors, then it is a V3/V4, and it shouldn't matter
which one this is as the GICv3 driver can find out all by itself. Also,
the GICv4 feature only matter for KVM, which can probe this on its own.

> +
> +			iounmap(dist_base);
> +		} else {
> +			gic_version = ACPI_MADT_GIC_VERSION_V2;
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index de3419e..13bc676 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -19,6 +19,7 @@
>   */
>  #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
>  #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
> +#define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
>  
>  struct acpi_table_header;
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 12:27     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:27 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> This self-probe infrastructure works in the similar way as OF,
> but there is some different in the mechanism:
> 
> For DT, the init fn will be called once it finds compatible strings
> in DT,  but for ACPI, we init irqchips by static tables, and in
> static ACPI tables, there are no compatible strings to indicate
> irqchips, but thanks to the GIC version presented in ACPI table,
> we can call the corresponding GIC drivers matching the GIC version
> with this framework.
> 
> This mechanism can also be used for clock declare and may also works
> on x86 for some table parsing too.
> 
> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
> work.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>  include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>  include/linux/acpi.h              | 16 ++++++++++++++++
>  include/linux/irqchip.h           | 13 +++++++++++++
>  include/linux/mod_devicetable.h   |  8 ++++++++
>  5 files changed, 83 insertions(+)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 6537b43..011468d 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>  
>  	return 0;
>  }
> +
> +/*
> + * This special acpi_table_id is the sentinel at the end of the
> + * acpi_table_id[] array of all irqchips. It is automatically placed at
> + * the end of the array by the linker, thanks to being part of a
> + * special section.
> + */
> +static const struct acpi_table_id
> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);

What is this thing for? Nobody refers to it (I know
drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
reason...).

> +
> +extern struct acpi_table_id __irqchip_acpi_table[];
> +
> +void __init acpi_irqchip_init(void)
> +{
> +	struct acpi_table_id *id;
> +
> +	if (acpi_disabled)
> +		return;
> +
> +	if (acpi_gic_version_init())
> +		return;

This is the only place where we need the version, right? So just get
acpi_gic_version_init to return the version number, and loose the global
variable.

> +
> +	/* scan the irqchip table to match the GIC version and its driver */
> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
> +		if (gic_version == (u8)id->driver_data) {
> +			acpi_table_parse(id->id,
> +					 (acpi_tbl_table_handler)id->handler);
> +			return;
> +		}
> +	}
> +
> +	pr_err("No matched driver GIC version %d\n", gic_version);
> +}
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 8bd374d..625776c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -181,6 +181,18 @@
>  #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>  #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_TABLE(name)						\
> +	. = ALIGN(8);							\
> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
> +	*(__##name##_acpi_table)					\
> +	*(__##name##_acpi_table_end)
> +
> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
> +#else
> +#define IRQCHIP_ACPI_MATCH_TABLE()
> +#endif
> +
>  #define KERNEL_DTB()							\
>  	STRUCT_ALIGN();							\
>  	VMLINUX_SYMBOL(__dtb_start) = .;				\
> @@ -516,6 +528,7 @@
>  	CPUIDLE_METHOD_OF_TABLES()					\
>  	KERNEL_DTB()							\
>  	IRQCHIP_OF_MATCH_TABLE()					\
> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>  	EARLYCON_TABLE()						\
>  	EARLYCON_OF_TABLES()
>  
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 0820cb1..04dd0bb 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>  
>  #endif
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__used __section(__##table##_acpi_table)		\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#else
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__attribute__((unused))					\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#endif
> +
>  #endif	/*_LINUX_ACPI_H*/
> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
> index 6388873..6b66d3e 100644
> --- a/include/linux/irqchip.h
> +++ b/include/linux/irqchip.h
> @@ -11,6 +11,7 @@
>  #ifndef _LINUX_IRQCHIP_H
>  #define _LINUX_IRQCHIP_H
>  
> +#include <linux/acpi.h>
>  #include <linux/of.h>
>  
>  /*
> @@ -25,6 +26,18 @@
>   */
>  #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>  
> +/*
> + * This macro must be used by the different ARM GIC drivers to declare
> + * the association between their version and their initialization function.
> + *
> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
> + * same file.
> + * @gic_version: version of GIC
> + * @fn: initialization function
> + */
> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)

I don't think this is the right approach. The MADT table has a *huge*
number of possible subtables, and none of them is matched by the GIC
version.

What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
macro doesn't reflect this at all (you've basically cloned OF, and
that's clearly not good enough).

This probably require an intermediate matching function, ending up with
something like:

#define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
		subtable, version, fn)

where match_madt_subtable is going to check that a given subtable is
really suitable for a given irqchip. None of that should be GIC
specific, really.

> +
>  #ifdef CONFIG_IRQCHIP
>  void irqchip_init(void);
>  #else
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index 34f25b7..105be1f 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -193,6 +193,14 @@ struct acpi_device_id {
>  	__u32 cls_msk;
>  };
>  
> +#define ACPI_TABLE_ID_LEN	5
> +
> +struct acpi_table_id {
> +	__u8 id[ACPI_TABLE_ID_LEN];
> +	const void *handler;
> +	kernel_ulong_t driver_data;
> +};
> +
>  #define PNP_ID_LEN	8
>  #define PNP_MAX_DEVICES	8
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-04 12:27     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:27 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> This self-probe infrastructure works in the similar way as OF,
> but there is some different in the mechanism:
> 
> For DT, the init fn will be called once it finds compatible strings
> in DT,  but for ACPI, we init irqchips by static tables, and in
> static ACPI tables, there are no compatible strings to indicate
> irqchips, but thanks to the GIC version presented in ACPI table,
> we can call the corresponding GIC drivers matching the GIC version
> with this framework.
> 
> This mechanism can also be used for clock declare and may also works
> on x86 for some table parsing too.
> 
> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
> work.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>  include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>  include/linux/acpi.h              | 16 ++++++++++++++++
>  include/linux/irqchip.h           | 13 +++++++++++++
>  include/linux/mod_devicetable.h   |  8 ++++++++
>  5 files changed, 83 insertions(+)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 6537b43..011468d 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>  
>  	return 0;
>  }
> +
> +/*
> + * This special acpi_table_id is the sentinel at the end of the
> + * acpi_table_id[] array of all irqchips. It is automatically placed at
> + * the end of the array by the linker, thanks to being part of a
> + * special section.
> + */
> +static const struct acpi_table_id
> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);

What is this thing for? Nobody refers to it (I know
drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
reason...).

> +
> +extern struct acpi_table_id __irqchip_acpi_table[];
> +
> +void __init acpi_irqchip_init(void)
> +{
> +	struct acpi_table_id *id;
> +
> +	if (acpi_disabled)
> +		return;
> +
> +	if (acpi_gic_version_init())
> +		return;

This is the only place where we need the version, right? So just get
acpi_gic_version_init to return the version number, and loose the global
variable.

> +
> +	/* scan the irqchip table to match the GIC version and its driver */
> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
> +		if (gic_version == (u8)id->driver_data) {
> +			acpi_table_parse(id->id,
> +					 (acpi_tbl_table_handler)id->handler);
> +			return;
> +		}
> +	}
> +
> +	pr_err("No matched driver GIC version %d\n", gic_version);
> +}
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 8bd374d..625776c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -181,6 +181,18 @@
>  #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>  #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_TABLE(name)						\
> +	. = ALIGN(8);							\
> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
> +	*(__##name##_acpi_table)					\
> +	*(__##name##_acpi_table_end)
> +
> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
> +#else
> +#define IRQCHIP_ACPI_MATCH_TABLE()
> +#endif
> +
>  #define KERNEL_DTB()							\
>  	STRUCT_ALIGN();							\
>  	VMLINUX_SYMBOL(__dtb_start) = .;				\
> @@ -516,6 +528,7 @@
>  	CPUIDLE_METHOD_OF_TABLES()					\
>  	KERNEL_DTB()							\
>  	IRQCHIP_OF_MATCH_TABLE()					\
> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>  	EARLYCON_TABLE()						\
>  	EARLYCON_OF_TABLES()
>  
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 0820cb1..04dd0bb 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>  
>  #endif
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__used __section(__##table##_acpi_table)		\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#else
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__attribute__((unused))					\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#endif
> +
>  #endif	/*_LINUX_ACPI_H*/
> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
> index 6388873..6b66d3e 100644
> --- a/include/linux/irqchip.h
> +++ b/include/linux/irqchip.h
> @@ -11,6 +11,7 @@
>  #ifndef _LINUX_IRQCHIP_H
>  #define _LINUX_IRQCHIP_H
>  
> +#include <linux/acpi.h>
>  #include <linux/of.h>
>  
>  /*
> @@ -25,6 +26,18 @@
>   */
>  #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>  
> +/*
> + * This macro must be used by the different ARM GIC drivers to declare
> + * the association between their version and their initialization function.
> + *
> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
> + * same file.
> + * @gic_version: version of GIC
> + * @fn: initialization function
> + */
> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)

I don't think this is the right approach. The MADT table has a *huge*
number of possible subtables, and none of them is matched by the GIC
version.

What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
macro doesn't reflect this at all (you've basically cloned OF, and
that's clearly not good enough).

This probably require an intermediate matching function, ending up with
something like:

#define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
		subtable, version, fn)

where match_madt_subtable is going to check that a given subtable is
really suitable for a given irqchip. None of that should be GIC
specific, really.

> +
>  #ifdef CONFIG_IRQCHIP
>  void irqchip_init(void);
>  #else
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index 34f25b7..105be1f 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -193,6 +193,14 @@ struct acpi_device_id {
>  	__u32 cls_msk;
>  };
>  
> +#define ACPI_TABLE_ID_LEN	5
> +
> +struct acpi_table_id {
> +	__u8 id[ACPI_TABLE_ID_LEN];
> +	const void *handler;
> +	kernel_ulong_t driver_data;
> +};
> +
>  #define PNP_ID_LEN	8
>  #define PNP_MAX_DEVICES	8
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-04 12:27     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> This self-probe infrastructure works in the similar way as OF,
> but there is some different in the mechanism:
> 
> For DT, the init fn will be called once it finds compatible strings
> in DT,  but for ACPI, we init irqchips by static tables, and in
> static ACPI tables, there are no compatible strings to indicate
> irqchips, but thanks to the GIC version presented in ACPI table,
> we can call the corresponding GIC drivers matching the GIC version
> with this framework.
> 
> This mechanism can also be used for clock declare and may also works
> on x86 for some table parsing too.
> 
> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
> work.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>  include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>  include/linux/acpi.h              | 16 ++++++++++++++++
>  include/linux/irqchip.h           | 13 +++++++++++++
>  include/linux/mod_devicetable.h   |  8 ++++++++
>  5 files changed, 83 insertions(+)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 6537b43..011468d 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>  
>  	return 0;
>  }
> +
> +/*
> + * This special acpi_table_id is the sentinel at the end of the
> + * acpi_table_id[] array of all irqchips. It is automatically placed at
> + * the end of the array by the linker, thanks to being part of a
> + * special section.
> + */
> +static const struct acpi_table_id
> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);

What is this thing for? Nobody refers to it (I know
drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
reason...).

> +
> +extern struct acpi_table_id __irqchip_acpi_table[];
> +
> +void __init acpi_irqchip_init(void)
> +{
> +	struct acpi_table_id *id;
> +
> +	if (acpi_disabled)
> +		return;
> +
> +	if (acpi_gic_version_init())
> +		return;

This is the only place where we need the version, right? So just get
acpi_gic_version_init to return the version number, and loose the global
variable.

> +
> +	/* scan the irqchip table to match the GIC version and its driver */
> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
> +		if (gic_version == (u8)id->driver_data) {
> +			acpi_table_parse(id->id,
> +					 (acpi_tbl_table_handler)id->handler);
> +			return;
> +		}
> +	}
> +
> +	pr_err("No matched driver GIC version %d\n", gic_version);
> +}
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 8bd374d..625776c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -181,6 +181,18 @@
>  #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>  #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_TABLE(name)						\
> +	. = ALIGN(8);							\
> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
> +	*(__##name##_acpi_table)					\
> +	*(__##name##_acpi_table_end)
> +
> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
> +#else
> +#define IRQCHIP_ACPI_MATCH_TABLE()
> +#endif
> +
>  #define KERNEL_DTB()							\
>  	STRUCT_ALIGN();							\
>  	VMLINUX_SYMBOL(__dtb_start) = .;				\
> @@ -516,6 +528,7 @@
>  	CPUIDLE_METHOD_OF_TABLES()					\
>  	KERNEL_DTB()							\
>  	IRQCHIP_OF_MATCH_TABLE()					\
> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>  	EARLYCON_TABLE()						\
>  	EARLYCON_OF_TABLES()
>  
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 0820cb1..04dd0bb 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>  
>  #endif
>  
> +#ifdef CONFIG_ACPI
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__used __section(__##table##_acpi_table)		\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#else
> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
> +	static const struct acpi_table_id __acpi_table_##name		\
> +		__attribute__((unused))					\
> +		 = { .id = table_id,					\
> +		     .handler = (void *)fn,				\
> +		     .driver_data = data }
> +#endif
> +
>  #endif	/*_LINUX_ACPI_H*/
> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
> index 6388873..6b66d3e 100644
> --- a/include/linux/irqchip.h
> +++ b/include/linux/irqchip.h
> @@ -11,6 +11,7 @@
>  #ifndef _LINUX_IRQCHIP_H
>  #define _LINUX_IRQCHIP_H
>  
> +#include <linux/acpi.h>
>  #include <linux/of.h>
>  
>  /*
> @@ -25,6 +26,18 @@
>   */
>  #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>  
> +/*
> + * This macro must be used by the different ARM GIC drivers to declare
> + * the association between their version and their initialization function.
> + *
> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
> + * same file.
> + * @gic_version: version of GIC
> + * @fn: initialization function
> + */
> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)

I don't think this is the right approach. The MADT table has a *huge*
number of possible subtables, and none of them is matched by the GIC
version.

What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
macro doesn't reflect this at all (you've basically cloned OF, and
that's clearly not good enough).

This probably require an intermediate matching function, ending up with
something like:

#define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
		subtable, version, fn)

where match_madt_subtable is going to check that a given subtable is
really suitable for a given irqchip. None of that should be GIC
specific, really.

> +
>  #ifdef CONFIG_IRQCHIP
>  void irqchip_init(void);
>  #else
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index 34f25b7..105be1f 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -193,6 +193,14 @@ struct acpi_device_id {
>  	__u32 cls_msk;
>  };
>  
> +#define ACPI_TABLE_ID_LEN	5
> +
> +struct acpi_table_id {
> +	__u8 id[ACPI_TABLE_ID_LEN];
> +	const void *handler;
> +	kernel_ulong_t driver_data;
> +};
> +
>  #define PNP_ID_LEN	8
>  #define PNP_MAX_DEVICES	8
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 13:17     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:17 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> 
> 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.
> 
> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> [hj: Rework this patch and fix multi issues]
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 169 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index c0b96c6..ebc5604 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>
> @@ -25,6 +26,7 @@
>  #include <linux/percpu.h>
>  #include <linux/slab.h>
>  
> +#include <linux/irqchip/arm-gic-acpi.h>
>  #include <linux/irqchip/arm-gic-v3.h>
>  
>  #include <asm/cputype.h>
> @@ -802,7 +804,8 @@ 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())
> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
> +		its_init(irq_domain_token_to_of_node(domain_token),
> +			 &gic_data.rdists, gic_data.domain);

This doesn't make much sense. The first parameter to its_init is indeed
supposed to be an of_node, but what is the point of calling its_init if
you *know* you don't have the necessary topological information to parse
the firmware tables?

I don't see *any* code that is going to parse the ITS table in this
series, so please don't call its_init passing a NULL pointer to it. This
is just gross.

>  
>  	gic_smp_init();
>  	gic_dist_init();
> @@ -818,6 +821,16 @@ out_free:
>  	return err;
>  }
>  
> +static int __init detect_distributor(void __iomem *dist_base)

We do have a naming convention in this file. All functions start with gic_.

> +{
> +	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;
> +}

This function doesn't detect anything, it validates that we have
something sensible. Please rename it to gic_validate_dist_version, or
something similar.

> +
>  #ifdef CONFIG_OF
>  static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>  {
> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  	struct redist_region *rdist_regs;
>  	u64 redist_stride;
>  	u32 nr_redist_regions;
> -	u32 reg;
>  	int err, i;
>  
>  	dist_base = of_iomap(node, 0);
> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  		return -ENXIO;
>  	}
>  
> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +	err = detect_distributor(dist_base);
> +	if (err) {
>  		pr_err("%s: no distributor detected, giving up\n",
>  			node->full_name);
> -		err = -ENODEV;
>  		goto out_unmap_dist;
>  	}
>  
> @@ -887,3 +898,156 @@ out_unmap_dist:
>  
>  IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> +
> +#ifdef CONFIG_ACPI
> +static struct redist_region *redist_regs __initdata;
> +static u32 nr_redist_regions __initdata;
> +static phys_addr_t dist_phys_base __initdata;
> +
> +static int __init
> +gic_acpi_register_redist(u64 phys_base, u64 size)

A physical address must use phys_addr_t.

> +{
> +	struct redist_region *redist_regs_new;
> +	void __iomem *redist_base;
> +
> +	redist_regs_new = krealloc(redist_regs,
> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
> +				   GFP_KERNEL);

NAK. If you have multiple regions, you count them, you allocate the
right number of regions. This will be far more efficient than doing this
realloc dance. It is not like we're not parsing the tables a zillion
times already. Doing it one more time won't hurt.

> +	if (!redist_regs_new) {
> +		pr_err("Couldn't allocate resource for GICR region\n");
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs = redist_regs_new;
> +
> +	redist_base = ioremap(phys_base, size);
> +	if (!redist_base) {
> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs[nr_redist_regions].phys_base = phys_base;
> +	redist_regs[nr_redist_regions].redist_base = redist_base;
> +	nr_redist_regions++;
> +	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;
> +
> +	if (BAD_MADT_ENTRY(header, end))
> +		return -EINVAL;
> +
> +	redist = (struct acpi_madt_generic_redistributor *)header;
> +	if (!redist->base_address)
> +		return -EINVAL;
> +
> +	return gic_acpi_register_redist(redist->base_address, redist->length);
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
> +				const unsigned long end)
> +{

How many versions of gic_acpi_parse_madt_distributor are we going to
get? Why isn't the ACPI parsing in a common file? Why do I have to read
the same code on and on until my eyes bleed?

> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	dist_phys_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
> +				      u32 gsi, unsigned int irq_type)
> +{
> +	/*
> +	 * Encode GSI and triggering information the way the GIC likes
> +	 * them.
> +	 */
> +	if (WARN_ON(gsi < 16))
> +		return -EINVAL;
> +
> +	if (gsi >= 32) {
> +		data->param[0] = 0;		/* SPI */
> +		data->param[1] = gsi - 32;
> +		data->param[2] = irq_type;
> +	} else {
> +		data->param[0] = 1; 		/* PPI */
> +		data->param[1] = gsi - 16;
> +		data->param[2] = 0xff << 4 | irq_type;
> +	}
> +
> +	data->param_count = 3;
> +
> +	return 0;
> +}
> +
> +static int __init
> +gic_acpi_init(struct acpi_table_header *table)
> +{
> +	int count, i, err = 0;
> +	void __iomem *dist_base;
> +
> +	/* Get distributor base address */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +				sizeof(struct acpi_table_madt),
> +				gic_acpi_parse_madt_distributor, table,
> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_err("No valid GICD entry exist\n");
> +		return -EINVAL;
> +	} else if (count > 1) {
> +		pr_err("More than one GICD entry detected\n");
> +		return -EINVAL;
> +	}
> +
> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
> +	if (!dist_base) {
> +		pr_err("Unable to map GICD registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	err = detect_distributor(dist_base);
> +	if (err) {
> +		pr_err("No distributor detected at @%p, giving up", dist_base);
> +		goto out_dist_unmap;
> +	}
> +
> +	/* Collect redistributor base addresses */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +			sizeof(struct acpi_table_madt),
> +			gic_acpi_parse_madt_redist, table,
> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_info("No valid GICR entries exist\n");
> +		err = -EINVAL;
> +		goto out_redist_unmap;
> +	}
> +
> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
> +			     (void *)ACPI_IRQ_MODEL_GIC);

There is no other global identifier for GICv3? It feels a bit weird to
use the same ID as GICv2 (though probably not harmful as you can't have
both as the same time). What are you planning to use for the ITS then?
You must make sure you have a global namespace.

> +	if (err)
> +		goto out_redist_unmap;
> +
> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
> +			   gic_acpi_gsi_desc_populate);
> +	return 0;
> +
> +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_GIC_VERSION_V3, gic_acpi_init);
> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);

As mentioned before, this doesn't work.

> +#endif
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-04 13:17     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:17 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> 
> 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.
> 
> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> [hj: Rework this patch and fix multi issues]
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 169 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index c0b96c6..ebc5604 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>
> @@ -25,6 +26,7 @@
>  #include <linux/percpu.h>
>  #include <linux/slab.h>
>  
> +#include <linux/irqchip/arm-gic-acpi.h>
>  #include <linux/irqchip/arm-gic-v3.h>
>  
>  #include <asm/cputype.h>
> @@ -802,7 +804,8 @@ 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())
> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
> +		its_init(irq_domain_token_to_of_node(domain_token),
> +			 &gic_data.rdists, gic_data.domain);

This doesn't make much sense. The first parameter to its_init is indeed
supposed to be an of_node, but what is the point of calling its_init if
you *know* you don't have the necessary topological information to parse
the firmware tables?

I don't see *any* code that is going to parse the ITS table in this
series, so please don't call its_init passing a NULL pointer to it. This
is just gross.

>  
>  	gic_smp_init();
>  	gic_dist_init();
> @@ -818,6 +821,16 @@ out_free:
>  	return err;
>  }
>  
> +static int __init detect_distributor(void __iomem *dist_base)

We do have a naming convention in this file. All functions start with gic_.

> +{
> +	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;
> +}

This function doesn't detect anything, it validates that we have
something sensible. Please rename it to gic_validate_dist_version, or
something similar.

> +
>  #ifdef CONFIG_OF
>  static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>  {
> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  	struct redist_region *rdist_regs;
>  	u64 redist_stride;
>  	u32 nr_redist_regions;
> -	u32 reg;
>  	int err, i;
>  
>  	dist_base = of_iomap(node, 0);
> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  		return -ENXIO;
>  	}
>  
> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +	err = detect_distributor(dist_base);
> +	if (err) {
>  		pr_err("%s: no distributor detected, giving up\n",
>  			node->full_name);
> -		err = -ENODEV;
>  		goto out_unmap_dist;
>  	}
>  
> @@ -887,3 +898,156 @@ out_unmap_dist:
>  
>  IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> +
> +#ifdef CONFIG_ACPI
> +static struct redist_region *redist_regs __initdata;
> +static u32 nr_redist_regions __initdata;
> +static phys_addr_t dist_phys_base __initdata;
> +
> +static int __init
> +gic_acpi_register_redist(u64 phys_base, u64 size)

A physical address must use phys_addr_t.

> +{
> +	struct redist_region *redist_regs_new;
> +	void __iomem *redist_base;
> +
> +	redist_regs_new = krealloc(redist_regs,
> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
> +				   GFP_KERNEL);

NAK. If you have multiple regions, you count them, you allocate the
right number of regions. This will be far more efficient than doing this
realloc dance. It is not like we're not parsing the tables a zillion
times already. Doing it one more time won't hurt.

> +	if (!redist_regs_new) {
> +		pr_err("Couldn't allocate resource for GICR region\n");
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs = redist_regs_new;
> +
> +	redist_base = ioremap(phys_base, size);
> +	if (!redist_base) {
> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs[nr_redist_regions].phys_base = phys_base;
> +	redist_regs[nr_redist_regions].redist_base = redist_base;
> +	nr_redist_regions++;
> +	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;
> +
> +	if (BAD_MADT_ENTRY(header, end))
> +		return -EINVAL;
> +
> +	redist = (struct acpi_madt_generic_redistributor *)header;
> +	if (!redist->base_address)
> +		return -EINVAL;
> +
> +	return gic_acpi_register_redist(redist->base_address, redist->length);
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
> +				const unsigned long end)
> +{

How many versions of gic_acpi_parse_madt_distributor are we going to
get? Why isn't the ACPI parsing in a common file? Why do I have to read
the same code on and on until my eyes bleed?

> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	dist_phys_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
> +				      u32 gsi, unsigned int irq_type)
> +{
> +	/*
> +	 * Encode GSI and triggering information the way the GIC likes
> +	 * them.
> +	 */
> +	if (WARN_ON(gsi < 16))
> +		return -EINVAL;
> +
> +	if (gsi >= 32) {
> +		data->param[0] = 0;		/* SPI */
> +		data->param[1] = gsi - 32;
> +		data->param[2] = irq_type;
> +	} else {
> +		data->param[0] = 1; 		/* PPI */
> +		data->param[1] = gsi - 16;
> +		data->param[2] = 0xff << 4 | irq_type;
> +	}
> +
> +	data->param_count = 3;
> +
> +	return 0;
> +}
> +
> +static int __init
> +gic_acpi_init(struct acpi_table_header *table)
> +{
> +	int count, i, err = 0;
> +	void __iomem *dist_base;
> +
> +	/* Get distributor base address */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +				sizeof(struct acpi_table_madt),
> +				gic_acpi_parse_madt_distributor, table,
> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_err("No valid GICD entry exist\n");
> +		return -EINVAL;
> +	} else if (count > 1) {
> +		pr_err("More than one GICD entry detected\n");
> +		return -EINVAL;
> +	}
> +
> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
> +	if (!dist_base) {
> +		pr_err("Unable to map GICD registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	err = detect_distributor(dist_base);
> +	if (err) {
> +		pr_err("No distributor detected at @%p, giving up", dist_base);
> +		goto out_dist_unmap;
> +	}
> +
> +	/* Collect redistributor base addresses */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +			sizeof(struct acpi_table_madt),
> +			gic_acpi_parse_madt_redist, table,
> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_info("No valid GICR entries exist\n");
> +		err = -EINVAL;
> +		goto out_redist_unmap;
> +	}
> +
> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
> +			     (void *)ACPI_IRQ_MODEL_GIC);

There is no other global identifier for GICv3? It feels a bit weird to
use the same ID as GICv2 (though probably not harmful as you can't have
both as the same time). What are you planning to use for the ITS then?
You must make sure you have a global namespace.

> +	if (err)
> +		goto out_redist_unmap;
> +
> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
> +			   gic_acpi_gsi_desc_populate);
> +	return 0;
> +
> +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_GIC_VERSION_V3, gic_acpi_init);
> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);

As mentioned before, this doesn't work.

> +#endif
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-04 13:17     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> 
> 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.
> 
> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
> [hj: Rework this patch and fix multi issues]
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 169 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index c0b96c6..ebc5604 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>
> @@ -25,6 +26,7 @@
>  #include <linux/percpu.h>
>  #include <linux/slab.h>
>  
> +#include <linux/irqchip/arm-gic-acpi.h>
>  #include <linux/irqchip/arm-gic-v3.h>
>  
>  #include <asm/cputype.h>
> @@ -802,7 +804,8 @@ 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())
> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
> +		its_init(irq_domain_token_to_of_node(domain_token),
> +			 &gic_data.rdists, gic_data.domain);

This doesn't make much sense. The first parameter to its_init is indeed
supposed to be an of_node, but what is the point of calling its_init if
you *know* you don't have the necessary topological information to parse
the firmware tables?

I don't see *any* code that is going to parse the ITS table in this
series, so please don't call its_init passing a NULL pointer to it. This
is just gross.

>  
>  	gic_smp_init();
>  	gic_dist_init();
> @@ -818,6 +821,16 @@ out_free:
>  	return err;
>  }
>  
> +static int __init detect_distributor(void __iomem *dist_base)

We do have a naming convention in this file. All functions start with gic_.

> +{
> +	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;
> +}

This function doesn't detect anything, it validates that we have
something sensible. Please rename it to gic_validate_dist_version, or
something similar.

> +
>  #ifdef CONFIG_OF
>  static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>  {
> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  	struct redist_region *rdist_regs;
>  	u64 redist_stride;
>  	u32 nr_redist_regions;
> -	u32 reg;
>  	int err, i;
>  
>  	dist_base = of_iomap(node, 0);
> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>  		return -ENXIO;
>  	}
>  
> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +	err = detect_distributor(dist_base);
> +	if (err) {
>  		pr_err("%s: no distributor detected, giving up\n",
>  			node->full_name);
> -		err = -ENODEV;
>  		goto out_unmap_dist;
>  	}
>  
> @@ -887,3 +898,156 @@ out_unmap_dist:
>  
>  IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> +
> +#ifdef CONFIG_ACPI
> +static struct redist_region *redist_regs __initdata;
> +static u32 nr_redist_regions __initdata;
> +static phys_addr_t dist_phys_base __initdata;
> +
> +static int __init
> +gic_acpi_register_redist(u64 phys_base, u64 size)

A physical address must use phys_addr_t.

> +{
> +	struct redist_region *redist_regs_new;
> +	void __iomem *redist_base;
> +
> +	redist_regs_new = krealloc(redist_regs,
> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
> +				   GFP_KERNEL);

NAK. If you have multiple regions, you count them, you allocate the
right number of regions. This will be far more efficient than doing this
realloc dance. It is not like we're not parsing the tables a zillion
times already. Doing it one more time won't hurt.

> +	if (!redist_regs_new) {
> +		pr_err("Couldn't allocate resource for GICR region\n");
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs = redist_regs_new;
> +
> +	redist_base = ioremap(phys_base, size);
> +	if (!redist_base) {
> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
> +		return -ENOMEM;
> +	}
> +
> +	redist_regs[nr_redist_regions].phys_base = phys_base;
> +	redist_regs[nr_redist_regions].redist_base = redist_base;
> +	nr_redist_regions++;
> +	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;
> +
> +	if (BAD_MADT_ENTRY(header, end))
> +		return -EINVAL;
> +
> +	redist = (struct acpi_madt_generic_redistributor *)header;
> +	if (!redist->base_address)
> +		return -EINVAL;
> +
> +	return gic_acpi_register_redist(redist->base_address, redist->length);
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
> +				const unsigned long end)
> +{

How many versions of gic_acpi_parse_madt_distributor are we going to
get? Why isn't the ACPI parsing in a common file? Why do I have to read
the same code on and on until my eyes bleed?

> +	struct acpi_madt_generic_distributor *dist;
> +
> +	dist = (struct acpi_madt_generic_distributor *)header;
> +
> +	if (BAD_MADT_ENTRY(dist, end))
> +		return -EINVAL;
> +
> +	dist_phys_base = dist->base_address;
> +	return 0;
> +}
> +
> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
> +				      u32 gsi, unsigned int irq_type)
> +{
> +	/*
> +	 * Encode GSI and triggering information the way the GIC likes
> +	 * them.
> +	 */
> +	if (WARN_ON(gsi < 16))
> +		return -EINVAL;
> +
> +	if (gsi >= 32) {
> +		data->param[0] = 0;		/* SPI */
> +		data->param[1] = gsi - 32;
> +		data->param[2] = irq_type;
> +	} else {
> +		data->param[0] = 1; 		/* PPI */
> +		data->param[1] = gsi - 16;
> +		data->param[2] = 0xff << 4 | irq_type;
> +	}
> +
> +	data->param_count = 3;
> +
> +	return 0;
> +}
> +
> +static int __init
> +gic_acpi_init(struct acpi_table_header *table)
> +{
> +	int count, i, err = 0;
> +	void __iomem *dist_base;
> +
> +	/* Get distributor base address */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +				sizeof(struct acpi_table_madt),
> +				gic_acpi_parse_madt_distributor, table,
> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_err("No valid GICD entry exist\n");
> +		return -EINVAL;
> +	} else if (count > 1) {
> +		pr_err("More than one GICD entry detected\n");
> +		return -EINVAL;
> +	}
> +
> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
> +	if (!dist_base) {
> +		pr_err("Unable to map GICD registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	err = detect_distributor(dist_base);
> +	if (err) {
> +		pr_err("No distributor detected at @%p, giving up", dist_base);
> +		goto out_dist_unmap;
> +	}
> +
> +	/* Collect redistributor base addresses */
> +	count = acpi_parse_entries(ACPI_SIG_MADT,
> +			sizeof(struct acpi_table_madt),
> +			gic_acpi_parse_madt_redist, table,
> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +	if (count <= 0) {
> +		pr_info("No valid GICR entries exist\n");
> +		err = -EINVAL;
> +		goto out_redist_unmap;
> +	}
> +
> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
> +			     (void *)ACPI_IRQ_MODEL_GIC);

There is no other global identifier for GICv3? It feels a bit weird to
use the same ID as GICv2 (though probably not harmful as you can't have
both as the same time). What are you planning to use for the ITS then?
You must make sure you have a global namespace.

> +	if (err)
> +		goto out_redist_unmap;
> +
> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
> +			   gic_acpi_gsi_desc_populate);
> +	return 0;
> +
> +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_GIC_VERSION_V3, gic_acpi_init);
> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);

As mentioned before, this doesn't work.

> +#endif
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 13:37     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:37 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> 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.
> 
> As GICR base in MADT GICC is another way to indicate the GIC version
> is 3 or 4, add its support to find out the GIC versions.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>  drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>  include/linux/irqchip/arm-gic-acpi.h |   2 +
>  3 files changed, 215 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 95454e3..3e5c8f4 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> 
>  static phys_addr_t dist_phy_base __initdata;
> 
> +u8 __init acpi_gic_version(void)
> +{
> +       return gic_version;
> +}
> +
>  static int __init
>  acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>                            const unsigned long end)
> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>  }
> 
>  static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * If GICC is enabled but has no valid gicr base address, then it
> +        * means GICR base is not presented via GICC
> +        */
> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static int __init
>  match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>  {
>         return 0;
> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>         count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>                                         match_gic_redist, 0);
> 
> -       /* that's true if we have at least one GIC redistributor entry */
> +       /* has at least one GIC redistributor entry */
> +       if (count > 0)
> +               return true;
> +
> +       /* else try to find GICR base in GICC entries */
> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
> +                                     gic_acpi_parse_madt_gicc, 0);
> +
>         return count > 0;
>  }
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index ebc5604..b72ccbb 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>                 writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>  }
> 
> -static int gic_populate_rdist(void)
> +static int gic_populate_rdist_with_regions(u64 mpidr)
>  {
> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>         u64 typer;
>         u32 aff;
>         int i;
> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>                 } while (!(typer & GICR_TYPER_LAST));
>         }
> 
> +       return -ENODEV;
> +}
> +
> +#ifdef CONFIG_ACPI
> +/*
> + * Populate redist when GIC redistributor address is presented in ACPI
> + * MADT GICC entries
> + */
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
> +#else
> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +static int gic_populate_rdist(void)
> +{
> +       u64 mpidr = cpu_logical_map(smp_processor_id());
> +
> +       if (gic_data.nr_redist_regions) {
> +               if (!gic_populate_rdist_with_regions(mpidr))
> +                       return 0;
> +       } else {
> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
> +                       return 0;
> +       }
> +
>         /* We couldn't even deal with ourselves... */
>         WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>              smp_processor_id(), (unsigned long long)mpidr);
> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> 
>  #ifdef CONFIG_ACPI
> +
> +struct acpi_gicc_redist {
> +       struct list_head list;
> +       u64 mpidr;
> +       phys_addr_t phys_base;
> +       void __iomem *redist_base;
> +};
> +
> +static LIST_HEAD(redist_list);
> +
>  static struct redist_region *redist_regs __initdata;
>  static u32 nr_redist_regions __initdata;
>  static phys_addr_t dist_phys_base __initdata;
> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>         return 0;
>  }
> 
> +static void __init
> +gic_acpi_release_redist_regions(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < nr_redist_regions; i++)
> +               if (redist_regs[i].redist_base)
> +                       iounmap(redist_regs[i].redist_base);
> +       kfree(redist_regs);
> +}
> +
>  static int __init
>  gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>                         const unsigned long end)
> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>  }
> 
>  static int __init
> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +
> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
> +       if (!redist)
> +               return -ENOMEM;
> +
> +       redist->mpidr = mpidr;
> +       redist->phys_base = phys_base;
> +
> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
> +               /* RD_base + SGI_base */
> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
> +       else
> +               /*
> +                * RD_base + SGI_base + VLPI_base,
> +                * we don't map reserved page as it's buggy to access it
> +                */
> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
> +
> +       if (!redist->redist_base) {
> +               kfree(redist);
> +               return -ENOMEM;
> +       }
> +
> +       list_add(&redist->list, &redist_list);
> +       return 0;
> +}
> +
> +static void __init
> +gic_acpi_release_gicc_redist(void)
> +{
> +       struct acpi_gicc_redist *redist, *t;
> +
> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
> +               list_del(&redist->list);
> +               iounmap(redist->redist_base);
> +               kfree(redist);
> +       }
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * just quietly ingore the disabled CPU(s) and continue
> +        * to find the enabled one(s), if we return error here,
> +        * the scanning will be stopped.
> +        */
> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
> +               return 0;
> +
> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
> +                                       gicc->arm_mpidr);
> +}
> +
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +       void __iomem *ptr;
> +       u32 reg;
> +
> +       list_for_each_entry(redist, &redist_list, list) {
> +               if (redist->mpidr != mpidr)
> +                       continue;
> +
> +               ptr = redist->redist_base;
> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +                       pr_warn("No redistributor present @%p\n", ptr);
> +                       return -ENODEV;
> +               }
> +
> +               gic_data_rdist_rd_base() = ptr;
> +               gic_data_rdist()->phys_base = redist->phys_base;
> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
> +                       smp_processor_id(),
> +                       (unsigned long long)mpidr,
> +                       &gic_data_rdist()->phys_base);
> +               return 0;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +static int __init collect_gicr_base(struct acpi_table_header *table)
> +{
> +       int count;
> +
> +       /* Collect redistributor base addresses in GICR entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_redist, table,
> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +       if (count > 0)
> +               return 0;
> +
> +       pr_info("No valid GICR entries exist, try GICC entries\n");
> +
> +       /* Collect redistributor base addresses in GICC entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_gicc, table,
> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
> +       if (count > 0 && !list_empty(&redist_list))
> +               return 0;
> +
> +       pr_info("No valid GICC entries exist for GICR base\n");
> +       return -ENODEV;
> +}
> +
> +static int __init
>  gic_acpi_init(struct acpi_table_header *table)
>  {
> -       int count, i, err = 0;
> +       int count, err = 0;
>         void __iomem *dist_base;
> 
>         /* Get distributor base address */
> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>         }
> 
>         /* Collect redistributor base addresses */
> -       count = acpi_parse_entries(ACPI_SIG_MADT,
> -                       sizeof(struct acpi_table_madt),
> -                       gic_acpi_parse_madt_redist, table,
> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> -       if (count <= 0) {
> -               pr_info("No valid GICR entries exist\n");
> -               err = -EINVAL;
> -               goto out_redist_unmap;
> -       }
> +       if (collect_gicr_base(table))
> +               goto out_release_redist;
> 
>         err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>                              (void *)ACPI_IRQ_MODEL_GIC);
>         if (err)
> -               goto out_redist_unmap;
> +               goto out_release_redist;
> 
>         acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>                            gic_acpi_gsi_desc_populate);
>         return 0;
> 
> -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_release_redist:
> +       gic_acpi_release_redist_regions();
> +       if (!list_empty(&redist_list))
> +               gic_acpi_release_gicc_redist();
>  out_dist_unmap:
>         iounmap(dist_base);
>         return err;
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index 56cd82c..0d43f515 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -21,5 +21,7 @@
>  #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>  #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
> 
> +u8 acpi_gic_version(void);
> +
>  #endif /* CONFIG_ACPI */
>  #endif /* ARM_GIC_ACPI_H_ */
> --
> 1.9.1
> 

This looks absolutely horrid. Why don't you simply populate one region
per redistributor, add a flag to struct redist_region so we know not to
check for GICR_TYPER_LAST but to move on to the next region instead?

We already have all the flexibility you require, please don't invent
stuff that is already there.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-04 13:37     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:37 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> 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.
> 
> As GICR base in MADT GICC is another way to indicate the GIC version
> is 3 or 4, add its support to find out the GIC versions.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>  drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>  include/linux/irqchip/arm-gic-acpi.h |   2 +
>  3 files changed, 215 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 95454e3..3e5c8f4 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> 
>  static phys_addr_t dist_phy_base __initdata;
> 
> +u8 __init acpi_gic_version(void)
> +{
> +       return gic_version;
> +}
> +
>  static int __init
>  acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>                            const unsigned long end)
> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>  }
> 
>  static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * If GICC is enabled but has no valid gicr base address, then it
> +        * means GICR base is not presented via GICC
> +        */
> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static int __init
>  match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>  {
>         return 0;
> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>         count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>                                         match_gic_redist, 0);
> 
> -       /* that's true if we have at least one GIC redistributor entry */
> +       /* has at least one GIC redistributor entry */
> +       if (count > 0)
> +               return true;
> +
> +       /* else try to find GICR base in GICC entries */
> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
> +                                     gic_acpi_parse_madt_gicc, 0);
> +
>         return count > 0;
>  }
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index ebc5604..b72ccbb 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>                 writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>  }
> 
> -static int gic_populate_rdist(void)
> +static int gic_populate_rdist_with_regions(u64 mpidr)
>  {
> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>         u64 typer;
>         u32 aff;
>         int i;
> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>                 } while (!(typer & GICR_TYPER_LAST));
>         }
> 
> +       return -ENODEV;
> +}
> +
> +#ifdef CONFIG_ACPI
> +/*
> + * Populate redist when GIC redistributor address is presented in ACPI
> + * MADT GICC entries
> + */
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
> +#else
> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +static int gic_populate_rdist(void)
> +{
> +       u64 mpidr = cpu_logical_map(smp_processor_id());
> +
> +       if (gic_data.nr_redist_regions) {
> +               if (!gic_populate_rdist_with_regions(mpidr))
> +                       return 0;
> +       } else {
> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
> +                       return 0;
> +       }
> +
>         /* We couldn't even deal with ourselves... */
>         WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>              smp_processor_id(), (unsigned long long)mpidr);
> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> 
>  #ifdef CONFIG_ACPI
> +
> +struct acpi_gicc_redist {
> +       struct list_head list;
> +       u64 mpidr;
> +       phys_addr_t phys_base;
> +       void __iomem *redist_base;
> +};
> +
> +static LIST_HEAD(redist_list);
> +
>  static struct redist_region *redist_regs __initdata;
>  static u32 nr_redist_regions __initdata;
>  static phys_addr_t dist_phys_base __initdata;
> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>         return 0;
>  }
> 
> +static void __init
> +gic_acpi_release_redist_regions(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < nr_redist_regions; i++)
> +               if (redist_regs[i].redist_base)
> +                       iounmap(redist_regs[i].redist_base);
> +       kfree(redist_regs);
> +}
> +
>  static int __init
>  gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>                         const unsigned long end)
> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>  }
> 
>  static int __init
> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +
> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
> +       if (!redist)
> +               return -ENOMEM;
> +
> +       redist->mpidr = mpidr;
> +       redist->phys_base = phys_base;
> +
> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
> +               /* RD_base + SGI_base */
> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
> +       else
> +               /*
> +                * RD_base + SGI_base + VLPI_base,
> +                * we don't map reserved page as it's buggy to access it
> +                */
> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
> +
> +       if (!redist->redist_base) {
> +               kfree(redist);
> +               return -ENOMEM;
> +       }
> +
> +       list_add(&redist->list, &redist_list);
> +       return 0;
> +}
> +
> +static void __init
> +gic_acpi_release_gicc_redist(void)
> +{
> +       struct acpi_gicc_redist *redist, *t;
> +
> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
> +               list_del(&redist->list);
> +               iounmap(redist->redist_base);
> +               kfree(redist);
> +       }
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * just quietly ingore the disabled CPU(s) and continue
> +        * to find the enabled one(s), if we return error here,
> +        * the scanning will be stopped.
> +        */
> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
> +               return 0;
> +
> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
> +                                       gicc->arm_mpidr);
> +}
> +
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +       void __iomem *ptr;
> +       u32 reg;
> +
> +       list_for_each_entry(redist, &redist_list, list) {
> +               if (redist->mpidr != mpidr)
> +                       continue;
> +
> +               ptr = redist->redist_base;
> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +                       pr_warn("No redistributor present @%p\n", ptr);
> +                       return -ENODEV;
> +               }
> +
> +               gic_data_rdist_rd_base() = ptr;
> +               gic_data_rdist()->phys_base = redist->phys_base;
> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
> +                       smp_processor_id(),
> +                       (unsigned long long)mpidr,
> +                       &gic_data_rdist()->phys_base);
> +               return 0;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +static int __init collect_gicr_base(struct acpi_table_header *table)
> +{
> +       int count;
> +
> +       /* Collect redistributor base addresses in GICR entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_redist, table,
> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +       if (count > 0)
> +               return 0;
> +
> +       pr_info("No valid GICR entries exist, try GICC entries\n");
> +
> +       /* Collect redistributor base addresses in GICC entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_gicc, table,
> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
> +       if (count > 0 && !list_empty(&redist_list))
> +               return 0;
> +
> +       pr_info("No valid GICC entries exist for GICR base\n");
> +       return -ENODEV;
> +}
> +
> +static int __init
>  gic_acpi_init(struct acpi_table_header *table)
>  {
> -       int count, i, err = 0;
> +       int count, err = 0;
>         void __iomem *dist_base;
> 
>         /* Get distributor base address */
> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>         }
> 
>         /* Collect redistributor base addresses */
> -       count = acpi_parse_entries(ACPI_SIG_MADT,
> -                       sizeof(struct acpi_table_madt),
> -                       gic_acpi_parse_madt_redist, table,
> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> -       if (count <= 0) {
> -               pr_info("No valid GICR entries exist\n");
> -               err = -EINVAL;
> -               goto out_redist_unmap;
> -       }
> +       if (collect_gicr_base(table))
> +               goto out_release_redist;
> 
>         err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>                              (void *)ACPI_IRQ_MODEL_GIC);
>         if (err)
> -               goto out_redist_unmap;
> +               goto out_release_redist;
> 
>         acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>                            gic_acpi_gsi_desc_populate);
>         return 0;
> 
> -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_release_redist:
> +       gic_acpi_release_redist_regions();
> +       if (!list_empty(&redist_list))
> +               gic_acpi_release_gicc_redist();
>  out_dist_unmap:
>         iounmap(dist_base);
>         return err;
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index 56cd82c..0d43f515 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -21,5 +21,7 @@
>  #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>  #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
> 
> +u8 acpi_gic_version(void);
> +
>  #endif /* CONFIG_ACPI */
>  #endif /* ARM_GIC_ACPI_H_ */
> --
> 1.9.1
> 

This looks absolutely horrid. Why don't you simply populate one region
per redistributor, add a flag to struct redist_region so we know not to
check for GICR_TYPER_LAST but to move on to the next region instead?

We already have all the flexibility you require, please don't invent
stuff that is already there.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-04 13:37     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> 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.
> 
> As GICR base in MADT GICC is another way to indicate the GIC version
> is 3 or 4, add its support to find out the GIC versions.
> 
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>  drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>  include/linux/irqchip/arm-gic-acpi.h |   2 +
>  3 files changed, 215 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
> index 95454e3..3e5c8f4 100644
> --- a/drivers/irqchip/irq-gic-acpi.c
> +++ b/drivers/irqchip/irq-gic-acpi.c
> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
> 
>  static phys_addr_t dist_phy_base __initdata;
> 
> +u8 __init acpi_gic_version(void)
> +{
> +       return gic_version;
> +}
> +
>  static int __init
>  acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>                            const unsigned long end)
> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>  }
> 
>  static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * If GICC is enabled but has no valid gicr base address, then it
> +        * means GICR base is not presented via GICC
> +        */
> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static int __init
>  match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>  {
>         return 0;
> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>         count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>                                         match_gic_redist, 0);
> 
> -       /* that's true if we have at least one GIC redistributor entry */
> +       /* has at least one GIC redistributor entry */
> +       if (count > 0)
> +               return true;
> +
> +       /* else try to find GICR base in GICC entries */
> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
> +                                     gic_acpi_parse_madt_gicc, 0);
> +
>         return count > 0;
>  }
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index ebc5604..b72ccbb 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>                 writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>  }
> 
> -static int gic_populate_rdist(void)
> +static int gic_populate_rdist_with_regions(u64 mpidr)
>  {
> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>         u64 typer;
>         u32 aff;
>         int i;
> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>                 } while (!(typer & GICR_TYPER_LAST));
>         }
> 
> +       return -ENODEV;
> +}
> +
> +#ifdef CONFIG_ACPI
> +/*
> + * Populate redist when GIC redistributor address is presented in ACPI
> + * MADT GICC entries
> + */
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
> +#else
> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       return -ENODEV;
> +}
> +#endif
> +
> +static int gic_populate_rdist(void)
> +{
> +       u64 mpidr = cpu_logical_map(smp_processor_id());
> +
> +       if (gic_data.nr_redist_regions) {
> +               if (!gic_populate_rdist_with_regions(mpidr))
> +                       return 0;
> +       } else {
> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
> +                       return 0;
> +       }
> +
>         /* We couldn't even deal with ourselves... */
>         WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>              smp_processor_id(), (unsigned long long)mpidr);
> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>  #endif
> 
>  #ifdef CONFIG_ACPI
> +
> +struct acpi_gicc_redist {
> +       struct list_head list;
> +       u64 mpidr;
> +       phys_addr_t phys_base;
> +       void __iomem *redist_base;
> +};
> +
> +static LIST_HEAD(redist_list);
> +
>  static struct redist_region *redist_regs __initdata;
>  static u32 nr_redist_regions __initdata;
>  static phys_addr_t dist_phys_base __initdata;
> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>         return 0;
>  }
> 
> +static void __init
> +gic_acpi_release_redist_regions(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < nr_redist_regions; i++)
> +               if (redist_regs[i].redist_base)
> +                       iounmap(redist_regs[i].redist_base);
> +       kfree(redist_regs);
> +}
> +
>  static int __init
>  gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>                         const unsigned long end)
> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>  }
> 
>  static int __init
> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +
> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
> +       if (!redist)
> +               return -ENOMEM;
> +
> +       redist->mpidr = mpidr;
> +       redist->phys_base = phys_base;
> +
> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
> +               /* RD_base + SGI_base */
> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
> +       else
> +               /*
> +                * RD_base + SGI_base + VLPI_base,
> +                * we don't map reserved page as it's buggy to access it
> +                */
> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
> +
> +       if (!redist->redist_base) {
> +               kfree(redist);
> +               return -ENOMEM;
> +       }
> +
> +       list_add(&redist->list, &redist_list);
> +       return 0;
> +}
> +
> +static void __init
> +gic_acpi_release_gicc_redist(void)
> +{
> +       struct acpi_gicc_redist *redist, *t;
> +
> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
> +               list_del(&redist->list);
> +               iounmap(redist->redist_base);
> +               kfree(redist);
> +       }
> +}
> +
> +static int __init
> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
> +                        const unsigned long end)
> +{
> +       struct acpi_madt_generic_interrupt *gicc;
> +
> +       gicc = (struct acpi_madt_generic_interrupt *)header;
> +
> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
> +               return -EINVAL;
> +
> +       /*
> +        * just quietly ingore the disabled CPU(s) and continue
> +        * to find the enabled one(s), if we return error here,
> +        * the scanning will be stopped.
> +        */
> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
> +               return 0;
> +
> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
> +                                       gicc->arm_mpidr);
> +}
> +
> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
> +{
> +       struct acpi_gicc_redist *redist;
> +       void __iomem *ptr;
> +       u32 reg;
> +
> +       list_for_each_entry(redist, &redist_list, list) {
> +               if (redist->mpidr != mpidr)
> +                       continue;
> +
> +               ptr = redist->redist_base;
> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
> +                       pr_warn("No redistributor present @%p\n", ptr);
> +                       return -ENODEV;
> +               }
> +
> +               gic_data_rdist_rd_base() = ptr;
> +               gic_data_rdist()->phys_base = redist->phys_base;
> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
> +                       smp_processor_id(),
> +                       (unsigned long long)mpidr,
> +                       &gic_data_rdist()->phys_base);
> +               return 0;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +static int __init collect_gicr_base(struct acpi_table_header *table)
> +{
> +       int count;
> +
> +       /* Collect redistributor base addresses in GICR entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_redist, table,
> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> +       if (count > 0)
> +               return 0;
> +
> +       pr_info("No valid GICR entries exist, try GICC entries\n");
> +
> +       /* Collect redistributor base addresses in GICC entries */
> +       count = acpi_parse_entries(ACPI_SIG_MADT,
> +                       sizeof(struct acpi_table_madt),
> +                       gic_acpi_parse_madt_gicc, table,
> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
> +       if (count > 0 && !list_empty(&redist_list))
> +               return 0;
> +
> +       pr_info("No valid GICC entries exist for GICR base\n");
> +       return -ENODEV;
> +}
> +
> +static int __init
>  gic_acpi_init(struct acpi_table_header *table)
>  {
> -       int count, i, err = 0;
> +       int count, err = 0;
>         void __iomem *dist_base;
> 
>         /* Get distributor base address */
> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>         }
> 
>         /* Collect redistributor base addresses */
> -       count = acpi_parse_entries(ACPI_SIG_MADT,
> -                       sizeof(struct acpi_table_madt),
> -                       gic_acpi_parse_madt_redist, table,
> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
> -       if (count <= 0) {
> -               pr_info("No valid GICR entries exist\n");
> -               err = -EINVAL;
> -               goto out_redist_unmap;
> -       }
> +       if (collect_gicr_base(table))
> +               goto out_release_redist;
> 
>         err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>                              (void *)ACPI_IRQ_MODEL_GIC);
>         if (err)
> -               goto out_redist_unmap;
> +               goto out_release_redist;
> 
>         acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>                            gic_acpi_gsi_desc_populate);
>         return 0;
> 
> -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_release_redist:
> +       gic_acpi_release_redist_regions();
> +       if (!list_empty(&redist_list))
> +               gic_acpi_release_gicc_redist();
>  out_dist_unmap:
>         iounmap(dist_base);
>         return err;
> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
> index 56cd82c..0d43f515 100644
> --- a/include/linux/irqchip/arm-gic-acpi.h
> +++ b/include/linux/irqchip/arm-gic-acpi.h
> @@ -21,5 +21,7 @@
>  #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>  #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
> 
> +u8 acpi_gic_version(void);
> +
>  #endif /* CONFIG_ACPI */
>  #endif /* ARM_GIC_ACPI_H_ */
> --
> 1.9.1
> 

This looks absolutely horrid. Why don't you simply populate one region
per redistributor, add a flag to struct redist_region so we know not to
check for GICR_TYPER_LAST but to move on to the next region instead?

We already have all the flexibility you require, please don't invent
stuff that is already there.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 14:02     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:02 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
> token that can be used to look up MSI doamin of a device.
> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
> or GIC ITS structure is used as a token for MSI domain.
> 
> In addition, this patch also provides low-level helper functions to parse
> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
> a copy of the structure for use in subsequent queries to avoid having
> to map and parse MADT multiple times.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/acpi/Makefile   |   1 +
>  drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/acpi/acpi_gic.h |  23 +++++
>  include/linux/acpi.h    |   1 +
>  4 files changed, 259 insertions(+)
>  create mode 100644 drivers/acpi/acpi_gic.c
>  create mode 100644 include/acpi/acpi_gic.h
> 
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 8321430..def54b9 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>  acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y				+= acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>  
>  # These are (potentially) separate modules
>  
> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
> new file mode 100644
> index 0000000..11ee4eb
> --- /dev/null
> +++ b/drivers/acpi/acpi_gic.c

I think this is starting badly. If this is GIC specific, it lives in
drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
specific at all. If there are things you need to expose through the ACPI
layer, add some indirections.

> @@ -0,0 +1,234 @@
> +/*
> + * File: acpi_gic.c
> + *
> + * ACPI helper functions for ARM GIC
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +
> +/*
> + * GIC MSI Frame data structures
> + */
> +struct gic_msi_frame_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_msi_frame frame;
> +};
> +
> +static LIST_HEAD(msi_frame_list);
> +
> +static int acpi_num_msi;
> +
> +/*
> + * GIC ITS data structures
> + */
> +struct gic_its_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_translator trans;
> +};
> +
> +static LIST_HEAD(its_list);
> +
> +static int acpi_num_its;
> +
> +/*
> + * GIC MSI Frame parsing stuff
> + */
> +inline int acpi_gic_get_num_msi_frame(void)
> +{
> +	return acpi_num_msi;
> +}

Really???

> +
> +static int __init
> +acpi_parse_madt_msi(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_msi_frame_handle *h;
> +	struct acpi_madt_generic_msi_frame *frame;
> +
> +	frame = (struct acpi_madt_generic_msi_frame *)header;
> +	if (BAD_MADT_ENTRY(frame, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_msi_frame_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	/** Note:
> +	 * We make a copy of this structure since this code is called
> +	 * prior to acpi_early_init(), which sets the acpi_gbl_permanent_mmap.
> +	 * Therefore, we could not keep just the pointer sincce the memory
> +	 * could be unmapped.
> +	 */
> +	memcpy(&h->frame, frame, sizeof(struct acpi_madt_generic_msi_frame));
> +
> +	list_add(&h->list, &msi_frame_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_msi_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_msi > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_msi, table,
> +				 ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC MSI FRAME exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_msi = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p)
> +{
> +	int i = 0;
> +	struct gic_msi_frame_handle *m;
> +
> +	if (index >= acpi_num_msi)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &msi_frame_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_msi)
> +		return -EINVAL;
> +
> +	*p = &(m->frame);
> +	return  0;
> +}
> +
> +/*
> + * GIC ITS parsing stuff
> + */
> +inline int acpi_gic_get_num_its(void)
> +{
> +	return acpi_num_its;
> +}
> +
> +static int __init
> +acpi_parse_madt_its(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_its_handle *h;
> +	struct acpi_madt_generic_translator *trans;
> +
> +	trans = (struct acpi_madt_generic_translator *)header;
> +	if (BAD_MADT_ENTRY(trans, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_its_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	memcpy(&h->trans, trans, sizeof(struct acpi_madt_generic_translator));
> +
> +	list_add(&h->list, &its_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_madt_gic_its_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_its > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_its, table,
> +				 ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC ITS exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_its = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p)
> +{
> +	int i = 0;
> +	struct gic_its_handle *m;
> +
> +	if (index >= acpi_num_its)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &its_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_its)
> +		return -EINVAL;
> +
> +	*p = &(m->trans);
> +	return  0;
> +}
> +
> +static void *acpi_gic_msi_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_msi_frame *msi;
> +
> +	/**
> +	* Since ACPI 5.1 currently does not define
> +	* a way to associate MSI frame ID to a device,
> +	* we can only support single MSI frame (index 0)
> +	* at the moment.
> +	*/
> +	err = acpi_gic_get_msi_frame(0, &msi);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) msi->base_address;
> +}
> +
> +static void *acpi_gic_its_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_translator *trans;
> +	int its_id = 0;
> +
> +	/**
> +	 * TODO: We need a way to retrieve GIC ITS ID from
> +	 * struct device pointer (in this case, the device
> +	 * would be the PCI host controller.
> +	 *
> +	 * This would be done by the IORT-related code.
> +	 *
> +	 * its_id = get_its_id(dev);
> +	 */
> +
> +	err = acpi_gic_get_its(its_id, &trans);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) trans->base_address;
> +}
> +
> +void *acpi_gic_get_msi_token(struct device *dev)
> +{
> +	void *token = acpi_gic_msi_token(dev);
> +
> +	if (!token)
> +		token = acpi_gic_its_token(dev);
> +
> +	return token;
> +}
> diff --git a/include/acpi/acpi_gic.h b/include/acpi/acpi_gic.h
> new file mode 100644
> index 0000000..34fa475
> --- /dev/null
> +++ b/include/acpi/acpi_gic.h
> @@ -0,0 +1,23 @@
> +/*
> + *  include/acpi/acpi_gic.h
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#ifndef __ACPI_GIC_H__
> +#define __ACPI_GIC_H__
> +
> +#ifdef CONFIG_ACPI
> +int acpi_gic_get_num_msi_frame(void);
> +int acpi_gic_msi_init(struct acpi_table_header *table);
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p);
> +
> +int acpi_gic_get_num_its(void);
> +int acpi_gic_its_init(struct acpi_table_header *table);
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p);
> +
> +void *acpi_gic_get_msi_token(struct device *dev);
> +#endif
> +
> +#endif /*__ACPI_GIC_H__*/
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 04dd0bb..5d58b61 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -44,6 +44,7 @@
>  
>  #include <acpi/acpi_bus.h>
>  #include <acpi/acpi_drivers.h>
> +#include <acpi/acpi_gic.h>

Ah! No.

>  #include <acpi/acpi_numa.h>
>  #include <acpi/acpi_io.h>
>  #include <asm/acpi.h>
> 

Right. Very little of what is above belongs to the ACPI layer. What
would belong here is a generic acpi_get_msi_domain_token(dev) that would
call into a controller-specific function to parse the various tables and
find out which GICv2m frame (or which ITS) is serving the given device.
This would include parsing of the IORT structures if they are available.

For GICv2m, it should be simplistic: just return the domain_token of the
v2m widget. For the ITS, it is slightly more complex, and there should
be some specific backend for that. There is no ACPI support for the ITS
yet, so that shouldn't be your concern at this point in time.

Overall, drivers/acpi should be hardware agnostic (or at least aim for
it), just like drivers/of is.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
@ 2015-08-04 14:02     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:02 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
> token that can be used to look up MSI doamin of a device.
> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
> or GIC ITS structure is used as a token for MSI domain.
> 
> In addition, this patch also provides low-level helper functions to parse
> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
> a copy of the structure for use in subsequent queries to avoid having
> to map and parse MADT multiple times.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/acpi/Makefile   |   1 +
>  drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/acpi/acpi_gic.h |  23 +++++
>  include/linux/acpi.h    |   1 +
>  4 files changed, 259 insertions(+)
>  create mode 100644 drivers/acpi/acpi_gic.c
>  create mode 100644 include/acpi/acpi_gic.h
> 
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 8321430..def54b9 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>  acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y				+= acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>  
>  # These are (potentially) separate modules
>  
> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
> new file mode 100644
> index 0000000..11ee4eb
> --- /dev/null
> +++ b/drivers/acpi/acpi_gic.c

I think this is starting badly. If this is GIC specific, it lives in
drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
specific at all. If there are things you need to expose through the ACPI
layer, add some indirections.

> @@ -0,0 +1,234 @@
> +/*
> + * File: acpi_gic.c
> + *
> + * ACPI helper functions for ARM GIC
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +
> +/*
> + * GIC MSI Frame data structures
> + */
> +struct gic_msi_frame_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_msi_frame frame;
> +};
> +
> +static LIST_HEAD(msi_frame_list);
> +
> +static int acpi_num_msi;
> +
> +/*
> + * GIC ITS data structures
> + */
> +struct gic_its_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_translator trans;
> +};
> +
> +static LIST_HEAD(its_list);
> +
> +static int acpi_num_its;
> +
> +/*
> + * GIC MSI Frame parsing stuff
> + */
> +inline int acpi_gic_get_num_msi_frame(void)
> +{
> +	return acpi_num_msi;
> +}

Really???

> +
> +static int __init
> +acpi_parse_madt_msi(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_msi_frame_handle *h;
> +	struct acpi_madt_generic_msi_frame *frame;
> +
> +	frame = (struct acpi_madt_generic_msi_frame *)header;
> +	if (BAD_MADT_ENTRY(frame, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_msi_frame_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	/** Note:
> +	 * We make a copy of this structure since this code is called
> +	 * prior to acpi_early_init(), which sets the acpi_gbl_permanent_mmap.
> +	 * Therefore, we could not keep just the pointer sincce the memory
> +	 * could be unmapped.
> +	 */
> +	memcpy(&h->frame, frame, sizeof(struct acpi_madt_generic_msi_frame));
> +
> +	list_add(&h->list, &msi_frame_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_msi_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_msi > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_msi, table,
> +				 ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC MSI FRAME exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_msi = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p)
> +{
> +	int i = 0;
> +	struct gic_msi_frame_handle *m;
> +
> +	if (index >= acpi_num_msi)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &msi_frame_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_msi)
> +		return -EINVAL;
> +
> +	*p = &(m->frame);
> +	return  0;
> +}
> +
> +/*
> + * GIC ITS parsing stuff
> + */
> +inline int acpi_gic_get_num_its(void)
> +{
> +	return acpi_num_its;
> +}
> +
> +static int __init
> +acpi_parse_madt_its(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_its_handle *h;
> +	struct acpi_madt_generic_translator *trans;
> +
> +	trans = (struct acpi_madt_generic_translator *)header;
> +	if (BAD_MADT_ENTRY(trans, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_its_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	memcpy(&h->trans, trans, sizeof(struct acpi_madt_generic_translator));
> +
> +	list_add(&h->list, &its_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_madt_gic_its_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_its > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_its, table,
> +				 ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC ITS exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_its = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p)
> +{
> +	int i = 0;
> +	struct gic_its_handle *m;
> +
> +	if (index >= acpi_num_its)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &its_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_its)
> +		return -EINVAL;
> +
> +	*p = &(m->trans);
> +	return  0;
> +}
> +
> +static void *acpi_gic_msi_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_msi_frame *msi;
> +
> +	/**
> +	* Since ACPI 5.1 currently does not define
> +	* a way to associate MSI frame ID to a device,
> +	* we can only support single MSI frame (index 0)
> +	* at the moment.
> +	*/
> +	err = acpi_gic_get_msi_frame(0, &msi);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) msi->base_address;
> +}
> +
> +static void *acpi_gic_its_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_translator *trans;
> +	int its_id = 0;
> +
> +	/**
> +	 * TODO: We need a way to retrieve GIC ITS ID from
> +	 * struct device pointer (in this case, the device
> +	 * would be the PCI host controller.
> +	 *
> +	 * This would be done by the IORT-related code.
> +	 *
> +	 * its_id = get_its_id(dev);
> +	 */
> +
> +	err = acpi_gic_get_its(its_id, &trans);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) trans->base_address;
> +}
> +
> +void *acpi_gic_get_msi_token(struct device *dev)
> +{
> +	void *token = acpi_gic_msi_token(dev);
> +
> +	if (!token)
> +		token = acpi_gic_its_token(dev);
> +
> +	return token;
> +}
> diff --git a/include/acpi/acpi_gic.h b/include/acpi/acpi_gic.h
> new file mode 100644
> index 0000000..34fa475
> --- /dev/null
> +++ b/include/acpi/acpi_gic.h
> @@ -0,0 +1,23 @@
> +/*
> + *  include/acpi/acpi_gic.h
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#ifndef __ACPI_GIC_H__
> +#define __ACPI_GIC_H__
> +
> +#ifdef CONFIG_ACPI
> +int acpi_gic_get_num_msi_frame(void);
> +int acpi_gic_msi_init(struct acpi_table_header *table);
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p);
> +
> +int acpi_gic_get_num_its(void);
> +int acpi_gic_its_init(struct acpi_table_header *table);
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p);
> +
> +void *acpi_gic_get_msi_token(struct device *dev);
> +#endif
> +
> +#endif /*__ACPI_GIC_H__*/
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 04dd0bb..5d58b61 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -44,6 +44,7 @@
>  
>  #include <acpi/acpi_bus.h>
>  #include <acpi/acpi_drivers.h>
> +#include <acpi/acpi_gic.h>

Ah! No.

>  #include <acpi/acpi_numa.h>
>  #include <acpi/acpi_io.h>
>  #include <asm/acpi.h>
> 

Right. Very little of what is above belongs to the ACPI layer. What
would belong here is a generic acpi_get_msi_domain_token(dev) that would
call into a controller-specific function to parse the various tables and
find out which GICv2m frame (or which ITS) is serving the given device.
This would include parsing of the IORT structures if they are available.

For GICv2m, it should be simplistic: just return the domain_token of the
v2m widget. For the ITS, it is slightly more complex, and there should
be some specific backend for that. There is no ACPI support for the ITS
yet, so that shouldn't be your concern at this point in time.

Overall, drivers/acpi should be hardware agnostic (or at least aim for
it), just like drivers/of is.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
@ 2015-08-04 14:02     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
> token that can be used to look up MSI doamin of a device.
> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
> or GIC ITS structure is used as a token for MSI domain.
> 
> In addition, this patch also provides low-level helper functions to parse
> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
> a copy of the structure for use in subsequent queries to avoid having
> to map and parse MADT multiple times.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/acpi/Makefile   |   1 +
>  drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/acpi/acpi_gic.h |  23 +++++
>  include/linux/acpi.h    |   1 +
>  4 files changed, 259 insertions(+)
>  create mode 100644 drivers/acpi/acpi_gic.c
>  create mode 100644 include/acpi/acpi_gic.h
> 
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 8321430..def54b9 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>  acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>  acpi-y				+= acpi_lpat.o
>  acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>  
>  # These are (potentially) separate modules
>  
> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
> new file mode 100644
> index 0000000..11ee4eb
> --- /dev/null
> +++ b/drivers/acpi/acpi_gic.c

I think this is starting badly. If this is GIC specific, it lives in
drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
specific at all. If there are things you need to expose through the ACPI
layer, add some indirections.

> @@ -0,0 +1,234 @@
> +/*
> + * File: acpi_gic.c
> + *
> + * ACPI helper functions for ARM GIC
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/init.h>
> +
> +/*
> + * GIC MSI Frame data structures
> + */
> +struct gic_msi_frame_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_msi_frame frame;
> +};
> +
> +static LIST_HEAD(msi_frame_list);
> +
> +static int acpi_num_msi;
> +
> +/*
> + * GIC ITS data structures
> + */
> +struct gic_its_handle {
> +	struct list_head list;
> +	struct acpi_madt_generic_translator trans;
> +};
> +
> +static LIST_HEAD(its_list);
> +
> +static int acpi_num_its;
> +
> +/*
> + * GIC MSI Frame parsing stuff
> + */
> +inline int acpi_gic_get_num_msi_frame(void)
> +{
> +	return acpi_num_msi;
> +}

Really???

> +
> +static int __init
> +acpi_parse_madt_msi(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_msi_frame_handle *h;
> +	struct acpi_madt_generic_msi_frame *frame;
> +
> +	frame = (struct acpi_madt_generic_msi_frame *)header;
> +	if (BAD_MADT_ENTRY(frame, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_msi_frame_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	/** Note:
> +	 * We make a copy of this structure since this code is called
> +	 * prior to acpi_early_init(), which sets the acpi_gbl_permanent_mmap.
> +	 * Therefore, we could not keep just the pointer sincce the memory
> +	 * could be unmapped.
> +	 */
> +	memcpy(&h->frame, frame, sizeof(struct acpi_madt_generic_msi_frame));
> +
> +	list_add(&h->list, &msi_frame_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_msi_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_msi > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_msi, table,
> +				 ACPI_MADT_TYPE_GENERIC_MSI_FRAME, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC MSI FRAME exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_msi = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p)
> +{
> +	int i = 0;
> +	struct gic_msi_frame_handle *m;
> +
> +	if (index >= acpi_num_msi)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &msi_frame_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_msi)
> +		return -EINVAL;
> +
> +	*p = &(m->frame);
> +	return  0;
> +}
> +
> +/*
> + * GIC ITS parsing stuff
> + */
> +inline int acpi_gic_get_num_its(void)
> +{
> +	return acpi_num_its;
> +}
> +
> +static int __init
> +acpi_parse_madt_its(struct acpi_subtable_header *header,
> +		    const unsigned long end)
> +{
> +	struct gic_its_handle *h;
> +	struct acpi_madt_generic_translator *trans;
> +
> +	trans = (struct acpi_madt_generic_translator *)header;
> +	if (BAD_MADT_ENTRY(trans, end))
> +		return -EINVAL;
> +
> +	h = kzalloc(sizeof(struct gic_its_handle *), GFP_KERNEL);
> +	if (!h)
> +		return -ENOMEM;
> +
> +	memcpy(&h->trans, trans, sizeof(struct acpi_madt_generic_translator));
> +
> +	list_add(&h->list, &its_list);
> +
> +	return 0;
> +}
> +
> +int __init acpi_gic_madt_gic_its_init(struct acpi_table_header *table)
> +{
> +	int ret = 0;
> +
> +	if (acpi_num_its > 0)
> +		return ret;
> +
> +	ret = acpi_parse_entries(ACPI_SIG_MADT,
> +				 sizeof(struct acpi_table_madt),
> +				 acpi_parse_madt_its, table,
> +				 ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 0);
> +	if (ret == 0) {
> +		pr_debug("No valid ACPI GIC ITS exist\n");
> +		return ret;
> +	}
> +
> +	acpi_num_its = ret;
> +	return 0;
> +}
> +
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p)
> +{
> +	int i = 0;
> +	struct gic_its_handle *m;
> +
> +	if (index >= acpi_num_its)
> +		return -EINVAL;
> +
> +	list_for_each_entry(m, &its_list, list) {
> +		if (i == index)
> +			break;
> +		i++;
> +	}
> +
> +	if (i == acpi_num_its)
> +		return -EINVAL;
> +
> +	*p = &(m->trans);
> +	return  0;
> +}
> +
> +static void *acpi_gic_msi_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_msi_frame *msi;
> +
> +	/**
> +	* Since ACPI 5.1 currently does not define
> +	* a way to associate MSI frame ID to a device,
> +	* we can only support single MSI frame (index 0)
> +	* at the moment.
> +	*/
> +	err = acpi_gic_get_msi_frame(0, &msi);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) msi->base_address;
> +}
> +
> +static void *acpi_gic_its_token(struct device *dev)
> +{
> +	int err;
> +	struct acpi_madt_generic_translator *trans;
> +	int its_id = 0;
> +
> +	/**
> +	 * TODO: We need a way to retrieve GIC ITS ID from
> +	 * struct device pointer (in this case, the device
> +	 * would be the PCI host controller.
> +	 *
> +	 * This would be done by the IORT-related code.
> +	 *
> +	 * its_id = get_its_id(dev);
> +	 */
> +
> +	err = acpi_gic_get_its(its_id, &trans);
> +	if (err)
> +		return NULL;
> +
> +	return (void *) trans->base_address;
> +}
> +
> +void *acpi_gic_get_msi_token(struct device *dev)
> +{
> +	void *token = acpi_gic_msi_token(dev);
> +
> +	if (!token)
> +		token = acpi_gic_its_token(dev);
> +
> +	return token;
> +}
> diff --git a/include/acpi/acpi_gic.h b/include/acpi/acpi_gic.h
> new file mode 100644
> index 0000000..34fa475
> --- /dev/null
> +++ b/include/acpi/acpi_gic.h
> @@ -0,0 +1,23 @@
> +/*
> + *  include/acpi/acpi_gic.h
> + *
> + * Copyright (C) 2015 Advanced Micro Devices, Inc.
> + * Authors: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> + */
> +
> +#ifndef __ACPI_GIC_H__
> +#define __ACPI_GIC_H__
> +
> +#ifdef CONFIG_ACPI
> +int acpi_gic_get_num_msi_frame(void);
> +int acpi_gic_msi_init(struct acpi_table_header *table);
> +int acpi_gic_get_msi_frame(int index, struct acpi_madt_generic_msi_frame **p);
> +
> +int acpi_gic_get_num_its(void);
> +int acpi_gic_its_init(struct acpi_table_header *table);
> +int acpi_gic_get_its(int index, struct acpi_madt_generic_translator **p);
> +
> +void *acpi_gic_get_msi_token(struct device *dev);
> +#endif
> +
> +#endif /*__ACPI_GIC_H__*/
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 04dd0bb..5d58b61 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -44,6 +44,7 @@
>  
>  #include <acpi/acpi_bus.h>
>  #include <acpi/acpi_drivers.h>
> +#include <acpi/acpi_gic.h>

Ah! No.

>  #include <acpi/acpi_numa.h>
>  #include <acpi/acpi_io.h>
>  #include <asm/acpi.h>
> 

Right. Very little of what is above belongs to the ACPI layer. What
would belong here is a generic acpi_get_msi_domain_token(dev) that would
call into a controller-specific function to parse the various tables and
find out which GICv2m frame (or which ITS) is serving the given device.
This would include parsing of the IORT structures if they are available.

For GICv2m, it should be simplistic: just return the domain_token of the
v2m widget. For the ITS, it is slightly more complex, and there should
be some specific backend for that. There is no ACPI support for the ITS
yet, so that shouldn't be your concern at this point in time.

Overall, drivers/acpi should be hardware agnostic (or at least aim for
it), just like drivers/of is.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 14:04     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:04 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>  drivers/pci/probe.c      |  3 +++
>  include/linux/pci-acpi.h |  4 ++++
>  3 files changed, 25 insertions(+)
> 
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..5f11653 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -9,6 +9,7 @@
>  
>  #include <linux/delay.h>
>  #include <linux/init.h>
> +#include <linux/irqdomain.h>
>  #include <linux/pci.h>
>  #include <linux/pci_hotplug.h>
>  #include <linux/module.h>
> @@ -16,6 +17,7 @@
>  #include <linux/pci-acpi.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/pm_qos.h>
> +#include <acpi/acpi_gic.h>
>  #include "pci.h"
>  
>  /*
> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>  	return dev_is_pci(dev);
>  }
>  
> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> +{
> +	struct irq_domain *d = NULL;
> +	void *token = acpi_gic_get_msi_token(&bus->dev);

Do you see why I positively *hate* having hardware details in generic
layers? They propagate everywhere...

> +
> +	if (token)
> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
> +
> +	if (!d)
> +		pr_debug("Fail to find domain for MSI\n");
> +
> +	return d;
> +}
> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
> +
>  static struct acpi_bus_type acpi_pci_bus = {
>  	.name = "PCI",
>  	.match = pci_acpi_bus_match,
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index a7afeac..8c1204c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -12,6 +12,7 @@
>  #include <linux/module.h>
>  #include <linux/cpumask.h>
>  #include <linux/pci-aspm.h>
> +#include <linux/pci-acpi.h>
>  #include <asm-generic/pci-bridge.h>
>  #include "pci.h"
>  
> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>  	 * should be called from here.
>  	 */
>  	d = pci_host_bridge_of_msi_domain(bus);
> +	if (!d)
> +		d = pci_host_bridge_acpi_msi_domain(bus);
>  
>  	return d;
>  }
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index a965efa..766d045 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>  static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>  #endif
>  
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
> +
>  extern const u8 pci_acpi_dsm_uuid[];
>  #define DEVICE_LABEL_DSM	0x07
>  #define RESET_DELAY_DSM		0x08
> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>  #else	/* CONFIG_ACPI */
>  static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
> +static inline struct irq_domain *
> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>  #endif	/* CONFIG_ACPI */
>  
>  #ifdef CONFIG_ACPI_APEI
> 

Once you solve the HW abstraction issue, this will be OK.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-04 14:04     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:04 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>  drivers/pci/probe.c      |  3 +++
>  include/linux/pci-acpi.h |  4 ++++
>  3 files changed, 25 insertions(+)
> 
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..5f11653 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -9,6 +9,7 @@
>  
>  #include <linux/delay.h>
>  #include <linux/init.h>
> +#include <linux/irqdomain.h>
>  #include <linux/pci.h>
>  #include <linux/pci_hotplug.h>
>  #include <linux/module.h>
> @@ -16,6 +17,7 @@
>  #include <linux/pci-acpi.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/pm_qos.h>
> +#include <acpi/acpi_gic.h>
>  #include "pci.h"
>  
>  /*
> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>  	return dev_is_pci(dev);
>  }
>  
> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> +{
> +	struct irq_domain *d = NULL;
> +	void *token = acpi_gic_get_msi_token(&bus->dev);

Do you see why I positively *hate* having hardware details in generic
layers? They propagate everywhere...

> +
> +	if (token)
> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
> +
> +	if (!d)
> +		pr_debug("Fail to find domain for MSI\n");
> +
> +	return d;
> +}
> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
> +
>  static struct acpi_bus_type acpi_pci_bus = {
>  	.name = "PCI",
>  	.match = pci_acpi_bus_match,
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index a7afeac..8c1204c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -12,6 +12,7 @@
>  #include <linux/module.h>
>  #include <linux/cpumask.h>
>  #include <linux/pci-aspm.h>
> +#include <linux/pci-acpi.h>
>  #include <asm-generic/pci-bridge.h>
>  #include "pci.h"
>  
> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>  	 * should be called from here.
>  	 */
>  	d = pci_host_bridge_of_msi_domain(bus);
> +	if (!d)
> +		d = pci_host_bridge_acpi_msi_domain(bus);
>  
>  	return d;
>  }
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index a965efa..766d045 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>  static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>  #endif
>  
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
> +
>  extern const u8 pci_acpi_dsm_uuid[];
>  #define DEVICE_LABEL_DSM	0x07
>  #define RESET_DELAY_DSM		0x08
> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>  #else	/* CONFIG_ACPI */
>  static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
> +static inline struct irq_domain *
> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>  #endif	/* CONFIG_ACPI */
>  
>  #ifdef CONFIG_ACPI_APEI
> 

Once you solve the HW abstraction issue, this will be OK.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-04 14:04     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>  drivers/pci/probe.c      |  3 +++
>  include/linux/pci-acpi.h |  4 ++++
>  3 files changed, 25 insertions(+)
> 
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..5f11653 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -9,6 +9,7 @@
>  
>  #include <linux/delay.h>
>  #include <linux/init.h>
> +#include <linux/irqdomain.h>
>  #include <linux/pci.h>
>  #include <linux/pci_hotplug.h>
>  #include <linux/module.h>
> @@ -16,6 +17,7 @@
>  #include <linux/pci-acpi.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/pm_qos.h>
> +#include <acpi/acpi_gic.h>
>  #include "pci.h"
>  
>  /*
> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>  	return dev_is_pci(dev);
>  }
>  
> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> +{
> +	struct irq_domain *d = NULL;
> +	void *token = acpi_gic_get_msi_token(&bus->dev);

Do you see why I positively *hate* having hardware details in generic
layers? They propagate everywhere...

> +
> +	if (token)
> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
> +
> +	if (!d)
> +		pr_debug("Fail to find domain for MSI\n");
> +
> +	return d;
> +}
> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
> +
>  static struct acpi_bus_type acpi_pci_bus = {
>  	.name = "PCI",
>  	.match = pci_acpi_bus_match,
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index a7afeac..8c1204c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -12,6 +12,7 @@
>  #include <linux/module.h>
>  #include <linux/cpumask.h>
>  #include <linux/pci-aspm.h>
> +#include <linux/pci-acpi.h>
>  #include <asm-generic/pci-bridge.h>
>  #include "pci.h"
>  
> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>  	 * should be called from here.
>  	 */
>  	d = pci_host_bridge_of_msi_domain(bus);
> +	if (!d)
> +		d = pci_host_bridge_acpi_msi_domain(bus);
>  
>  	return d;
>  }
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index a965efa..766d045 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>  static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>  #endif
>  
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
> +
>  extern const u8 pci_acpi_dsm_uuid[];
>  #define DEVICE_LABEL_DSM	0x07
>  #define RESET_DELAY_DSM		0x08
> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>  #else	/* CONFIG_ACPI */
>  static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
> +static inline struct irq_domain *
> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>  #endif	/* CONFIG_ACPI */
>  
>  #ifdef CONFIG_ACPI_APEI
> 

Once you solve the HW abstraction issue, this will be OK.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
  2015-07-29 10:08   ` Hanjun Guo
  (?)
@ 2015-08-04 14:23     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:23 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces gicv2m_acpi_init(), which uses information
> in MADT GIC MSI frames structure to initialize GICv2m driver.
> It also refactors gicv2m_init_one() to handle both DT and ACPI
> initialization path.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>  drivers/irqchip/irq-gic.c       |   3 ++
>  include/linux/irqchip/arm-gic.h |   7 +++
>  3 files changed, 98 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
> index d0fcbf8..c491a08 100644
> --- a/drivers/irqchip/irq-gic-v2m.c
> +++ b/drivers/irqchip/irq-gic-v2m.c
> @@ -15,6 +15,7 @@
>  
>  #define pr_fmt(fmt) "GICv2m: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/irq.h>
>  #include <linux/irqdomain.h>
>  #include <linux/kernel.h>
> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>  	return true;
>  }
>  
> +char gicv2m_domain_name[] = "GICV2M";
> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
> +

Can't these be static? Why do we need them?

>  static struct irq_chip gicv2m_pmsi_irq_chip = {
>  	.name			= "pMSI",
>  };
> @@ -224,8 +229,9 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
>  	.chip	= &gicv2m_pmsi_irq_chip,
>  };
>  
> -static int __init gicv2m_init_one(struct device_node *node,
> -				  struct irq_domain *parent)
> +static int __init gicv2m_init_one(struct irq_domain *parent,
> +				  u32 *spi_start, u32 *nr_spis,
> +				  struct resource *res, void *token)
>  {
>  	int ret;
>  	struct v2m_data *v2m;
> @@ -237,28 +243,22 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		return -ENOMEM;
>  	}
>  
> -	ret = of_address_to_resource(node, 0, &v2m->res);
> -	if (ret) {
> -		pr_err("Failed to allocate v2m resource.\n");
> -		goto err_free_v2m;
> -	}
> -
> -	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
> +	v2m->base = ioremap(res->start, resource_size(res));
>  	if (!v2m->base) {
>  		pr_err("Failed to map GICv2m resource\n");
>  		ret = -ENOMEM;
>  		goto err_free_v2m;
>  	}
> +	memcpy(&v2m->res, res, sizeof(struct resource));
>  
> -	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
> -	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
> -		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> -			v2m->spi_start, v2m->nr_spis);
> +	if (*spi_start && *nr_spis) {
> +		v2m->spi_start = *spi_start;
> +		v2m->nr_spis = *nr_spis;
>  	} else {
>  		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
>  
> -		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> -		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
> +		v2m->spi_start = *spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> +		v2m->nr_spis = *nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
>  	}
>  
>  	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
> @@ -273,7 +273,7 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_iounmap;
>  	}
>  
> -	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
> +	inner_domain = irq_domain_add_tree(token, &gicv2m_domain_ops, v2m);
>  	if (!inner_domain) {
>  		pr_err("Failed to create GICv2m domain\n");
>  		ret = -ENOMEM;
> @@ -282,9 +282,11 @@ static int __init gicv2m_init_one(struct device_node *node,
>  
>  	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
>  	inner_domain->parent = parent;
> -	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
> +	inner_domain->name = gicv2m_domain_name;
> +
> +	pci_domain = pci_msi_create_irq_domain(token, &gicv2m_msi_domain_info,
>  					       inner_domain);
> -	plat_domain = platform_msi_create_irq_domain(node,
> +	plat_domain = platform_msi_create_irq_domain(token,
>  						     &gicv2m_pmsi_domain_info,
>  						     inner_domain);
>  	if (!pci_domain || !plat_domain) {
> @@ -293,11 +295,10 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_free_domains;
>  	}
>  
> -	spin_lock_init(&v2m->msi_cnt_lock);
> +	pci_domain->name = gicv2m_pci_msi_domain_name;
> +	plat_domain->name = gicv2m_plat_msi_domain_name;
>  
> -	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
> -		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
> -		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
> +	spin_lock_init(&v2m->msi_cnt_lock);
>  
>  	return 0;
>  
> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>  
>  	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>  	     child = of_find_matching_node(child, gicv2m_device_id)) {
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct resource res;
> +
>  		if (!of_find_property(child, "msi-controller", NULL))
>  			continue;
>  
> -		ret = gicv2m_init_one(child, parent);
> +		ret = of_address_to_resource(child, 0, &res);
> +		if (ret) {
> +			pr_err("Failed to allocate v2m resource.\n");
> +			break;
> +		}
> +
> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,

If these spi_start and nr_spis pointers passed to gicv2m_init_one are
only for the benefit of printing the message below, just move the
message inside the function...

> +				      child);
>  		if (ret) {
>  			of_node_put(node);
>  			break;
>  		}
> +
> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
>  	}
>  
>  	return ret;
>  }
> +
> +#ifdef CONFIG_ACPI
> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
> +			    struct irq_domain *parent)
> +{
> +	int i, ret;
> +
> +	ret = acpi_gic_msi_init(table);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
> +		struct resource res;
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct acpi_madt_generic_msi_frame *m;
> +
> +		ret = acpi_gic_get_msi_frame(i, &m);
> +		if (ret)
> +			return ret;
> +

All of that should be moved here. And we don't need to build an
intermediate representation. Just build the v2m_data structures as you go.

> +		res.start = m->base_address;
> +		res.end = m->base_address + 0x1000;
> +
> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
> +			spi_start = m->spi_base;
> +			nr_spis = m->spi_count;
> +
> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +		}
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
> +				      (void *)(m->base_address));
> +		if (ret)
> +			break;
> +
> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
> +			m->msi_frame_id,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
> +	}
> +	return ret;
> +}
> +
> +#endif /* CONFIG_ACPI */
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bec6b00..531ebbc 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>  	 */
>  	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>  
> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
> +		gicv2m_acpi_init(table, gic_data[0].domain);
> +
>  	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>  			   gic_acpi_gsi_desc_populate);
>  	return 0;
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 97799b7..27d8196 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>  
>  int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>  
> +#ifdef CONFIG_ACPI
> +struct acpi_table_header;
> +
> +int gicv2m_acpi_init(struct acpi_table_header *table,
> +		     struct irq_domain *parent);
> +#endif
> +
>  void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>  int gic_get_cpu_id(unsigned int cpu);
>  void gic_migrate_target(unsigned int new_cpu_id);
> 

This needs rework to do the parsing of the tables in this driver. Just
expose the domain_token through a function that you register with the
ACPI layer.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
@ 2015-08-04 14:23     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:23 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces gicv2m_acpi_init(), which uses information
> in MADT GIC MSI frames structure to initialize GICv2m driver.
> It also refactors gicv2m_init_one() to handle both DT and ACPI
> initialization path.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>  drivers/irqchip/irq-gic.c       |   3 ++
>  include/linux/irqchip/arm-gic.h |   7 +++
>  3 files changed, 98 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
> index d0fcbf8..c491a08 100644
> --- a/drivers/irqchip/irq-gic-v2m.c
> +++ b/drivers/irqchip/irq-gic-v2m.c
> @@ -15,6 +15,7 @@
>  
>  #define pr_fmt(fmt) "GICv2m: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/irq.h>
>  #include <linux/irqdomain.h>
>  #include <linux/kernel.h>
> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>  	return true;
>  }
>  
> +char gicv2m_domain_name[] = "GICV2M";
> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
> +

Can't these be static? Why do we need them?

>  static struct irq_chip gicv2m_pmsi_irq_chip = {
>  	.name			= "pMSI",
>  };
> @@ -224,8 +229,9 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
>  	.chip	= &gicv2m_pmsi_irq_chip,
>  };
>  
> -static int __init gicv2m_init_one(struct device_node *node,
> -				  struct irq_domain *parent)
> +static int __init gicv2m_init_one(struct irq_domain *parent,
> +				  u32 *spi_start, u32 *nr_spis,
> +				  struct resource *res, void *token)
>  {
>  	int ret;
>  	struct v2m_data *v2m;
> @@ -237,28 +243,22 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		return -ENOMEM;
>  	}
>  
> -	ret = of_address_to_resource(node, 0, &v2m->res);
> -	if (ret) {
> -		pr_err("Failed to allocate v2m resource.\n");
> -		goto err_free_v2m;
> -	}
> -
> -	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
> +	v2m->base = ioremap(res->start, resource_size(res));
>  	if (!v2m->base) {
>  		pr_err("Failed to map GICv2m resource\n");
>  		ret = -ENOMEM;
>  		goto err_free_v2m;
>  	}
> +	memcpy(&v2m->res, res, sizeof(struct resource));
>  
> -	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
> -	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
> -		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> -			v2m->spi_start, v2m->nr_spis);
> +	if (*spi_start && *nr_spis) {
> +		v2m->spi_start = *spi_start;
> +		v2m->nr_spis = *nr_spis;
>  	} else {
>  		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
>  
> -		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> -		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
> +		v2m->spi_start = *spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> +		v2m->nr_spis = *nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
>  	}
>  
>  	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
> @@ -273,7 +273,7 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_iounmap;
>  	}
>  
> -	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
> +	inner_domain = irq_domain_add_tree(token, &gicv2m_domain_ops, v2m);
>  	if (!inner_domain) {
>  		pr_err("Failed to create GICv2m domain\n");
>  		ret = -ENOMEM;
> @@ -282,9 +282,11 @@ static int __init gicv2m_init_one(struct device_node *node,
>  
>  	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
>  	inner_domain->parent = parent;
> -	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
> +	inner_domain->name = gicv2m_domain_name;
> +
> +	pci_domain = pci_msi_create_irq_domain(token, &gicv2m_msi_domain_info,
>  					       inner_domain);
> -	plat_domain = platform_msi_create_irq_domain(node,
> +	plat_domain = platform_msi_create_irq_domain(token,
>  						     &gicv2m_pmsi_domain_info,
>  						     inner_domain);
>  	if (!pci_domain || !plat_domain) {
> @@ -293,11 +295,10 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_free_domains;
>  	}
>  
> -	spin_lock_init(&v2m->msi_cnt_lock);
> +	pci_domain->name = gicv2m_pci_msi_domain_name;
> +	plat_domain->name = gicv2m_plat_msi_domain_name;
>  
> -	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
> -		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
> -		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
> +	spin_lock_init(&v2m->msi_cnt_lock);
>  
>  	return 0;
>  
> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>  
>  	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>  	     child = of_find_matching_node(child, gicv2m_device_id)) {
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct resource res;
> +
>  		if (!of_find_property(child, "msi-controller", NULL))
>  			continue;
>  
> -		ret = gicv2m_init_one(child, parent);
> +		ret = of_address_to_resource(child, 0, &res);
> +		if (ret) {
> +			pr_err("Failed to allocate v2m resource.\n");
> +			break;
> +		}
> +
> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,

If these spi_start and nr_spis pointers passed to gicv2m_init_one are
only for the benefit of printing the message below, just move the
message inside the function...

> +				      child);
>  		if (ret) {
>  			of_node_put(node);
>  			break;
>  		}
> +
> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
>  	}
>  
>  	return ret;
>  }
> +
> +#ifdef CONFIG_ACPI
> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
> +			    struct irq_domain *parent)
> +{
> +	int i, ret;
> +
> +	ret = acpi_gic_msi_init(table);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
> +		struct resource res;
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct acpi_madt_generic_msi_frame *m;
> +
> +		ret = acpi_gic_get_msi_frame(i, &m);
> +		if (ret)
> +			return ret;
> +

All of that should be moved here. And we don't need to build an
intermediate representation. Just build the v2m_data structures as you go.

> +		res.start = m->base_address;
> +		res.end = m->base_address + 0x1000;
> +
> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
> +			spi_start = m->spi_base;
> +			nr_spis = m->spi_count;
> +
> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +		}
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
> +				      (void *)(m->base_address));
> +		if (ret)
> +			break;
> +
> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
> +			m->msi_frame_id,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
> +	}
> +	return ret;
> +}
> +
> +#endif /* CONFIG_ACPI */
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bec6b00..531ebbc 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>  	 */
>  	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>  
> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
> +		gicv2m_acpi_init(table, gic_data[0].domain);
> +
>  	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>  			   gic_acpi_gsi_desc_populate);
>  	return 0;
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 97799b7..27d8196 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>  
>  int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>  
> +#ifdef CONFIG_ACPI
> +struct acpi_table_header;
> +
> +int gicv2m_acpi_init(struct acpi_table_header *table,
> +		     struct irq_domain *parent);
> +#endif
> +
>  void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>  int gic_get_cpu_id(unsigned int cpu);
>  void gic_migrate_target(unsigned int new_cpu_id);
> 

This needs rework to do the parsing of the tables in this driver. Just
expose the domain_token through a function that you register with the
ACPI layer.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
@ 2015-08-04 14:23     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-04 14:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 29/07/15 11:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> 
> This patch introduces gicv2m_acpi_init(), which uses information
> in MADT GIC MSI frames structure to initialize GICv2m driver.
> It also refactors gicv2m_init_one() to handle both DT and ACPI
> initialization path.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>  drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>  drivers/irqchip/irq-gic.c       |   3 ++
>  include/linux/irqchip/arm-gic.h |   7 +++
>  3 files changed, 98 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
> index d0fcbf8..c491a08 100644
> --- a/drivers/irqchip/irq-gic-v2m.c
> +++ b/drivers/irqchip/irq-gic-v2m.c
> @@ -15,6 +15,7 @@
>  
>  #define pr_fmt(fmt) "GICv2m: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/irq.h>
>  #include <linux/irqdomain.h>
>  #include <linux/kernel.h>
> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>  	return true;
>  }
>  
> +char gicv2m_domain_name[] = "GICV2M";
> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
> +

Can't these be static? Why do we need them?

>  static struct irq_chip gicv2m_pmsi_irq_chip = {
>  	.name			= "pMSI",
>  };
> @@ -224,8 +229,9 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {
>  	.chip	= &gicv2m_pmsi_irq_chip,
>  };
>  
> -static int __init gicv2m_init_one(struct device_node *node,
> -				  struct irq_domain *parent)
> +static int __init gicv2m_init_one(struct irq_domain *parent,
> +				  u32 *spi_start, u32 *nr_spis,
> +				  struct resource *res, void *token)
>  {
>  	int ret;
>  	struct v2m_data *v2m;
> @@ -237,28 +243,22 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		return -ENOMEM;
>  	}
>  
> -	ret = of_address_to_resource(node, 0, &v2m->res);
> -	if (ret) {
> -		pr_err("Failed to allocate v2m resource.\n");
> -		goto err_free_v2m;
> -	}
> -
> -	v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
> +	v2m->base = ioremap(res->start, resource_size(res));
>  	if (!v2m->base) {
>  		pr_err("Failed to map GICv2m resource\n");
>  		ret = -ENOMEM;
>  		goto err_free_v2m;
>  	}
> +	memcpy(&v2m->res, res, sizeof(struct resource));
>  
> -	if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
> -	    !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
> -		pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> -			v2m->spi_start, v2m->nr_spis);
> +	if (*spi_start && *nr_spis) {
> +		v2m->spi_start = *spi_start;
> +		v2m->nr_spis = *nr_spis;
>  	} else {
>  		u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
>  
> -		v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> -		v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
> +		v2m->spi_start = *spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
> +		v2m->nr_spis = *nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
>  	}
>  
>  	if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) {
> @@ -273,7 +273,7 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_iounmap;
>  	}
>  
> -	inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m);
> +	inner_domain = irq_domain_add_tree(token, &gicv2m_domain_ops, v2m);
>  	if (!inner_domain) {
>  		pr_err("Failed to create GICv2m domain\n");
>  		ret = -ENOMEM;
> @@ -282,9 +282,11 @@ static int __init gicv2m_init_one(struct device_node *node,
>  
>  	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
>  	inner_domain->parent = parent;
> -	pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info,
> +	inner_domain->name = gicv2m_domain_name;
> +
> +	pci_domain = pci_msi_create_irq_domain(token, &gicv2m_msi_domain_info,
>  					       inner_domain);
> -	plat_domain = platform_msi_create_irq_domain(node,
> +	plat_domain = platform_msi_create_irq_domain(token,
>  						     &gicv2m_pmsi_domain_info,
>  						     inner_domain);
>  	if (!pci_domain || !plat_domain) {
> @@ -293,11 +295,10 @@ static int __init gicv2m_init_one(struct device_node *node,
>  		goto err_free_domains;
>  	}
>  
> -	spin_lock_init(&v2m->msi_cnt_lock);
> +	pci_domain->name = gicv2m_pci_msi_domain_name;
> +	plat_domain->name = gicv2m_plat_msi_domain_name;
>  
> -	pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
> -		(unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
> -		v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
> +	spin_lock_init(&v2m->msi_cnt_lock);
>  
>  	return 0;
>  
> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>  
>  	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>  	     child = of_find_matching_node(child, gicv2m_device_id)) {
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct resource res;
> +
>  		if (!of_find_property(child, "msi-controller", NULL))
>  			continue;
>  
> -		ret = gicv2m_init_one(child, parent);
> +		ret = of_address_to_resource(child, 0, &res);
> +		if (ret) {
> +			pr_err("Failed to allocate v2m resource.\n");
> +			break;
> +		}
> +
> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,

If these spi_start and nr_spis pointers passed to gicv2m_init_one are
only for the benefit of printing the message below, just move the
message inside the function...

> +				      child);
>  		if (ret) {
>  			of_node_put(node);
>  			break;
>  		}
> +
> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
>  	}
>  
>  	return ret;
>  }
> +
> +#ifdef CONFIG_ACPI
> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
> +			    struct irq_domain *parent)
> +{
> +	int i, ret;
> +
> +	ret = acpi_gic_msi_init(table);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
> +		struct resource res;
> +		u32 spi_start = 0, nr_spis = 0;
> +		struct acpi_madt_generic_msi_frame *m;
> +
> +		ret = acpi_gic_get_msi_frame(i, &m);
> +		if (ret)
> +			return ret;
> +

All of that should be moved here. And we don't need to build an
intermediate representation. Just build the v2m_data structures as you go.

> +		res.start = m->base_address;
> +		res.end = m->base_address + 0x1000;
> +
> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
> +			spi_start = m->spi_base;
> +			nr_spis = m->spi_count;
> +
> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
> +				spi_start, nr_spis);
> +		}
> +
> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
> +				      (void *)(m->base_address));
> +		if (ret)
> +			break;
> +
> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
> +			m->msi_frame_id,
> +			(unsigned long)res.start, (unsigned long)res.end,
> +			spi_start, (spi_start + nr_spis));
> +	}
> +	return ret;
> +}
> +
> +#endif /* CONFIG_ACPI */
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index bec6b00..531ebbc 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>  	 */
>  	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>  
> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
> +		gicv2m_acpi_init(table, gic_data[0].domain);
> +
>  	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>  			   gic_acpi_gsi_desc_populate);
>  	return 0;
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 97799b7..27d8196 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>  
>  int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>  
> +#ifdef CONFIG_ACPI
> +struct acpi_table_header;
> +
> +int gicv2m_acpi_init(struct acpi_table_header *table,
> +		     struct irq_domain *parent);
> +#endif
> +
>  void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>  int gic_get_cpu_id(unsigned int cpu);
>  void gic_migrate_target(unsigned int new_cpu_id);
> 

This needs rework to do the parsing of the tables in this driver. Just
expose the domain_token through a function that you register with the
ACPI layer.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
  2015-08-04 12:06     ` Marc Zyngier
  (?)
@ 2015-08-05 12:40       ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 12:40 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 08:06 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> There is a field added in ACPI 6.0 MADT table to indicate the
>> GIC version, so parse the table to get its value for later use.
>>
>> If GIC version presented in MADT is 0, we need to fallback to
>> hardware discovery to get the GIC version.
>>
>> In ACPI MADT table there is no compatible strings to indicate
>> various irqchips and also ACPI doesn't support irqchips which
>> are not compatible with ARM GIC spec, so GIC version can be used
>> to load different GIC drivers which is needed for the later patch.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   arch/arm64/Kconfig                   |   1 +
>>   drivers/irqchip/Kconfig              |   3 +
>>   drivers/irqchip/Makefile             |   1 +
>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>   5 files changed, 115 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 318175f..f2ff61f 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -16,6 +16,7 @@ config ARM64
>>   	select ARM_AMBA
>>   	select ARM_ARCH_TIMER
>>   	select ARM_GIC
>> +	select ARM_GIC_ACPI if ACPI
>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>   	select ARM_GIC_V2M if PCI_MSI
>>   	select ARM_GIC_V3
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index 120d815..557ec2f 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>   	  The maximum number of VICs available in the system, for
>>   	  power management.
>>
>> +config ARM_GIC_ACPI
>> +	bool
>> +
>>   config ATMEL_AIC_IRQ
>>   	bool
>>   	select GENERIC_IRQ_CHIP
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 11d08c9..383f421 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> new file mode 100644
>> index 0000000..6537b43
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -0,0 +1,109 @@
>> +/*
>> + * ACPI based support for ARM GIC init
>> + *
>> + * Copyright (C) 2015, Linaro Ltd.
>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/init.h>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +
>> +/* GIC version presented in MADT GIC distributor structure */
>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>> +
>> +static phys_addr_t dist_phy_base __initdata;
>> +
>> +static int __init
>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>> +			   const unsigned long end)
>> +{
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	gic_version = dist->version;
>> +	dist_phy_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>> +{
>> +	return 0;
>> +}
>> +
>> +static bool __init acpi_gic_redist_is_present(void)
>> +{
>> +	int count;
>> +
>> +	/* scan MADT table to find if we have redistributor entries */
>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>> +					match_gic_redist, 0);
>> +
>> +	/* that's true if we have at least one GIC redistributor entry */
>> +	return count > 0;
>> +}
>> +
>> +static int __init acpi_gic_version_init(void)
>> +{
>> +	int count;
>> +	u32 reg;
>> +	void __iomem *dist_base;
>> +
>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>> +				      acpi_gic_parse_distributor, 0);
>> +
>> +	if (count <= 0) {
>> +		pr_err("No valid GIC distributor entry exists\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/*
>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>> +	 * which has no gic_version field in distributor structure and
>> +	 * reserved as 0.
>> +	 *
>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>> +	 * for GICv3/4), so we need to handle it separately.
>> +	 */
>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>> +		/* it's GICv3/v4 if redistributor is present */
>> +		if (acpi_gic_redist_is_present()) {
>> +			dist_base = ioremap(dist_phy_base,
>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>> +			if (!dist_base)
>> +				return -ENOMEM;
>> +
>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>> +					    GIC_PIDR2_ARCH_MASK;
>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>> +			else
>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>
> Frankly, why should we care? If there is no redistributor, this is a V2.
> If there are redistributors, then it is a V3/V4, and it shouldn't matter
> which one this is as the GICv3 driver can find out all by itself. Also,
> the GICv4 feature only matter for KVM, which can probe this on its own.

For hardware discovery, it works.

I use the gic_version in later patch to ioremap physical base address of
GICR (which 2 or 4 64k pages), but I can get it from register in later
patch then remove the code above.

For gic version in GICD subtable, we must consider V4 as firmware may
just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
we need to match V4 in the GICv3 driver.

Thanks
Hanjun

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 12:40       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 12:40 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 08:06 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> There is a field added in ACPI 6.0 MADT table to indicate the
>> GIC version, so parse the table to get its value for later use.
>>
>> If GIC version presented in MADT is 0, we need to fallback to
>> hardware discovery to get the GIC version.
>>
>> In ACPI MADT table there is no compatible strings to indicate
>> various irqchips and also ACPI doesn't support irqchips which
>> are not compatible with ARM GIC spec, so GIC version can be used
>> to load different GIC drivers which is needed for the later patch.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   arch/arm64/Kconfig                   |   1 +
>>   drivers/irqchip/Kconfig              |   3 +
>>   drivers/irqchip/Makefile             |   1 +
>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>   5 files changed, 115 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 318175f..f2ff61f 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -16,6 +16,7 @@ config ARM64
>>   	select ARM_AMBA
>>   	select ARM_ARCH_TIMER
>>   	select ARM_GIC
>> +	select ARM_GIC_ACPI if ACPI
>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>   	select ARM_GIC_V2M if PCI_MSI
>>   	select ARM_GIC_V3
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index 120d815..557ec2f 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>   	  The maximum number of VICs available in the system, for
>>   	  power management.
>>
>> +config ARM_GIC_ACPI
>> +	bool
>> +
>>   config ATMEL_AIC_IRQ
>>   	bool
>>   	select GENERIC_IRQ_CHIP
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 11d08c9..383f421 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> new file mode 100644
>> index 0000000..6537b43
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -0,0 +1,109 @@
>> +/*
>> + * ACPI based support for ARM GIC init
>> + *
>> + * Copyright (C) 2015, Linaro Ltd.
>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/init.h>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +
>> +/* GIC version presented in MADT GIC distributor structure */
>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>> +
>> +static phys_addr_t dist_phy_base __initdata;
>> +
>> +static int __init
>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>> +			   const unsigned long end)
>> +{
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	gic_version = dist->version;
>> +	dist_phy_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>> +{
>> +	return 0;
>> +}
>> +
>> +static bool __init acpi_gic_redist_is_present(void)
>> +{
>> +	int count;
>> +
>> +	/* scan MADT table to find if we have redistributor entries */
>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>> +					match_gic_redist, 0);
>> +
>> +	/* that's true if we have at least one GIC redistributor entry */
>> +	return count > 0;
>> +}
>> +
>> +static int __init acpi_gic_version_init(void)
>> +{
>> +	int count;
>> +	u32 reg;
>> +	void __iomem *dist_base;
>> +
>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>> +				      acpi_gic_parse_distributor, 0);
>> +
>> +	if (count <= 0) {
>> +		pr_err("No valid GIC distributor entry exists\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/*
>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>> +	 * which has no gic_version field in distributor structure and
>> +	 * reserved as 0.
>> +	 *
>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>> +	 * for GICv3/4), so we need to handle it separately.
>> +	 */
>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>> +		/* it's GICv3/v4 if redistributor is present */
>> +		if (acpi_gic_redist_is_present()) {
>> +			dist_base = ioremap(dist_phy_base,
>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>> +			if (!dist_base)
>> +				return -ENOMEM;
>> +
>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>> +					    GIC_PIDR2_ARCH_MASK;
>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>> +			else
>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>
> Frankly, why should we care? If there is no redistributor, this is a V2.
> If there are redistributors, then it is a V3/V4, and it shouldn't matter
> which one this is as the GICv3 driver can find out all by itself. Also,
> the GICv4 feature only matter for KVM, which can probe this on its own.

For hardware discovery, it works.

I use the gic_version in later patch to ioremap physical base address of
GICR (which 2 or 4 64k pages), but I can get it from register in later
patch then remove the code above.

For gic version in GICD subtable, we must consider V4 as firmware may
just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
we need to match V4 in the GICv3 driver.

Thanks
Hanjun

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 12:40       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/04/2015 08:06 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> There is a field added in ACPI 6.0 MADT table to indicate the
>> GIC version, so parse the table to get its value for later use.
>>
>> If GIC version presented in MADT is 0, we need to fallback to
>> hardware discovery to get the GIC version.
>>
>> In ACPI MADT table there is no compatible strings to indicate
>> various irqchips and also ACPI doesn't support irqchips which
>> are not compatible with ARM GIC spec, so GIC version can be used
>> to load different GIC drivers which is needed for the later patch.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   arch/arm64/Kconfig                   |   1 +
>>   drivers/irqchip/Kconfig              |   3 +
>>   drivers/irqchip/Makefile             |   1 +
>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>   5 files changed, 115 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 318175f..f2ff61f 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -16,6 +16,7 @@ config ARM64
>>   	select ARM_AMBA
>>   	select ARM_ARCH_TIMER
>>   	select ARM_GIC
>> +	select ARM_GIC_ACPI if ACPI
>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>   	select ARM_GIC_V2M if PCI_MSI
>>   	select ARM_GIC_V3
>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>> index 120d815..557ec2f 100644
>> --- a/drivers/irqchip/Kconfig
>> +++ b/drivers/irqchip/Kconfig
>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>   	  The maximum number of VICs available in the system, for
>>   	  power management.
>>
>> +config ARM_GIC_ACPI
>> +	bool
>> +
>>   config ATMEL_AIC_IRQ
>>   	bool
>>   	select GENERIC_IRQ_CHIP
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 11d08c9..383f421 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> new file mode 100644
>> index 0000000..6537b43
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -0,0 +1,109 @@
>> +/*
>> + * ACPI based support for ARM GIC init
>> + *
>> + * Copyright (C) 2015, Linaro Ltd.
>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/init.h>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +
>> +/* GIC version presented in MADT GIC distributor structure */
>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>> +
>> +static phys_addr_t dist_phy_base __initdata;
>> +
>> +static int __init
>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>> +			   const unsigned long end)
>> +{
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	gic_version = dist->version;
>> +	dist_phy_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>> +{
>> +	return 0;
>> +}
>> +
>> +static bool __init acpi_gic_redist_is_present(void)
>> +{
>> +	int count;
>> +
>> +	/* scan MADT table to find if we have redistributor entries */
>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>> +					match_gic_redist, 0);
>> +
>> +	/* that's true if we have at least one GIC redistributor entry */
>> +	return count > 0;
>> +}
>> +
>> +static int __init acpi_gic_version_init(void)
>> +{
>> +	int count;
>> +	u32 reg;
>> +	void __iomem *dist_base;
>> +
>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>> +				      acpi_gic_parse_distributor, 0);
>> +
>> +	if (count <= 0) {
>> +		pr_err("No valid GIC distributor entry exists\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/*
>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>> +	 * which has no gic_version field in distributor structure and
>> +	 * reserved as 0.
>> +	 *
>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>> +	 * for GICv3/4), so we need to handle it separately.
>> +	 */
>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>> +		/* it's GICv3/v4 if redistributor is present */
>> +		if (acpi_gic_redist_is_present()) {
>> +			dist_base = ioremap(dist_phy_base,
>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>> +			if (!dist_base)
>> +				return -ENOMEM;
>> +
>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>> +					    GIC_PIDR2_ARCH_MASK;
>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>> +			else
>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>
> Frankly, why should we care? If there is no redistributor, this is a V2.
> If there are redistributors, then it is a V3/V4, and it shouldn't matter
> which one this is as the GICv3 driver can find out all by itself. Also,
> the GICv4 feature only matter for KVM, which can probe this on its own.

For hardware discovery, it works.

I use the gic_version in later patch to ioremap physical base address of
GICR (which 2 or 4 64k pages), but I can get it from register in later
patch then remove the code above.

For gic version in GICD subtable, we must consider V4 as firmware may
just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
we need to match V4 in the GICv3 driver.

Thanks
Hanjun

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
  2015-08-05 12:40       ` Hanjun Guo
  (?)
@ 2015-08-05 12:57         ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-05 12:57 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 13:40, Hanjun Guo wrote:
> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>> GIC version, so parse the table to get its value for later use.
>>>
>>> If GIC version presented in MADT is 0, we need to fallback to
>>> hardware discovery to get the GIC version.
>>>
>>> In ACPI MADT table there is no compatible strings to indicate
>>> various irqchips and also ACPI doesn't support irqchips which
>>> are not compatible with ARM GIC spec, so GIC version can be used
>>> to load different GIC drivers which is needed for the later patch.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   arch/arm64/Kconfig                   |   1 +
>>>   drivers/irqchip/Kconfig              |   3 +
>>>   drivers/irqchip/Makefile             |   1 +
>>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>   5 files changed, 115 insertions(+)
>>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 318175f..f2ff61f 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -16,6 +16,7 @@ config ARM64
>>>   	select ARM_AMBA
>>>   	select ARM_ARCH_TIMER
>>>   	select ARM_GIC
>>> +	select ARM_GIC_ACPI if ACPI
>>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>>   	select ARM_GIC_V2M if PCI_MSI
>>>   	select ARM_GIC_V3
>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>> index 120d815..557ec2f 100644
>>> --- a/drivers/irqchip/Kconfig
>>> +++ b/drivers/irqchip/Kconfig
>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>   	  The maximum number of VICs available in the system, for
>>>   	  power management.
>>>
>>> +config ARM_GIC_ACPI
>>> +	bool
>>> +
>>>   config ATMEL_AIC_IRQ
>>>   	bool
>>>   	select GENERIC_IRQ_CHIP
>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>> index 11d08c9..383f421 100644
>>> --- a/drivers/irqchip/Makefile
>>> +++ b/drivers/irqchip/Makefile
>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> new file mode 100644
>>> index 0000000..6537b43
>>> --- /dev/null
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -0,0 +1,109 @@
>>> +/*
>>> + * ACPI based support for ARM GIC init
>>> + *
>>> + * Copyright (C) 2015, Linaro Ltd.
>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>> +
>>> +#include <linux/acpi.h>
>>> +#include <linux/init.h>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>> +#include <linux/irqchip/arm-gic-v3.h>
>>> +
>>> +/* GIC version presented in MADT GIC distributor structure */
>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>> +
>>> +static phys_addr_t dist_phy_base __initdata;
>>> +
>>> +static int __init
>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>> +			   const unsigned long end)
>>> +{
>>> +	struct acpi_madt_generic_distributor *dist;
>>> +
>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +	if (BAD_MADT_ENTRY(dist, end))
>>> +		return -EINVAL;
>>> +
>>> +	gic_version = dist->version;
>>> +	dist_phy_base = dist->base_address;
>>> +	return 0;
>>> +}
>>> +
>>> +static int __init
>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static bool __init acpi_gic_redist_is_present(void)
>>> +{
>>> +	int count;
>>> +
>>> +	/* scan MADT table to find if we have redistributor entries */
>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>> +					match_gic_redist, 0);
>>> +
>>> +	/* that's true if we have at least one GIC redistributor entry */
>>> +	return count > 0;
>>> +}
>>> +
>>> +static int __init acpi_gic_version_init(void)
>>> +{
>>> +	int count;
>>> +	u32 reg;
>>> +	void __iomem *dist_base;
>>> +
>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>> +				      acpi_gic_parse_distributor, 0);
>>> +
>>> +	if (count <= 0) {
>>> +		pr_err("No valid GIC distributor entry exists\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/*
>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>> +	 * which has no gic_version field in distributor structure and
>>> +	 * reserved as 0.
>>> +	 *
>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>> +	 * for GICv3/4), so we need to handle it separately.
>>> +	 */
>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>> +		/* it's GICv3/v4 if redistributor is present */
>>> +		if (acpi_gic_redist_is_present()) {
>>> +			dist_base = ioremap(dist_phy_base,
>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>> +			if (!dist_base)
>>> +				return -ENOMEM;
>>> +
>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>> +					    GIC_PIDR2_ARCH_MASK;
>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>> +			else
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>
>> Frankly, why should we care? If there is no redistributor, this is a V2.
>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>> which one this is as the GICv3 driver can find out all by itself. Also,
>> the GICv4 feature only matter for KVM, which can probe this on its own.
> 
> For hardware discovery, it works.
> 
> I use the gic_version in later patch to ioremap physical base address of
> GICR (which 2 or 4 64k pages), but I can get it from register in later
> patch then remove the code above.
> 
> For gic version in GICD subtable, we must consider V4 as firmware may
> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
> we need to match V4 in the GICv3 driver.

My point is: the GICv3 driver doesn't give a damn. At all. And it
shouldn't! The *only* difference is the size of the redistributor, and
this can be worked out *inside the GIC driver* by looking at:

- GICR_PIDR2.ArchRev (and not GICD_PIDR2)
- GICR_TYPER.VLPIS

Whatever the firmware says is absolutely irrelevant, and even if we
needed to override what the HW reports (because it is broken), we can
implement it as a quirk inside the driver itself, without any of this
ioremap dance that doesn't even do the right thing.

So to "we must consider V4", my answer is no. Certainly not at this
location.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 12:57         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-05 12:57 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 13:40, Hanjun Guo wrote:
> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>> GIC version, so parse the table to get its value for later use.
>>>
>>> If GIC version presented in MADT is 0, we need to fallback to
>>> hardware discovery to get the GIC version.
>>>
>>> In ACPI MADT table there is no compatible strings to indicate
>>> various irqchips and also ACPI doesn't support irqchips which
>>> are not compatible with ARM GIC spec, so GIC version can be used
>>> to load different GIC drivers which is needed for the later patch.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   arch/arm64/Kconfig                   |   1 +
>>>   drivers/irqchip/Kconfig              |   3 +
>>>   drivers/irqchip/Makefile             |   1 +
>>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>   5 files changed, 115 insertions(+)
>>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 318175f..f2ff61f 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -16,6 +16,7 @@ config ARM64
>>>   	select ARM_AMBA
>>>   	select ARM_ARCH_TIMER
>>>   	select ARM_GIC
>>> +	select ARM_GIC_ACPI if ACPI
>>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>>   	select ARM_GIC_V2M if PCI_MSI
>>>   	select ARM_GIC_V3
>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>> index 120d815..557ec2f 100644
>>> --- a/drivers/irqchip/Kconfig
>>> +++ b/drivers/irqchip/Kconfig
>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>   	  The maximum number of VICs available in the system, for
>>>   	  power management.
>>>
>>> +config ARM_GIC_ACPI
>>> +	bool
>>> +
>>>   config ATMEL_AIC_IRQ
>>>   	bool
>>>   	select GENERIC_IRQ_CHIP
>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>> index 11d08c9..383f421 100644
>>> --- a/drivers/irqchip/Makefile
>>> +++ b/drivers/irqchip/Makefile
>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> new file mode 100644
>>> index 0000000..6537b43
>>> --- /dev/null
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -0,0 +1,109 @@
>>> +/*
>>> + * ACPI based support for ARM GIC init
>>> + *
>>> + * Copyright (C) 2015, Linaro Ltd.
>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>> +
>>> +#include <linux/acpi.h>
>>> +#include <linux/init.h>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>> +#include <linux/irqchip/arm-gic-v3.h>
>>> +
>>> +/* GIC version presented in MADT GIC distributor structure */
>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>> +
>>> +static phys_addr_t dist_phy_base __initdata;
>>> +
>>> +static int __init
>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>> +			   const unsigned long end)
>>> +{
>>> +	struct acpi_madt_generic_distributor *dist;
>>> +
>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +	if (BAD_MADT_ENTRY(dist, end))
>>> +		return -EINVAL;
>>> +
>>> +	gic_version = dist->version;
>>> +	dist_phy_base = dist->base_address;
>>> +	return 0;
>>> +}
>>> +
>>> +static int __init
>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static bool __init acpi_gic_redist_is_present(void)
>>> +{
>>> +	int count;
>>> +
>>> +	/* scan MADT table to find if we have redistributor entries */
>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>> +					match_gic_redist, 0);
>>> +
>>> +	/* that's true if we have at least one GIC redistributor entry */
>>> +	return count > 0;
>>> +}
>>> +
>>> +static int __init acpi_gic_version_init(void)
>>> +{
>>> +	int count;
>>> +	u32 reg;
>>> +	void __iomem *dist_base;
>>> +
>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>> +				      acpi_gic_parse_distributor, 0);
>>> +
>>> +	if (count <= 0) {
>>> +		pr_err("No valid GIC distributor entry exists\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/*
>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>> +	 * which has no gic_version field in distributor structure and
>>> +	 * reserved as 0.
>>> +	 *
>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>> +	 * for GICv3/4), so we need to handle it separately.
>>> +	 */
>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>> +		/* it's GICv3/v4 if redistributor is present */
>>> +		if (acpi_gic_redist_is_present()) {
>>> +			dist_base = ioremap(dist_phy_base,
>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>> +			if (!dist_base)
>>> +				return -ENOMEM;
>>> +
>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>> +					    GIC_PIDR2_ARCH_MASK;
>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>> +			else
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>
>> Frankly, why should we care? If there is no redistributor, this is a V2.
>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>> which one this is as the GICv3 driver can find out all by itself. Also,
>> the GICv4 feature only matter for KVM, which can probe this on its own.
> 
> For hardware discovery, it works.
> 
> I use the gic_version in later patch to ioremap physical base address of
> GICR (which 2 or 4 64k pages), but I can get it from register in later
> patch then remove the code above.
> 
> For gic version in GICD subtable, we must consider V4 as firmware may
> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
> we need to match V4 in the GICv3 driver.

My point is: the GICv3 driver doesn't give a damn. At all. And it
shouldn't! The *only* difference is the size of the redistributor, and
this can be worked out *inside the GIC driver* by looking at:

- GICR_PIDR2.ArchRev (and not GICD_PIDR2)
- GICR_TYPER.VLPIS

Whatever the firmware says is absolutely irrelevant, and even if we
needed to override what the HW reports (because it is broken), we can
implement it as a quirk inside the driver itself, without any of this
ioremap dance that doesn't even do the right thing.

So to "we must consider V4", my answer is no. Certainly not at this
location.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 12:57         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-05 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/08/15 13:40, Hanjun Guo wrote:
> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>> GIC version, so parse the table to get its value for later use.
>>>
>>> If GIC version presented in MADT is 0, we need to fallback to
>>> hardware discovery to get the GIC version.
>>>
>>> In ACPI MADT table there is no compatible strings to indicate
>>> various irqchips and also ACPI doesn't support irqchips which
>>> are not compatible with ARM GIC spec, so GIC version can be used
>>> to load different GIC drivers which is needed for the later patch.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   arch/arm64/Kconfig                   |   1 +
>>>   drivers/irqchip/Kconfig              |   3 +
>>>   drivers/irqchip/Makefile             |   1 +
>>>   drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>   include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>   5 files changed, 115 insertions(+)
>>>   create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 318175f..f2ff61f 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -16,6 +16,7 @@ config ARM64
>>>   	select ARM_AMBA
>>>   	select ARM_ARCH_TIMER
>>>   	select ARM_GIC
>>> +	select ARM_GIC_ACPI if ACPI
>>>   	select AUDIT_ARCH_COMPAT_GENERIC
>>>   	select ARM_GIC_V2M if PCI_MSI
>>>   	select ARM_GIC_V3
>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>> index 120d815..557ec2f 100644
>>> --- a/drivers/irqchip/Kconfig
>>> +++ b/drivers/irqchip/Kconfig
>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>   	  The maximum number of VICs available in the system, for
>>>   	  power management.
>>>
>>> +config ARM_GIC_ACPI
>>> +	bool
>>> +
>>>   config ATMEL_AIC_IRQ
>>>   	bool
>>>   	select GENERIC_IRQ_CHIP
>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>> index 11d08c9..383f421 100644
>>> --- a/drivers/irqchip/Makefile
>>> +++ b/drivers/irqchip/Makefile
>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>   obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>   obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>   obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>   obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>   obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> new file mode 100644
>>> index 0000000..6537b43
>>> --- /dev/null
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -0,0 +1,109 @@
>>> +/*
>>> + * ACPI based support for ARM GIC init
>>> + *
>>> + * Copyright (C) 2015, Linaro Ltd.
>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>> +
>>> +#include <linux/acpi.h>
>>> +#include <linux/init.h>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>> +#include <linux/irqchip/arm-gic-v3.h>
>>> +
>>> +/* GIC version presented in MADT GIC distributor structure */
>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>> +
>>> +static phys_addr_t dist_phy_base __initdata;
>>> +
>>> +static int __init
>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>> +			   const unsigned long end)
>>> +{
>>> +	struct acpi_madt_generic_distributor *dist;
>>> +
>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +	if (BAD_MADT_ENTRY(dist, end))
>>> +		return -EINVAL;
>>> +
>>> +	gic_version = dist->version;
>>> +	dist_phy_base = dist->base_address;
>>> +	return 0;
>>> +}
>>> +
>>> +static int __init
>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static bool __init acpi_gic_redist_is_present(void)
>>> +{
>>> +	int count;
>>> +
>>> +	/* scan MADT table to find if we have redistributor entries */
>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>> +					match_gic_redist, 0);
>>> +
>>> +	/* that's true if we have at least one GIC redistributor entry */
>>> +	return count > 0;
>>> +}
>>> +
>>> +static int __init acpi_gic_version_init(void)
>>> +{
>>> +	int count;
>>> +	u32 reg;
>>> +	void __iomem *dist_base;
>>> +
>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>> +				      acpi_gic_parse_distributor, 0);
>>> +
>>> +	if (count <= 0) {
>>> +		pr_err("No valid GIC distributor entry exists\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/*
>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>> +	 * which has no gic_version field in distributor structure and
>>> +	 * reserved as 0.
>>> +	 *
>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>> +	 * for GICv3/4), so we need to handle it separately.
>>> +	 */
>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>> +		/* it's GICv3/v4 if redistributor is present */
>>> +		if (acpi_gic_redist_is_present()) {
>>> +			dist_base = ioremap(dist_phy_base,
>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>> +			if (!dist_base)
>>> +				return -ENOMEM;
>>> +
>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>> +					    GIC_PIDR2_ARCH_MASK;
>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>> +			else
>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>
>> Frankly, why should we care? If there is no redistributor, this is a V2.
>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>> which one this is as the GICv3 driver can find out all by itself. Also,
>> the GICv4 feature only matter for KVM, which can probe this on its own.
> 
> For hardware discovery, it works.
> 
> I use the gic_version in later patch to ioremap physical base address of
> GICR (which 2 or 4 64k pages), but I can get it from register in later
> patch then remove the code above.
> 
> For gic version in GICD subtable, we must consider V4 as firmware may
> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
> we need to match V4 in the GICv3 driver.

My point is: the GICv3 driver doesn't give a damn. At all. And it
shouldn't! The *only* difference is the size of the redistributor, and
this can be worked out *inside the GIC driver* by looking at:

- GICR_PIDR2.ArchRev (and not GICD_PIDR2)
- GICR_TYPER.VLPIS

Whatever the firmware says is absolutely irrelevant, and even if we
needed to override what the HW reports (because it is broken), we can
implement it as a quirk inside the driver itself, without any of this
ioremap dance that doesn't even do the right thing.

So to "we must consider V4", my answer is no. Certainly not at this
location.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
  2015-08-05 12:57         ` Marc Zyngier
  (?)
@ 2015-08-05 13:11           ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:11 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/05/2015 08:57 PM, Marc Zyngier wrote:
> On 05/08/15 13:40, Hanjun Guo wrote:
>> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>>> GIC version, so parse the table to get its value for later use.
>>>>
>>>> If GIC version presented in MADT is 0, we need to fallback to
>>>> hardware discovery to get the GIC version.
>>>>
>>>> In ACPI MADT table there is no compatible strings to indicate
>>>> various irqchips and also ACPI doesn't support irqchips which
>>>> are not compatible with ARM GIC spec, so GIC version can be used
>>>> to load different GIC drivers which is needed for the later patch.
>>>>
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    arch/arm64/Kconfig                   |   1 +
>>>>    drivers/irqchip/Kconfig              |   3 +
>>>>    drivers/irqchip/Makefile             |   1 +
>>>>    drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>>    include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>>    5 files changed, 115 insertions(+)
>>>>    create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>>
>>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>>> index 318175f..f2ff61f 100644
>>>> --- a/arch/arm64/Kconfig
>>>> +++ b/arch/arm64/Kconfig
>>>> @@ -16,6 +16,7 @@ config ARM64
>>>>    	select ARM_AMBA
>>>>    	select ARM_ARCH_TIMER
>>>>    	select ARM_GIC
>>>> +	select ARM_GIC_ACPI if ACPI
>>>>    	select AUDIT_ARCH_COMPAT_GENERIC
>>>>    	select ARM_GIC_V2M if PCI_MSI
>>>>    	select ARM_GIC_V3
>>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>>> index 120d815..557ec2f 100644
>>>> --- a/drivers/irqchip/Kconfig
>>>> +++ b/drivers/irqchip/Kconfig
>>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>>    	  The maximum number of VICs available in the system, for
>>>>    	  power management.
>>>>
>>>> +config ARM_GIC_ACPI
>>>> +	bool
>>>> +
>>>>    config ATMEL_AIC_IRQ
>>>>    	bool
>>>>    	select GENERIC_IRQ_CHIP
>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>>> index 11d08c9..383f421 100644
>>>> --- a/drivers/irqchip/Makefile
>>>> +++ b/drivers/irqchip/Makefile
>>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>>    obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>>    obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>>    obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>>    obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>>> new file mode 100644
>>>> index 0000000..6537b43
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>>> @@ -0,0 +1,109 @@
>>>> +/*
>>>> + * ACPI based support for ARM GIC init
>>>> + *
>>>> + * Copyright (C) 2015, Linaro Ltd.
>>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + */
>>>> +
>>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>>> +
>>>> +#include <linux/acpi.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>> +#include <linux/irqchip/arm-gic-v3.h>
>>>> +
>>>> +/* GIC version presented in MADT GIC distributor structure */
>>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>> +
>>>> +static phys_addr_t dist_phy_base __initdata;
>>>> +
>>>> +static int __init
>>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>> +			   const unsigned long end)
>>>> +{
>>>> +	struct acpi_madt_generic_distributor *dist;
>>>> +
>>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>>> +
>>>> +	if (BAD_MADT_ENTRY(dist, end))
>>>> +		return -EINVAL;
>>>> +
>>>> +	gic_version = dist->version;
>>>> +	dist_phy_base = dist->base_address;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int __init
>>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>> +{
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static bool __init acpi_gic_redist_is_present(void)
>>>> +{
>>>> +	int count;
>>>> +
>>>> +	/* scan MADT table to find if we have redistributor entries */
>>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>> +					match_gic_redist, 0);
>>>> +
>>>> +	/* that's true if we have at least one GIC redistributor entry */
>>>> +	return count > 0;
>>>> +}
>>>> +
>>>> +static int __init acpi_gic_version_init(void)
>>>> +{
>>>> +	int count;
>>>> +	u32 reg;
>>>> +	void __iomem *dist_base;
>>>> +
>>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>>> +				      acpi_gic_parse_distributor, 0);
>>>> +
>>>> +	if (count <= 0) {
>>>> +		pr_err("No valid GIC distributor entry exists\n");
>>>> +		return -ENODEV;
>>>> +	}
>>>> +
>>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>>> +	 * which has no gic_version field in distributor structure and
>>>> +	 * reserved as 0.
>>>> +	 *
>>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>>> +	 * for GICv3/4), so we need to handle it separately.
>>>> +	 */
>>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>>> +		/* it's GICv3/v4 if redistributor is present */
>>>> +		if (acpi_gic_redist_is_present()) {
>>>> +			dist_base = ioremap(dist_phy_base,
>>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>>> +			if (!dist_base)
>>>> +				return -ENOMEM;
>>>> +
>>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>>> +					    GIC_PIDR2_ARCH_MASK;
>>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>>> +			else
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>>
>>> Frankly, why should we care? If there is no redistributor, this is a V2.
>>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>>> which one this is as the GICv3 driver can find out all by itself. Also,
>>> the GICv4 feature only matter for KVM, which can probe this on its own.
>>
>> For hardware discovery, it works.
>>
>> I use the gic_version in later patch to ioremap physical base address of
>> GICR (which 2 or 4 64k pages), but I can get it from register in later
>> patch then remove the code above.
>>
>> For gic version in GICD subtable, we must consider V4 as firmware may
>> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
>> we need to match V4 in the GICv3 driver.
>
> My point is: the GICv3 driver doesn't give a damn. At all. And it
> shouldn't! The *only* difference is the size of the redistributor, and
> this can be worked out *inside the GIC driver* by looking at:
>
> - GICR_PIDR2.ArchRev (and not GICD_PIDR2)
> - GICR_TYPER.VLPIS
>
> Whatever the firmware says is absolutely irrelevant, and even if we
> needed to override what the HW reports (because it is broken), we can
> implement it as a quirk inside the driver itself, without any of this
> ioremap dance that doesn't even do the right thing.
>
> So to "we must consider V4", my answer is no. Certainly not at this
> location.

Sorry, I didn't make it clear. what I mean is that when GIC version
is presented as V4, we can match the GICv3 driver with it, and
everything will be the same in the driver itself.

Thanks
Hanjun

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

* Re: [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 13:11           ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:11 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/05/2015 08:57 PM, Marc Zyngier wrote:
> On 05/08/15 13:40, Hanjun Guo wrote:
>> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>>> GIC version, so parse the table to get its value for later use.
>>>>
>>>> If GIC version presented in MADT is 0, we need to fallback to
>>>> hardware discovery to get the GIC version.
>>>>
>>>> In ACPI MADT table there is no compatible strings to indicate
>>>> various irqchips and also ACPI doesn't support irqchips which
>>>> are not compatible with ARM GIC spec, so GIC version can be used
>>>> to load different GIC drivers which is needed for the later patch.
>>>>
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    arch/arm64/Kconfig                   |   1 +
>>>>    drivers/irqchip/Kconfig              |   3 +
>>>>    drivers/irqchip/Makefile             |   1 +
>>>>    drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>>    include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>>    5 files changed, 115 insertions(+)
>>>>    create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>>
>>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>>> index 318175f..f2ff61f 100644
>>>> --- a/arch/arm64/Kconfig
>>>> +++ b/arch/arm64/Kconfig
>>>> @@ -16,6 +16,7 @@ config ARM64
>>>>    	select ARM_AMBA
>>>>    	select ARM_ARCH_TIMER
>>>>    	select ARM_GIC
>>>> +	select ARM_GIC_ACPI if ACPI
>>>>    	select AUDIT_ARCH_COMPAT_GENERIC
>>>>    	select ARM_GIC_V2M if PCI_MSI
>>>>    	select ARM_GIC_V3
>>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>>> index 120d815..557ec2f 100644
>>>> --- a/drivers/irqchip/Kconfig
>>>> +++ b/drivers/irqchip/Kconfig
>>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>>    	  The maximum number of VICs available in the system, for
>>>>    	  power management.
>>>>
>>>> +config ARM_GIC_ACPI
>>>> +	bool
>>>> +
>>>>    config ATMEL_AIC_IRQ
>>>>    	bool
>>>>    	select GENERIC_IRQ_CHIP
>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>>> index 11d08c9..383f421 100644
>>>> --- a/drivers/irqchip/Makefile
>>>> +++ b/drivers/irqchip/Makefile
>>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>>    obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>>    obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>>    obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>>    obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>>> new file mode 100644
>>>> index 0000000..6537b43
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>>> @@ -0,0 +1,109 @@
>>>> +/*
>>>> + * ACPI based support for ARM GIC init
>>>> + *
>>>> + * Copyright (C) 2015, Linaro Ltd.
>>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + */
>>>> +
>>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>>> +
>>>> +#include <linux/acpi.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>> +#include <linux/irqchip/arm-gic-v3.h>
>>>> +
>>>> +/* GIC version presented in MADT GIC distributor structure */
>>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>> +
>>>> +static phys_addr_t dist_phy_base __initdata;
>>>> +
>>>> +static int __init
>>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>> +			   const unsigned long end)
>>>> +{
>>>> +	struct acpi_madt_generic_distributor *dist;
>>>> +
>>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>>> +
>>>> +	if (BAD_MADT_ENTRY(dist, end))
>>>> +		return -EINVAL;
>>>> +
>>>> +	gic_version = dist->version;
>>>> +	dist_phy_base = dist->base_address;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int __init
>>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>> +{
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static bool __init acpi_gic_redist_is_present(void)
>>>> +{
>>>> +	int count;
>>>> +
>>>> +	/* scan MADT table to find if we have redistributor entries */
>>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>> +					match_gic_redist, 0);
>>>> +
>>>> +	/* that's true if we have at least one GIC redistributor entry */
>>>> +	return count > 0;
>>>> +}
>>>> +
>>>> +static int __init acpi_gic_version_init(void)
>>>> +{
>>>> +	int count;
>>>> +	u32 reg;
>>>> +	void __iomem *dist_base;
>>>> +
>>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>>> +				      acpi_gic_parse_distributor, 0);
>>>> +
>>>> +	if (count <= 0) {
>>>> +		pr_err("No valid GIC distributor entry exists\n");
>>>> +		return -ENODEV;
>>>> +	}
>>>> +
>>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>>> +	 * which has no gic_version field in distributor structure and
>>>> +	 * reserved as 0.
>>>> +	 *
>>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>>> +	 * for GICv3/4), so we need to handle it separately.
>>>> +	 */
>>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>>> +		/* it's GICv3/v4 if redistributor is present */
>>>> +		if (acpi_gic_redist_is_present()) {
>>>> +			dist_base = ioremap(dist_phy_base,
>>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>>> +			if (!dist_base)
>>>> +				return -ENOMEM;
>>>> +
>>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>>> +					    GIC_PIDR2_ARCH_MASK;
>>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>>> +			else
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>>
>>> Frankly, why should we care? If there is no redistributor, this is a V2.
>>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>>> which one this is as the GICv3 driver can find out all by itself. Also,
>>> the GICv4 feature only matter for KVM, which can probe this on its own.
>>
>> For hardware discovery, it works.
>>
>> I use the gic_version in later patch to ioremap physical base address of
>> GICR (which 2 or 4 64k pages), but I can get it from register in later
>> patch then remove the code above.
>>
>> For gic version in GICD subtable, we must consider V4 as firmware may
>> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
>> we need to match V4 in the GICv3 driver.
>
> My point is: the GICv3 driver doesn't give a damn. At all. And it
> shouldn't! The *only* difference is the size of the redistributor, and
> this can be worked out *inside the GIC driver* by looking at:
>
> - GICR_PIDR2.ArchRev (and not GICD_PIDR2)
> - GICR_TYPER.VLPIS
>
> Whatever the firmware says is absolutely irrelevant, and even if we
> needed to override what the HW reports (because it is broken), we can
> implement it as a quirk inside the driver itself, without any of this
> ioremap dance that doesn't even do the right thing.
>
> So to "we must consider V4", my answer is no. Certainly not at this
> location.

Sorry, I didn't make it clear. what I mean is that when GIC version
is presented as V4, we can match the GICv3 driver with it, and
everything will be the same in the driver itself.

Thanks
Hanjun

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

* [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT
@ 2015-08-05 13:11           ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/05/2015 08:57 PM, Marc Zyngier wrote:
> On 05/08/15 13:40, Hanjun Guo wrote:
>> On 08/04/2015 08:06 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> There is a field added in ACPI 6.0 MADT table to indicate the
>>>> GIC version, so parse the table to get its value for later use.
>>>>
>>>> If GIC version presented in MADT is 0, we need to fallback to
>>>> hardware discovery to get the GIC version.
>>>>
>>>> In ACPI MADT table there is no compatible strings to indicate
>>>> various irqchips and also ACPI doesn't support irqchips which
>>>> are not compatible with ARM GIC spec, so GIC version can be used
>>>> to load different GIC drivers which is needed for the later patch.
>>>>
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    arch/arm64/Kconfig                   |   1 +
>>>>    drivers/irqchip/Kconfig              |   3 +
>>>>    drivers/irqchip/Makefile             |   1 +
>>>>    drivers/irqchip/irq-gic-acpi.c       | 109 +++++++++++++++++++++++++++++++++++
>>>>    include/linux/irqchip/arm-gic-acpi.h |   1 +
>>>>    5 files changed, 115 insertions(+)
>>>>    create mode 100644 drivers/irqchip/irq-gic-acpi.c
>>>>
>>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>>> index 318175f..f2ff61f 100644
>>>> --- a/arch/arm64/Kconfig
>>>> +++ b/arch/arm64/Kconfig
>>>> @@ -16,6 +16,7 @@ config ARM64
>>>>    	select ARM_AMBA
>>>>    	select ARM_ARCH_TIMER
>>>>    	select ARM_GIC
>>>> +	select ARM_GIC_ACPI if ACPI
>>>>    	select AUDIT_ARCH_COMPAT_GENERIC
>>>>    	select ARM_GIC_V2M if PCI_MSI
>>>>    	select ARM_GIC_V3
>>>> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
>>>> index 120d815..557ec2f 100644
>>>> --- a/drivers/irqchip/Kconfig
>>>> +++ b/drivers/irqchip/Kconfig
>>>> @@ -47,6 +47,9 @@ config ARM_VIC_NR
>>>>    	  The maximum number of VICs available in the system, for
>>>>    	  power management.
>>>>
>>>> +config ARM_GIC_ACPI
>>>> +	bool
>>>> +
>>>>    config ATMEL_AIC_IRQ
>>>>    	bool
>>>>    	select GENERIC_IRQ_CHIP
>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>>> index 11d08c9..383f421 100644
>>>> --- a/drivers/irqchip/Makefile
>>>> +++ b/drivers/irqchip/Makefile
>>>> @@ -23,6 +23,7 @@ obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V2M)		+= irq-gic-v2m.o
>>>>    obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
>>>>    obj-$(CONFIG_ARM_GIC_V3_ITS)		+= irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
>>>> +obj-$(CONFIG_ARM_GIC_ACPI)		+= irq-gic-acpi.o
>>>>    obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
>>>>    obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
>>>>    obj-$(CONFIG_ATMEL_AIC_IRQ)		+= irq-atmel-aic-common.o irq-atmel-aic.o
>>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>>> new file mode 100644
>>>> index 0000000..6537b43
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>>> @@ -0,0 +1,109 @@
>>>> +/*
>>>> + * ACPI based support for ARM GIC init
>>>> + *
>>>> + * Copyright (C) 2015, Linaro Ltd.
>>>> + * 	Author: Hanjun Guo <hanjun.guo@linaro.org>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + */
>>>> +
>>>> +#define pr_fmt(fmt) "ACPI: GIC: " fmt
>>>> +
>>>> +#include <linux/acpi.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>> +#include <linux/irqchip/arm-gic-v3.h>
>>>> +
>>>> +/* GIC version presented in MADT GIC distributor structure */
>>>> +static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>> +
>>>> +static phys_addr_t dist_phy_base __initdata;
>>>> +
>>>> +static int __init
>>>> +acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>> +			   const unsigned long end)
>>>> +{
>>>> +	struct acpi_madt_generic_distributor *dist;
>>>> +
>>>> +	dist = (struct acpi_madt_generic_distributor *)header;
>>>> +
>>>> +	if (BAD_MADT_ENTRY(dist, end))
>>>> +		return -EINVAL;
>>>> +
>>>> +	gic_version = dist->version;
>>>> +	dist_phy_base = dist->base_address;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int __init
>>>> +match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>> +{
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static bool __init acpi_gic_redist_is_present(void)
>>>> +{
>>>> +	int count;
>>>> +
>>>> +	/* scan MADT table to find if we have redistributor entries */
>>>> +	count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>> +					match_gic_redist, 0);
>>>> +
>>>> +	/* that's true if we have at least one GIC redistributor entry */
>>>> +	return count > 0;
>>>> +}
>>>> +
>>>> +static int __init acpi_gic_version_init(void)
>>>> +{
>>>> +	int count;
>>>> +	u32 reg;
>>>> +	void __iomem *dist_base;
>>>> +
>>>> +	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
>>>> +				      acpi_gic_parse_distributor, 0);
>>>> +
>>>> +	if (count <= 0) {
>>>> +		pr_err("No valid GIC distributor entry exists\n");
>>>> +		return -ENODEV;
>>>> +	}
>>>> +
>>>> +	if (gic_version >= ACPI_MADT_GIC_VERSION_RESERVED) {
>>>> +		pr_err("Invalid GIC version %d in MADT\n", gic_version);
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * when the GIC version is 0, we fallback to hardware discovery.
>>>> +	 * this is also needed to keep compatiable with ACPI 5.1,
>>>> +	 * which has no gic_version field in distributor structure and
>>>> +	 * reserved as 0.
>>>> +	 *
>>>> +	 * For hardware discovery, the offset for GICv1/2 and GICv3/4 to
>>>> +	 * get the GIC version is different (0xFE8 for GICv1/2 and 0xFFE8
>>>> +	 * for GICv3/4), so we need to handle it separately.
>>>> +	 */
>>>> +	if (gic_version	== ACPI_MADT_GIC_VERSION_NONE) {
>>>> +		/* it's GICv3/v4 if redistributor is present */
>>>> +		if (acpi_gic_redist_is_present()) {
>>>> +			dist_base = ioremap(dist_phy_base,
>>>> +					    ACPI_GICV3_DIST_MEM_SIZE);
>>>> +			if (!dist_base)
>>>> +				return -ENOMEM;
>>>> +
>>>> +			reg = readl_relaxed(dist_base + GICD_PIDR2) &
>>>> +					    GIC_PIDR2_ARCH_MASK;
>>>> +			if (reg == GIC_PIDR2_ARCH_GICv3)
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V3;
>>>> +			else
>>>> +				gic_version = ACPI_MADT_GIC_VERSION_V4;
>>>
>>> Frankly, why should we care? If there is no redistributor, this is a V2.
>>> If there are redistributors, then it is a V3/V4, and it shouldn't matter
>>> which one this is as the GICv3 driver can find out all by itself. Also,
>>> the GICv4 feature only matter for KVM, which can probe this on its own.
>>
>> For hardware discovery, it works.
>>
>> I use the gic_version in later patch to ioremap physical base address of
>> GICR (which 2 or 4 64k pages), but I can get it from register in later
>> patch then remove the code above.
>>
>> For gic version in GICD subtable, we must consider V4 as firmware may
>> just present ACPI_MADT_GIC_VERSION_V4 as the GIC version, that's why
>> we need to match V4 in the GICv3 driver.
>
> My point is: the GICv3 driver doesn't give a damn. At all. And it
> shouldn't! The *only* difference is the size of the redistributor, and
> this can be worked out *inside the GIC driver* by looking at:
>
> - GICR_PIDR2.ArchRev (and not GICD_PIDR2)
> - GICR_TYPER.VLPIS
>
> Whatever the firmware says is absolutely irrelevant, and even if we
> needed to override what the HW reports (because it is broken), we can
> implement it as a quirk inside the driver itself, without any of this
> ioremap dance that doesn't even do the right thing.
>
> So to "we must consider V4", my answer is no. Certainly not at this
> location.

Sorry, I didn't make it clear. what I mean is that when GIC version
is presented as V4, we can match the GICv3 driver with it, and
everything will be the same in the driver itself.

Thanks
Hanjun

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
  2015-08-04 12:27     ` Marc Zyngier
  (?)
@ 2015-08-05 13:24       ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:24 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

Hi Marc,

On 08/04/2015 08:27 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> This self-probe infrastructure works in the similar way as OF,
>> but there is some different in the mechanism:
>>
>> For DT, the init fn will be called once it finds compatible strings
>> in DT,  but for ACPI, we init irqchips by static tables, and in
>> static ACPI tables, there are no compatible strings to indicate
>> irqchips, but thanks to the GIC version presented in ACPI table,
>> we can call the corresponding GIC drivers matching the GIC version
>> with this framework.
>>
>> This mechanism can also be used for clock declare and may also works
>> on x86 for some table parsing too.
>>
>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>> work.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>   include/linux/irqchip.h           | 13 +++++++++++++
>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>   5 files changed, 83 insertions(+)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 6537b43..011468d 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>
>>   	return 0;
>>   }
>> +
>> +/*
>> + * This special acpi_table_id is the sentinel at the end of the
>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>> + * the end of the array by the linker, thanks to being part of a
>> + * special section.
>> + */
>> +static const struct acpi_table_id
>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>
> What is this thing for? Nobody refers to it (I know
> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
> reason...).

If I'm not mistaken, this is for proper section termination, please
see below:

/* scan the irqchip table to match the GIC version and its driver */
for (id = __irqchip_acpi_table; id->id[0]; id++) {
...
}

Then irqchip_acpi_match_end will be the end of the table section,
which will terminate the scanning.

>
>> +
>> +extern struct acpi_table_id __irqchip_acpi_table[];
>> +
>> +void __init acpi_irqchip_init(void)
>> +{
>> +	struct acpi_table_id *id;
>> +
>> +	if (acpi_disabled)
>> +		return;
>> +
>> +	if (acpi_gic_version_init())
>> +		return;
>
> This is the only place where we need the version, right? So just get
> acpi_gic_version_init to return the version number, and loose the global
> variable.

The global variable is still needed because we need to get the GIC
version when scanning the MADT tables, we can't return the table value
directly in acpi_table_parse_madt() at now.

>
>> +
>> +	/* scan the irqchip table to match the GIC version and its driver */
>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>> +		if (gic_version == (u8)id->driver_data) {
>> +			acpi_table_parse(id->id,
>> +					 (acpi_tbl_table_handler)id->handler);
>> +			return;
>> +		}
>> +	}
>> +
>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>> +}
>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>> index 8bd374d..625776c 100644
>> --- a/include/asm-generic/vmlinux.lds.h
>> +++ b/include/asm-generic/vmlinux.lds.h
>> @@ -181,6 +181,18 @@
>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_TABLE(name)						\
>> +	. = ALIGN(8);							\
>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>> +	*(__##name##_acpi_table)					\
>> +	*(__##name##_acpi_table_end)
>> +
>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>> +#else
>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>> +#endif
>> +
>>   #define KERNEL_DTB()							\
>>   	STRUCT_ALIGN();							\
>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>> @@ -516,6 +528,7 @@
>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>   	KERNEL_DTB()							\
>>   	IRQCHIP_OF_MATCH_TABLE()					\
>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>   	EARLYCON_TABLE()						\
>>   	EARLYCON_OF_TABLES()
>>
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 0820cb1..04dd0bb 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>
>>   #endif
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__used __section(__##table##_acpi_table)		\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#else
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__attribute__((unused))					\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#endif
>> +
>>   #endif	/*_LINUX_ACPI_H*/
>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>> index 6388873..6b66d3e 100644
>> --- a/include/linux/irqchip.h
>> +++ b/include/linux/irqchip.h
>> @@ -11,6 +11,7 @@
>>   #ifndef _LINUX_IRQCHIP_H
>>   #define _LINUX_IRQCHIP_H
>>
>> +#include <linux/acpi.h>
>>   #include <linux/of.h>
>>
>>   /*
>> @@ -25,6 +26,18 @@
>>    */
>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>
>> +/*
>> + * This macro must be used by the different ARM GIC drivers to declare
>> + * the association between their version and their initialization function.
>> + *
>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>> + * same file.
>> + * @gic_version: version of GIC
>> + * @fn: initialization function
>> + */
>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>
> I don't think this is the right approach. The MADT table has a *huge*
> number of possible subtables, and none of them is matched by the GIC
> version.
>
> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
> macro doesn't reflect this at all (you've basically cloned OF, and
> that's clearly not good enough).
>
> This probably require an intermediate matching function, ending up with
> something like:
>
> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
> 		subtable, version, fn)
>
> where match_madt_subtable is going to check that a given subtable is
> really suitable for a given irqchip. None of that should be GIC
> specific, really.

I'm little confused here, in the previous patch, the gic version is
stored, so we only need to match the GIC driver with the gic version.

In the GIC dirver itself, we will match the madt subtable to find
information we need to init the GIC, so I'm not sure why
match_madt_subtable in the ACPI_DECLARE, I think I missed something,
please correct me.

Thanks
Hanjun

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-05 13:24       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:24 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

Hi Marc,

On 08/04/2015 08:27 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> This self-probe infrastructure works in the similar way as OF,
>> but there is some different in the mechanism:
>>
>> For DT, the init fn will be called once it finds compatible strings
>> in DT,  but for ACPI, we init irqchips by static tables, and in
>> static ACPI tables, there are no compatible strings to indicate
>> irqchips, but thanks to the GIC version presented in ACPI table,
>> we can call the corresponding GIC drivers matching the GIC version
>> with this framework.
>>
>> This mechanism can also be used for clock declare and may also works
>> on x86 for some table parsing too.
>>
>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>> work.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>   include/linux/irqchip.h           | 13 +++++++++++++
>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>   5 files changed, 83 insertions(+)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 6537b43..011468d 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>
>>   	return 0;
>>   }
>> +
>> +/*
>> + * This special acpi_table_id is the sentinel at the end of the
>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>> + * the end of the array by the linker, thanks to being part of a
>> + * special section.
>> + */
>> +static const struct acpi_table_id
>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>
> What is this thing for? Nobody refers to it (I know
> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
> reason...).

If I'm not mistaken, this is for proper section termination, please
see below:

/* scan the irqchip table to match the GIC version and its driver */
for (id = __irqchip_acpi_table; id->id[0]; id++) {
...
}

Then irqchip_acpi_match_end will be the end of the table section,
which will terminate the scanning.

>
>> +
>> +extern struct acpi_table_id __irqchip_acpi_table[];
>> +
>> +void __init acpi_irqchip_init(void)
>> +{
>> +	struct acpi_table_id *id;
>> +
>> +	if (acpi_disabled)
>> +		return;
>> +
>> +	if (acpi_gic_version_init())
>> +		return;
>
> This is the only place where we need the version, right? So just get
> acpi_gic_version_init to return the version number, and loose the global
> variable.

The global variable is still needed because we need to get the GIC
version when scanning the MADT tables, we can't return the table value
directly in acpi_table_parse_madt() at now.

>
>> +
>> +	/* scan the irqchip table to match the GIC version and its driver */
>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>> +		if (gic_version == (u8)id->driver_data) {
>> +			acpi_table_parse(id->id,
>> +					 (acpi_tbl_table_handler)id->handler);
>> +			return;
>> +		}
>> +	}
>> +
>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>> +}
>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>> index 8bd374d..625776c 100644
>> --- a/include/asm-generic/vmlinux.lds.h
>> +++ b/include/asm-generic/vmlinux.lds.h
>> @@ -181,6 +181,18 @@
>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_TABLE(name)						\
>> +	. = ALIGN(8);							\
>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>> +	*(__##name##_acpi_table)					\
>> +	*(__##name##_acpi_table_end)
>> +
>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>> +#else
>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>> +#endif
>> +
>>   #define KERNEL_DTB()							\
>>   	STRUCT_ALIGN();							\
>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>> @@ -516,6 +528,7 @@
>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>   	KERNEL_DTB()							\
>>   	IRQCHIP_OF_MATCH_TABLE()					\
>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>   	EARLYCON_TABLE()						\
>>   	EARLYCON_OF_TABLES()
>>
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 0820cb1..04dd0bb 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>
>>   #endif
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__used __section(__##table##_acpi_table)		\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#else
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__attribute__((unused))					\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#endif
>> +
>>   #endif	/*_LINUX_ACPI_H*/
>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>> index 6388873..6b66d3e 100644
>> --- a/include/linux/irqchip.h
>> +++ b/include/linux/irqchip.h
>> @@ -11,6 +11,7 @@
>>   #ifndef _LINUX_IRQCHIP_H
>>   #define _LINUX_IRQCHIP_H
>>
>> +#include <linux/acpi.h>
>>   #include <linux/of.h>
>>
>>   /*
>> @@ -25,6 +26,18 @@
>>    */
>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>
>> +/*
>> + * This macro must be used by the different ARM GIC drivers to declare
>> + * the association between their version and their initialization function.
>> + *
>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>> + * same file.
>> + * @gic_version: version of GIC
>> + * @fn: initialization function
>> + */
>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>
> I don't think this is the right approach. The MADT table has a *huge*
> number of possible subtables, and none of them is matched by the GIC
> version.
>
> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
> macro doesn't reflect this at all (you've basically cloned OF, and
> that's clearly not good enough).
>
> This probably require an intermediate matching function, ending up with
> something like:
>
> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
> 		subtable, version, fn)
>
> where match_madt_subtable is going to check that a given subtable is
> really suitable for a given irqchip. None of that should be GIC
> specific, really.

I'm little confused here, in the previous patch, the gic version is
stored, so we only need to match the GIC driver with the gic version.

In the GIC dirver itself, we will match the madt subtable to find
information we need to init the GIC, so I'm not sure why
match_madt_subtable in the ACPI_DECLARE, I think I missed something,
please correct me.

Thanks
Hanjun

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

* [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-05 13:24       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 13:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 08/04/2015 08:27 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> This self-probe infrastructure works in the similar way as OF,
>> but there is some different in the mechanism:
>>
>> For DT, the init fn will be called once it finds compatible strings
>> in DT,  but for ACPI, we init irqchips by static tables, and in
>> static ACPI tables, there are no compatible strings to indicate
>> irqchips, but thanks to the GIC version presented in ACPI table,
>> we can call the corresponding GIC drivers matching the GIC version
>> with this framework.
>>
>> This mechanism can also be used for clock declare and may also works
>> on x86 for some table parsing too.
>>
>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>> work.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>   include/linux/irqchip.h           | 13 +++++++++++++
>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>   5 files changed, 83 insertions(+)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 6537b43..011468d 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>
>>   	return 0;
>>   }
>> +
>> +/*
>> + * This special acpi_table_id is the sentinel at the end of the
>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>> + * the end of the array by the linker, thanks to being part of a
>> + * special section.
>> + */
>> +static const struct acpi_table_id
>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>
> What is this thing for? Nobody refers to it (I know
> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
> reason...).

If I'm not mistaken, this is for proper section termination, please
see below:

/* scan the irqchip table to match the GIC version and its driver */
for (id = __irqchip_acpi_table; id->id[0]; id++) {
...
}

Then irqchip_acpi_match_end will be the end of the table section,
which will terminate the scanning.

>
>> +
>> +extern struct acpi_table_id __irqchip_acpi_table[];
>> +
>> +void __init acpi_irqchip_init(void)
>> +{
>> +	struct acpi_table_id *id;
>> +
>> +	if (acpi_disabled)
>> +		return;
>> +
>> +	if (acpi_gic_version_init())
>> +		return;
>
> This is the only place where we need the version, right? So just get
> acpi_gic_version_init to return the version number, and loose the global
> variable.

The global variable is still needed because we need to get the GIC
version when scanning the MADT tables, we can't return the table value
directly in acpi_table_parse_madt() at now.

>
>> +
>> +	/* scan the irqchip table to match the GIC version and its driver */
>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>> +		if (gic_version == (u8)id->driver_data) {
>> +			acpi_table_parse(id->id,
>> +					 (acpi_tbl_table_handler)id->handler);
>> +			return;
>> +		}
>> +	}
>> +
>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>> +}
>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>> index 8bd374d..625776c 100644
>> --- a/include/asm-generic/vmlinux.lds.h
>> +++ b/include/asm-generic/vmlinux.lds.h
>> @@ -181,6 +181,18 @@
>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_TABLE(name)						\
>> +	. = ALIGN(8);							\
>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>> +	*(__##name##_acpi_table)					\
>> +	*(__##name##_acpi_table_end)
>> +
>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>> +#else
>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>> +#endif
>> +
>>   #define KERNEL_DTB()							\
>>   	STRUCT_ALIGN();							\
>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>> @@ -516,6 +528,7 @@
>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>   	KERNEL_DTB()							\
>>   	IRQCHIP_OF_MATCH_TABLE()					\
>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>   	EARLYCON_TABLE()						\
>>   	EARLYCON_OF_TABLES()
>>
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 0820cb1..04dd0bb 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>
>>   #endif
>>
>> +#ifdef CONFIG_ACPI
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__used __section(__##table##_acpi_table)		\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#else
>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>> +	static const struct acpi_table_id __acpi_table_##name		\
>> +		__attribute__((unused))					\
>> +		 = { .id = table_id,					\
>> +		     .handler = (void *)fn,				\
>> +		     .driver_data = data }
>> +#endif
>> +
>>   #endif	/*_LINUX_ACPI_H*/
>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>> index 6388873..6b66d3e 100644
>> --- a/include/linux/irqchip.h
>> +++ b/include/linux/irqchip.h
>> @@ -11,6 +11,7 @@
>>   #ifndef _LINUX_IRQCHIP_H
>>   #define _LINUX_IRQCHIP_H
>>
>> +#include <linux/acpi.h>
>>   #include <linux/of.h>
>>
>>   /*
>> @@ -25,6 +26,18 @@
>>    */
>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>
>> +/*
>> + * This macro must be used by the different ARM GIC drivers to declare
>> + * the association between their version and their initialization function.
>> + *
>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>> + * same file.
>> + * @gic_version: version of GIC
>> + * @fn: initialization function
>> + */
>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>
> I don't think this is the right approach. The MADT table has a *huge*
> number of possible subtables, and none of them is matched by the GIC
> version.
>
> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
> macro doesn't reflect this at all (you've basically cloned OF, and
> that's clearly not good enough).
>
> This probably require an intermediate matching function, ending up with
> something like:
>
> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
> 		subtable, version, fn)
>
> where match_madt_subtable is going to check that a given subtable is
> really suitable for a given irqchip. None of that should be GIC
> specific, really.

I'm little confused here, in the previous patch, the gic version is
stored, so we only need to match the GIC driver with the gic version.

In the GIC dirver itself, we will match the madt subtable to find
information we need to init the GIC, so I'm not sure why
match_madt_subtable in the ACPI_DECLARE, I think I missed something,
please correct me.

Thanks
Hanjun

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
  2015-08-04 13:17     ` Marc Zyngier
  (?)
@ 2015-08-05 14:00       ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:00 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 09:17 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>
>> 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.
>>
>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>> [hj: Rework this patch and fix multi issues]
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index c0b96c6..ebc5604 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>
>> @@ -25,6 +26,7 @@
>>   #include <linux/percpu.h>
>>   #include <linux/slab.h>
>>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>>   #include <linux/irqchip/arm-gic-v3.h>
>>
>>   #include <asm/cputype.h>
>> @@ -802,7 +804,8 @@ 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())
>> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
>> +		its_init(irq_domain_token_to_of_node(domain_token),
>> +			 &gic_data.rdists, gic_data.domain);
>
> This doesn't make much sense. The first parameter to its_init is indeed
> supposed to be an of_node, but what is the point of calling its_init if
> you *know* you don't have the necessary topological information to parse
> the firmware tables?
>
> I don't see *any* code that is going to parse the ITS table in this
> series, so please don't call its_init passing a NULL pointer to it. This
> is just gross.

OK, the ITS ACPI code is in later patch which combined with IORT. How
about moving it to the GIC of init code temporary?

>
>>
>>   	gic_smp_init();
>>   	gic_dist_init();
>> @@ -818,6 +821,16 @@ out_free:
>>   	return err;
>>   }
>>
>> +static int __init detect_distributor(void __iomem *dist_base)
>
> We do have a naming convention in this file. All functions start with gic_.
>
>> +{
>> +	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;
>> +}
>
> This function doesn't detect anything, it validates that we have
> something sensible. Please rename it to gic_validate_dist_version, or
> something similar.

Ok.

>
>> +
>>   #ifdef CONFIG_OF
>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>   {
>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   	struct redist_region *rdist_regs;
>>   	u64 redist_stride;
>>   	u32 nr_redist_regions;
>> -	u32 reg;
>>   	int err, i;
>>
>>   	dist_base = of_iomap(node, 0);
>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   		return -ENXIO;
>>   	}
>>
>> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>>   		pr_err("%s: no distributor detected, giving up\n",
>>   			node->full_name);
>> -		err = -ENODEV;
>>   		goto out_unmap_dist;
>>   	}
>>
>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>
>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>> +
>> +#ifdef CONFIG_ACPI
>> +static struct redist_region *redist_regs __initdata;
>> +static u32 nr_redist_regions __initdata;
>> +static phys_addr_t dist_phys_base __initdata;
>> +
>> +static int __init
>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>
> A physical address must use phys_addr_t.

OK.

>
>> +{
>> +	struct redist_region *redist_regs_new;
>> +	void __iomem *redist_base;
>> +
>> +	redist_regs_new = krealloc(redist_regs,
>> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
>> +				   GFP_KERNEL);
>
> NAK. If you have multiple regions, you count them, you allocate the
> right number of regions. This will be far more efficient than doing this
> realloc dance. It is not like we're not parsing the tables a zillion
> times already. Doing it one more time won't hurt.

Agreed, will update in next version.

>
>> +	if (!redist_regs_new) {
>> +		pr_err("Couldn't allocate resource for GICR region\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs = redist_regs_new;
>> +
>> +	redist_base = ioremap(phys_base, size);
>> +	if (!redist_base) {
>> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs[nr_redist_regions].phys_base = phys_base;
>> +	redist_regs[nr_redist_regions].redist_base = redist_base;
>> +	nr_redist_regions++;
>> +	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;
>> +
>> +	if (BAD_MADT_ENTRY(header, end))
>> +		return -EINVAL;
>> +
>> +	redist = (struct acpi_madt_generic_redistributor *)header;
>> +	if (!redist->base_address)
>> +		return -EINVAL;
>> +
>> +	return gic_acpi_register_redist(redist->base_address, redist->length);
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>> +				const unsigned long end)
>> +{
>
> How many versions of gic_acpi_parse_madt_distributor are we going to
> get? Why isn't the ACPI parsing in a common file? Why do I have to read
> the same code on and on until my eyes bleed?

I will try to move it to common file irq-gic-acpi.c.

>
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	dist_phys_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>> +				      u32 gsi, unsigned int irq_type)
>> +{
>> +	/*
>> +	 * Encode GSI and triggering information the way the GIC likes
>> +	 * them.
>> +	 */
>> +	if (WARN_ON(gsi < 16))
>> +		return -EINVAL;
>> +
>> +	if (gsi >= 32) {
>> +		data->param[0] = 0;		/* SPI */
>> +		data->param[1] = gsi - 32;
>> +		data->param[2] = irq_type;
>> +	} else {
>> +		data->param[0] = 1; 		/* PPI */
>> +		data->param[1] = gsi - 16;
>> +		data->param[2] = 0xff << 4 | irq_type;
>> +	}
>> +
>> +	data->param_count = 3;
>> +
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +gic_acpi_init(struct acpi_table_header *table)
>> +{
>> +	int count, i, err = 0;
>> +	void __iomem *dist_base;
>> +
>> +	/* Get distributor base address */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +				sizeof(struct acpi_table_madt),
>> +				gic_acpi_parse_madt_distributor, table,
>> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_err("No valid GICD entry exist\n");
>> +		return -EINVAL;
>> +	} else if (count > 1) {
>> +		pr_err("More than one GICD entry detected\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>> +	if (!dist_base) {
>> +		pr_err("Unable to map GICD registers\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>> +		pr_err("No distributor detected at @%p, giving up", dist_base);
>> +		goto out_dist_unmap;
>> +	}
>> +
>> +	/* Collect redistributor base addresses */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +			sizeof(struct acpi_table_madt),
>> +			gic_acpi_parse_madt_redist, table,
>> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_info("No valid GICR entries exist\n");
>> +		err = -EINVAL;
>> +		goto out_redist_unmap;
>> +	}
>> +
>> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>> +			     (void *)ACPI_IRQ_MODEL_GIC);
>
> There is no other global identifier for GICv3? It feels a bit weird to
> use the same ID as GICv2 (though probably not harmful as you can't have
> both as the same time). What are you planning to use for the ITS then?
> You must make sure you have a global namespace.

I will use the ITS physical base address as the token for ITS, maybe I
can use the GICD physical base address here instead?

>
>> +	if (err)
>> +		goto out_redist_unmap;
>> +
>> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>> +			   gic_acpi_gsi_desc_populate);
>> +	return 0;
>> +
>> +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_GIC_VERSION_V3, gic_acpi_init);
>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>
> As mentioned before, this doesn't work.

hmm, I think we need more discussion for this one, but we need to match
V4 for GICv3 drivers, and everything will be the same in the dirver
as I said before.

Thanks
Hanjun

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-05 14:00       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:00 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 09:17 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>
>> 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.
>>
>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>> [hj: Rework this patch and fix multi issues]
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index c0b96c6..ebc5604 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>
>> @@ -25,6 +26,7 @@
>>   #include <linux/percpu.h>
>>   #include <linux/slab.h>
>>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>>   #include <linux/irqchip/arm-gic-v3.h>
>>
>>   #include <asm/cputype.h>
>> @@ -802,7 +804,8 @@ 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())
>> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
>> +		its_init(irq_domain_token_to_of_node(domain_token),
>> +			 &gic_data.rdists, gic_data.domain);
>
> This doesn't make much sense. The first parameter to its_init is indeed
> supposed to be an of_node, but what is the point of calling its_init if
> you *know* you don't have the necessary topological information to parse
> the firmware tables?
>
> I don't see *any* code that is going to parse the ITS table in this
> series, so please don't call its_init passing a NULL pointer to it. This
> is just gross.

OK, the ITS ACPI code is in later patch which combined with IORT. How
about moving it to the GIC of init code temporary?

>
>>
>>   	gic_smp_init();
>>   	gic_dist_init();
>> @@ -818,6 +821,16 @@ out_free:
>>   	return err;
>>   }
>>
>> +static int __init detect_distributor(void __iomem *dist_base)
>
> We do have a naming convention in this file. All functions start with gic_.
>
>> +{
>> +	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;
>> +}
>
> This function doesn't detect anything, it validates that we have
> something sensible. Please rename it to gic_validate_dist_version, or
> something similar.

Ok.

>
>> +
>>   #ifdef CONFIG_OF
>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>   {
>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   	struct redist_region *rdist_regs;
>>   	u64 redist_stride;
>>   	u32 nr_redist_regions;
>> -	u32 reg;
>>   	int err, i;
>>
>>   	dist_base = of_iomap(node, 0);
>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   		return -ENXIO;
>>   	}
>>
>> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>>   		pr_err("%s: no distributor detected, giving up\n",
>>   			node->full_name);
>> -		err = -ENODEV;
>>   		goto out_unmap_dist;
>>   	}
>>
>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>
>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>> +
>> +#ifdef CONFIG_ACPI
>> +static struct redist_region *redist_regs __initdata;
>> +static u32 nr_redist_regions __initdata;
>> +static phys_addr_t dist_phys_base __initdata;
>> +
>> +static int __init
>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>
> A physical address must use phys_addr_t.

OK.

>
>> +{
>> +	struct redist_region *redist_regs_new;
>> +	void __iomem *redist_base;
>> +
>> +	redist_regs_new = krealloc(redist_regs,
>> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
>> +				   GFP_KERNEL);
>
> NAK. If you have multiple regions, you count them, you allocate the
> right number of regions. This will be far more efficient than doing this
> realloc dance. It is not like we're not parsing the tables a zillion
> times already. Doing it one more time won't hurt.

Agreed, will update in next version.

>
>> +	if (!redist_regs_new) {
>> +		pr_err("Couldn't allocate resource for GICR region\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs = redist_regs_new;
>> +
>> +	redist_base = ioremap(phys_base, size);
>> +	if (!redist_base) {
>> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs[nr_redist_regions].phys_base = phys_base;
>> +	redist_regs[nr_redist_regions].redist_base = redist_base;
>> +	nr_redist_regions++;
>> +	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;
>> +
>> +	if (BAD_MADT_ENTRY(header, end))
>> +		return -EINVAL;
>> +
>> +	redist = (struct acpi_madt_generic_redistributor *)header;
>> +	if (!redist->base_address)
>> +		return -EINVAL;
>> +
>> +	return gic_acpi_register_redist(redist->base_address, redist->length);
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>> +				const unsigned long end)
>> +{
>
> How many versions of gic_acpi_parse_madt_distributor are we going to
> get? Why isn't the ACPI parsing in a common file? Why do I have to read
> the same code on and on until my eyes bleed?

I will try to move it to common file irq-gic-acpi.c.

>
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	dist_phys_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>> +				      u32 gsi, unsigned int irq_type)
>> +{
>> +	/*
>> +	 * Encode GSI and triggering information the way the GIC likes
>> +	 * them.
>> +	 */
>> +	if (WARN_ON(gsi < 16))
>> +		return -EINVAL;
>> +
>> +	if (gsi >= 32) {
>> +		data->param[0] = 0;		/* SPI */
>> +		data->param[1] = gsi - 32;
>> +		data->param[2] = irq_type;
>> +	} else {
>> +		data->param[0] = 1; 		/* PPI */
>> +		data->param[1] = gsi - 16;
>> +		data->param[2] = 0xff << 4 | irq_type;
>> +	}
>> +
>> +	data->param_count = 3;
>> +
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +gic_acpi_init(struct acpi_table_header *table)
>> +{
>> +	int count, i, err = 0;
>> +	void __iomem *dist_base;
>> +
>> +	/* Get distributor base address */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +				sizeof(struct acpi_table_madt),
>> +				gic_acpi_parse_madt_distributor, table,
>> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_err("No valid GICD entry exist\n");
>> +		return -EINVAL;
>> +	} else if (count > 1) {
>> +		pr_err("More than one GICD entry detected\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>> +	if (!dist_base) {
>> +		pr_err("Unable to map GICD registers\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>> +		pr_err("No distributor detected at @%p, giving up", dist_base);
>> +		goto out_dist_unmap;
>> +	}
>> +
>> +	/* Collect redistributor base addresses */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +			sizeof(struct acpi_table_madt),
>> +			gic_acpi_parse_madt_redist, table,
>> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_info("No valid GICR entries exist\n");
>> +		err = -EINVAL;
>> +		goto out_redist_unmap;
>> +	}
>> +
>> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>> +			     (void *)ACPI_IRQ_MODEL_GIC);
>
> There is no other global identifier for GICv3? It feels a bit weird to
> use the same ID as GICv2 (though probably not harmful as you can't have
> both as the same time). What are you planning to use for the ITS then?
> You must make sure you have a global namespace.

I will use the ITS physical base address as the token for ITS, maybe I
can use the GICD physical base address here instead?

>
>> +	if (err)
>> +		goto out_redist_unmap;
>> +
>> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>> +			   gic_acpi_gsi_desc_populate);
>> +	return 0;
>> +
>> +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_GIC_VERSION_V3, gic_acpi_init);
>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>
> As mentioned before, this doesn't work.

hmm, I think we need more discussion for this one, but we need to match
V4 for GICv3 drivers, and everything will be the same in the dirver
as I said before.

Thanks
Hanjun

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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-05 14:00       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/04/2015 09:17 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>
>> 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.
>>
>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>> [hj: Rework this patch and fix multi issues]
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index c0b96c6..ebc5604 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>
>> @@ -25,6 +26,7 @@
>>   #include <linux/percpu.h>
>>   #include <linux/slab.h>
>>
>> +#include <linux/irqchip/arm-gic-acpi.h>
>>   #include <linux/irqchip/arm-gic-v3.h>
>>
>>   #include <asm/cputype.h>
>> @@ -802,7 +804,8 @@ 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())
>> -		its_init(domain_token, &gic_data.rdists, gic_data.domain);
>> +		its_init(irq_domain_token_to_of_node(domain_token),
>> +			 &gic_data.rdists, gic_data.domain);
>
> This doesn't make much sense. The first parameter to its_init is indeed
> supposed to be an of_node, but what is the point of calling its_init if
> you *know* you don't have the necessary topological information to parse
> the firmware tables?
>
> I don't see *any* code that is going to parse the ITS table in this
> series, so please don't call its_init passing a NULL pointer to it. This
> is just gross.

OK, the ITS ACPI code is in later patch which combined with IORT. How
about moving it to the GIC of init code temporary?

>
>>
>>   	gic_smp_init();
>>   	gic_dist_init();
>> @@ -818,6 +821,16 @@ out_free:
>>   	return err;
>>   }
>>
>> +static int __init detect_distributor(void __iomem *dist_base)
>
> We do have a naming convention in this file. All functions start with gic_.
>
>> +{
>> +	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;
>> +}
>
> This function doesn't detect anything, it validates that we have
> something sensible. Please rename it to gic_validate_dist_version, or
> something similar.

Ok.

>
>> +
>>   #ifdef CONFIG_OF
>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>   {
>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   	struct redist_region *rdist_regs;
>>   	u64 redist_stride;
>>   	u32 nr_redist_regions;
>> -	u32 reg;
>>   	int err, i;
>>
>>   	dist_base = of_iomap(node, 0);
>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>   		return -ENXIO;
>>   	}
>>
>> -	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> -	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>>   		pr_err("%s: no distributor detected, giving up\n",
>>   			node->full_name);
>> -		err = -ENODEV;
>>   		goto out_unmap_dist;
>>   	}
>>
>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>
>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>> +
>> +#ifdef CONFIG_ACPI
>> +static struct redist_region *redist_regs __initdata;
>> +static u32 nr_redist_regions __initdata;
>> +static phys_addr_t dist_phys_base __initdata;
>> +
>> +static int __init
>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>
> A physical address must use phys_addr_t.

OK.

>
>> +{
>> +	struct redist_region *redist_regs_new;
>> +	void __iomem *redist_base;
>> +
>> +	redist_regs_new = krealloc(redist_regs,
>> +				   sizeof(*redist_regs) * (nr_redist_regions + 1),
>> +				   GFP_KERNEL);
>
> NAK. If you have multiple regions, you count them, you allocate the
> right number of regions. This will be far more efficient than doing this
> realloc dance. It is not like we're not parsing the tables a zillion
> times already. Doing it one more time won't hurt.

Agreed, will update in next version.

>
>> +	if (!redist_regs_new) {
>> +		pr_err("Couldn't allocate resource for GICR region\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs = redist_regs_new;
>> +
>> +	redist_base = ioremap(phys_base, size);
>> +	if (!redist_base) {
>> +		pr_err("Couldn't map GICR region @%llx\n", phys_base);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	redist_regs[nr_redist_regions].phys_base = phys_base;
>> +	redist_regs[nr_redist_regions].redist_base = redist_base;
>> +	nr_redist_regions++;
>> +	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;
>> +
>> +	if (BAD_MADT_ENTRY(header, end))
>> +		return -EINVAL;
>> +
>> +	redist = (struct acpi_madt_generic_redistributor *)header;
>> +	if (!redist->base_address)
>> +		return -EINVAL;
>> +
>> +	return gic_acpi_register_redist(redist->base_address, redist->length);
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>> +				const unsigned long end)
>> +{
>
> How many versions of gic_acpi_parse_madt_distributor are we going to
> get? Why isn't the ACPI parsing in a common file? Why do I have to read
> the same code on and on until my eyes bleed?

I will try to move it to common file irq-gic-acpi.c.

>
>> +	struct acpi_madt_generic_distributor *dist;
>> +
>> +	dist = (struct acpi_madt_generic_distributor *)header;
>> +
>> +	if (BAD_MADT_ENTRY(dist, end))
>> +		return -EINVAL;
>> +
>> +	dist_phys_base = dist->base_address;
>> +	return 0;
>> +}
>> +
>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>> +				      u32 gsi, unsigned int irq_type)
>> +{
>> +	/*
>> +	 * Encode GSI and triggering information the way the GIC likes
>> +	 * them.
>> +	 */
>> +	if (WARN_ON(gsi < 16))
>> +		return -EINVAL;
>> +
>> +	if (gsi >= 32) {
>> +		data->param[0] = 0;		/* SPI */
>> +		data->param[1] = gsi - 32;
>> +		data->param[2] = irq_type;
>> +	} else {
>> +		data->param[0] = 1; 		/* PPI */
>> +		data->param[1] = gsi - 16;
>> +		data->param[2] = 0xff << 4 | irq_type;
>> +	}
>> +
>> +	data->param_count = 3;
>> +
>> +	return 0;
>> +}
>> +
>> +static int __init
>> +gic_acpi_init(struct acpi_table_header *table)
>> +{
>> +	int count, i, err = 0;
>> +	void __iomem *dist_base;
>> +
>> +	/* Get distributor base address */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +				sizeof(struct acpi_table_madt),
>> +				gic_acpi_parse_madt_distributor, table,
>> +				ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_err("No valid GICD entry exist\n");
>> +		return -EINVAL;
>> +	} else if (count > 1) {
>> +		pr_err("More than one GICD entry detected\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>> +	if (!dist_base) {
>> +		pr_err("Unable to map GICD registers\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	err = detect_distributor(dist_base);
>> +	if (err) {
>> +		pr_err("No distributor detected at @%p, giving up", dist_base);
>> +		goto out_dist_unmap;
>> +	}
>> +
>> +	/* Collect redistributor base addresses */
>> +	count = acpi_parse_entries(ACPI_SIG_MADT,
>> +			sizeof(struct acpi_table_madt),
>> +			gic_acpi_parse_madt_redist, table,
>> +			ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +	if (count <= 0) {
>> +		pr_info("No valid GICR entries exist\n");
>> +		err = -EINVAL;
>> +		goto out_redist_unmap;
>> +	}
>> +
>> +	err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>> +			     (void *)ACPI_IRQ_MODEL_GIC);
>
> There is no other global identifier for GICv3? It feels a bit weird to
> use the same ID as GICv2 (though probably not harmful as you can't have
> both as the same time). What are you planning to use for the ITS then?
> You must make sure you have a global namespace.

I will use the ITS physical base address as the token for ITS, maybe I
can use the GICD physical base address here instead?

>
>> +	if (err)
>> +		goto out_redist_unmap;
>> +
>> +	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>> +			   gic_acpi_gsi_desc_populate);
>> +	return 0;
>> +
>> +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_GIC_VERSION_V3, gic_acpi_init);
>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>
> As mentioned before, this doesn't work.

hmm, I think we need more discussion for this one, but we need to match
V4 for GICv3 drivers, and everything will be the same in the dirver
as I said before.

Thanks
Hanjun

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
  2015-08-04 13:37     ` Marc Zyngier
  (?)
@ 2015-08-05 14:11       ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:11 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 09:37 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> 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.
>>
>> As GICR base in MADT GICC is another way to indicate the GIC version
>> is 3 or 4, add its support to find out the GIC versions.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 95454e3..3e5c8f4 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>
>>   static phys_addr_t dist_phy_base __initdata;
>>
>> +u8 __init acpi_gic_version(void)
>> +{
>> +       return gic_version;
>> +}
>> +
>>   static int __init
>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>                             const unsigned long end)
>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>   }
>>
>>   static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * If GICC is enabled but has no valid gicr base address, then it
>> +        * means GICR base is not presented via GICC
>> +        */
>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>> +               return -ENODEV;
>> +
>> +       return 0;
>> +}
>> +
>> +static int __init
>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>   {
>>          return 0;
>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>                                          match_gic_redist, 0);
>>
>> -       /* that's true if we have at least one GIC redistributor entry */
>> +       /* has at least one GIC redistributor entry */
>> +       if (count > 0)
>> +               return true;
>> +
>> +       /* else try to find GICR base in GICC entries */
>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>> +                                     gic_acpi_parse_madt_gicc, 0);
>> +
>>          return count > 0;
>>   }
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index ebc5604..b72ccbb 100644
>> --- a/drivers/irqchip/irq-gic-v3.c
>> +++ b/drivers/irqchip/irq-gic-v3.c
>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>   }
>>
>> -static int gic_populate_rdist(void)
>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>   {
>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>          u64 typer;
>>          u32 aff;
>>          int i;
>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>                  } while (!(typer & GICR_TYPER_LAST));
>>          }
>>
>> +       return -ENODEV;
>> +}
>> +
>> +#ifdef CONFIG_ACPI
>> +/*
>> + * Populate redist when GIC redistributor address is presented in ACPI
>> + * MADT GICC entries
>> + */
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>> +#else
>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       return -ENODEV;
>> +}
>> +#endif
>> +
>> +static int gic_populate_rdist(void)
>> +{
>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>> +
>> +       if (gic_data.nr_redist_regions) {
>> +               if (!gic_populate_rdist_with_regions(mpidr))
>> +                       return 0;
>> +       } else {
>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>> +                       return 0;
>> +       }
>> +
>>          /* We couldn't even deal with ourselves... */
>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>               smp_processor_id(), (unsigned long long)mpidr);
>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>>
>>   #ifdef CONFIG_ACPI
>> +
>> +struct acpi_gicc_redist {
>> +       struct list_head list;
>> +       u64 mpidr;
>> +       phys_addr_t phys_base;
>> +       void __iomem *redist_base;
>> +};
>> +
>> +static LIST_HEAD(redist_list);
>> +
>>   static struct redist_region *redist_regs __initdata;
>>   static u32 nr_redist_regions __initdata;
>>   static phys_addr_t dist_phys_base __initdata;
>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>          return 0;
>>   }
>>
>> +static void __init
>> +gic_acpi_release_redist_regions(void)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < nr_redist_regions; i++)
>> +               if (redist_regs[i].redist_base)
>> +                       iounmap(redist_regs[i].redist_base);
>> +       kfree(redist_regs);
>> +}
>> +
>>   static int __init
>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>                          const unsigned long end)
>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>   }
>>
>>   static int __init
>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +
>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>> +       if (!redist)
>> +               return -ENOMEM;
>> +
>> +       redist->mpidr = mpidr;
>> +       redist->phys_base = phys_base;
>> +
>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>> +               /* RD_base + SGI_base */
>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>> +       else
>> +               /*
>> +                * RD_base + SGI_base + VLPI_base,
>> +                * we don't map reserved page as it's buggy to access it
>> +                */
>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>> +
>> +       if (!redist->redist_base) {
>> +               kfree(redist);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       list_add(&redist->list, &redist_list);
>> +       return 0;
>> +}
>> +
>> +static void __init
>> +gic_acpi_release_gicc_redist(void)
>> +{
>> +       struct acpi_gicc_redist *redist, *t;
>> +
>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>> +               list_del(&redist->list);
>> +               iounmap(redist->redist_base);
>> +               kfree(redist);
>> +       }
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * just quietly ingore the disabled CPU(s) and continue
>> +        * to find the enabled one(s), if we return error here,
>> +        * the scanning will be stopped.
>> +        */
>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>> +               return 0;
>> +
>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>> +                                       gicc->arm_mpidr);
>> +}
>> +
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +       void __iomem *ptr;
>> +       u32 reg;
>> +
>> +       list_for_each_entry(redist, &redist_list, list) {
>> +               if (redist->mpidr != mpidr)
>> +                       continue;
>> +
>> +               ptr = redist->redist_base;
>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +                       pr_warn("No redistributor present @%p\n", ptr);
>> +                       return -ENODEV;
>> +               }
>> +
>> +               gic_data_rdist_rd_base() = ptr;
>> +               gic_data_rdist()->phys_base = redist->phys_base;
>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>> +                       smp_processor_id(),
>> +                       (unsigned long long)mpidr,
>> +                       &gic_data_rdist()->phys_base);
>> +               return 0;
>> +       }
>> +
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>> +{
>> +       int count;
>> +
>> +       /* Collect redistributor base addresses in GICR entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_redist, table,
>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +       if (count > 0)
>> +               return 0;
>> +
>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>> +
>> +       /* Collect redistributor base addresses in GICC entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_gicc, table,
>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>> +       if (count > 0 && !list_empty(&redist_list))
>> +               return 0;
>> +
>> +       pr_info("No valid GICC entries exist for GICR base\n");
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init
>>   gic_acpi_init(struct acpi_table_header *table)
>>   {
>> -       int count, i, err = 0;
>> +       int count, err = 0;
>>          void __iomem *dist_base;
>>
>>          /* Get distributor base address */
>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>          }
>>
>>          /* Collect redistributor base addresses */
>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>> -                       sizeof(struct acpi_table_madt),
>> -                       gic_acpi_parse_madt_redist, table,
>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> -       if (count <= 0) {
>> -               pr_info("No valid GICR entries exist\n");
>> -               err = -EINVAL;
>> -               goto out_redist_unmap;
>> -       }
>> +       if (collect_gicr_base(table))
>> +               goto out_release_redist;
>>
>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>          if (err)
>> -               goto out_redist_unmap;
>> +               goto out_release_redist;
>>
>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>                             gic_acpi_gsi_desc_populate);
>>          return 0;
>>
>> -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_release_redist:
>> +       gic_acpi_release_redist_regions();
>> +       if (!list_empty(&redist_list))
>> +               gic_acpi_release_gicc_redist();
>>   out_dist_unmap:
>>          iounmap(dist_base);
>>          return err;
>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>> index 56cd82c..0d43f515 100644
>> --- a/include/linux/irqchip/arm-gic-acpi.h
>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>> @@ -21,5 +21,7 @@
>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>
>> +u8 acpi_gic_version(void);
>> +
>>   #endif /* CONFIG_ACPI */
>>   #endif /* ARM_GIC_ACPI_H_ */
>> --
>> 1.9.1
>>
>
> This looks absolutely horrid. Why don't you simply populate one region
> per redistributor, add a flag to struct redist_region so we know not to
> check for GICR_TYPER_LAST but to move on to the next region instead?

There is no regions in GICC structures, and only have the GICR base
address for each CPU, I think we can't figure out which GICR bases
are belonging to a GICR region.

So do you mean populate each GICR base as a region, and use the
existing infrastructure ?

Thanks
Hanjun

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-05 14:11       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:11 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 09:37 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> 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.
>>
>> As GICR base in MADT GICC is another way to indicate the GIC version
>> is 3 or 4, add its support to find out the GIC versions.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 95454e3..3e5c8f4 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>
>>   static phys_addr_t dist_phy_base __initdata;
>>
>> +u8 __init acpi_gic_version(void)
>> +{
>> +       return gic_version;
>> +}
>> +
>>   static int __init
>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>                             const unsigned long end)
>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>   }
>>
>>   static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * If GICC is enabled but has no valid gicr base address, then it
>> +        * means GICR base is not presented via GICC
>> +        */
>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>> +               return -ENODEV;
>> +
>> +       return 0;
>> +}
>> +
>> +static int __init
>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>   {
>>          return 0;
>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>                                          match_gic_redist, 0);
>>
>> -       /* that's true if we have at least one GIC redistributor entry */
>> +       /* has at least one GIC redistributor entry */
>> +       if (count > 0)
>> +               return true;
>> +
>> +       /* else try to find GICR base in GICC entries */
>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>> +                                     gic_acpi_parse_madt_gicc, 0);
>> +
>>          return count > 0;
>>   }
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index ebc5604..b72ccbb 100644
>> --- a/drivers/irqchip/irq-gic-v3.c
>> +++ b/drivers/irqchip/irq-gic-v3.c
>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>   }
>>
>> -static int gic_populate_rdist(void)
>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>   {
>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>          u64 typer;
>>          u32 aff;
>>          int i;
>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>                  } while (!(typer & GICR_TYPER_LAST));
>>          }
>>
>> +       return -ENODEV;
>> +}
>> +
>> +#ifdef CONFIG_ACPI
>> +/*
>> + * Populate redist when GIC redistributor address is presented in ACPI
>> + * MADT GICC entries
>> + */
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>> +#else
>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       return -ENODEV;
>> +}
>> +#endif
>> +
>> +static int gic_populate_rdist(void)
>> +{
>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>> +
>> +       if (gic_data.nr_redist_regions) {
>> +               if (!gic_populate_rdist_with_regions(mpidr))
>> +                       return 0;
>> +       } else {
>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>> +                       return 0;
>> +       }
>> +
>>          /* We couldn't even deal with ourselves... */
>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>               smp_processor_id(), (unsigned long long)mpidr);
>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>>
>>   #ifdef CONFIG_ACPI
>> +
>> +struct acpi_gicc_redist {
>> +       struct list_head list;
>> +       u64 mpidr;
>> +       phys_addr_t phys_base;
>> +       void __iomem *redist_base;
>> +};
>> +
>> +static LIST_HEAD(redist_list);
>> +
>>   static struct redist_region *redist_regs __initdata;
>>   static u32 nr_redist_regions __initdata;
>>   static phys_addr_t dist_phys_base __initdata;
>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>          return 0;
>>   }
>>
>> +static void __init
>> +gic_acpi_release_redist_regions(void)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < nr_redist_regions; i++)
>> +               if (redist_regs[i].redist_base)
>> +                       iounmap(redist_regs[i].redist_base);
>> +       kfree(redist_regs);
>> +}
>> +
>>   static int __init
>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>                          const unsigned long end)
>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>   }
>>
>>   static int __init
>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +
>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>> +       if (!redist)
>> +               return -ENOMEM;
>> +
>> +       redist->mpidr = mpidr;
>> +       redist->phys_base = phys_base;
>> +
>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>> +               /* RD_base + SGI_base */
>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>> +       else
>> +               /*
>> +                * RD_base + SGI_base + VLPI_base,
>> +                * we don't map reserved page as it's buggy to access it
>> +                */
>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>> +
>> +       if (!redist->redist_base) {
>> +               kfree(redist);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       list_add(&redist->list, &redist_list);
>> +       return 0;
>> +}
>> +
>> +static void __init
>> +gic_acpi_release_gicc_redist(void)
>> +{
>> +       struct acpi_gicc_redist *redist, *t;
>> +
>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>> +               list_del(&redist->list);
>> +               iounmap(redist->redist_base);
>> +               kfree(redist);
>> +       }
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * just quietly ingore the disabled CPU(s) and continue
>> +        * to find the enabled one(s), if we return error here,
>> +        * the scanning will be stopped.
>> +        */
>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>> +               return 0;
>> +
>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>> +                                       gicc->arm_mpidr);
>> +}
>> +
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +       void __iomem *ptr;
>> +       u32 reg;
>> +
>> +       list_for_each_entry(redist, &redist_list, list) {
>> +               if (redist->mpidr != mpidr)
>> +                       continue;
>> +
>> +               ptr = redist->redist_base;
>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +                       pr_warn("No redistributor present @%p\n", ptr);
>> +                       return -ENODEV;
>> +               }
>> +
>> +               gic_data_rdist_rd_base() = ptr;
>> +               gic_data_rdist()->phys_base = redist->phys_base;
>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>> +                       smp_processor_id(),
>> +                       (unsigned long long)mpidr,
>> +                       &gic_data_rdist()->phys_base);
>> +               return 0;
>> +       }
>> +
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>> +{
>> +       int count;
>> +
>> +       /* Collect redistributor base addresses in GICR entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_redist, table,
>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +       if (count > 0)
>> +               return 0;
>> +
>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>> +
>> +       /* Collect redistributor base addresses in GICC entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_gicc, table,
>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>> +       if (count > 0 && !list_empty(&redist_list))
>> +               return 0;
>> +
>> +       pr_info("No valid GICC entries exist for GICR base\n");
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init
>>   gic_acpi_init(struct acpi_table_header *table)
>>   {
>> -       int count, i, err = 0;
>> +       int count, err = 0;
>>          void __iomem *dist_base;
>>
>>          /* Get distributor base address */
>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>          }
>>
>>          /* Collect redistributor base addresses */
>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>> -                       sizeof(struct acpi_table_madt),
>> -                       gic_acpi_parse_madt_redist, table,
>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> -       if (count <= 0) {
>> -               pr_info("No valid GICR entries exist\n");
>> -               err = -EINVAL;
>> -               goto out_redist_unmap;
>> -       }
>> +       if (collect_gicr_base(table))
>> +               goto out_release_redist;
>>
>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>          if (err)
>> -               goto out_redist_unmap;
>> +               goto out_release_redist;
>>
>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>                             gic_acpi_gsi_desc_populate);
>>          return 0;
>>
>> -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_release_redist:
>> +       gic_acpi_release_redist_regions();
>> +       if (!list_empty(&redist_list))
>> +               gic_acpi_release_gicc_redist();
>>   out_dist_unmap:
>>          iounmap(dist_base);
>>          return err;
>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>> index 56cd82c..0d43f515 100644
>> --- a/include/linux/irqchip/arm-gic-acpi.h
>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>> @@ -21,5 +21,7 @@
>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>
>> +u8 acpi_gic_version(void);
>> +
>>   #endif /* CONFIG_ACPI */
>>   #endif /* ARM_GIC_ACPI_H_ */
>> --
>> 1.9.1
>>
>
> This looks absolutely horrid. Why don't you simply populate one region
> per redistributor, add a flag to struct redist_region so we know not to
> check for GICR_TYPER_LAST but to move on to the next region instead?

There is no regions in GICC structures, and only have the GICR base
address for each CPU, I think we can't figure out which GICR bases
are belonging to a GICR region.

So do you mean populate each GICR base as a region, and use the
existing infrastructure ?

Thanks
Hanjun

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

* [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-05 14:11       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-05 14:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/04/2015 09:37 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> 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.
>>
>> As GICR base in MADT GICC is another way to indicate the GIC version
>> is 3 or 4, add its support to find out the GIC versions.
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>> index 95454e3..3e5c8f4 100644
>> --- a/drivers/irqchip/irq-gic-acpi.c
>> +++ b/drivers/irqchip/irq-gic-acpi.c
>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>
>>   static phys_addr_t dist_phy_base __initdata;
>>
>> +u8 __init acpi_gic_version(void)
>> +{
>> +       return gic_version;
>> +}
>> +
>>   static int __init
>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>                             const unsigned long end)
>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>   }
>>
>>   static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * If GICC is enabled but has no valid gicr base address, then it
>> +        * means GICR base is not presented via GICC
>> +        */
>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>> +               return -ENODEV;
>> +
>> +       return 0;
>> +}
>> +
>> +static int __init
>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>   {
>>          return 0;
>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>                                          match_gic_redist, 0);
>>
>> -       /* that's true if we have at least one GIC redistributor entry */
>> +       /* has at least one GIC redistributor entry */
>> +       if (count > 0)
>> +               return true;
>> +
>> +       /* else try to find GICR base in GICC entries */
>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>> +                                     gic_acpi_parse_madt_gicc, 0);
>> +
>>          return count > 0;
>>   }
>>
>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>> index ebc5604..b72ccbb 100644
>> --- a/drivers/irqchip/irq-gic-v3.c
>> +++ b/drivers/irqchip/irq-gic-v3.c
>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>   }
>>
>> -static int gic_populate_rdist(void)
>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>   {
>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>          u64 typer;
>>          u32 aff;
>>          int i;
>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>                  } while (!(typer & GICR_TYPER_LAST));
>>          }
>>
>> +       return -ENODEV;
>> +}
>> +
>> +#ifdef CONFIG_ACPI
>> +/*
>> + * Populate redist when GIC redistributor address is presented in ACPI
>> + * MADT GICC entries
>> + */
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>> +#else
>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       return -ENODEV;
>> +}
>> +#endif
>> +
>> +static int gic_populate_rdist(void)
>> +{
>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>> +
>> +       if (gic_data.nr_redist_regions) {
>> +               if (!gic_populate_rdist_with_regions(mpidr))
>> +                       return 0;
>> +       } else {
>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>> +                       return 0;
>> +       }
>> +
>>          /* We couldn't even deal with ourselves... */
>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>               smp_processor_id(), (unsigned long long)mpidr);
>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>   #endif
>>
>>   #ifdef CONFIG_ACPI
>> +
>> +struct acpi_gicc_redist {
>> +       struct list_head list;
>> +       u64 mpidr;
>> +       phys_addr_t phys_base;
>> +       void __iomem *redist_base;
>> +};
>> +
>> +static LIST_HEAD(redist_list);
>> +
>>   static struct redist_region *redist_regs __initdata;
>>   static u32 nr_redist_regions __initdata;
>>   static phys_addr_t dist_phys_base __initdata;
>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>          return 0;
>>   }
>>
>> +static void __init
>> +gic_acpi_release_redist_regions(void)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < nr_redist_regions; i++)
>> +               if (redist_regs[i].redist_base)
>> +                       iounmap(redist_regs[i].redist_base);
>> +       kfree(redist_regs);
>> +}
>> +
>>   static int __init
>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>                          const unsigned long end)
>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>   }
>>
>>   static int __init
>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +
>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>> +       if (!redist)
>> +               return -ENOMEM;
>> +
>> +       redist->mpidr = mpidr;
>> +       redist->phys_base = phys_base;
>> +
>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>> +               /* RD_base + SGI_base */
>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>> +       else
>> +               /*
>> +                * RD_base + SGI_base + VLPI_base,
>> +                * we don't map reserved page as it's buggy to access it
>> +                */
>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>> +
>> +       if (!redist->redist_base) {
>> +               kfree(redist);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       list_add(&redist->list, &redist_list);
>> +       return 0;
>> +}
>> +
>> +static void __init
>> +gic_acpi_release_gicc_redist(void)
>> +{
>> +       struct acpi_gicc_redist *redist, *t;
>> +
>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>> +               list_del(&redist->list);
>> +               iounmap(redist->redist_base);
>> +               kfree(redist);
>> +       }
>> +}
>> +
>> +static int __init
>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>> +                        const unsigned long end)
>> +{
>> +       struct acpi_madt_generic_interrupt *gicc;
>> +
>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>> +
>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * just quietly ingore the disabled CPU(s) and continue
>> +        * to find the enabled one(s), if we return error here,
>> +        * the scanning will be stopped.
>> +        */
>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>> +               return 0;
>> +
>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>> +                                       gicc->arm_mpidr);
>> +}
>> +
>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>> +{
>> +       struct acpi_gicc_redist *redist;
>> +       void __iomem *ptr;
>> +       u32 reg;
>> +
>> +       list_for_each_entry(redist, &redist_list, list) {
>> +               if (redist->mpidr != mpidr)
>> +                       continue;
>> +
>> +               ptr = redist->redist_base;
>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>> +                       pr_warn("No redistributor present @%p\n", ptr);
>> +                       return -ENODEV;
>> +               }
>> +
>> +               gic_data_rdist_rd_base() = ptr;
>> +               gic_data_rdist()->phys_base = redist->phys_base;
>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>> +                       smp_processor_id(),
>> +                       (unsigned long long)mpidr,
>> +                       &gic_data_rdist()->phys_base);
>> +               return 0;
>> +       }
>> +
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>> +{
>> +       int count;
>> +
>> +       /* Collect redistributor base addresses in GICR entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_redist, table,
>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> +       if (count > 0)
>> +               return 0;
>> +
>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>> +
>> +       /* Collect redistributor base addresses in GICC entries */
>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>> +                       sizeof(struct acpi_table_madt),
>> +                       gic_acpi_parse_madt_gicc, table,
>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>> +       if (count > 0 && !list_empty(&redist_list))
>> +               return 0;
>> +
>> +       pr_info("No valid GICC entries exist for GICR base\n");
>> +       return -ENODEV;
>> +}
>> +
>> +static int __init
>>   gic_acpi_init(struct acpi_table_header *table)
>>   {
>> -       int count, i, err = 0;
>> +       int count, err = 0;
>>          void __iomem *dist_base;
>>
>>          /* Get distributor base address */
>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>          }
>>
>>          /* Collect redistributor base addresses */
>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>> -                       sizeof(struct acpi_table_madt),
>> -                       gic_acpi_parse_madt_redist, table,
>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>> -       if (count <= 0) {
>> -               pr_info("No valid GICR entries exist\n");
>> -               err = -EINVAL;
>> -               goto out_redist_unmap;
>> -       }
>> +       if (collect_gicr_base(table))
>> +               goto out_release_redist;
>>
>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>          if (err)
>> -               goto out_redist_unmap;
>> +               goto out_release_redist;
>>
>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>                             gic_acpi_gsi_desc_populate);
>>          return 0;
>>
>> -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_release_redist:
>> +       gic_acpi_release_redist_regions();
>> +       if (!list_empty(&redist_list))
>> +               gic_acpi_release_gicc_redist();
>>   out_dist_unmap:
>>          iounmap(dist_base);
>>          return err;
>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>> index 56cd82c..0d43f515 100644
>> --- a/include/linux/irqchip/arm-gic-acpi.h
>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>> @@ -21,5 +21,7 @@
>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>
>> +u8 acpi_gic_version(void);
>> +
>>   #endif /* CONFIG_ACPI */
>>   #endif /* ARM_GIC_ACPI_H_ */
>> --
>> 1.9.1
>>
>
> This looks absolutely horrid. Why don't you simply populate one region
> per redistributor, add a flag to struct redist_region so we know not to
> check for GICR_TYPER_LAST but to move on to the next region instead?

There is no regions in GICC structures, and only have the GICR base
address for each CPU, I think we can't figure out which GICR bases
are belonging to a GICR region.

So do you mean populate each GICR base as a region, and use the
existing infrastructure ?

Thanks
Hanjun

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
  2015-08-05 13:24       ` Hanjun Guo
  (?)
@ 2015-08-06 16:29         ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:29 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 14:24, Hanjun Guo wrote:
> Hi Marc,
> 
> On 08/04/2015 08:27 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> This self-probe infrastructure works in the similar way as OF,
>>> but there is some different in the mechanism:
>>>
>>> For DT, the init fn will be called once it finds compatible strings
>>> in DT,  but for ACPI, we init irqchips by static tables, and in
>>> static ACPI tables, there are no compatible strings to indicate
>>> irqchips, but thanks to the GIC version presented in ACPI table,
>>> we can call the corresponding GIC drivers matching the GIC version
>>> with this framework.
>>>
>>> This mechanism can also be used for clock declare and may also works
>>> on x86 for some table parsing too.
>>>
>>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>>> work.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>>   include/linux/irqchip.h           | 13 +++++++++++++
>>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>>   5 files changed, 83 insertions(+)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 6537b43..011468d 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>>
>>>   	return 0;
>>>   }
>>> +
>>> +/*
>>> + * This special acpi_table_id is the sentinel at the end of the
>>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>>> + * the end of the array by the linker, thanks to being part of a
>>> + * special section.
>>> + */
>>> +static const struct acpi_table_id
>>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>>
>> What is this thing for? Nobody refers to it (I know
>> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
>> reason...).
> 
> If I'm not mistaken, this is for proper section termination, please
> see below:
> 
> /* scan the irqchip table to match the GIC version and its driver */
> for (id = __irqchip_acpi_table; id->id[0]; id++) {
> ...
> }
> 
> Then irqchip_acpi_match_end will be the end of the table section,
> which will terminate the scanning.

Yeah, I got that bit, but I didn't realized this was getting pulled into
the section. It's probably fine then.

>>
>>> +
>>> +extern struct acpi_table_id __irqchip_acpi_table[];
>>> +
>>> +void __init acpi_irqchip_init(void)
>>> +{
>>> +	struct acpi_table_id *id;
>>> +
>>> +	if (acpi_disabled)
>>> +		return;
>>> +
>>> +	if (acpi_gic_version_init())
>>> +		return;
>>
>> This is the only place where we need the version, right? So just get
>> acpi_gic_version_init to return the version number, and loose the global
>> variable.
> 
> The global variable is still needed because we need to get the GIC
> version when scanning the MADT tables, we can't return the table value
> directly in acpi_table_parse_madt() at now.
> 
>>
>>> +
>>> +	/* scan the irqchip table to match the GIC version and its driver */
>>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>>> +		if (gic_version == (u8)id->driver_data) {
>>> +			acpi_table_parse(id->id,
>>> +					 (acpi_tbl_table_handler)id->handler);
>>> +			return;
>>> +		}
>>> +	}
>>> +
>>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>>> +}
>>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>>> index 8bd374d..625776c 100644
>>> --- a/include/asm-generic/vmlinux.lds.h
>>> +++ b/include/asm-generic/vmlinux.lds.h
>>> @@ -181,6 +181,18 @@
>>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_TABLE(name)						\
>>> +	. = ALIGN(8);							\
>>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>>> +	*(__##name##_acpi_table)					\
>>> +	*(__##name##_acpi_table_end)
>>> +
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>>> +#else
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>>> +#endif
>>> +
>>>   #define KERNEL_DTB()							\
>>>   	STRUCT_ALIGN();							\
>>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>>> @@ -516,6 +528,7 @@
>>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>>   	KERNEL_DTB()							\
>>>   	IRQCHIP_OF_MATCH_TABLE()					\
>>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>>   	EARLYCON_TABLE()						\
>>>   	EARLYCON_OF_TABLES()
>>>
>>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>>> index 0820cb1..04dd0bb 100644
>>> --- a/include/linux/acpi.h
>>> +++ b/include/linux/acpi.h
>>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>>
>>>   #endif
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__used __section(__##table##_acpi_table)		\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#else
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__attribute__((unused))					\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#endif
>>> +
>>>   #endif	/*_LINUX_ACPI_H*/
>>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>>> index 6388873..6b66d3e 100644
>>> --- a/include/linux/irqchip.h
>>> +++ b/include/linux/irqchip.h
>>> @@ -11,6 +11,7 @@
>>>   #ifndef _LINUX_IRQCHIP_H
>>>   #define _LINUX_IRQCHIP_H
>>>
>>> +#include <linux/acpi.h>
>>>   #include <linux/of.h>
>>>
>>>   /*
>>> @@ -25,6 +26,18 @@
>>>    */
>>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>>
>>> +/*
>>> + * This macro must be used by the different ARM GIC drivers to declare
>>> + * the association between their version and their initialization function.
>>> + *
>>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>>> + * same file.
>>> + * @gic_version: version of GIC
>>> + * @fn: initialization function
>>> + */
>>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>>
>> I don't think this is the right approach. The MADT table has a *huge*
>> number of possible subtables, and none of them is matched by the GIC
>> version.
>>
>> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
>> macro doesn't reflect this at all (you've basically cloned OF, and
>> that's clearly not good enough).
>>
>> This probably require an intermediate matching function, ending up with
>> something like:
>>
>> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
>> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
>> 		subtable, version, fn)
>>
>> where match_madt_subtable is going to check that a given subtable is
>> really suitable for a given irqchip. None of that should be GIC
>> specific, really.
> 
> I'm little confused here, in the previous patch, the gic version is
> stored, so we only need to match the GIC driver with the gic version.
> 
> In the GIC dirver itself, we will match the madt subtable to find
> information we need to init the GIC, so I'm not sure why
> match_madt_subtable in the ACPI_DECLARE, I think I missed something,
> please correct me.

What you're missing is that it should be possible to use
IRQCHIP_ACPI_DECLARE with something that is *not* a GIC. It shouldn't be
GIC specific in any way.

You must have a generic way of describing a match in a table by naming
one of its structures, and possibly a type value inside this structures.

I want to be able to write something like:

IRQCHIP_ACPI_DECLARE(ioapic, ACPI_IOAPIC, 0, ioacpi_acpi_probe);

where ACPI_IOAPIC is 1 (the type for the IOAPIC structure in the MADT
table).

For GICv3, I want to be able to write:

IRQCHIP_ACPI_DECLARE(gicv3, ACPI_GICD, ACPI_GICD_GICV3, \
                     gicv3_acpi_probe);

where ACPI_GICD is 0xC, and ACPI_GICD_GICV3 is 3.

Do you see what I'm aiming for? We follow the spec, strictly the spec,
but all the spec. No shortcut that only ends up matching the GIC in MADT.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-06 16:29         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:29 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 14:24, Hanjun Guo wrote:
> Hi Marc,
> 
> On 08/04/2015 08:27 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> This self-probe infrastructure works in the similar way as OF,
>>> but there is some different in the mechanism:
>>>
>>> For DT, the init fn will be called once it finds compatible strings
>>> in DT,  but for ACPI, we init irqchips by static tables, and in
>>> static ACPI tables, there are no compatible strings to indicate
>>> irqchips, but thanks to the GIC version presented in ACPI table,
>>> we can call the corresponding GIC drivers matching the GIC version
>>> with this framework.
>>>
>>> This mechanism can also be used for clock declare and may also works
>>> on x86 for some table parsing too.
>>>
>>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>>> work.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>>   include/linux/irqchip.h           | 13 +++++++++++++
>>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>>   5 files changed, 83 insertions(+)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 6537b43..011468d 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>>
>>>   	return 0;
>>>   }
>>> +
>>> +/*
>>> + * This special acpi_table_id is the sentinel at the end of the
>>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>>> + * the end of the array by the linker, thanks to being part of a
>>> + * special section.
>>> + */
>>> +static const struct acpi_table_id
>>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>>
>> What is this thing for? Nobody refers to it (I know
>> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
>> reason...).
> 
> If I'm not mistaken, this is for proper section termination, please
> see below:
> 
> /* scan the irqchip table to match the GIC version and its driver */
> for (id = __irqchip_acpi_table; id->id[0]; id++) {
> ...
> }
> 
> Then irqchip_acpi_match_end will be the end of the table section,
> which will terminate the scanning.

Yeah, I got that bit, but I didn't realized this was getting pulled into
the section. It's probably fine then.

>>
>>> +
>>> +extern struct acpi_table_id __irqchip_acpi_table[];
>>> +
>>> +void __init acpi_irqchip_init(void)
>>> +{
>>> +	struct acpi_table_id *id;
>>> +
>>> +	if (acpi_disabled)
>>> +		return;
>>> +
>>> +	if (acpi_gic_version_init())
>>> +		return;
>>
>> This is the only place where we need the version, right? So just get
>> acpi_gic_version_init to return the version number, and loose the global
>> variable.
> 
> The global variable is still needed because we need to get the GIC
> version when scanning the MADT tables, we can't return the table value
> directly in acpi_table_parse_madt() at now.
> 
>>
>>> +
>>> +	/* scan the irqchip table to match the GIC version and its driver */
>>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>>> +		if (gic_version == (u8)id->driver_data) {
>>> +			acpi_table_parse(id->id,
>>> +					 (acpi_tbl_table_handler)id->handler);
>>> +			return;
>>> +		}
>>> +	}
>>> +
>>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>>> +}
>>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>>> index 8bd374d..625776c 100644
>>> --- a/include/asm-generic/vmlinux.lds.h
>>> +++ b/include/asm-generic/vmlinux.lds.h
>>> @@ -181,6 +181,18 @@
>>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_TABLE(name)						\
>>> +	. = ALIGN(8);							\
>>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>>> +	*(__##name##_acpi_table)					\
>>> +	*(__##name##_acpi_table_end)
>>> +
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>>> +#else
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>>> +#endif
>>> +
>>>   #define KERNEL_DTB()							\
>>>   	STRUCT_ALIGN();							\
>>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>>> @@ -516,6 +528,7 @@
>>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>>   	KERNEL_DTB()							\
>>>   	IRQCHIP_OF_MATCH_TABLE()					\
>>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>>   	EARLYCON_TABLE()						\
>>>   	EARLYCON_OF_TABLES()
>>>
>>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>>> index 0820cb1..04dd0bb 100644
>>> --- a/include/linux/acpi.h
>>> +++ b/include/linux/acpi.h
>>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>>
>>>   #endif
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__used __section(__##table##_acpi_table)		\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#else
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__attribute__((unused))					\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#endif
>>> +
>>>   #endif	/*_LINUX_ACPI_H*/
>>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>>> index 6388873..6b66d3e 100644
>>> --- a/include/linux/irqchip.h
>>> +++ b/include/linux/irqchip.h
>>> @@ -11,6 +11,7 @@
>>>   #ifndef _LINUX_IRQCHIP_H
>>>   #define _LINUX_IRQCHIP_H
>>>
>>> +#include <linux/acpi.h>
>>>   #include <linux/of.h>
>>>
>>>   /*
>>> @@ -25,6 +26,18 @@
>>>    */
>>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>>
>>> +/*
>>> + * This macro must be used by the different ARM GIC drivers to declare
>>> + * the association between their version and their initialization function.
>>> + *
>>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>>> + * same file.
>>> + * @gic_version: version of GIC
>>> + * @fn: initialization function
>>> + */
>>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>>
>> I don't think this is the right approach. The MADT table has a *huge*
>> number of possible subtables, and none of them is matched by the GIC
>> version.
>>
>> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
>> macro doesn't reflect this at all (you've basically cloned OF, and
>> that's clearly not good enough).
>>
>> This probably require an intermediate matching function, ending up with
>> something like:
>>
>> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
>> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
>> 		subtable, version, fn)
>>
>> where match_madt_subtable is going to check that a given subtable is
>> really suitable for a given irqchip. None of that should be GIC
>> specific, really.
> 
> I'm little confused here, in the previous patch, the gic version is
> stored, so we only need to match the GIC driver with the gic version.
> 
> In the GIC dirver itself, we will match the madt subtable to find
> information we need to init the GIC, so I'm not sure why
> match_madt_subtable in the ACPI_DECLARE, I think I missed something,
> please correct me.

What you're missing is that it should be possible to use
IRQCHIP_ACPI_DECLARE with something that is *not* a GIC. It shouldn't be
GIC specific in any way.

You must have a generic way of describing a match in a table by naming
one of its structures, and possibly a type value inside this structures.

I want to be able to write something like:

IRQCHIP_ACPI_DECLARE(ioapic, ACPI_IOAPIC, 0, ioacpi_acpi_probe);

where ACPI_IOAPIC is 1 (the type for the IOAPIC structure in the MADT
table).

For GICv3, I want to be able to write:

IRQCHIP_ACPI_DECLARE(gicv3, ACPI_GICD, ACPI_GICD_GICV3, \
                     gicv3_acpi_probe);

where ACPI_GICD is 0xC, and ACPI_GICD_GICV3 is 3.

Do you see what I'm aiming for? We follow the spec, strictly the spec,
but all the spec. No shortcut that only ends up matching the GIC in MADT.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller
@ 2015-08-06 16:29         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/08/15 14:24, Hanjun Guo wrote:
> Hi Marc,
> 
> On 08/04/2015 08:27 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> This self-probe infrastructure works in the similar way as OF,
>>> but there is some different in the mechanism:
>>>
>>> For DT, the init fn will be called once it finds compatible strings
>>> in DT,  but for ACPI, we init irqchips by static tables, and in
>>> static ACPI tables, there are no compatible strings to indicate
>>> irqchips, but thanks to the GIC version presented in ACPI table,
>>> we can call the corresponding GIC drivers matching the GIC version
>>> with this framework.
>>>
>>> This mechanism can also be used for clock declare and may also works
>>> on x86 for some table parsing too.
>>>
>>> This patch is based on Tomasz Nowicki <tomasz.nowicki@linaro.org>'s
>>> work.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c    | 33 +++++++++++++++++++++++++++++++++
>>>   include/asm-generic/vmlinux.lds.h | 13 +++++++++++++
>>>   include/linux/acpi.h              | 16 ++++++++++++++++
>>>   include/linux/irqchip.h           | 13 +++++++++++++
>>>   include/linux/mod_devicetable.h   |  8 ++++++++
>>>   5 files changed, 83 insertions(+)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 6537b43..011468d 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -107,3 +107,36 @@ static int __init acpi_gic_version_init(void)
>>>
>>>   	return 0;
>>>   }
>>> +
>>> +/*
>>> + * This special acpi_table_id is the sentinel at the end of the
>>> + * acpi_table_id[] array of all irqchips. It is automatically placed at
>>> + * the end of the array by the linker, thanks to being part of a
>>> + * special section.
>>> + */
>>> +static const struct acpi_table_id
>>> +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end);
>>
>> What is this thing for? Nobody refers to it (I know
>> drivers/irqchip/irqchip.c has a similar thing, but that's not enough a
>> reason...).
> 
> If I'm not mistaken, this is for proper section termination, please
> see below:
> 
> /* scan the irqchip table to match the GIC version and its driver */
> for (id = __irqchip_acpi_table; id->id[0]; id++) {
> ...
> }
> 
> Then irqchip_acpi_match_end will be the end of the table section,
> which will terminate the scanning.

Yeah, I got that bit, but I didn't realized this was getting pulled into
the section. It's probably fine then.

>>
>>> +
>>> +extern struct acpi_table_id __irqchip_acpi_table[];
>>> +
>>> +void __init acpi_irqchip_init(void)
>>> +{
>>> +	struct acpi_table_id *id;
>>> +
>>> +	if (acpi_disabled)
>>> +		return;
>>> +
>>> +	if (acpi_gic_version_init())
>>> +		return;
>>
>> This is the only place where we need the version, right? So just get
>> acpi_gic_version_init to return the version number, and loose the global
>> variable.
> 
> The global variable is still needed because we need to get the GIC
> version when scanning the MADT tables, we can't return the table value
> directly in acpi_table_parse_madt() at now.
> 
>>
>>> +
>>> +	/* scan the irqchip table to match the GIC version and its driver */
>>> +	for (id = __irqchip_acpi_table; id->id[0]; id++) {
>>> +		if (gic_version == (u8)id->driver_data) {
>>> +			acpi_table_parse(id->id,
>>> +					 (acpi_tbl_table_handler)id->handler);
>>> +			return;
>>> +		}
>>> +	}
>>> +
>>> +	pr_err("No matched driver GIC version %d\n", gic_version);
>>> +}
>>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
>>> index 8bd374d..625776c 100644
>>> --- a/include/asm-generic/vmlinux.lds.h
>>> +++ b/include/asm-generic/vmlinux.lds.h
>>> @@ -181,6 +181,18 @@
>>>   #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>>>   #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_TABLE(name)						\
>>> +	. = ALIGN(8);							\
>>> +	VMLINUX_SYMBOL(__##name##_acpi_table) = .;			\
>>> +	*(__##name##_acpi_table)					\
>>> +	*(__##name##_acpi_table_end)
>>> +
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()	ACPI_TABLE(irqchip)
>>> +#else
>>> +#define IRQCHIP_ACPI_MATCH_TABLE()
>>> +#endif
>>> +
>>>   #define KERNEL_DTB()							\
>>>   	STRUCT_ALIGN();							\
>>>   	VMLINUX_SYMBOL(__dtb_start) = .;				\
>>> @@ -516,6 +528,7 @@
>>>   	CPUIDLE_METHOD_OF_TABLES()					\
>>>   	KERNEL_DTB()							\
>>>   	IRQCHIP_OF_MATCH_TABLE()					\
>>> +	IRQCHIP_ACPI_MATCH_TABLE()					\
>>>   	EARLYCON_TABLE()						\
>>>   	EARLYCON_OF_TABLES()
>>>
>>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>>> index 0820cb1..04dd0bb 100644
>>> --- a/include/linux/acpi.h
>>> +++ b/include/linux/acpi.h
>>> @@ -829,4 +829,20 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
>>>
>>>   #endif
>>>
>>> +#ifdef CONFIG_ACPI
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__used __section(__##table##_acpi_table)		\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#else
>>> +#define ACPI_DECLARE(table, name, table_id, data, fn)			\
>>> +	static const struct acpi_table_id __acpi_table_##name		\
>>> +		__attribute__((unused))					\
>>> +		 = { .id = table_id,					\
>>> +		     .handler = (void *)fn,				\
>>> +		     .driver_data = data }
>>> +#endif
>>> +
>>>   #endif	/*_LINUX_ACPI_H*/
>>> diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h
>>> index 6388873..6b66d3e 100644
>>> --- a/include/linux/irqchip.h
>>> +++ b/include/linux/irqchip.h
>>> @@ -11,6 +11,7 @@
>>>   #ifndef _LINUX_IRQCHIP_H
>>>   #define _LINUX_IRQCHIP_H
>>>
>>> +#include <linux/acpi.h>
>>>   #include <linux/of.h>
>>>
>>>   /*
>>> @@ -25,6 +26,18 @@
>>>    */
>>>   #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
>>>
>>> +/*
>>> + * This macro must be used by the different ARM GIC drivers to declare
>>> + * the association between their version and their initialization function.
>>> + *
>>> + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
>>> + * same file.
>>> + * @gic_version: version of GIC
>>> + * @fn: initialization function
>>> + */
>>> +#define IRQCHIP_ACPI_DECLARE(name, gic_version, fn)	\
>>> +	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, gic_version, fn)
>>
>> I don't think this is the right approach. The MADT table has a *huge*
>> number of possible subtables, and none of them is matched by the GIC
>> version.
>>
>> What you *really* want is MADT -> GICD -> GIC type. Your ACPI_DECLARE
>> macro doesn't reflect this at all (you've basically cloned OF, and
>> that's clearly not good enough).
>>
>> This probably require an intermediate matching function, ending up with
>> something like:
>>
>> #define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \
>> 	ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, match_madt_subtable,\
>> 		subtable, version, fn)
>>
>> where match_madt_subtable is going to check that a given subtable is
>> really suitable for a given irqchip. None of that should be GIC
>> specific, really.
> 
> I'm little confused here, in the previous patch, the gic version is
> stored, so we only need to match the GIC driver with the gic version.
> 
> In the GIC dirver itself, we will match the madt subtable to find
> information we need to init the GIC, so I'm not sure why
> match_madt_subtable in the ACPI_DECLARE, I think I missed something,
> please correct me.

What you're missing is that it should be possible to use
IRQCHIP_ACPI_DECLARE with something that is *not* a GIC. It shouldn't be
GIC specific in any way.

You must have a generic way of describing a match in a table by naming
one of its structures, and possibly a type value inside this structures.

I want to be able to write something like:

IRQCHIP_ACPI_DECLARE(ioapic, ACPI_IOAPIC, 0, ioacpi_acpi_probe);

where ACPI_IOAPIC is 1 (the type for the IOAPIC structure in the MADT
table).

For GICv3, I want to be able to write:

IRQCHIP_ACPI_DECLARE(gicv3, ACPI_GICD, ACPI_GICD_GICV3, \
                     gicv3_acpi_probe);

where ACPI_GICD is 0xC, and ACPI_GICD_GICV3 is 3.

Do you see what I'm aiming for? We follow the spec, strictly the spec,
but all the spec. No shortcut that only ends up matching the GIC in MADT.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
  2015-08-05 14:00       ` Hanjun Guo
  (?)
@ 2015-08-06 16:42         ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 15:00, Hanjun Guo wrote:
> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>
>>> 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.
>>>
>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>> [hj: Rework this patch and fix multi issues]
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index c0b96c6..ebc5604 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>
>>> @@ -25,6 +26,7 @@
>>>   #include <linux/percpu.h>
>>>   #include <linux/slab.h>
>>>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>   #include <linux/irqchip/arm-gic-v3.h>
>>>
>>>   #include <asm/cputype.h>
>>> @@ -802,7 +804,8 @@ 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())
>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>> +                     &gic_data.rdists, gic_data.domain);
>>
>> This doesn't make much sense. The first parameter to its_init is indeed
>> supposed to be an of_node, but what is the point of calling its_init if
>> you *know* you don't have the necessary topological information to parse
>> the firmware tables?
>>
>> I don't see *any* code that is going to parse the ITS table in this
>> series, so please don't call its_init passing a NULL pointer to it. This
>> is just gross.
> 
> OK, the ITS ACPI code is in later patch which combined with IORT. How
> about moving it to the GIC of init code temporary?

Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
NULL. But don't call it with a NULL parameter.

>>
>>>
>>>      gic_smp_init();
>>>      gic_dist_init();
>>> @@ -818,6 +821,16 @@ out_free:
>>>      return err;
>>>   }
>>>
>>> +static int __init detect_distributor(void __iomem *dist_base)
>>
>> We do have a naming convention in this file. All functions start with gic_.
>>
>>> +{
>>> +    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;
>>> +}
>>
>> This function doesn't detect anything, it validates that we have
>> something sensible. Please rename it to gic_validate_dist_version, or
>> something similar.
> 
> Ok.
> 
>>
>>> +
>>>   #ifdef CONFIG_OF
>>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>>   {
>>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>      struct redist_region *rdist_regs;
>>>      u64 redist_stride;
>>>      u32 nr_redist_regions;
>>> -    u32 reg;
>>>      int err, i;
>>>
>>>      dist_base = of_iomap(node, 0);
>>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>              return -ENXIO;
>>>      }
>>>
>>> -    reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> -    if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>>              pr_err("%s: no distributor detected, giving up\n",
>>>                      node->full_name);
>>> -            err = -ENODEV;
>>>              goto out_unmap_dist;
>>>      }
>>>
>>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>>
>>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +static struct redist_region *redist_regs __initdata;
>>> +static u32 nr_redist_regions __initdata;
>>> +static phys_addr_t dist_phys_base __initdata;
>>> +
>>> +static int __init
>>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>>
>> A physical address must use phys_addr_t.
> 
> OK.
> 
>>
>>> +{
>>> +    struct redist_region *redist_regs_new;
>>> +    void __iomem *redist_base;
>>> +
>>> +    redist_regs_new = krealloc(redist_regs,
>>> +                               sizeof(*redist_regs) * (nr_redist_regions + 1),
>>> +                               GFP_KERNEL);
>>
>> NAK. If you have multiple regions, you count them, you allocate the
>> right number of regions. This will be far more efficient than doing this
>> realloc dance. It is not like we're not parsing the tables a zillion
>> times already. Doing it one more time won't hurt.
> 
> Agreed, will update in next version.
> 
>>
>>> +    if (!redist_regs_new) {
>>> +            pr_err("Couldn't allocate resource for GICR region\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs = redist_regs_new;
>>> +
>>> +    redist_base = ioremap(phys_base, size);
>>> +    if (!redist_base) {
>>> +            pr_err("Couldn't map GICR region @%llx\n", phys_base);
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs[nr_redist_regions].phys_base = phys_base;
>>> +    redist_regs[nr_redist_regions].redist_base = redist_base;
>>> +    nr_redist_regions++;
>>> +    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;
>>> +
>>> +    if (BAD_MADT_ENTRY(header, end))
>>> +            return -EINVAL;
>>> +
>>> +    redist = (struct acpi_madt_generic_redistributor *)header;
>>> +    if (!redist->base_address)
>>> +            return -EINVAL;
>>> +
>>> +    return gic_acpi_register_redist(redist->base_address, redist->length);
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>>> +                            const unsigned long end)
>>> +{
>>
>> How many versions of gic_acpi_parse_madt_distributor are we going to
>> get? Why isn't the ACPI parsing in a common file? Why do I have to read
>> the same code on and on until my eyes bleed?
> 
> I will try to move it to common file irq-gic-acpi.c.
> 
>>
>>> +    struct acpi_madt_generic_distributor *dist;
>>> +
>>> +    dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +    if (BAD_MADT_ENTRY(dist, end))
>>> +            return -EINVAL;
>>> +
>>> +    dist_phys_base = dist->base_address;
>>> +    return 0;
>>> +}
>>> +
>>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>> +                                  u32 gsi, unsigned int irq_type)
>>> +{
>>> +    /*
>>> +     * Encode GSI and triggering information the way the GIC likes
>>> +     * them.
>>> +     */
>>> +    if (WARN_ON(gsi < 16))
>>> +            return -EINVAL;
>>> +
>>> +    if (gsi >= 32) {
>>> +            data->param[0] = 0;             /* SPI */
>>> +            data->param[1] = gsi - 32;
>>> +            data->param[2] = irq_type;
>>> +    } else {
>>> +            data->param[0] = 1;             /* PPI */
>>> +            data->param[1] = gsi - 16;
>>> +            data->param[2] = 0xff << 4 | irq_type;
>>> +    }
>>> +
>>> +    data->param_count = 3;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_init(struct acpi_table_header *table)
>>> +{
>>> +    int count, i, err = 0;
>>> +    void __iomem *dist_base;
>>> +
>>> +    /* Get distributor base address */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                            sizeof(struct acpi_table_madt),
>>> +                            gic_acpi_parse_madt_distributor, table,
>>> +                            ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_err("No valid GICD entry exist\n");
>>> +            return -EINVAL;
>>> +    } else if (count > 1) {
>>> +            pr_err("More than one GICD entry detected\n");
>>> +            return -EINVAL;
>>> +    }
>>> +
>>> +    dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>>> +    if (!dist_base) {
>>> +            pr_err("Unable to map GICD registers\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>> +            pr_err("No distributor detected at @%p, giving up", dist_base);
>>> +            goto out_dist_unmap;
>>> +    }
>>> +
>>> +    /* Collect redistributor base addresses */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                    sizeof(struct acpi_table_madt),
>>> +                    gic_acpi_parse_madt_redist, table,
>>> +                    ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_info("No valid GICR entries exist\n");
>>> +            err = -EINVAL;
>>> +            goto out_redist_unmap;
>>> +    }
>>> +
>>> +    err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>> +                         (void *)ACPI_IRQ_MODEL_GIC);
>>
>> There is no other global identifier for GICv3? It feels a bit weird to
>> use the same ID as GICv2 (though probably not harmful as you can't have
>> both as the same time). What are you planning to use for the ITS then?
>> You must make sure you have a global namespace.
> 
> I will use the ITS physical base address as the token for ITS, maybe I
> can use the GICD physical base address here instead?

That should be fine as long as the physical address cannot be
interpreted as a kernel address. Which is still a bit dodgy. I'd be more
happy if you had a proper namespace.

>>
>>> +    if (err)
>>> +            goto out_redist_unmap;
>>> +
>>> +    acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>> +                       gic_acpi_gsi_desc_populate);
>>> +    return 0;
>>> +
>>> +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_GIC_VERSION_V3, gic_acpi_init);
>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>
>> As mentioned before, this doesn't work.
> 
> hmm, I think we need more discussion for this one, but we need to match
> V4 for GICv3 drivers, and everything will be the same in the dirver
> as I said before.

And as I said before, you don't need to distinguish v3 from v4 in the
ACPI code. Matching GICv3 is enough.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-06 16:42         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 15:00, Hanjun Guo wrote:
> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>
>>> 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.
>>>
>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>> [hj: Rework this patch and fix multi issues]
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index c0b96c6..ebc5604 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>
>>> @@ -25,6 +26,7 @@
>>>   #include <linux/percpu.h>
>>>   #include <linux/slab.h>
>>>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>   #include <linux/irqchip/arm-gic-v3.h>
>>>
>>>   #include <asm/cputype.h>
>>> @@ -802,7 +804,8 @@ 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())
>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>> +                     &gic_data.rdists, gic_data.domain);
>>
>> This doesn't make much sense. The first parameter to its_init is indeed
>> supposed to be an of_node, but what is the point of calling its_init if
>> you *know* you don't have the necessary topological information to parse
>> the firmware tables?
>>
>> I don't see *any* code that is going to parse the ITS table in this
>> series, so please don't call its_init passing a NULL pointer to it. This
>> is just gross.
> 
> OK, the ITS ACPI code is in later patch which combined with IORT. How
> about moving it to the GIC of init code temporary?

Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
NULL. But don't call it with a NULL parameter.

>>
>>>
>>>      gic_smp_init();
>>>      gic_dist_init();
>>> @@ -818,6 +821,16 @@ out_free:
>>>      return err;
>>>   }
>>>
>>> +static int __init detect_distributor(void __iomem *dist_base)
>>
>> We do have a naming convention in this file. All functions start with gic_.
>>
>>> +{
>>> +    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;
>>> +}
>>
>> This function doesn't detect anything, it validates that we have
>> something sensible. Please rename it to gic_validate_dist_version, or
>> something similar.
> 
> Ok.
> 
>>
>>> +
>>>   #ifdef CONFIG_OF
>>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>>   {
>>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>      struct redist_region *rdist_regs;
>>>      u64 redist_stride;
>>>      u32 nr_redist_regions;
>>> -    u32 reg;
>>>      int err, i;
>>>
>>>      dist_base = of_iomap(node, 0);
>>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>              return -ENXIO;
>>>      }
>>>
>>> -    reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> -    if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>>              pr_err("%s: no distributor detected, giving up\n",
>>>                      node->full_name);
>>> -            err = -ENODEV;
>>>              goto out_unmap_dist;
>>>      }
>>>
>>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>>
>>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +static struct redist_region *redist_regs __initdata;
>>> +static u32 nr_redist_regions __initdata;
>>> +static phys_addr_t dist_phys_base __initdata;
>>> +
>>> +static int __init
>>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>>
>> A physical address must use phys_addr_t.
> 
> OK.
> 
>>
>>> +{
>>> +    struct redist_region *redist_regs_new;
>>> +    void __iomem *redist_base;
>>> +
>>> +    redist_regs_new = krealloc(redist_regs,
>>> +                               sizeof(*redist_regs) * (nr_redist_regions + 1),
>>> +                               GFP_KERNEL);
>>
>> NAK. If you have multiple regions, you count them, you allocate the
>> right number of regions. This will be far more efficient than doing this
>> realloc dance. It is not like we're not parsing the tables a zillion
>> times already. Doing it one more time won't hurt.
> 
> Agreed, will update in next version.
> 
>>
>>> +    if (!redist_regs_new) {
>>> +            pr_err("Couldn't allocate resource for GICR region\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs = redist_regs_new;
>>> +
>>> +    redist_base = ioremap(phys_base, size);
>>> +    if (!redist_base) {
>>> +            pr_err("Couldn't map GICR region @%llx\n", phys_base);
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs[nr_redist_regions].phys_base = phys_base;
>>> +    redist_regs[nr_redist_regions].redist_base = redist_base;
>>> +    nr_redist_regions++;
>>> +    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;
>>> +
>>> +    if (BAD_MADT_ENTRY(header, end))
>>> +            return -EINVAL;
>>> +
>>> +    redist = (struct acpi_madt_generic_redistributor *)header;
>>> +    if (!redist->base_address)
>>> +            return -EINVAL;
>>> +
>>> +    return gic_acpi_register_redist(redist->base_address, redist->length);
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>>> +                            const unsigned long end)
>>> +{
>>
>> How many versions of gic_acpi_parse_madt_distributor are we going to
>> get? Why isn't the ACPI parsing in a common file? Why do I have to read
>> the same code on and on until my eyes bleed?
> 
> I will try to move it to common file irq-gic-acpi.c.
> 
>>
>>> +    struct acpi_madt_generic_distributor *dist;
>>> +
>>> +    dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +    if (BAD_MADT_ENTRY(dist, end))
>>> +            return -EINVAL;
>>> +
>>> +    dist_phys_base = dist->base_address;
>>> +    return 0;
>>> +}
>>> +
>>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>> +                                  u32 gsi, unsigned int irq_type)
>>> +{
>>> +    /*
>>> +     * Encode GSI and triggering information the way the GIC likes
>>> +     * them.
>>> +     */
>>> +    if (WARN_ON(gsi < 16))
>>> +            return -EINVAL;
>>> +
>>> +    if (gsi >= 32) {
>>> +            data->param[0] = 0;             /* SPI */
>>> +            data->param[1] = gsi - 32;
>>> +            data->param[2] = irq_type;
>>> +    } else {
>>> +            data->param[0] = 1;             /* PPI */
>>> +            data->param[1] = gsi - 16;
>>> +            data->param[2] = 0xff << 4 | irq_type;
>>> +    }
>>> +
>>> +    data->param_count = 3;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_init(struct acpi_table_header *table)
>>> +{
>>> +    int count, i, err = 0;
>>> +    void __iomem *dist_base;
>>> +
>>> +    /* Get distributor base address */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                            sizeof(struct acpi_table_madt),
>>> +                            gic_acpi_parse_madt_distributor, table,
>>> +                            ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_err("No valid GICD entry exist\n");
>>> +            return -EINVAL;
>>> +    } else if (count > 1) {
>>> +            pr_err("More than one GICD entry detected\n");
>>> +            return -EINVAL;
>>> +    }
>>> +
>>> +    dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>>> +    if (!dist_base) {
>>> +            pr_err("Unable to map GICD registers\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>> +            pr_err("No distributor detected at @%p, giving up", dist_base);
>>> +            goto out_dist_unmap;
>>> +    }
>>> +
>>> +    /* Collect redistributor base addresses */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                    sizeof(struct acpi_table_madt),
>>> +                    gic_acpi_parse_madt_redist, table,
>>> +                    ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_info("No valid GICR entries exist\n");
>>> +            err = -EINVAL;
>>> +            goto out_redist_unmap;
>>> +    }
>>> +
>>> +    err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>> +                         (void *)ACPI_IRQ_MODEL_GIC);
>>
>> There is no other global identifier for GICv3? It feels a bit weird to
>> use the same ID as GICv2 (though probably not harmful as you can't have
>> both as the same time). What are you planning to use for the ITS then?
>> You must make sure you have a global namespace.
> 
> I will use the ITS physical base address as the token for ITS, maybe I
> can use the GICD physical base address here instead?

That should be fine as long as the physical address cannot be
interpreted as a kernel address. Which is still a bit dodgy. I'd be more
happy if you had a proper namespace.

>>
>>> +    if (err)
>>> +            goto out_redist_unmap;
>>> +
>>> +    acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>> +                       gic_acpi_gsi_desc_populate);
>>> +    return 0;
>>> +
>>> +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_GIC_VERSION_V3, gic_acpi_init);
>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>
>> As mentioned before, this doesn't work.
> 
> hmm, I think we need more discussion for this one, but we need to match
> V4 for GICv3 drivers, and everything will be the same in the dirver
> as I said before.

And as I said before, you don't need to distinguish v3 from v4 in the
ACPI code. Matching GICv3 is enough.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-06 16:42         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/08/15 15:00, Hanjun Guo wrote:
> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>
>>> 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.
>>>
>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>> [hj: Rework this patch and fix multi issues]
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>   1 file changed, 169 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index c0b96c6..ebc5604 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>
>>> @@ -25,6 +26,7 @@
>>>   #include <linux/percpu.h>
>>>   #include <linux/slab.h>
>>>
>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>   #include <linux/irqchip/arm-gic-v3.h>
>>>
>>>   #include <asm/cputype.h>
>>> @@ -802,7 +804,8 @@ 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())
>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>> +                     &gic_data.rdists, gic_data.domain);
>>
>> This doesn't make much sense. The first parameter to its_init is indeed
>> supposed to be an of_node, but what is the point of calling its_init if
>> you *know* you don't have the necessary topological information to parse
>> the firmware tables?
>>
>> I don't see *any* code that is going to parse the ITS table in this
>> series, so please don't call its_init passing a NULL pointer to it. This
>> is just gross.
> 
> OK, the ITS ACPI code is in later patch which combined with IORT. How
> about moving it to the GIC of init code temporary?

Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
NULL. But don't call it with a NULL parameter.

>>
>>>
>>>      gic_smp_init();
>>>      gic_dist_init();
>>> @@ -818,6 +821,16 @@ out_free:
>>>      return err;
>>>   }
>>>
>>> +static int __init detect_distributor(void __iomem *dist_base)
>>
>> We do have a naming convention in this file. All functions start with gic_.
>>
>>> +{
>>> +    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;
>>> +}
>>
>> This function doesn't detect anything, it validates that we have
>> something sensible. Please rename it to gic_validate_dist_version, or
>> something similar.
> 
> Ok.
> 
>>
>>> +
>>>   #ifdef CONFIG_OF
>>>   static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>>>   {
>>> @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>      struct redist_region *rdist_regs;
>>>      u64 redist_stride;
>>>      u32 nr_redist_regions;
>>> -    u32 reg;
>>>      int err, i;
>>>
>>>      dist_base = of_iomap(node, 0);
>>> @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
>>>              return -ENXIO;
>>>      }
>>>
>>> -    reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> -    if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>>              pr_err("%s: no distributor detected, giving up\n",
>>>                      node->full_name);
>>> -            err = -ENODEV;
>>>              goto out_unmap_dist;
>>>      }
>>>
>>> @@ -887,3 +898,156 @@ out_unmap_dist:
>>>
>>>   IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +static struct redist_region *redist_regs __initdata;
>>> +static u32 nr_redist_regions __initdata;
>>> +static phys_addr_t dist_phys_base __initdata;
>>> +
>>> +static int __init
>>> +gic_acpi_register_redist(u64 phys_base, u64 size)
>>
>> A physical address must use phys_addr_t.
> 
> OK.
> 
>>
>>> +{
>>> +    struct redist_region *redist_regs_new;
>>> +    void __iomem *redist_base;
>>> +
>>> +    redist_regs_new = krealloc(redist_regs,
>>> +                               sizeof(*redist_regs) * (nr_redist_regions + 1),
>>> +                               GFP_KERNEL);
>>
>> NAK. If you have multiple regions, you count them, you allocate the
>> right number of regions. This will be far more efficient than doing this
>> realloc dance. It is not like we're not parsing the tables a zillion
>> times already. Doing it one more time won't hurt.
> 
> Agreed, will update in next version.
> 
>>
>>> +    if (!redist_regs_new) {
>>> +            pr_err("Couldn't allocate resource for GICR region\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs = redist_regs_new;
>>> +
>>> +    redist_base = ioremap(phys_base, size);
>>> +    if (!redist_base) {
>>> +            pr_err("Couldn't map GICR region @%llx\n", phys_base);
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    redist_regs[nr_redist_regions].phys_base = phys_base;
>>> +    redist_regs[nr_redist_regions].redist_base = redist_base;
>>> +    nr_redist_regions++;
>>> +    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;
>>> +
>>> +    if (BAD_MADT_ENTRY(header, end))
>>> +            return -EINVAL;
>>> +
>>> +    redist = (struct acpi_madt_generic_redistributor *)header;
>>> +    if (!redist->base_address)
>>> +            return -EINVAL;
>>> +
>>> +    return gic_acpi_register_redist(redist->base_address, redist->length);
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
>>> +                            const unsigned long end)
>>> +{
>>
>> How many versions of gic_acpi_parse_madt_distributor are we going to
>> get? Why isn't the ACPI parsing in a common file? Why do I have to read
>> the same code on and on until my eyes bleed?
> 
> I will try to move it to common file irq-gic-acpi.c.
> 
>>
>>> +    struct acpi_madt_generic_distributor *dist;
>>> +
>>> +    dist = (struct acpi_madt_generic_distributor *)header;
>>> +
>>> +    if (BAD_MADT_ENTRY(dist, end))
>>> +            return -EINVAL;
>>> +
>>> +    dist_phys_base = dist->base_address;
>>> +    return 0;
>>> +}
>>> +
>>> +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>> +                                  u32 gsi, unsigned int irq_type)
>>> +{
>>> +    /*
>>> +     * Encode GSI and triggering information the way the GIC likes
>>> +     * them.
>>> +     */
>>> +    if (WARN_ON(gsi < 16))
>>> +            return -EINVAL;
>>> +
>>> +    if (gsi >= 32) {
>>> +            data->param[0] = 0;             /* SPI */
>>> +            data->param[1] = gsi - 32;
>>> +            data->param[2] = irq_type;
>>> +    } else {
>>> +            data->param[0] = 1;             /* PPI */
>>> +            data->param[1] = gsi - 16;
>>> +            data->param[2] = 0xff << 4 | irq_type;
>>> +    }
>>> +
>>> +    data->param_count = 3;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_init(struct acpi_table_header *table)
>>> +{
>>> +    int count, i, err = 0;
>>> +    void __iomem *dist_base;
>>> +
>>> +    /* Get distributor base address */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                            sizeof(struct acpi_table_madt),
>>> +                            gic_acpi_parse_madt_distributor, table,
>>> +                            ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_err("No valid GICD entry exist\n");
>>> +            return -EINVAL;
>>> +    } else if (count > 1) {
>>> +            pr_err("More than one GICD entry detected\n");
>>> +            return -EINVAL;
>>> +    }
>>> +
>>> +    dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
>>> +    if (!dist_base) {
>>> +            pr_err("Unable to map GICD registers\n");
>>> +            return -ENOMEM;
>>> +    }
>>> +
>>> +    err = detect_distributor(dist_base);
>>> +    if (err) {
>>> +            pr_err("No distributor detected at @%p, giving up", dist_base);
>>> +            goto out_dist_unmap;
>>> +    }
>>> +
>>> +    /* Collect redistributor base addresses */
>>> +    count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                    sizeof(struct acpi_table_madt),
>>> +                    gic_acpi_parse_madt_redist, table,
>>> +                    ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +    if (count <= 0) {
>>> +            pr_info("No valid GICR entries exist\n");
>>> +            err = -EINVAL;
>>> +            goto out_redist_unmap;
>>> +    }
>>> +
>>> +    err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>> +                         (void *)ACPI_IRQ_MODEL_GIC);
>>
>> There is no other global identifier for GICv3? It feels a bit weird to
>> use the same ID as GICv2 (though probably not harmful as you can't have
>> both as the same time). What are you planning to use for the ITS then?
>> You must make sure you have a global namespace.
> 
> I will use the ITS physical base address as the token for ITS, maybe I
> can use the GICD physical base address here instead?

That should be fine as long as the physical address cannot be
interpreted as a kernel address. Which is still a bit dodgy. I'd be more
happy if you had a proper namespace.

>>
>>> +    if (err)
>>> +            goto out_redist_unmap;
>>> +
>>> +    acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>> +                       gic_acpi_gsi_desc_populate);
>>> +    return 0;
>>> +
>>> +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_GIC_VERSION_V3, gic_acpi_init);
>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>
>> As mentioned before, this doesn't work.
> 
> hmm, I think we need more discussion for this one, but we need to match
> V4 for GICv3 drivers, and everything will be the same in the dirver
> as I said before.

And as I said before, you don't need to distinguish v3 from v4 in the
ACPI code. Matching GICv3 is enough.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
  2015-08-05 14:11       ` Hanjun Guo
  (?)
@ 2015-08-06 16:42         ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 15:11, Hanjun Guo wrote:
> On 08/04/2015 09:37 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> 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.
>>>
>>> As GICR base in MADT GICC is another way to indicate the GIC version
>>> is 3 or 4, add its support to find out the GIC versions.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 95454e3..3e5c8f4 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>
>>>   static phys_addr_t dist_phy_base __initdata;
>>>
>>> +u8 __init acpi_gic_version(void)
>>> +{
>>> +       return gic_version;
>>> +}
>>> +
>>>   static int __init
>>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>                             const unsigned long end)
>>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * If GICC is enabled but has no valid gicr base address, then it
>>> +        * means GICR base is not presented via GICC
>>> +        */
>>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>>> +               return -ENODEV;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int __init
>>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>   {
>>>          return 0;
>>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>                                          match_gic_redist, 0);
>>>
>>> -       /* that's true if we have at least one GIC redistributor entry */
>>> +       /* has at least one GIC redistributor entry */
>>> +       if (count > 0)
>>> +               return true;
>>> +
>>> +       /* else try to find GICR base in GICC entries */
>>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>>> +                                     gic_acpi_parse_madt_gicc, 0);
>>> +
>>>          return count > 0;
>>>   }
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index ebc5604..b72ccbb 100644
>>> --- a/drivers/irqchip/irq-gic-v3.c
>>> +++ b/drivers/irqchip/irq-gic-v3.c
>>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>>   }
>>>
>>> -static int gic_populate_rdist(void)
>>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>>   {
>>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>>          u64 typer;
>>>          u32 aff;
>>>          int i;
>>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>>                  } while (!(typer & GICR_TYPER_LAST));
>>>          }
>>>
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +/*
>>> + * Populate redist when GIC redistributor address is presented in ACPI
>>> + * MADT GICC entries
>>> + */
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>>> +#else
>>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       return -ENODEV;
>>> +}
>>> +#endif
>>> +
>>> +static int gic_populate_rdist(void)
>>> +{
>>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>>> +
>>> +       if (gic_data.nr_redist_regions) {
>>> +               if (!gic_populate_rdist_with_regions(mpidr))
>>> +                       return 0;
>>> +       } else {
>>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>>> +                       return 0;
>>> +       }
>>> +
>>>          /* We couldn't even deal with ourselves... */
>>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>>               smp_processor_id(), (unsigned long long)mpidr);
>>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>>
>>>   #ifdef CONFIG_ACPI
>>> +
>>> +struct acpi_gicc_redist {
>>> +       struct list_head list;
>>> +       u64 mpidr;
>>> +       phys_addr_t phys_base;
>>> +       void __iomem *redist_base;
>>> +};
>>> +
>>> +static LIST_HEAD(redist_list);
>>> +
>>>   static struct redist_region *redist_regs __initdata;
>>>   static u32 nr_redist_regions __initdata;
>>>   static phys_addr_t dist_phys_base __initdata;
>>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>>          return 0;
>>>   }
>>>
>>> +static void __init
>>> +gic_acpi_release_redist_regions(void)
>>> +{
>>> +       int i;
>>> +
>>> +       for (i = 0; i < nr_redist_regions; i++)
>>> +               if (redist_regs[i].redist_base)
>>> +                       iounmap(redist_regs[i].redist_base);
>>> +       kfree(redist_regs);
>>> +}
>>> +
>>>   static int __init
>>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>>                          const unsigned long end)
>>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +
>>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>>> +       if (!redist)
>>> +               return -ENOMEM;
>>> +
>>> +       redist->mpidr = mpidr;
>>> +       redist->phys_base = phys_base;
>>> +
>>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>>> +               /* RD_base + SGI_base */
>>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>>> +       else
>>> +               /*
>>> +                * RD_base + SGI_base + VLPI_base,
>>> +                * we don't map reserved page as it's buggy to access it
>>> +                */
>>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>>> +
>>> +       if (!redist->redist_base) {
>>> +               kfree(redist);
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       list_add(&redist->list, &redist_list);
>>> +       return 0;
>>> +}
>>> +
>>> +static void __init
>>> +gic_acpi_release_gicc_redist(void)
>>> +{
>>> +       struct acpi_gicc_redist *redist, *t;
>>> +
>>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>>> +               list_del(&redist->list);
>>> +               iounmap(redist->redist_base);
>>> +               kfree(redist);
>>> +       }
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * just quietly ingore the disabled CPU(s) and continue
>>> +        * to find the enabled one(s), if we return error here,
>>> +        * the scanning will be stopped.
>>> +        */
>>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>>> +               return 0;
>>> +
>>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>>> +                                       gicc->arm_mpidr);
>>> +}
>>> +
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +       void __iomem *ptr;
>>> +       u32 reg;
>>> +
>>> +       list_for_each_entry(redist, &redist_list, list) {
>>> +               if (redist->mpidr != mpidr)
>>> +                       continue;
>>> +
>>> +               ptr = redist->redist_base;
>>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +                       pr_warn("No redistributor present @%p\n", ptr);
>>> +                       return -ENODEV;
>>> +               }
>>> +
>>> +               gic_data_rdist_rd_base() = ptr;
>>> +               gic_data_rdist()->phys_base = redist->phys_base;
>>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>>> +                       smp_processor_id(),
>>> +                       (unsigned long long)mpidr,
>>> +                       &gic_data_rdist()->phys_base);
>>> +               return 0;
>>> +       }
>>> +
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>>> +{
>>> +       int count;
>>> +
>>> +       /* Collect redistributor base addresses in GICR entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_redist, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +       if (count > 0)
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>>> +
>>> +       /* Collect redistributor base addresses in GICC entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_gicc, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>>> +       if (count > 0 && !list_empty(&redist_list))
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICC entries exist for GICR base\n");
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init
>>>   gic_acpi_init(struct acpi_table_header *table)
>>>   {
>>> -       int count, i, err = 0;
>>> +       int count, err = 0;
>>>          void __iomem *dist_base;
>>>
>>>          /* Get distributor base address */
>>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>>          }
>>>
>>>          /* Collect redistributor base addresses */
>>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> -                       sizeof(struct acpi_table_madt),
>>> -                       gic_acpi_parse_madt_redist, table,
>>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> -       if (count <= 0) {
>>> -               pr_info("No valid GICR entries exist\n");
>>> -               err = -EINVAL;
>>> -               goto out_redist_unmap;
>>> -       }
>>> +       if (collect_gicr_base(table))
>>> +               goto out_release_redist;
>>>
>>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>>          if (err)
>>> -               goto out_redist_unmap;
>>> +               goto out_release_redist;
>>>
>>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>>                             gic_acpi_gsi_desc_populate);
>>>          return 0;
>>>
>>> -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_release_redist:
>>> +       gic_acpi_release_redist_regions();
>>> +       if (!list_empty(&redist_list))
>>> +               gic_acpi_release_gicc_redist();
>>>   out_dist_unmap:
>>>          iounmap(dist_base);
>>>          return err;
>>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>>> index 56cd82c..0d43f515 100644
>>> --- a/include/linux/irqchip/arm-gic-acpi.h
>>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>>> @@ -21,5 +21,7 @@
>>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>>
>>> +u8 acpi_gic_version(void);
>>> +
>>>   #endif /* CONFIG_ACPI */
>>>   #endif /* ARM_GIC_ACPI_H_ */
>>> --
>>> 1.9.1
>>>
>>
>> This looks absolutely horrid. Why don't you simply populate one region
>> per redistributor, add a flag to struct redist_region so we know not to
>> check for GICR_TYPER_LAST but to move on to the next region instead?
> 
> There is no regions in GICC structures, and only have the GICR base
> address for each CPU, I think we can't figure out which GICR bases
> are belonging to a GICR region.
> 
> So do you mean populate each GICR base as a region, and use the
> existing infrastructure ?

This is exactly what I wrote.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-06 16:42         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: Hanjun Guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 05/08/15 15:11, Hanjun Guo wrote:
> On 08/04/2015 09:37 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> 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.
>>>
>>> As GICR base in MADT GICC is another way to indicate the GIC version
>>> is 3 or 4, add its support to find out the GIC versions.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 95454e3..3e5c8f4 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>
>>>   static phys_addr_t dist_phy_base __initdata;
>>>
>>> +u8 __init acpi_gic_version(void)
>>> +{
>>> +       return gic_version;
>>> +}
>>> +
>>>   static int __init
>>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>                             const unsigned long end)
>>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * If GICC is enabled but has no valid gicr base address, then it
>>> +        * means GICR base is not presented via GICC
>>> +        */
>>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>>> +               return -ENODEV;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int __init
>>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>   {
>>>          return 0;
>>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>                                          match_gic_redist, 0);
>>>
>>> -       /* that's true if we have at least one GIC redistributor entry */
>>> +       /* has at least one GIC redistributor entry */
>>> +       if (count > 0)
>>> +               return true;
>>> +
>>> +       /* else try to find GICR base in GICC entries */
>>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>>> +                                     gic_acpi_parse_madt_gicc, 0);
>>> +
>>>          return count > 0;
>>>   }
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index ebc5604..b72ccbb 100644
>>> --- a/drivers/irqchip/irq-gic-v3.c
>>> +++ b/drivers/irqchip/irq-gic-v3.c
>>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>>   }
>>>
>>> -static int gic_populate_rdist(void)
>>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>>   {
>>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>>          u64 typer;
>>>          u32 aff;
>>>          int i;
>>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>>                  } while (!(typer & GICR_TYPER_LAST));
>>>          }
>>>
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +/*
>>> + * Populate redist when GIC redistributor address is presented in ACPI
>>> + * MADT GICC entries
>>> + */
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>>> +#else
>>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       return -ENODEV;
>>> +}
>>> +#endif
>>> +
>>> +static int gic_populate_rdist(void)
>>> +{
>>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>>> +
>>> +       if (gic_data.nr_redist_regions) {
>>> +               if (!gic_populate_rdist_with_regions(mpidr))
>>> +                       return 0;
>>> +       } else {
>>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>>> +                       return 0;
>>> +       }
>>> +
>>>          /* We couldn't even deal with ourselves... */
>>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>>               smp_processor_id(), (unsigned long long)mpidr);
>>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>>
>>>   #ifdef CONFIG_ACPI
>>> +
>>> +struct acpi_gicc_redist {
>>> +       struct list_head list;
>>> +       u64 mpidr;
>>> +       phys_addr_t phys_base;
>>> +       void __iomem *redist_base;
>>> +};
>>> +
>>> +static LIST_HEAD(redist_list);
>>> +
>>>   static struct redist_region *redist_regs __initdata;
>>>   static u32 nr_redist_regions __initdata;
>>>   static phys_addr_t dist_phys_base __initdata;
>>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>>          return 0;
>>>   }
>>>
>>> +static void __init
>>> +gic_acpi_release_redist_regions(void)
>>> +{
>>> +       int i;
>>> +
>>> +       for (i = 0; i < nr_redist_regions; i++)
>>> +               if (redist_regs[i].redist_base)
>>> +                       iounmap(redist_regs[i].redist_base);
>>> +       kfree(redist_regs);
>>> +}
>>> +
>>>   static int __init
>>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>>                          const unsigned long end)
>>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +
>>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>>> +       if (!redist)
>>> +               return -ENOMEM;
>>> +
>>> +       redist->mpidr = mpidr;
>>> +       redist->phys_base = phys_base;
>>> +
>>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>>> +               /* RD_base + SGI_base */
>>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>>> +       else
>>> +               /*
>>> +                * RD_base + SGI_base + VLPI_base,
>>> +                * we don't map reserved page as it's buggy to access it
>>> +                */
>>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>>> +
>>> +       if (!redist->redist_base) {
>>> +               kfree(redist);
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       list_add(&redist->list, &redist_list);
>>> +       return 0;
>>> +}
>>> +
>>> +static void __init
>>> +gic_acpi_release_gicc_redist(void)
>>> +{
>>> +       struct acpi_gicc_redist *redist, *t;
>>> +
>>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>>> +               list_del(&redist->list);
>>> +               iounmap(redist->redist_base);
>>> +               kfree(redist);
>>> +       }
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * just quietly ingore the disabled CPU(s) and continue
>>> +        * to find the enabled one(s), if we return error here,
>>> +        * the scanning will be stopped.
>>> +        */
>>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>>> +               return 0;
>>> +
>>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>>> +                                       gicc->arm_mpidr);
>>> +}
>>> +
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +       void __iomem *ptr;
>>> +       u32 reg;
>>> +
>>> +       list_for_each_entry(redist, &redist_list, list) {
>>> +               if (redist->mpidr != mpidr)
>>> +                       continue;
>>> +
>>> +               ptr = redist->redist_base;
>>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +                       pr_warn("No redistributor present @%p\n", ptr);
>>> +                       return -ENODEV;
>>> +               }
>>> +
>>> +               gic_data_rdist_rd_base() = ptr;
>>> +               gic_data_rdist()->phys_base = redist->phys_base;
>>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>>> +                       smp_processor_id(),
>>> +                       (unsigned long long)mpidr,
>>> +                       &gic_data_rdist()->phys_base);
>>> +               return 0;
>>> +       }
>>> +
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>>> +{
>>> +       int count;
>>> +
>>> +       /* Collect redistributor base addresses in GICR entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_redist, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +       if (count > 0)
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>>> +
>>> +       /* Collect redistributor base addresses in GICC entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_gicc, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>>> +       if (count > 0 && !list_empty(&redist_list))
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICC entries exist for GICR base\n");
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init
>>>   gic_acpi_init(struct acpi_table_header *table)
>>>   {
>>> -       int count, i, err = 0;
>>> +       int count, err = 0;
>>>          void __iomem *dist_base;
>>>
>>>          /* Get distributor base address */
>>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>>          }
>>>
>>>          /* Collect redistributor base addresses */
>>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> -                       sizeof(struct acpi_table_madt),
>>> -                       gic_acpi_parse_madt_redist, table,
>>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> -       if (count <= 0) {
>>> -               pr_info("No valid GICR entries exist\n");
>>> -               err = -EINVAL;
>>> -               goto out_redist_unmap;
>>> -       }
>>> +       if (collect_gicr_base(table))
>>> +               goto out_release_redist;
>>>
>>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>>          if (err)
>>> -               goto out_redist_unmap;
>>> +               goto out_release_redist;
>>>
>>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>>                             gic_acpi_gsi_desc_populate);
>>>          return 0;
>>>
>>> -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_release_redist:
>>> +       gic_acpi_release_redist_regions();
>>> +       if (!list_empty(&redist_list))
>>> +               gic_acpi_release_gicc_redist();
>>>   out_dist_unmap:
>>>          iounmap(dist_base);
>>>          return err;
>>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>>> index 56cd82c..0d43f515 100644
>>> --- a/include/linux/irqchip/arm-gic-acpi.h
>>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>>> @@ -21,5 +21,7 @@
>>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>>
>>> +u8 acpi_gic_version(void);
>>> +
>>>   #endif /* CONFIG_ACPI */
>>>   #endif /* ARM_GIC_ACPI_H_ */
>>> --
>>> 1.9.1
>>>
>>
>> This looks absolutely horrid. Why don't you simply populate one region
>> per redistributor, add a flag to struct redist_region so we know not to
>> check for GICR_TYPER_LAST but to move on to the next region instead?
> 
> There is no regions in GICC structures, and only have the GICR base
> address for each CPU, I think we can't figure out which GICR bases
> are belonging to a GICR region.
> 
> So do you mean populate each GICR base as a region, and use the
> existing infrastructure ?

This is exactly what I wrote.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures
@ 2015-08-06 16:42         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-06 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/08/15 15:11, Hanjun Guo wrote:
> On 08/04/2015 09:37 PM, Marc Zyngier wrote:
>> On 29/07/15 11:08, Hanjun Guo wrote:
>>> 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.
>>>
>>> As GICR base in MADT GICC is another way to indicate the GIC version
>>> is 3 or 4, add its support to find out the GIC versions.
>>>
>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>> ---
>>>   drivers/irqchip/irq-gic-acpi.c       |  35 ++++++-
>>>   drivers/irqchip/irq-gic-v3.c         | 197 +++++++++++++++++++++++++++++++----
>>>   include/linux/irqchip/arm-gic-acpi.h |   2 +
>>>   3 files changed, 215 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c
>>> index 95454e3..3e5c8f4 100644
>>> --- a/drivers/irqchip/irq-gic-acpi.c
>>> +++ b/drivers/irqchip/irq-gic-acpi.c
>>> @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
>>>
>>>   static phys_addr_t dist_phy_base __initdata;
>>>
>>> +u8 __init acpi_gic_version(void)
>>> +{
>>> +       return gic_version;
>>> +}
>>> +
>>>   static int __init
>>>   acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>                             const unsigned long end)
>>> @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * If GICC is enabled but has no valid gicr base address, then it
>>> +        * means GICR base is not presented via GICC
>>> +        */
>>> +       if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
>>> +               return -ENODEV;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int __init
>>>   match_gic_redist(struct acpi_subtable_header *header, const unsigned long end)
>>>   {
>>>          return 0;
>>> @@ -51,7 +77,14 @@ static bool __init acpi_gic_redist_is_present(void)
>>>          count  =  acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
>>>                                          match_gic_redist, 0);
>>>
>>> -       /* that's true if we have at least one GIC redistributor entry */
>>> +       /* has at least one GIC redistributor entry */
>>> +       if (count > 0)
>>> +               return true;
>>> +
>>> +       /* else try to find GICR base in GICC entries */
>>> +       count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
>>> +                                     gic_acpi_parse_madt_gicc, 0);
>>> +
>>>          return count > 0;
>>>   }
>>>
>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>> index ebc5604..b72ccbb 100644
>>> --- a/drivers/irqchip/irq-gic-v3.c
>>> +++ b/drivers/irqchip/irq-gic-v3.c
>>> @@ -389,9 +389,8 @@ static void __init gic_dist_init(void)
>>>                  writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
>>>   }
>>>
>>> -static int gic_populate_rdist(void)
>>> +static int gic_populate_rdist_with_regions(u64 mpidr)
>>>   {
>>> -       u64 mpidr = cpu_logical_map(smp_processor_id());
>>>          u64 typer;
>>>          u32 aff;
>>>          int i;
>>> @@ -439,6 +438,34 @@ static int gic_populate_rdist(void)
>>>                  } while (!(typer & GICR_TYPER_LAST));
>>>          }
>>>
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +#ifdef CONFIG_ACPI
>>> +/*
>>> + * Populate redist when GIC redistributor address is presented in ACPI
>>> + * MADT GICC entries
>>> + */
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr);
>>> +#else
>>> +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       return -ENODEV;
>>> +}
>>> +#endif
>>> +
>>> +static int gic_populate_rdist(void)
>>> +{
>>> +       u64 mpidr = cpu_logical_map(smp_processor_id());
>>> +
>>> +       if (gic_data.nr_redist_regions) {
>>> +               if (!gic_populate_rdist_with_regions(mpidr))
>>> +                       return 0;
>>> +       } else {
>>> +               if (!gic_populate_rdist_with_gicr_base(mpidr))
>>> +                       return 0;
>>> +       }
>>> +
>>>          /* We couldn't even deal with ourselves... */
>>>          WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
>>>               smp_processor_id(), (unsigned long long)mpidr);
>>> @@ -900,6 +927,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
>>>   #endif
>>>
>>>   #ifdef CONFIG_ACPI
>>> +
>>> +struct acpi_gicc_redist {
>>> +       struct list_head list;
>>> +       u64 mpidr;
>>> +       phys_addr_t phys_base;
>>> +       void __iomem *redist_base;
>>> +};
>>> +
>>> +static LIST_HEAD(redist_list);
>>> +
>>>   static struct redist_region *redist_regs __initdata;
>>>   static u32 nr_redist_regions __initdata;
>>>   static phys_addr_t dist_phys_base __initdata;
>>> @@ -932,6 +969,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size)
>>>          return 0;
>>>   }
>>>
>>> +static void __init
>>> +gic_acpi_release_redist_regions(void)
>>> +{
>>> +       int i;
>>> +
>>> +       for (i = 0; i < nr_redist_regions; i++)
>>> +               if (redist_regs[i].redist_base)
>>> +                       iounmap(redist_regs[i].redist_base);
>>> +       kfree(redist_regs);
>>> +}
>>> +
>>>   static int __init
>>>   gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
>>>                          const unsigned long end)
>>> @@ -989,9 +1037,130 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
>>>   }
>>>
>>>   static int __init
>>> +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +
>>> +       redist = kzalloc(sizeof(*redist), GFP_KERNEL);
>>> +       if (!redist)
>>> +               return -ENOMEM;
>>> +
>>> +       redist->mpidr = mpidr;
>>> +       redist->phys_base = phys_base;
>>> +
>>> +       if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
>>> +               /* RD_base + SGI_base */
>>> +               redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
>>> +       else
>>> +               /*
>>> +                * RD_base + SGI_base + VLPI_base,
>>> +                * we don't map reserved page as it's buggy to access it
>>> +                */
>>> +               redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
>>> +
>>> +       if (!redist->redist_base) {
>>> +               kfree(redist);
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       list_add(&redist->list, &redist_list);
>>> +       return 0;
>>> +}
>>> +
>>> +static void __init
>>> +gic_acpi_release_gicc_redist(void)
>>> +{
>>> +       struct acpi_gicc_redist *redist, *t;
>>> +
>>> +       list_for_each_entry_safe(redist, t, &redist_list, list) {
>>> +               list_del(&redist->list);
>>> +               iounmap(redist->redist_base);
>>> +               kfree(redist);
>>> +       }
>>> +}
>>> +
>>> +static int __init
>>> +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
>>> +                        const unsigned long end)
>>> +{
>>> +       struct acpi_madt_generic_interrupt *gicc;
>>> +
>>> +       gicc = (struct acpi_madt_generic_interrupt *)header;
>>> +
>>> +       if (BAD_MADT_GICC_ENTRY(gicc, end))
>>> +               return -EINVAL;
>>> +
>>> +       /*
>>> +        * just quietly ingore the disabled CPU(s) and continue
>>> +        * to find the enabled one(s), if we return error here,
>>> +        * the scanning will be stopped.
>>> +        */
>>> +       if (!(gicc->flags & ACPI_MADT_ENABLED))
>>> +               return 0;
>>> +
>>> +       return gic_acpi_add_gicc_redist(gicc->gicr_base_address,
>>> +                                       gicc->arm_mpidr);
>>> +}
>>> +
>>> +static int gic_populate_rdist_with_gicr_base(u64 mpidr)
>>> +{
>>> +       struct acpi_gicc_redist *redist;
>>> +       void __iomem *ptr;
>>> +       u32 reg;
>>> +
>>> +       list_for_each_entry(redist, &redist_list, list) {
>>> +               if (redist->mpidr != mpidr)
>>> +                       continue;
>>> +
>>> +               ptr = redist->redist_base;
>>> +               reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
>>> +               if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
>>> +                       pr_warn("No redistributor present @%p\n", ptr);
>>> +                       return -ENODEV;
>>> +               }
>>> +
>>> +               gic_data_rdist_rd_base() = ptr;
>>> +               gic_data_rdist()->phys_base = redist->phys_base;
>>> +               pr_info("CPU%d: found redistributor %llx phys base:%pa\n",
>>> +                       smp_processor_id(),
>>> +                       (unsigned long long)mpidr,
>>> +                       &gic_data_rdist()->phys_base);
>>> +               return 0;
>>> +       }
>>> +
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init collect_gicr_base(struct acpi_table_header *table)
>>> +{
>>> +       int count;
>>> +
>>> +       /* Collect redistributor base addresses in GICR entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_redist, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> +       if (count > 0)
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICR entries exist, try GICC entries\n");
>>> +
>>> +       /* Collect redistributor base addresses in GICC entries */
>>> +       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> +                       sizeof(struct acpi_table_madt),
>>> +                       gic_acpi_parse_madt_gicc, table,
>>> +                       ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
>>> +       if (count > 0 && !list_empty(&redist_list))
>>> +               return 0;
>>> +
>>> +       pr_info("No valid GICC entries exist for GICR base\n");
>>> +       return -ENODEV;
>>> +}
>>> +
>>> +static int __init
>>>   gic_acpi_init(struct acpi_table_header *table)
>>>   {
>>> -       int count, i, err = 0;
>>> +       int count, err = 0;
>>>          void __iomem *dist_base;
>>>
>>>          /* Get distributor base address */
>>> @@ -1020,30 +1189,22 @@ gic_acpi_init(struct acpi_table_header *table)
>>>          }
>>>
>>>          /* Collect redistributor base addresses */
>>> -       count = acpi_parse_entries(ACPI_SIG_MADT,
>>> -                       sizeof(struct acpi_table_madt),
>>> -                       gic_acpi_parse_madt_redist, table,
>>> -                       ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
>>> -       if (count <= 0) {
>>> -               pr_info("No valid GICR entries exist\n");
>>> -               err = -EINVAL;
>>> -               goto out_redist_unmap;
>>> -       }
>>> +       if (collect_gicr_base(table))
>>> +               goto out_release_redist;
>>>
>>>          err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
>>>                               (void *)ACPI_IRQ_MODEL_GIC);
>>>          if (err)
>>> -               goto out_redist_unmap;
>>> +               goto out_release_redist;
>>>
>>>          acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>>                             gic_acpi_gsi_desc_populate);
>>>          return 0;
>>>
>>> -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_release_redist:
>>> +       gic_acpi_release_redist_regions();
>>> +       if (!list_empty(&redist_list))
>>> +               gic_acpi_release_gicc_redist();
>>>   out_dist_unmap:
>>>          iounmap(dist_base);
>>>          return err;
>>> diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
>>> index 56cd82c..0d43f515 100644
>>> --- a/include/linux/irqchip/arm-gic-acpi.h
>>> +++ b/include/linux/irqchip/arm-gic-acpi.h
>>> @@ -21,5 +21,7 @@
>>>   #define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
>>>   #define ACPI_GICV3_DIST_MEM_SIZE       (SZ_64K)
>>>
>>> +u8 acpi_gic_version(void);
>>> +
>>>   #endif /* CONFIG_ACPI */
>>>   #endif /* ARM_GIC_ACPI_H_ */
>>> --
>>> 1.9.1
>>>
>>
>> This looks absolutely horrid. Why don't you simply populate one region
>> per redistributor, add a flag to struct redist_region so we know not to
>> check for GICR_TYPER_LAST but to move on to the next region instead?
> 
> There is no regions in GICC structures, and only have the GICR base
> address for each CPU, I think we can't figure out which GICR bases
> are belonging to a GICR region.
> 
> So do you mean populate each GICR base as a region, and use the
> existing infrastructure ?

This is exactly what I wrote.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-08-04 14:04     ` Marc Zyngier
  (?)
@ 2015-08-07  8:42       ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-07  8:42 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 10:04 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.

Sure, I will sync with Suravee to fix that.

Thanks for you comments!
Hanjun

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07  8:42       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-07  8:42 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

On 08/04/2015 10:04 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.

Sure, I will sync with Suravee to fix that.

Thanks for you comments!
Hanjun

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07  8:42       ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-07  8:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/04/2015 10:04 PM, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.

Sure, I will sync with Suravee to fix that.

Thanks for you comments!
Hanjun

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-07-29 10:08   ` Hanjun Guo
@ 2015-08-07 10:03     ` Tomasz Nowicki
  -1 siblings, 0 replies; 116+ messages in thread
From: Tomasz Nowicki @ 2015-08-07 10:03 UTC (permalink / raw)
  To: Hanjun Guo, Marc Zyngier, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Timur Tabi, Grant Likely, Mark Brown,
	Wei Huang, linux-arm-kernel, linux-acpi, linux-kernel,
	linaro-acpi

On 29.07.2015 12:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>
> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>   drivers/pci/probe.c      |  3 +++
>   include/linux/pci-acpi.h |  4 ++++
>   3 files changed, 25 insertions(+)
>
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..5f11653 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -9,6 +9,7 @@
>
>   #include <linux/delay.h>
>   #include <linux/init.h>
> +#include <linux/irqdomain.h>
>   #include <linux/pci.h>
>   #include <linux/pci_hotplug.h>
>   #include <linux/module.h>
> @@ -16,6 +17,7 @@
>   #include <linux/pci-acpi.h>
>   #include <linux/pm_runtime.h>
>   #include <linux/pm_qos.h>
> +#include <acpi/acpi_gic.h>
>   #include "pci.h"
>
>   /*
> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>   	return dev_is_pci(dev);
>   }
>
> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> +{
> +	struct irq_domain *d = NULL;
> +	void *token = acpi_gic_get_msi_token(&bus->dev);
> +
> +	if (token)
> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
> +
> +	if (!d)
> +		pr_debug("Fail to find domain for MSI\n");
> +
> +	return d;
> +}
> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
> +
>   static struct acpi_bus_type acpi_pci_bus = {
>   	.name = "PCI",
>   	.match = pci_acpi_bus_match,
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index a7afeac..8c1204c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -12,6 +12,7 @@
>   #include <linux/module.h>
>   #include <linux/cpumask.h>
>   #include <linux/pci-aspm.h>
> +#include <linux/pci-acpi.h>
>   #include <asm-generic/pci-bridge.h>
>   #include "pci.h"
>
> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>   	 * should be called from here.
>   	 */
>   	d = pci_host_bridge_of_msi_domain(bus);
> +	if (!d)
> +		d = pci_host_bridge_acpi_msi_domain(bus);

Please use acpi_disabled here.

BTW. This is another place where we need to know our firmware - DT vs 
ACPI. I know we can use acpi_disabled but I think more about generic 
solution. Since we already have:
struct fwnode_handle	*fwnode;
we can create macro which identify h/w description style, something like:

#define FWNODE_TYPE(dev)	dev_fwnode(dev)->type

and then:

switch (FWNODE_TYPE(&bus->dev)) {
case FWNODE_OF:
...
case FWNODE_ACPI:
...
case FWNODE_XXX:
...
}

Root bus is special case since it has no frimware type but we could 
factor out pci_set_bus_of_node(). For platform devices we have all we 
need. Just thinking aloud, let me know your thoughts.

Regards,
Tomasz





>
>   	return d;
>   }
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index a965efa..766d045 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>   #endif
>
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
> +
>   extern const u8 pci_acpi_dsm_uuid[];
>   #define DEVICE_LABEL_DSM	0x07
>   #define RESET_DELAY_DSM		0x08
> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>   #else	/* CONFIG_ACPI */
>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
> +static inline struct irq_domain *
> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>   #endif	/* CONFIG_ACPI */
>
>   #ifdef CONFIG_ACPI_APEI
>

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07 10:03     ` Tomasz Nowicki
  0 siblings, 0 replies; 116+ messages in thread
From: Tomasz Nowicki @ 2015-08-07 10:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 29.07.2015 12:08, Hanjun Guo wrote:
> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>
> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> ---
>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>   drivers/pci/probe.c      |  3 +++
>   include/linux/pci-acpi.h |  4 ++++
>   3 files changed, 25 insertions(+)
>
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index 314a625..5f11653 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -9,6 +9,7 @@
>
>   #include <linux/delay.h>
>   #include <linux/init.h>
> +#include <linux/irqdomain.h>
>   #include <linux/pci.h>
>   #include <linux/pci_hotplug.h>
>   #include <linux/module.h>
> @@ -16,6 +17,7 @@
>   #include <linux/pci-acpi.h>
>   #include <linux/pm_runtime.h>
>   #include <linux/pm_qos.h>
> +#include <acpi/acpi_gic.h>
>   #include "pci.h"
>
>   /*
> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>   	return dev_is_pci(dev);
>   }
>
> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
> +{
> +	struct irq_domain *d = NULL;
> +	void *token = acpi_gic_get_msi_token(&bus->dev);
> +
> +	if (token)
> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
> +
> +	if (!d)
> +		pr_debug("Fail to find domain for MSI\n");
> +
> +	return d;
> +}
> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
> +
>   static struct acpi_bus_type acpi_pci_bus = {
>   	.name = "PCI",
>   	.match = pci_acpi_bus_match,
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index a7afeac..8c1204c 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -12,6 +12,7 @@
>   #include <linux/module.h>
>   #include <linux/cpumask.h>
>   #include <linux/pci-aspm.h>
> +#include <linux/pci-acpi.h>
>   #include <asm-generic/pci-bridge.h>
>   #include "pci.h"
>
> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>   	 * should be called from here.
>   	 */
>   	d = pci_host_bridge_of_msi_domain(bus);
> +	if (!d)
> +		d = pci_host_bridge_acpi_msi_domain(bus);

Please use acpi_disabled here.

BTW. This is another place where we need to know our firmware - DT vs 
ACPI. I know we can use acpi_disabled but I think more about generic 
solution. Since we already have:
struct fwnode_handle	*fwnode;
we can create macro which identify h/w description style, something like:

#define FWNODE_TYPE(dev)	dev_fwnode(dev)->type

and then:

switch (FWNODE_TYPE(&bus->dev)) {
case FWNODE_OF:
...
case FWNODE_ACPI:
...
case FWNODE_XXX:
...
}

Root bus is special case since it has no frimware type but we could 
factor out pci_set_bus_of_node(). For platform devices we have all we 
need. Just thinking aloud, let me know your thoughts.

Regards,
Tomasz





>
>   	return d;
>   }
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index a965efa..766d045 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>   #endif
>
> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
> +
>   extern const u8 pci_acpi_dsm_uuid[];
>   #define DEVICE_LABEL_DSM	0x07
>   #define RESET_DELAY_DSM		0x08
> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>   #else	/* CONFIG_ACPI */
>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
> +static inline struct irq_domain *
> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>   #endif	/* CONFIG_ACPI */
>
>   #ifdef CONFIG_ACPI_APEI
>

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-08-07 10:03     ` Tomasz Nowicki
@ 2015-08-07 10:48       ` Mark Brown
  -1 siblings, 0 replies; 116+ messages in thread
From: Mark Brown @ 2015-08-07 10:48 UTC (permalink / raw)
  To: Tomasz Nowicki
  Cc: Hanjun Guo, Marc Zyngier, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki, Thomas Gleixner, Jiang Liu,
	Bjorn Helgaas, Lorenzo Pieralisi, Suravee Suthikulpanit,
	Timur Tabi, Grant Likely, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

[-- Attachment #1: Type: text/plain, Size: 1227 bytes --]

On Fri, Aug 07, 2015 at 12:03:24PM +0200, Tomasz Nowicki wrote:

> >@@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
> >  	 * should be called from here.
> >  	 */
> >  	d = pci_host_bridge_of_msi_domain(bus);
> >+	if (!d)
> >+		d = pci_host_bridge_acpi_msi_domain(bus);
> 
> Please use acpi_disabled here.

> BTW. This is another place where we need to know our firmware - DT vs ACPI.
> I know we can use acpi_disabled but I think more about generic solution.
> Since we already have:
> struct fwnode_handle	*fwnode;
> we can create macro which identify h/w description style, something like:

> #define FWNODE_TYPE(dev)	dev_fwnode(dev)->type

> and then:

> switch (FWNODE_TYPE(&bus->dev)) {
> case FWNODE_OF:
> ...
> case FWNODE_ACPI:
> ...
> case FWNODE_XXX:
> ...
> }

> Root bus is special case since it has no frimware type but we could factor
> out pci_set_bus_of_node(). For platform devices we have all we need. Just
> thinking aloud, let me know your thoughts.

Not knowing the particular detail here but can we not go a step further
than that and have a fwnode_disabled() for this which does appropriate
things for both ACPI and DT?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07 10:48       ` Mark Brown
  0 siblings, 0 replies; 116+ messages in thread
From: Mark Brown @ 2015-08-07 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Aug 07, 2015 at 12:03:24PM +0200, Tomasz Nowicki wrote:

> >@@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
> >  	 * should be called from here.
> >  	 */
> >  	d = pci_host_bridge_of_msi_domain(bus);
> >+	if (!d)
> >+		d = pci_host_bridge_acpi_msi_domain(bus);
> 
> Please use acpi_disabled here.

> BTW. This is another place where we need to know our firmware - DT vs ACPI.
> I know we can use acpi_disabled but I think more about generic solution.
> Since we already have:
> struct fwnode_handle	*fwnode;
> we can create macro which identify h/w description style, something like:

> #define FWNODE_TYPE(dev)	dev_fwnode(dev)->type

> and then:

> switch (FWNODE_TYPE(&bus->dev)) {
> case FWNODE_OF:
> ...
> case FWNODE_ACPI:
> ...
> case FWNODE_XXX:
> ...
> }

> Root bus is special case since it has no frimware type but we could factor
> out pci_set_bus_of_node(). For platform devices we have all we need. Just
> thinking aloud, let me know your thoughts.

Not knowing the particular detail here but can we not go a step further
than that and have a fwnode_disabled() for this which does appropriate
things for both ACPI and DT?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150807/f5c2fece/attachment.sig>

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-08-07 10:03     ` Tomasz Nowicki
  (?)
@ 2015-08-07 12:06       ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-07 12:06 UTC (permalink / raw)
  To: Tomasz Nowicki, hanjun.guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, grant.likely, Mark Brown,
	Wei Huang, linux-arm-kernel, linux-acpi, linux-kernel,
	linaro-acpi

On 07/08/15 11:03, Tomasz Nowicki wrote:
> On 29.07.2015 12:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
> 
> Please use acpi_disabled here.

No, thanks. pci_host_bridge_acpi_msi_domain() can return NULL if ACPI is
disabled, just like pci_host_bridge_of_msi_domain will return NULL if
there is no domain to be found (or no OF support).

Littering various firmware predicates all over the place hardly seem
like a scalable solution, and I'd expect the ACPI backends to be self
contained.

> BTW. This is another place where we need to know our firmware - DT vs 
> ACPI. I know we can use acpi_disabled but I think more about generic 
> solution. Since we already have:
> struct fwnode_handle	*fwnode;
> we can create macro which identify h/w description style, something like:
> 
> #define FWNODE_TYPE(dev)	dev_fwnode(dev)->type
> 
> and then:
> 
> switch (FWNODE_TYPE(&bus->dev)) {
> case FWNODE_OF:
> ...
> case FWNODE_ACPI:
> ...
> case FWNODE_XXX:
> ...
> }
> 
> Root bus is special case since it has no frimware type but we could 
> factor out pci_set_bus_of_node(). For platform devices we have all we 
> need. Just thinking aloud, let me know your thoughts.

For that to work, we'd need to start converging device_node and
fwnode_handle. Having both feels quite redundant at the moment.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07 12:06       ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-07 12:06 UTC (permalink / raw)
  To: Tomasz Nowicki, hanjun.guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, grant.likely, Mark Brown,
	Wei Huang, linux-arm-kernel, linux-acpi, linux-kernel,
	linaro-acpi

On 07/08/15 11:03, Tomasz Nowicki wrote:
> On 29.07.2015 12:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
> 
> Please use acpi_disabled here.

No, thanks. pci_host_bridge_acpi_msi_domain() can return NULL if ACPI is
disabled, just like pci_host_bridge_of_msi_domain will return NULL if
there is no domain to be found (or no OF support).

Littering various firmware predicates all over the place hardly seem
like a scalable solution, and I'd expect the ACPI backends to be self
contained.

> BTW. This is another place where we need to know our firmware - DT vs 
> ACPI. I know we can use acpi_disabled but I think more about generic 
> solution. Since we already have:
> struct fwnode_handle	*fwnode;
> we can create macro which identify h/w description style, something like:
> 
> #define FWNODE_TYPE(dev)	dev_fwnode(dev)->type
> 
> and then:
> 
> switch (FWNODE_TYPE(&bus->dev)) {
> case FWNODE_OF:
> ...
> case FWNODE_ACPI:
> ...
> case FWNODE_XXX:
> ...
> }
> 
> Root bus is special case since it has no frimware type but we could 
> factor out pci_set_bus_of_node(). For platform devices we have all we 
> need. Just thinking aloud, let me know your thoughts.

For that to work, we'd need to start converging device_node and
fwnode_handle. Having both feels quite redundant at the moment.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-07 12:06       ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-07 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/08/15 11:03, Tomasz Nowicki wrote:
> On 29.07.2015 12:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
> 
> Please use acpi_disabled here.

No, thanks. pci_host_bridge_acpi_msi_domain() can return NULL if ACPI is
disabled, just like pci_host_bridge_of_msi_domain will return NULL if
there is no domain to be found (or no OF support).

Littering various firmware predicates all over the place hardly seem
like a scalable solution, and I'd expect the ACPI backends to be self
contained.

> BTW. This is another place where we need to know our firmware - DT vs 
> ACPI. I know we can use acpi_disabled but I think more about generic 
> solution. Since we already have:
> struct fwnode_handle	*fwnode;
> we can create macro which identify h/w description style, something like:
> 
> #define FWNODE_TYPE(dev)	dev_fwnode(dev)->type
> 
> and then:
> 
> switch (FWNODE_TYPE(&bus->dev)) {
> case FWNODE_OF:
> ...
> case FWNODE_ACPI:
> ...
> case FWNODE_XXX:
> ...
> }
> 
> Root bus is special case since it has no frimware type but we could 
> factor out pci_set_bus_of_node(). For platform devices we have all we 
> need. Just thinking aloud, let me know your thoughts.

For that to work, we'd need to start converging device_node and
fwnode_handle. Having both feels quite redundant at the moment.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
  2015-08-04 14:02     ` Marc Zyngier
  (?)
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  -1 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

Sorry for late reply. Please see my comments below.

On 8/4/15 21:02, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
>> token that can be used to look up MSI doamin of a device.
>> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
>> or GIC ITS structure is used as a token for MSI domain.
>>
>> In addition, this patch also provides low-level helper functions to parse
>> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
>> a copy of the structure for use in subsequent queries to avoid having
>> to map and parse MADT multiple times.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/acpi/Makefile   |   1 +
>>   drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/acpi/acpi_gic.h |  23 +++++
>>   include/linux/acpi.h    |   1 +
>>   4 files changed, 259 insertions(+)
>>   create mode 100644 drivers/acpi/acpi_gic.c
>>   create mode 100644 include/acpi/acpi_gic.h
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index 8321430..def54b9 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>>   acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>   acpi-y				+= acpi_lpat.o
>>   acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
>> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>>
>>   # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
>> new file mode 100644
>> index 0000000..11ee4eb
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_gic.c
>
> I think this is starting badly. If this is GIC specific, it lives in
> drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
> specific at all. If there are things you need to expose through the ACPI
> layer, add some indirections.

OK, originally, I intended for this to be an intermediate layer b/w ACPI 
and irqchip, but I guess that's still not what you are looking for. I'll 
rework this again.

[....]
>> +
>> +#endif /*__ACPI_GIC_H__*/
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 04dd0bb..5d58b61 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -44,6 +44,7 @@
>>
>>   #include <acpi/acpi_bus.h>
>>   #include <acpi/acpi_drivers.h>
>> +#include <acpi/acpi_gic.h>
>
> Ah! No.
>
>>   #include <acpi/acpi_numa.h>
>>   #include <acpi/acpi_io.h>
>>   #include <asm/acpi.h>
>>
>
> Right. Very little of what is above belongs to the ACPI layer. What
> would belong here is a generic acpi_get_msi_domain_token(dev) that would
> call into a controller-specific function to parse the various tables and
> find out which GICv2m frame (or which ITS) is serving the given device.
> This would include parsing of the IORT structures if they are available.

The problem here is we would need to figure out the hook into *a 
controller-specific function* from a generic layer (ACPI in this case).

> For GICv2m, it should be simplistic: just return the domain_token of the
> v2m widget. For the ITS, it is slightly more complex, and there should
> be some specific backend for that. There is no ACPI support for the ITS
> yet, so that shouldn't be your concern at this point in time.
>
> Overall, drivers/acpi should be hardware agnostic (or at least aim for
> it), just like drivers/of is.

I think I understand how you don't like the current approach. Lemme try 
a different approach and send out another revision.

Thanks,
Suravee

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

* Re: [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

Sorry for late reply. Please see my comments below.

On 8/4/15 21:02, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
>> token that can be used to look up MSI doamin of a device.
>> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
>> or GIC ITS structure is used as a token for MSI domain.
>>
>> In addition, this patch also provides low-level helper functions to parse
>> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
>> a copy of the structure for use in subsequent queries to avoid having
>> to map and parse MADT multiple times.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/acpi/Makefile   |   1 +
>>   drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/acpi/acpi_gic.h |  23 +++++
>>   include/linux/acpi.h    |   1 +
>>   4 files changed, 259 insertions(+)
>>   create mode 100644 drivers/acpi/acpi_gic.c
>>   create mode 100644 include/acpi/acpi_gic.h
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index 8321430..def54b9 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>>   acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>   acpi-y				+= acpi_lpat.o
>>   acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
>> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>>
>>   # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
>> new file mode 100644
>> index 0000000..11ee4eb
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_gic.c
>
> I think this is starting badly. If this is GIC specific, it lives in
> drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
> specific at all. If there are things you need to expose through the ACPI
> layer, add some indirections.

OK, originally, I intended for this to be an intermediate layer b/w ACPI 
and irqchip, but I guess that's still not what you are looking for. I'll 
rework this again.

[....]
>> +
>> +#endif /*__ACPI_GIC_H__*/
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 04dd0bb..5d58b61 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -44,6 +44,7 @@
>>
>>   #include <acpi/acpi_bus.h>
>>   #include <acpi/acpi_drivers.h>
>> +#include <acpi/acpi_gic.h>
>
> Ah! No.
>
>>   #include <acpi/acpi_numa.h>
>>   #include <acpi/acpi_io.h>
>>   #include <asm/acpi.h>
>>
>
> Right. Very little of what is above belongs to the ACPI layer. What
> would belong here is a generic acpi_get_msi_domain_token(dev) that would
> call into a controller-specific function to parse the various tables and
> find out which GICv2m frame (or which ITS) is serving the given device.
> This would include parsing of the IORT structures if they are available.

The problem here is we would need to figure out the hook into *a 
controller-specific function* from a generic layer (ACPI in this case).

> For GICv2m, it should be simplistic: just return the domain_token of the
> v2m widget. For the ITS, it is slightly more complex, and there should
> be some specific backend for that. There is no ACPI support for the ITS
> yet, so that shouldn't be your concern at this point in time.
>
> Overall, drivers/acpi should be hardware agnostic (or at least aim for
> it), just like drivers/of is.

I think I understand how you don't like the current approach. Lemme try 
a different approach and send out another revision.

Thanks,
Suravee

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

* [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

Sorry for late reply. Please see my comments below.

On 8/4/15 21:02, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces acpi_gic_get_msi_token(), which returns irq-domain
>> token that can be used to look up MSI doamin of a device.
>> In both GIC MSI and ITS cases, the base_address specified in the GIC MSI
>> or GIC ITS structure is used as a token for MSI domain.
>>
>> In addition, this patch also provides low-level helper functions to parse
>> and query GIC MSI structure and GIC ITS from MADT. Once parsed, it keeps
>> a copy of the structure for use in subsequent queries to avoid having
>> to map and parse MADT multiple times.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/acpi/Makefile   |   1 +
>>   drivers/acpi/acpi_gic.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/acpi/acpi_gic.h |  23 +++++
>>   include/linux/acpi.h    |   1 +
>>   4 files changed, 259 insertions(+)
>>   create mode 100644 drivers/acpi/acpi_gic.c
>>   create mode 100644 include/acpi/acpi_gic.h
>>
>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>> index 8321430..def54b9 100644
>> --- a/drivers/acpi/Makefile
>> +++ b/drivers/acpi/Makefile
>> @@ -54,6 +54,7 @@ acpi-$(CONFIG_ACPI_NUMA)	+= numa.o
>>   acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
>>   acpi-y				+= acpi_lpat.o
>>   acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
>> +acpi-$(CONFIG_ARM_GIC_ACPI)	+= acpi_gic.o
>>
>>   # These are (potentially) separate modules
>>
>> diff --git a/drivers/acpi/acpi_gic.c b/drivers/acpi/acpi_gic.c
>> new file mode 100644
>> index 0000000..11ee4eb
>> --- /dev/null
>> +++ b/drivers/acpi/acpi_gic.c
>
> I think this is starting badly. If this is GIC specific, it lives in
> drivers/irqchip. Nothing in drivers/acpi should be interrupt-controller
> specific at all. If there are things you need to expose through the ACPI
> layer, add some indirections.

OK, originally, I intended for this to be an intermediate layer b/w ACPI 
and irqchip, but I guess that's still not what you are looking for. I'll 
rework this again.

[....]
>> +
>> +#endif /*__ACPI_GIC_H__*/
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 04dd0bb..5d58b61 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -44,6 +44,7 @@
>>
>>   #include <acpi/acpi_bus.h>
>>   #include <acpi/acpi_drivers.h>
>> +#include <acpi/acpi_gic.h>
>
> Ah! No.
>
>>   #include <acpi/acpi_numa.h>
>>   #include <acpi/acpi_io.h>
>>   #include <asm/acpi.h>
>>
>
> Right. Very little of what is above belongs to the ACPI layer. What
> would belong here is a generic acpi_get_msi_domain_token(dev) that would
> call into a controller-specific function to parse the various tables and
> find out which GICv2m frame (or which ITS) is serving the given device.
> This would include parsing of the IORT structures if they are available.

The problem here is we would need to figure out the hook into *a 
controller-specific function* from a generic layer (ACPI in this case).

> For GICv2m, it should be simplistic: just return the domain_token of the
> v2m widget. For the ITS, it is slightly more complex, and there should
> be some specific backend for that. There is no ACPI support for the ITS
> yet, so that shouldn't be your concern at this point in time.
>
> Overall, drivers/acpi should be hardware agnostic (or at least aim for
> it), just like drivers/of is.

I think I understand how you don't like the current approach. Lemme try 
a different approach and send out another revision.

Thanks,
Suravee

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
  2015-08-04 14:04     ` Marc Zyngier
  (?)
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  -1 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

On 8/4/15 21:04, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.
>
> Thanks,
>
> 	M.
>

Ok. Thanks,

Suravee

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

* Re: [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

On 8/4/15 21:04, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.
>
> Thanks,
>
> 	M.
>

Ok. Thanks,

Suravee

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

* [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge
@ 2015-08-09  8:02       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 8/4/15 21:04, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces pci_host_bridge_acpi_msi_domain(), which queries
>> a GIC MSI irq-domain token and use it to retrieve an irq_domain with
>> DOMAIN_BUS_PCI_MSI bus type, and bind it to PCI host-bridge.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/pci/pci-acpi.c   | 18 ++++++++++++++++++
>>   drivers/pci/probe.c      |  3 +++
>>   include/linux/pci-acpi.h |  4 ++++
>>   3 files changed, 25 insertions(+)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index 314a625..5f11653 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -9,6 +9,7 @@
>>
>>   #include <linux/delay.h>
>>   #include <linux/init.h>
>> +#include <linux/irqdomain.h>
>>   #include <linux/pci.h>
>>   #include <linux/pci_hotplug.h>
>>   #include <linux/module.h>
>> @@ -16,6 +17,7 @@
>>   #include <linux/pci-acpi.h>
>>   #include <linux/pm_runtime.h>
>>   #include <linux/pm_qos.h>
>> +#include <acpi/acpi_gic.h>
>>   #include "pci.h"
>>
>>   /*
>> @@ -681,6 +683,22 @@ static bool pci_acpi_bus_match(struct device *dev)
>>   	return dev_is_pci(dev);
>>   }
>>
>> +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
>> +{
>> +	struct irq_domain *d = NULL;
>> +	void *token = acpi_gic_get_msi_token(&bus->dev);
>
> Do you see why I positively *hate* having hardware details in generic
> layers? They propagate everywhere...
>
>> +
>> +	if (token)
>> +		d = irq_find_matching_host(token, DOMAIN_BUS_PCI_MSI);
>> +
>> +	if (!d)
>> +		pr_debug("Fail to find domain for MSI\n");
>> +
>> +	return d;
>> +}
>> +#endif /*CONFIG_GENERIC_MSI_IRQ_DOMAIN*/
>> +
>>   static struct acpi_bus_type acpi_pci_bus = {
>>   	.name = "PCI",
>>   	.match = pci_acpi_bus_match,
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index a7afeac..8c1204c 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -12,6 +12,7 @@
>>   #include <linux/module.h>
>>   #include <linux/cpumask.h>
>>   #include <linux/pci-aspm.h>
>> +#include <linux/pci-acpi.h>
>>   #include <asm-generic/pci-bridge.h>
>>   #include "pci.h"
>>
>> @@ -670,6 +671,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
>>   	 * should be called from here.
>>   	 */
>>   	d = pci_host_bridge_of_msi_domain(bus);
>> +	if (!d)
>> +		d = pci_host_bridge_acpi_msi_domain(bus);
>>
>>   	return d;
>>   }
>> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
>> index a965efa..766d045 100644
>> --- a/include/linux/pci-acpi.h
>> +++ b/include/linux/pci-acpi.h
>> @@ -77,6 +77,8 @@ static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
>>   static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
>>   #endif
>>
>> +struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
>> +
>>   extern const u8 pci_acpi_dsm_uuid[];
>>   #define DEVICE_LABEL_DSM	0x07
>>   #define RESET_DELAY_DSM		0x08
>> @@ -85,6 +87,8 @@ extern const u8 pci_acpi_dsm_uuid[];
>>   #else	/* CONFIG_ACPI */
>>   static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>>   static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>> +static inline struct irq_domain *
>> +pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
>>   #endif	/* CONFIG_ACPI */
>>
>>   #ifdef CONFIG_ACPI_APEI
>>
>
> Once you solve the HW abstraction issue, this will be OK.
>
> Thanks,
>
> 	M.
>

Ok. Thanks,

Suravee

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

* Re: [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
  2015-08-04 14:23     ` Marc Zyngier
  (?)
@ 2015-08-09  8:04       ` Suravee Suthikulpanit
  -1 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:04 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

On 8/4/15 21:23, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces gicv2m_acpi_init(), which uses information
>> in MADT GIC MSI frames structure to initialize GICv2m driver.
>> It also refactors gicv2m_init_one() to handle both DT and ACPI
>> initialization path.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>>   drivers/irqchip/irq-gic.c       |   3 ++
>>   include/linux/irqchip/arm-gic.h |   7 +++
>>   3 files changed, 98 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
>> index d0fcbf8..c491a08 100644
>> --- a/drivers/irqchip/irq-gic-v2m.c
>> +++ b/drivers/irqchip/irq-gic-v2m.c
>> @@ -15,6 +15,7 @@
>>
>>   #define pr_fmt(fmt) "GICv2m: " fmt
>>
>> +#include <linux/acpi.h>
>>   #include <linux/irq.h>
>>   #include <linux/irqdomain.h>
>>   #include <linux/kernel.h>
>> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>>   	return true;
>>   }
>>
>> +char gicv2m_domain_name[] = "GICV2M";
>> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
>> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
>> +
>
> Can't these be static? Why do we need them?

Of course, this is not needed. I figured it was useful when I was 
debugging the irq domain hierarchy stuff. I'll remove it then.

[...]
>> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>>
>>   	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>>   	     child = of_find_matching_node(child, gicv2m_device_id)) {
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct resource res;
>> +
>>   		if (!of_find_property(child, "msi-controller", NULL))
>>   			continue;
>>
>> -		ret = gicv2m_init_one(child, parent);
>> +		ret = of_address_to_resource(child, 0, &res);
>> +		if (ret) {
>> +			pr_err("Failed to allocate v2m resource.\n");
>> +			break;
>> +		}
>> +
>> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
>> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
>> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>
> If these spi_start and nr_spis pointers passed to gicv2m_init_one are
> only for the benefit of printing the message below, just move the
> message inside the function...
>

Ok.

>> +				      child);
>>   		if (ret) {
>>   			of_node_put(node);
>>   			break;
>>   		}
>> +
>> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>>   	}
>>
>>   	return ret;
>>   }
>> +
>> +#ifdef CONFIG_ACPI
>> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
>> +			    struct irq_domain *parent)
>> +{
>> +	int i, ret;
>> +
>> +	ret = acpi_gic_msi_init(table);
>> +	if (ret)
>> +		return ret;
>> +
>> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
>> +		struct resource res;
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct acpi_madt_generic_msi_frame *m;
>> +
>> +		ret = acpi_gic_get_msi_frame(i, &m);
>> +		if (ret)
>> +			return ret;
>> +
>
> All of that should be moved here. And we don't need to build an
> intermediate representation. Just build the v2m_data structures as you go.

I'll rework the ACPI MADT parsing, and move it into this file, and get 
rid of the structure.

>> +		res.start = m->base_address;
>> +		res.end = m->base_address + 0x1000;
>> +
>> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
>> +			spi_start = m->spi_base;
>> +			nr_spis = m->spi_count;
>> +
>> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +		}
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>> +				      (void *)(m->base_address));
>> +		if (ret)
>> +			break;
>> +
>> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
>> +			m->msi_frame_id,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>> +	}
>> +	return ret;
>> +}
>> +
>> +#endif /* CONFIG_ACPI */
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index bec6b00..531ebbc 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>>   	 */
>>   	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>>
>> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
>> +		gicv2m_acpi_init(table, gic_data[0].domain);
>> +
>>   	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>   			   gic_acpi_gsi_desc_populate);
>>   	return 0;
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 97799b7..27d8196 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>>
>>   int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>>
>> +#ifdef CONFIG_ACPI
>> +struct acpi_table_header;
>> +
>> +int gicv2m_acpi_init(struct acpi_table_header *table,
>> +		     struct irq_domain *parent);
>> +#endif
>> +
>>   void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>>   int gic_get_cpu_id(unsigned int cpu);
>>   void gic_migrate_target(unsigned int new_cpu_id);
>>
>
> This needs rework to do the parsing of the tables in this driver. Just
> expose the domain_token through a function that you register with the
> ACPI layer.

Ok. I'll investigate and rework this to only expose the domain_token.

Basically, I would need a way to pass down a device from ACPI layer into 
irqchips (e.g. GICv2m and GICv3-ITS), so that it can verify the device 
with the MSI domains and return the appropriate domain token (or some 
sort of domain reference).

Thanks,
Suravee

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

* Re: [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
@ 2015-08-09  8:04       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:04 UTC (permalink / raw)
  To: Marc Zyngier, Hanjun Guo, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Timur Tabi, Tomasz Nowicki, grant.likely, Mark Brown, Wei Huang,
	linux-arm-kernel, linux-acpi, linux-kernel, linaro-acpi

Hi Marc,

On 8/4/15 21:23, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces gicv2m_acpi_init(), which uses information
>> in MADT GIC MSI frames structure to initialize GICv2m driver.
>> It also refactors gicv2m_init_one() to handle both DT and ACPI
>> initialization path.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>>   drivers/irqchip/irq-gic.c       |   3 ++
>>   include/linux/irqchip/arm-gic.h |   7 +++
>>   3 files changed, 98 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
>> index d0fcbf8..c491a08 100644
>> --- a/drivers/irqchip/irq-gic-v2m.c
>> +++ b/drivers/irqchip/irq-gic-v2m.c
>> @@ -15,6 +15,7 @@
>>
>>   #define pr_fmt(fmt) "GICv2m: " fmt
>>
>> +#include <linux/acpi.h>
>>   #include <linux/irq.h>
>>   #include <linux/irqdomain.h>
>>   #include <linux/kernel.h>
>> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>>   	return true;
>>   }
>>
>> +char gicv2m_domain_name[] = "GICV2M";
>> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
>> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
>> +
>
> Can't these be static? Why do we need them?

Of course, this is not needed. I figured it was useful when I was 
debugging the irq domain hierarchy stuff. I'll remove it then.

[...]
>> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>>
>>   	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>>   	     child = of_find_matching_node(child, gicv2m_device_id)) {
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct resource res;
>> +
>>   		if (!of_find_property(child, "msi-controller", NULL))
>>   			continue;
>>
>> -		ret = gicv2m_init_one(child, parent);
>> +		ret = of_address_to_resource(child, 0, &res);
>> +		if (ret) {
>> +			pr_err("Failed to allocate v2m resource.\n");
>> +			break;
>> +		}
>> +
>> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
>> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
>> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>
> If these spi_start and nr_spis pointers passed to gicv2m_init_one are
> only for the benefit of printing the message below, just move the
> message inside the function...
>

Ok.

>> +				      child);
>>   		if (ret) {
>>   			of_node_put(node);
>>   			break;
>>   		}
>> +
>> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>>   	}
>>
>>   	return ret;
>>   }
>> +
>> +#ifdef CONFIG_ACPI
>> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
>> +			    struct irq_domain *parent)
>> +{
>> +	int i, ret;
>> +
>> +	ret = acpi_gic_msi_init(table);
>> +	if (ret)
>> +		return ret;
>> +
>> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
>> +		struct resource res;
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct acpi_madt_generic_msi_frame *m;
>> +
>> +		ret = acpi_gic_get_msi_frame(i, &m);
>> +		if (ret)
>> +			return ret;
>> +
>
> All of that should be moved here. And we don't need to build an
> intermediate representation. Just build the v2m_data structures as you go.

I'll rework the ACPI MADT parsing, and move it into this file, and get 
rid of the structure.

>> +		res.start = m->base_address;
>> +		res.end = m->base_address + 0x1000;
>> +
>> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
>> +			spi_start = m->spi_base;
>> +			nr_spis = m->spi_count;
>> +
>> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +		}
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>> +				      (void *)(m->base_address));
>> +		if (ret)
>> +			break;
>> +
>> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
>> +			m->msi_frame_id,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>> +	}
>> +	return ret;
>> +}
>> +
>> +#endif /* CONFIG_ACPI */
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index bec6b00..531ebbc 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>>   	 */
>>   	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>>
>> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
>> +		gicv2m_acpi_init(table, gic_data[0].domain);
>> +
>>   	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>   			   gic_acpi_gsi_desc_populate);
>>   	return 0;
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 97799b7..27d8196 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>>
>>   int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>>
>> +#ifdef CONFIG_ACPI
>> +struct acpi_table_header;
>> +
>> +int gicv2m_acpi_init(struct acpi_table_header *table,
>> +		     struct irq_domain *parent);
>> +#endif
>> +
>>   void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>>   int gic_get_cpu_id(unsigned int cpu);
>>   void gic_migrate_target(unsigned int new_cpu_id);
>>
>
> This needs rework to do the parsing of the tables in this driver. Just
> expose the domain_token through a function that you register with the
> ACPI layer.

Ok. I'll investigate and rework this to only expose the domain_token.

Basically, I would need a way to pass down a device from ACPI layer into 
irqchips (e.g. GICv2m and GICv3-ITS), so that it can verify the device 
with the MSI domains and return the appropriate domain token (or some 
sort of domain reference).

Thanks,
Suravee

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

* [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init()
@ 2015-08-09  8:04       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 116+ messages in thread
From: Suravee Suthikulpanit @ 2015-08-09  8:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 8/4/15 21:23, Marc Zyngier wrote:
> On 29/07/15 11:08, Hanjun Guo wrote:
>> From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>>
>> This patch introduces gicv2m_acpi_init(), which uses information
>> in MADT GIC MSI frames structure to initialize GICv2m driver.
>> It also refactors gicv2m_init_one() to handle both DT and ACPI
>> initialization path.
>>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> ---
>>   drivers/irqchip/irq-gic-v2m.c   | 111 +++++++++++++++++++++++++++++++---------
>>   drivers/irqchip/irq-gic.c       |   3 ++
>>   include/linux/irqchip/arm-gic.h |   7 +++
>>   3 files changed, 98 insertions(+), 23 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
>> index d0fcbf8..c491a08 100644
>> --- a/drivers/irqchip/irq-gic-v2m.c
>> +++ b/drivers/irqchip/irq-gic-v2m.c
>> @@ -15,6 +15,7 @@
>>
>>   #define pr_fmt(fmt) "GICv2m: " fmt
>>
>> +#include <linux/acpi.h>
>>   #include <linux/irq.h>
>>   #include <linux/irqdomain.h>
>>   #include <linux/kernel.h>
>> @@ -211,6 +212,10 @@ static bool is_msi_spi_valid(u32 base, u32 num)
>>   	return true;
>>   }
>>
>> +char gicv2m_domain_name[] = "GICV2M";
>> +char gicv2m_pci_msi_domain_name[] = "GICV2M-PCI-MSI";
>> +char gicv2m_plat_msi_domain_name[] = "GICV2M-PLAT-MSI";
>> +
>
> Can't these be static? Why do we need them?

Of course, this is not needed. I figured it was useful when I was 
debugging the irq domain hierarchy stuff. I'll remove it then.

[...]
>> @@ -329,15 +330,79 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
>>
>>   	for (child = of_find_matching_node(node, gicv2m_device_id); child;
>>   	     child = of_find_matching_node(child, gicv2m_device_id)) {
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct resource res;
>> +
>>   		if (!of_find_property(child, "msi-controller", NULL))
>>   			continue;
>>
>> -		ret = gicv2m_init_one(child, parent);
>> +		ret = of_address_to_resource(child, 0, &res);
>> +		if (ret) {
>> +			pr_err("Failed to allocate v2m resource.\n");
>> +			break;
>> +		}
>> +
>> +		if (!of_property_read_u32(child, "arm,msi-base-spi", &spi_start) &&
>> +		    !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
>> +			pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>
> If these spi_start and nr_spis pointers passed to gicv2m_init_one are
> only for the benefit of printing the message below, just move the
> message inside the function...
>

Ok.

>> +				      child);
>>   		if (ret) {
>>   			of_node_put(node);
>>   			break;
>>   		}
>> +
>> +		pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", child->name,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>>   	}
>>
>>   	return ret;
>>   }
>> +
>> +#ifdef CONFIG_ACPI
>> +int __init gicv2m_acpi_init(struct acpi_table_header *table,
>> +			    struct irq_domain *parent)
>> +{
>> +	int i, ret;
>> +
>> +	ret = acpi_gic_msi_init(table);
>> +	if (ret)
>> +		return ret;
>> +
>> +	for (i = 0; i < acpi_gic_get_num_msi_frame(); i++) {
>> +		struct resource res;
>> +		u32 spi_start = 0, nr_spis = 0;
>> +		struct acpi_madt_generic_msi_frame *m;
>> +
>> +		ret = acpi_gic_get_msi_frame(i, &m);
>> +		if (ret)
>> +			return ret;
>> +
>
> All of that should be moved here. And we don't need to build an
> intermediate representation. Just build the v2m_data structures as you go.

I'll rework the ACPI MADT parsing, and move it into this file, and get 
rid of the structure.

>> +		res.start = m->base_address;
>> +		res.end = m->base_address + 0x1000;
>> +
>> +		if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
>> +			spi_start = m->spi_base;
>> +			nr_spis = m->spi_count;
>> +
>> +			pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
>> +				spi_start, nr_spis);
>> +		}
>> +
>> +		ret = gicv2m_init_one(parent, &spi_start, &nr_spis, &res,
>> +				      (void *)(m->base_address));
>> +		if (ret)
>> +			break;
>> +
>> +		pr_info("MSI frame ID %u: range[%#lx:%#lx], SPI[%d:%d]\n",
>> +			m->msi_frame_id,
>> +			(unsigned long)res.start, (unsigned long)res.end,
>> +			spi_start, (spi_start + nr_spis));
>> +	}
>> +	return ret;
>> +}
>> +
>> +#endif /* CONFIG_ACPI */
>> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
>> index bec6b00..531ebbc 100644
>> --- a/drivers/irqchip/irq-gic.c
>> +++ b/drivers/irqchip/irq-gic.c
>> @@ -1159,6 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table)
>>   	 */
>>   	gic_init_bases(0, -1, dist_base, cpu_base, 0, (void *)ACPI_IRQ_MODEL_GIC);
>>
>> +	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
>> +		gicv2m_acpi_init(table, gic_data[0].domain);
>> +
>>   	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_GIC,
>>   			   gic_acpi_gsi_desc_populate);
>>   	return 0;
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 97799b7..27d8196 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -109,6 +109,13 @@ static inline void gic_init(unsigned int nr, int start,
>>
>>   int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
>>
>> +#ifdef CONFIG_ACPI
>> +struct acpi_table_header;
>> +
>> +int gicv2m_acpi_init(struct acpi_table_header *table,
>> +		     struct irq_domain *parent);
>> +#endif
>> +
>>   void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
>>   int gic_get_cpu_id(unsigned int cpu);
>>   void gic_migrate_target(unsigned int new_cpu_id);
>>
>
> This needs rework to do the parsing of the tables in this driver. Just
> expose the domain_token through a function that you register with the
> ACPI layer.

Ok. I'll investigate and rework this to only expose the domain_token.

Basically, I would need a way to pass down a device from ACPI layer into 
irqchips (e.g. GICv2m and GICv3-ITS), so that it can verify the device 
with the MSI domains and return the appropriate domain token (or some 
sort of domain reference).

Thanks,
Suravee

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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
  2015-08-06 16:42         ` Marc Zyngier
  (?)
@ 2015-08-11  7:19           ` Hanjun Guo
  -1 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-11  7:19 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

Hi Marc,

On 08/07/2015 12:42 AM, Marc Zyngier wrote:
> On 05/08/15 15:00, Hanjun Guo wrote:
>> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>>
>>>> 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.
>>>>
>>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>> [hj: Rework this patch and fix multi issues]
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>>    1 file changed, 169 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>>> index c0b96c6..ebc5604 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>
>>>> @@ -25,6 +26,7 @@
>>>>    #include <linux/percpu.h>
>>>>    #include <linux/slab.h>
>>>>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>>    #include <linux/irqchip/arm-gic-v3.h>
>>>>
>>>>    #include <asm/cputype.h>
>>>> @@ -802,7 +804,8 @@ 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())
>>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>>> +                     &gic_data.rdists, gic_data.domain);
>>>
>>> This doesn't make much sense. The first parameter to its_init is indeed
>>> supposed to be an of_node, but what is the point of calling its_init if
>>> you *know* you don't have the necessary topological information to parse
>>> the firmware tables?
>>>
>>> I don't see *any* code that is going to parse the ITS table in this
>>> series, so please don't call its_init passing a NULL pointer to it. This
>>> is just gross.
>>
>> OK, the ITS ACPI code is in later patch which combined with IORT. How
>> about moving it to the GIC of init code temporary?
>
> Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
> NULL. But don't call it with a NULL parameter.

OK.

[...]

>>>> +}
>>>> +IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init);
>>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>>
>>> As mentioned before, this doesn't work.
>>
>> hmm, I think we need more discussion for this one, but we need to match
>> V4 for GICv3 drivers, and everything will be the same in the dirver
>> as I said before.
>
> And as I said before, you don't need to distinguish v3 from v4 in the
> ACPI code. Matching GICv3 is enough.

OK, how about the following code when parsing the GIC version?

/*
  * GICv3 driver can find out it's V3 or V4 itself, just set the
  * gic_version to V3 to match the driver if firmware presented V4.
  */
if (gic_version == ACPI_MADT_GIC_VERSION_V4)
         gic_version = ACPI_MADT_GIC_VERSION_V3;

Thanks
Hanjun



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

* Re: [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-11  7:19           ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-11  7:19 UTC (permalink / raw)
  To: Marc Zyngier, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	suravee.suthikulpanit, Timur Tabi, Tomasz Nowicki, grant.likely,
	Mark Brown, Wei Huang, linux-arm-kernel, linux-acpi,
	linux-kernel, linaro-acpi

Hi Marc,

On 08/07/2015 12:42 AM, Marc Zyngier wrote:
> On 05/08/15 15:00, Hanjun Guo wrote:
>> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>>
>>>> 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.
>>>>
>>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>> [hj: Rework this patch and fix multi issues]
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>>    1 file changed, 169 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>>> index c0b96c6..ebc5604 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>
>>>> @@ -25,6 +26,7 @@
>>>>    #include <linux/percpu.h>
>>>>    #include <linux/slab.h>
>>>>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>>    #include <linux/irqchip/arm-gic-v3.h>
>>>>
>>>>    #include <asm/cputype.h>
>>>> @@ -802,7 +804,8 @@ 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())
>>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>>> +                     &gic_data.rdists, gic_data.domain);
>>>
>>> This doesn't make much sense. The first parameter to its_init is indeed
>>> supposed to be an of_node, but what is the point of calling its_init if
>>> you *know* you don't have the necessary topological information to parse
>>> the firmware tables?
>>>
>>> I don't see *any* code that is going to parse the ITS table in this
>>> series, so please don't call its_init passing a NULL pointer to it. This
>>> is just gross.
>>
>> OK, the ITS ACPI code is in later patch which combined with IORT. How
>> about moving it to the GIC of init code temporary?
>
> Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
> NULL. But don't call it with a NULL parameter.

OK.

[...]

>>>> +}
>>>> +IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init);
>>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>>
>>> As mentioned before, this doesn't work.
>>
>> hmm, I think we need more discussion for this one, but we need to match
>> V4 for GICv3 drivers, and everything will be the same in the dirver
>> as I said before.
>
> And as I said before, you don't need to distinguish v3 from v4 in the
> ACPI code. Matching GICv3 is enough.

OK, how about the following code when parsing the GIC version?

/*
  * GICv3 driver can find out it's V3 or V4 itself, just set the
  * gic_version to V3 to match the driver if firmware presented V4.
  */
if (gic_version == ACPI_MADT_GIC_VERSION_V4)
         gic_version = ACPI_MADT_GIC_VERSION_V3;

Thanks
Hanjun



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

* [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization
@ 2015-08-11  7:19           ` Hanjun Guo
  0 siblings, 0 replies; 116+ messages in thread
From: Hanjun Guo @ 2015-08-11  7:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 08/07/2015 12:42 AM, Marc Zyngier wrote:
> On 05/08/15 15:00, Hanjun Guo wrote:
>> On 08/04/2015 09:17 PM, Marc Zyngier wrote:
>>> On 29/07/15 11:08, Hanjun Guo wrote:
>>>> From: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>>
>>>> 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.
>>>>
>>>> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
>>>> [hj: Rework this patch and fix multi issues]
>>>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>>>> ---
>>>>    drivers/irqchip/irq-gic-v3.c | 174 +++++++++++++++++++++++++++++++++++++++++--
>>>>    1 file changed, 169 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
>>>> index c0b96c6..ebc5604 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>
>>>> @@ -25,6 +26,7 @@
>>>>    #include <linux/percpu.h>
>>>>    #include <linux/slab.h>
>>>>
>>>> +#include <linux/irqchip/arm-gic-acpi.h>
>>>>    #include <linux/irqchip/arm-gic-v3.h>
>>>>
>>>>    #include <asm/cputype.h>
>>>> @@ -802,7 +804,8 @@ 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())
>>>> -            its_init(domain_token, &gic_data.rdists, gic_data.domain);
>>>> +            its_init(irq_domain_token_to_of_node(domain_token),
>>>> +                     &gic_data.rdists, gic_data.domain);
>>>
>>> This doesn't make much sense. The first parameter to its_init is indeed
>>> supposed to be an of_node, but what is the point of calling its_init if
>>> you *know* you don't have the necessary topological information to parse
>>> the firmware tables?
>>>
>>> I don't see *any* code that is going to parse the ITS table in this
>>> series, so please don't call its_init passing a NULL pointer to it. This
>>> is just gross.
>>
>> OK, the ITS ACPI code is in later patch which combined with IORT. How
>> about moving it to the GIC of init code temporary?
>
> Just don't call its_init if irq_domain_token_to_of_node(domain_token) is
> NULL. But don't call it with a NULL parameter.

OK.

[...]

>>>> +}
>>>> +IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init);
>>>> +IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_GIC_VERSION_V4, gic_acpi_init);
>>>
>>> As mentioned before, this doesn't work.
>>
>> hmm, I think we need more discussion for this one, but we need to match
>> V4 for GICv3 drivers, and everything will be the same in the dirver
>> as I said before.
>
> And as I said before, you don't need to distinguish v3 from v4 in the
> ACPI code. Matching GICv3 is enough.

OK, how about the following code when parsing the GIC version?

/*
  * GICv3 driver can find out it's V3 or V4 itself, just set the
  * gic_version to V3 to match the driver if firmware presented V4.
  */
if (gic_version == ACPI_MADT_GIC_VERSION_V4)
         gic_version = ACPI_MADT_GIC_VERSION_V3;

Thanks
Hanjun

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-07-29 10:08 ` Hanjun Guo
@ 2015-08-11 22:01   ` Timur Tabi
  -1 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 22:01 UTC (permalink / raw)
  To: Hanjun Guo, Marc Zyngier, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki
  Cc: Thomas Gleixner, Jiang Liu, Bjorn Helgaas, Lorenzo Pieralisi,
	Suravee Suthikulpanit, Tomasz Nowicki, Grant Likely, Mark Brown,
	Wei Huang, linux-arm-kernel, linux-acpi, linux-kernel,
	linaro-acpi

On 07/29/2015 05:08 AM, Hanjun Guo wrote:
> Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
> at:
>
> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain

Is it my imagination, or is Marc's branch based on v3.9-rc7?

Also, shouldn't this code be based on the upstream kernel, and not the 
LEG kernel?

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:01   ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 22:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/29/2015 05:08 AM, Hanjun Guo wrote:
> Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
> at:
>
> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain

Is it my imagination, or is Marc's branch based on v3.9-rc7?

Also, shouldn't this code be based on the upstream kernel, and not the 
LEG kernel?

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [Linaro-acpi] [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 22:01   ` Timur Tabi
  (?)
@ 2015-08-11 22:24     ` G Gregory
  -1 siblings, 0 replies; 116+ messages in thread
From: G Gregory @ 2015-08-11 22:24 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Hanjun Guo, Marc Zyngier, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki, Wei Huang, linux-acpi,
	Linaro ACPI Mailman List, linux-kernel, Mark Brown,
	Bjorn Helgaas, Thomas Gleixner, Jiang Liu, linux-arm-kernel

On 11 August 2015 at 23:01, Timur Tabi <timur@codeaurora.org> wrote:
> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
>>
>> Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
>> at:
>>
>> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
>
>
> Is it my imagination, or is Marc's branch based on v3.9-rc7?
>
Looks like 4.2-rc2 to me.

> Also, shouldn't this code be based on the upstream kernel, and not the LEG
> kernel?
>
Nothing LEG kernelly in there.

Graeme

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

* Re: [Linaro-acpi] [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:24     ` G Gregory
  0 siblings, 0 replies; 116+ messages in thread
From: G Gregory @ 2015-08-11 22:24 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Hanjun Guo, Marc Zyngier, Jason Cooper, Will Deacon,
	Catalin Marinas, Rafael J. Wysocki, Wei Huang, linux-acpi,
	Linaro ACPI Mailman List, linux-kernel, Mark Brown,
	Bjorn Helgaas, Thomas Gleixner, Jiang Liu, linux-arm-kernel

On 11 August 2015 at 23:01, Timur Tabi <timur@codeaurora.org> wrote:
> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
>>
>> Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
>> at:
>>
>> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
>
>
> Is it my imagination, or is Marc's branch based on v3.9-rc7?
>
Looks like 4.2-rc2 to me.

> Also, shouldn't this code be based on the upstream kernel, and not the LEG
> kernel?
>
Nothing LEG kernelly in there.

Graeme

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

* [Linaro-acpi] [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:24     ` G Gregory
  0 siblings, 0 replies; 116+ messages in thread
From: G Gregory @ 2015-08-11 22:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 11 August 2015 at 23:01, Timur Tabi <timur@codeaurora.org> wrote:
> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
>>
>> Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
>> at:
>>
>> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
>
>
> Is it my imagination, or is Marc's branch based on v3.9-rc7?
>
Looks like 4.2-rc2 to me.

> Also, shouldn't this code be based on the upstream kernel, and not the LEG
> kernel?
>
Nothing LEG kernelly in there.

Graeme

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 22:01   ` Timur Tabi
  (?)
@ 2015-08-11 22:25     ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:25 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Tue, 11 Aug 2015 23:01:57 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
> > Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
> > at:
> >
> > git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
> 
> Is it my imagination, or is Marc's branch based on v3.9-rc7?

That's definitely your imagination. I've stopped working on 3.9 over
two years ago...

> Also, shouldn't this code be based on the upstream kernel, and not the 
> LEG kernel?

My branch, as far as I can tell by looking at my own git tree, is based
on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
only work on this thing called "the Linux kernel". You may have heard
of it! ;-)

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:25     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:25 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Tue, 11 Aug 2015 23:01:57 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
> > Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
> > at:
> >
> > git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
> 
> Is it my imagination, or is Marc's branch based on v3.9-rc7?

That's definitely your imagination. I've stopped working on 3.9 over
two years ago...

> Also, shouldn't this code be based on the upstream kernel, and not the 
> LEG kernel?

My branch, as far as I can tell by looking at my own git tree, is based
on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
only work on this thing called "the Linux kernel". You may have heard
of it! ;-)

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:25     ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 11 Aug 2015 23:01:57 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 07/29/2015 05:08 AM, Hanjun Guo wrote:
> > Patches are on top of Marc's branch irq/gsi-irq-domain-v2, and available
> > at:
> >
> > git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain
> 
> Is it my imagination, or is Marc's branch based on v3.9-rc7?

That's definitely your imagination. I've stopped working on 3.9 over
two years ago...

> Also, shouldn't this code be based on the upstream kernel, and not the 
> LEG kernel?

My branch, as far as I can tell by looking at my own git tree, is based
on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
only work on this thing called "the Linux kernel". You may have heard
of it! ;-)

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 22:25     ` Marc Zyngier
  (?)
@ 2015-08-11 22:36       ` Timur Tabi
  -1 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 22:36 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> My branch, as far as I can tell by looking at my own git tree, is based
> on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> only work on this thing called "the Linux kernel". You may have heard
> of it!;-)

Then what is this:

git://git.linaro.org/leg/acpi/acpi.git
                      ^^^

This is your tree, isn't it?  Hanjun said, "Patches are on top of Marc's 
branch irq/gsi-irq-domain-v2, and available at: 
git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".


-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:36       ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 22:36 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> My branch, as far as I can tell by looking at my own git tree, is based
> on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> only work on this thing called "the Linux kernel". You may have heard
> of it!;-)

Then what is this:

git://git.linaro.org/leg/acpi/acpi.git
                      ^^^

This is your tree, isn't it?  Hanjun said, "Patches are on top of Marc's 
branch irq/gsi-irq-domain-v2, and available at: 
git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".


-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:36       ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 22:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> My branch, as far as I can tell by looking at my own git tree, is based
> on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> only work on this thing called "the Linux kernel". You may have heard
> of it!;-)

Then what is this:

git://git.linaro.org/leg/acpi/acpi.git
                      ^^^

This is your tree, isn't it?  Hanjun said, "Patches are on top of Marc's 
branch irq/gsi-irq-domain-v2, and available at: 
git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".


-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 22:36       ` Timur Tabi
  (?)
@ 2015-08-11 22:48         ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:48 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Tue, 11 Aug 2015 23:36:14 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> > My branch, as far as I can tell by looking at my own git tree, is based
> > on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> > only work on this thing called "the Linux kernel". You may have heard
> > of it!;-)
> 
> Then what is this:
> 
> git://git.linaro.org/leg/acpi/acpi.git
>                       ^^^
> 
> This is your tree, isn't it?  

My tree would have "maz" in it, and would rather be hosted on
kernel.org.

> Hanjun said, "Patches are on top of Marc's 
> branch irq/gsi-irq-domain-v2, and available at: 
> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".

I don't see any contradiction here. Hanjun picked the patches from my
own branch in my own tree, put his own patches on top, and pushed that
out on an branch called gsi-irqdomain that is definitely based on
4.2-rc2. I have no idea where your 3.9-rc7 comes from.

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:48         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:48 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Tue, 11 Aug 2015 23:36:14 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> > My branch, as far as I can tell by looking at my own git tree, is based
> > on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> > only work on this thing called "the Linux kernel". You may have heard
> > of it!;-)
> 
> Then what is this:
> 
> git://git.linaro.org/leg/acpi/acpi.git
>                       ^^^
> 
> This is your tree, isn't it?  

My tree would have "maz" in it, and would rather be hosted on
kernel.org.

> Hanjun said, "Patches are on top of Marc's 
> branch irq/gsi-irq-domain-v2, and available at: 
> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".

I don't see any contradiction here. Hanjun picked the patches from my
own branch in my own tree, put his own patches on top, and pushed that
out on an branch called gsi-irqdomain that is definitely based on
4.2-rc2. I have no idea where your 3.9-rc7 comes from.

	M.
-- 
Jazz is not dead. It just smells funny.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 22:48         ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-11 22:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 11 Aug 2015 23:36:14 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:25 PM, Marc Zyngier wrote:
> > My branch, as far as I can tell by looking at my own git tree, is based
> > on v4.2-rc2. As for "the LEG kernel", I have no idea what that is. I
> > only work on this thing called "the Linux kernel". You may have heard
> > of it!;-)
> 
> Then what is this:
> 
> git://git.linaro.org/leg/acpi/acpi.git
>                       ^^^
> 
> This is your tree, isn't it?  

My tree would have "maz" in it, and would rather be hosted on
kernel.org.

> Hanjun said, "Patches are on top of Marc's 
> branch irq/gsi-irq-domain-v2, and available at: 
> git://git.linaro.org/leg/acpi/acpi.git gsi-irqdomain".

I don't see any contradiction here. Hanjun picked the patches from my
own branch in my own tree, put his own patches on top, and pushed that
out on an branch called gsi-irqdomain that is definitely based on
4.2-rc2. I have no idea where your 3.9-rc7 comes from.

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 22:48         ` Marc Zyngier
  (?)
@ 2015-08-11 23:33           ` Timur Tabi
  -1 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 23:33 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> I don't see any contradiction here. Hanjun picked the patches from my
> own branch in my own tree, put his own patches on top, and pushed that
> out on an branch called gsi-irqdomain that is definitely based on
> 4.2-rc2. I have no idea where your 3.9-rc7 comes from.

Ok, so that's not your kernel, but the LEG kernel instead.

The top commits show this:

Follows: tracking-mainline-llct-20130415.0, 
tracking-mainline-llct-20130417.0, v3.9-rc7

Also,
	$ git tag | grep v4

shows no v4.x tags.

Anyway, I don't want to make a big deal about this.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 23:33           ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 23:33 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> I don't see any contradiction here. Hanjun picked the patches from my
> own branch in my own tree, put his own patches on top, and pushed that
> out on an branch called gsi-irqdomain that is definitely based on
> 4.2-rc2. I have no idea where your 3.9-rc7 comes from.

Ok, so that's not your kernel, but the LEG kernel instead.

The top commits show this:

Follows: tracking-mainline-llct-20130415.0, 
tracking-mainline-llct-20130417.0, v3.9-rc7

Also,
	$ git tag | grep v4

shows no v4.x tags.

Anyway, I don't want to make a big deal about this.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-11 23:33           ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-11 23:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> I don't see any contradiction here. Hanjun picked the patches from my
> own branch in my own tree, put his own patches on top, and pushed that
> out on an branch called gsi-irqdomain that is definitely based on
> 4.2-rc2. I have no idea where your 3.9-rc7 comes from.

Ok, so that's not your kernel, but the LEG kernel instead.

The top commits show this:

Follows: tracking-mainline-llct-20130415.0, 
tracking-mainline-llct-20130417.0, v3.9-rc7

Also,
	$ git tag | grep v4

shows no v4.x tags.

Anyway, I don't want to make a big deal about this.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-11 23:33           ` Timur Tabi
  (?)
@ 2015-08-12  7:21             ` Marc Zyngier
  -1 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-12  7:21 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Wed, 12 Aug 2015 00:33:44 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> > I don't see any contradiction here. Hanjun picked the patches from my
> > own branch in my own tree, put his own patches on top, and pushed that
> > out on an branch called gsi-irqdomain that is definitely based on
> > 4.2-rc2. I have no idea where your 3.9-rc7 comes from.
> 
> Ok, so that's not your kernel, but the LEG kernel instead.
> 
> The top commits show this:
> 
> Follows: tracking-mainline-llct-20130415.0, 
> tracking-mainline-llct-20130417.0, v3.9-rc7
> 
> Also,
> 	$ git tag | grep v4
> 
> shows no v4.x tags.
> 
> Anyway, I don't want to make a big deal about this.

I just cloned this repository, and none of the branches I received have
this as their top commit. I can only guess that you're looking at
something else.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-12  7:21             ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-12  7:21 UTC (permalink / raw)
  To: Timur Tabi
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On Wed, 12 Aug 2015 00:33:44 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> > I don't see any contradiction here. Hanjun picked the patches from my
> > own branch in my own tree, put his own patches on top, and pushed that
> > out on an branch called gsi-irqdomain that is definitely based on
> > 4.2-rc2. I have no idea where your 3.9-rc7 comes from.
> 
> Ok, so that's not your kernel, but the LEG kernel instead.
> 
> The top commits show this:
> 
> Follows: tracking-mainline-llct-20130415.0, 
> tracking-mainline-llct-20130417.0, v3.9-rc7
> 
> Also,
> 	$ git tag | grep v4
> 
> shows no v4.x tags.
> 
> Anyway, I don't want to make a big deal about this.

I just cloned this repository, and none of the branches I received have
this as their top commit. I can only guess that you're looking at
something else.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-12  7:21             ` Marc Zyngier
  0 siblings, 0 replies; 116+ messages in thread
From: Marc Zyngier @ 2015-08-12  7:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 12 Aug 2015 00:33:44 +0100
Timur Tabi <timur@codeaurora.org> wrote:

> On 08/11/2015 05:48 PM, Marc Zyngier wrote:
> > I don't see any contradiction here. Hanjun picked the patches from my
> > own branch in my own tree, put his own patches on top, and pushed that
> > out on an branch called gsi-irqdomain that is definitely based on
> > 4.2-rc2. I have no idea where your 3.9-rc7 comes from.
> 
> Ok, so that's not your kernel, but the LEG kernel instead.
> 
> The top commits show this:
> 
> Follows: tracking-mainline-llct-20130415.0, 
> tracking-mainline-llct-20130417.0, v3.9-rc7
> 
> Also,
> 	$ git tag | grep v4
> 
> shows no v4.x tags.
> 
> Anyway, I don't want to make a big deal about this.

I just cloned this repository, and none of the branches I received have
this as their top commit. I can only guess that you're looking at
something else.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
  2015-08-12  7:21             ` Marc Zyngier
  (?)
@ 2015-08-12 19:20               ` Timur Tabi
  -1 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-12 19:20 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/12/2015 02:21 AM, Marc Zyngier wrote:
> I just cloned this repository, and none of the branches I received have
> this as their top commit. I can only guess that you're looking at
> something else.

It took me way too long, but I can see the v4.2-rc2 merge commit now.  I 
blame sunspots for my poor git-fu.  Sorry for all the noise.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-12 19:20               ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-12 19:20 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: hanjun.guo, Jason Cooper, Will Deacon, Catalin Marinas,
	Rafael J. Wysocki, Thomas Gleixner, Jiang Liu, Bjorn Helgaas,
	Lorenzo Pieralisi, suravee.suthikulpanit, Tomasz Nowicki,
	grant.likely, Mark Brown, Wei Huang, linux-arm-kernel,
	linux-acpi, linux-kernel, linaro-acpi

On 08/12/2015 02:21 AM, Marc Zyngier wrote:
> I just cloned this repository, and none of the branches I received have
> this as their top commit. I can only guess that you're looking at
> something else.

It took me way too long, but I can see the v4.2-rc2 merge commit now.  I 
blame sunspots for my poor git-fu.  Sorry for all the noise.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

* [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support
@ 2015-08-12 19:20               ` Timur Tabi
  0 siblings, 0 replies; 116+ messages in thread
From: Timur Tabi @ 2015-08-12 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/12/2015 02:21 AM, Marc Zyngier wrote:
> I just cloned this repository, and none of the branches I received have
> this as their top commit. I can only guess that you're looking at
> something else.

It took me way too long, but I can see the v4.2-rc2 merge commit now.  I 
blame sunspots for my poor git-fu.  Sorry for all the noise.

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

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

end of thread, other threads:[~2015-08-12 19:20 UTC | newest]

Thread overview: 116+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-29 10:08 [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support Hanjun Guo
2015-07-29 10:08 ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 01/10] irqchip / GIC: Add GIC version support in ACPI MADT Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 12:06   ` Marc Zyngier
2015-08-04 12:06     ` Marc Zyngier
2015-08-04 12:06     ` Marc Zyngier
2015-08-05 12:40     ` Hanjun Guo
2015-08-05 12:40       ` Hanjun Guo
2015-08-05 12:40       ` Hanjun Guo
2015-08-05 12:57       ` Marc Zyngier
2015-08-05 12:57         ` Marc Zyngier
2015-08-05 12:57         ` Marc Zyngier
2015-08-05 13:11         ` Hanjun Guo
2015-08-05 13:11           ` Hanjun Guo
2015-08-05 13:11           ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 02/10] ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 12:27   ` Marc Zyngier
2015-08-04 12:27     ` Marc Zyngier
2015-08-04 12:27     ` Marc Zyngier
2015-08-05 13:24     ` Hanjun Guo
2015-08-05 13:24       ` Hanjun Guo
2015-08-05 13:24       ` Hanjun Guo
2015-08-06 16:29       ` Marc Zyngier
2015-08-06 16:29         ` Marc Zyngier
2015-08-06 16:29         ` Marc Zyngier
2015-07-29 10:08 ` [PATCH v4 03/10] irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 04/10] irqchip / GICv3: Refactor gic_of_init() for GICv3 driver Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 05/10] irqchip / GICv3: remove the useless comparision of device node in xlate Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 06/10] irqchip / GICv3: Add ACPI support for GICv3+ initialization Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 13:17   ` Marc Zyngier
2015-08-04 13:17     ` Marc Zyngier
2015-08-04 13:17     ` Marc Zyngier
2015-08-05 14:00     ` Hanjun Guo
2015-08-05 14:00       ` Hanjun Guo
2015-08-05 14:00       ` Hanjun Guo
2015-08-06 16:42       ` Marc Zyngier
2015-08-06 16:42         ` Marc Zyngier
2015-08-06 16:42         ` Marc Zyngier
2015-08-11  7:19         ` Hanjun Guo
2015-08-11  7:19           ` Hanjun Guo
2015-08-11  7:19           ` Hanjun Guo
2015-07-29 10:08 ` [PATCH v4 07/10] irqchip / GICv3 / ACPI: Add GICR support via GICC structures Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 13:37   ` Marc Zyngier
2015-08-04 13:37     ` Marc Zyngier
2015-08-04 13:37     ` Marc Zyngier
2015-08-05 14:11     ` Hanjun Guo
2015-08-05 14:11       ` Hanjun Guo
2015-08-05 14:11       ` Hanjun Guo
2015-08-06 16:42       ` Marc Zyngier
2015-08-06 16:42         ` Marc Zyngier
2015-08-06 16:42         ` Marc Zyngier
2015-07-29 10:08 ` [PATCH v4 08/10] ACPI: GIC: Add ACPI helper functions to query irq-domain tokens for for GIC MSI and ITS Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 14:02   ` Marc Zyngier
2015-08-04 14:02     ` Marc Zyngier
2015-08-04 14:02     ` Marc Zyngier
2015-08-09  8:02     ` Suravee Suthikulpanit
2015-08-09  8:02       ` Suravee Suthikulpanit
2015-08-09  8:02       ` Suravee Suthikulpanit
2015-07-29 10:08 ` [PATCH v4 09/10] PCI: ACPI: Bind GIC MSI frame to PCI host bridge Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 14:04   ` Marc Zyngier
2015-08-04 14:04     ` Marc Zyngier
2015-08-04 14:04     ` Marc Zyngier
2015-08-07  8:42     ` Hanjun Guo
2015-08-07  8:42       ` Hanjun Guo
2015-08-07  8:42       ` Hanjun Guo
2015-08-09  8:02     ` Suravee Suthikulpanit
2015-08-09  8:02       ` Suravee Suthikulpanit
2015-08-09  8:02       ` Suravee Suthikulpanit
2015-08-07 10:03   ` Tomasz Nowicki
2015-08-07 10:03     ` Tomasz Nowicki
2015-08-07 10:48     ` Mark Brown
2015-08-07 10:48       ` Mark Brown
2015-08-07 12:06     ` Marc Zyngier
2015-08-07 12:06       ` Marc Zyngier
2015-08-07 12:06       ` Marc Zyngier
2015-07-29 10:08 ` [PATCH v4 10/10] irqchip / gicv2m: Introducing gicv2m_acpi_init() Hanjun Guo
2015-07-29 10:08   ` Hanjun Guo
2015-08-04 14:23   ` Marc Zyngier
2015-08-04 14:23     ` Marc Zyngier
2015-08-04 14:23     ` Marc Zyngier
2015-08-09  8:04     ` Suravee Suthikulpanit
2015-08-09  8:04       ` Suravee Suthikulpanit
2015-08-09  8:04       ` Suravee Suthikulpanit
2015-08-11 22:01 ` [PATCH v4 00/10] ACPI GIC Self-probing, GICv2m and GICv3 support Timur Tabi
2015-08-11 22:01   ` Timur Tabi
2015-08-11 22:24   ` [Linaro-acpi] " G Gregory
2015-08-11 22:24     ` G Gregory
2015-08-11 22:24     ` G Gregory
2015-08-11 22:25   ` Marc Zyngier
2015-08-11 22:25     ` Marc Zyngier
2015-08-11 22:25     ` Marc Zyngier
2015-08-11 22:36     ` Timur Tabi
2015-08-11 22:36       ` Timur Tabi
2015-08-11 22:36       ` Timur Tabi
2015-08-11 22:48       ` Marc Zyngier
2015-08-11 22:48         ` Marc Zyngier
2015-08-11 22:48         ` Marc Zyngier
2015-08-11 23:33         ` Timur Tabi
2015-08-11 23:33           ` Timur Tabi
2015-08-11 23:33           ` Timur Tabi
2015-08-12  7:21           ` Marc Zyngier
2015-08-12  7:21             ` Marc Zyngier
2015-08-12  7:21             ` Marc Zyngier
2015-08-12 19:20             ` Timur Tabi
2015-08-12 19:20               ` Timur Tabi
2015-08-12 19:20               ` Timur Tabi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.