This patch set introduce self-probe infrastructure to init IRQ controllers and stacked irqdomain support for ACPI based GICv2/3 init.
The self-probe infrastructure for ACPI GIC init is similar as IRQCHIP_DECLARE() and based on the GIC version support in ACPI MADT table.
We introduce acpi_irq_domain for GICv2/3 core domain to support stacked irqdomain, and pass the gsi (global system interrupt) as the agument (void *arg) for gic_irq_domain_alloc(), then we can alloc virqs via acpi_register_gsi() with stacked irqdomain.
In order to make ACPI related GIC init code slef-contained, I consolidated all the GIC init code into drivers/irqchip/irq-gic-acpi.c.
update from RFC version: - Consolidate all the GIC init code into drivers/irqchip/irq-gic-acpi.c
Hanjun Guo (8): irqchip / GIC: Add GIC version support in ACPI MADT irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code irqchip / gic: Add stacked irqdomain support for ACPI based GICv2 init ACPI / gsi: Add gsi_mutex to synchronize acpi_register_gsi()/acpi_unregister_gsi() irqchip / GICv3: Add ACPI support for GICv3+ initialization irqchip / GICv3: Add stacked irqdomain support for ACPI based init irqchip / GICv2 / ACPI: Consolidate GICv2 ACPI related init code irqchip / GICv3 / ACPI: Consolidate GICv3 ACPI related init code
Tomasz Nowicki (3): ACPICA: Introduce GIC version for arm based system ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
arch/arm64/Kconfig | 1 + arch/arm64/include/asm/irq.h | 13 -- arch/arm64/kernel/acpi.c | 25 --- drivers/acpi/Makefile | 1 + drivers/acpi/gsi.c | 41 +++-- drivers/acpi/irq.c | 40 +++++ drivers/irqchip/Kconfig | 3 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-gic-acpi.c | 318 +++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3.c | 149 +++++++++------- drivers/irqchip/irq-gic.c | 129 ++------------ drivers/irqchip/irqchip.h | 12 ++ include/acpi/actbl1.h | 17 +- include/asm-generic/vmlinux.lds.h | 13 ++ include/linux/acpi.h | 14 ++ include/linux/acpi_irq.h | 4 +- include/linux/irqchip/arm-gic-acpi.h | 13 +- include/linux/irqchip/arm-gic-v3.h | 10 ++ include/linux/mod_devicetable.h | 7 + 19 files changed, 577 insertions(+), 234 deletions(-) create mode 100644 drivers/acpi/irq.c create mode 100644 drivers/irqchip/irq-gic-acpi.c
From: Tomasz Nowicki tomasz.nowicki@linaro.org
A new field is added in GIC distributor to indication the GIC version, support it in ACPICA for later use
Will upstreamed by Lv Zheng after ACPICA supporting ACPI 6.0 is released.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- include/acpi/actbl1.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index b80b0e6..b4f0f74 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -819,7 +819,7 @@ struct acpi_madt_generic_interrupt { #define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */ #define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */
-/* 12: Generic Distributor (ACPI 5.0) */ +/* 12: Generic Distributor (ACPI 6.0) */
struct acpi_madt_generic_distributor { struct acpi_subtable_header header; @@ -827,7 +827,20 @@ struct acpi_madt_generic_distributor { u32 gic_id; u64 base_address; u32 global_irq_base; - u32 reserved2; /* reserved - must be zero */ + u8 gic_version; + u8 reserved2[3]; /* reserved - must be zero */ +}; + +/* Values for gic_version in Generic Distributor (ACPI 6.0) */ + +enum acpi_madt_gic_ver_type +{ + ACPI_MADT_GIC_VER_UNKNOWN = 0, + ACPI_MADT_GIC_VER_V1 = 1, + ACPI_MADT_GIC_VER_V2 = 2, + ACPI_MADT_GIC_VER_V3 = 3, + ACPI_MADT_GIC_VER_V4 = 4, + ACPI_MADT_GIC_VER_RESERVED = 5 /* 5 and greater are reserved */ };
/* 13: Generic MSI Frame (ACPI 5.1) */
From: Tomasz Nowicki tomasz.nowicki@linaro.org
This self-probe infrastructure works in the similar way as OF, but there is some different in the mechanism:
For OF, the init fn will be called once it finds comptiable strings in DT, but for ACPI, we init irqchips by static tables, and in static ACPI tables, there are no comptiable strings to indicate irqchips, so every init function with IRQCHIP_ACPI_DECLARE in the same table will be called, but thanks to the GIC version presented in ACPI table, we can init different GIC irqchips with this framework.
This mechanism can also be used for clock declare and may also works on x86 for some table parsing too.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org [hj: introduce struct acpi_table_id instead of acpi_device_id] [hj: rework it more generic to all ACPI tables and fix some issues] Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/Makefile | 1 + drivers/acpi/irq.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/irqchip/irqchip.h | 12 ++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++++++++++ include/linux/acpi.h | 14 ++++++++++++++ include/linux/mod_devicetable.h | 7 +++++++ 6 files changed, 84 insertions(+) create mode 100644 drivers/acpi/irq.c
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8a063e2..3e4aec3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_ACPI_HED) += hed.o obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o +obj-$(CONFIG_IRQCHIP) += irq.o
# processor has its own "processor." module_param namespace processor-y := processor_driver.o processor_throttling.o diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 0000000..65d6b93 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Linaro Ltd. + * Author: Tomasz Nowicki tomasz.nowicki@linaro.org + * Hanjun Guo hanjun.guo@linaro.org + * + * Inspired by drivers/irqchip/irqchip.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + */ + +#include <linux/init.h> +#include <linux/acpi.h> + +/* + * 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; + + for (id = __irqchip_acpi_table; id->id[0]; id++) + acpi_table_parse(id->id, (acpi_tbl_table_handler)id->data); +} diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h index 0f6486d..1949546 100644 --- a/drivers/irqchip/irqchip.h +++ b/drivers/irqchip/irqchip.h @@ -11,6 +11,7 @@ #ifndef _IRQCHIP_H #define _IRQCHIP_H
+#include <linux/acpi.h> #include <linux/of.h>
/* @@ -25,4 +26,15 @@ */ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
+/* + * This macro must be used by the different irqchip drivers to declare + * the association between their ACPI table and their initialization function. + * + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the + * same file. + * @table_id: name of the ACPI table signature + * @fn: initialization function + */ +#define IRQCHIP_ACPI_DECLARE(name, table_id, fn) \ + ACPI_DECLARE(irqchip, name, table_id, fn) #endif 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 90e4ed1e..b904af3 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -820,4 +820,18 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
#endif
+#ifdef CONFIG_ACPI +#define ACPI_DECLARE(table, name, table_id, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __used __section(__##table##_acpi_table) \ + = { .id = table_id, \ + .data = (void *)fn } +#else +#define ACPI_DECLARE(table, name, table_id, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __attribute__((unused)) \ + = { .id = table_id, \ + .data = (void*)fn } +#endif + #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 3bfd567..47c1ea1 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -199,6 +199,13 @@ struct pnp_device_id { kernel_ulong_t driver_data; };
+#define ACPI_TABLE_ID_LEN 5 + +struct acpi_table_id { + __u8 id[ACPI_TABLE_ID_LEN]; + const void *data; +}; + struct pnp_card_device_id { __u8 id[PNP_ID_LEN]; kernel_ulong_t driver_data;
Hi Hanjun,
On 18/05/15 13:59, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
This self-probe infrastructure works in the similar way as OF, but there is some different in the mechanism:
For OF, the init fn will be called once it finds comptiable strings in DT, but for ACPI, we init irqchips by static tables, and in static ACPI tables, there are no comptiable strings to indicate irqchips, so every init function with IRQCHIP_ACPI_DECLARE in the same table will be called, but thanks to the GIC version presented in ACPI table, we can init different GIC irqchips with this framework.
This triggers an immediate question: If we can find out the GIC version in the ACPI tables, which can't we just call the irqchips that implement the support for this version?
i.e: the GICv2 irqchip code would have a line like:
IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_GIC_VER_V2, gic_v2_acpi_init);
and the probing code would simply call the drivers that have declared their interest for this version code.
Having code that tests for the version in each driver is not an option (this is exactly what we're trying to avoid).
Thanks,
M.
This mechanism can also be used for clock declare and may also works on x86 for some table parsing too.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org [hj: introduce struct acpi_table_id instead of acpi_device_id] [hj: rework it more generic to all ACPI tables and fix some issues] Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/Makefile | 1 + drivers/acpi/irq.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/irqchip/irqchip.h | 12 ++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++++++++++ include/linux/acpi.h | 14 ++++++++++++++ include/linux/mod_devicetable.h | 7 +++++++ 6 files changed, 84 insertions(+) create mode 100644 drivers/acpi/irq.c
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8a063e2..3e4aec3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_ACPI_HED) += hed.o obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o +obj-$(CONFIG_IRQCHIP) += irq.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o processor_throttling.o diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 0000000..65d6b93 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,37 @@ +/*
- Copyright (c) 2015, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
Hanjun Guo <hanjun.guo@linaro.org>
- Inspired by drivers/irqchip/irqchip.c
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- */
+#include <linux/init.h> +#include <linux/acpi.h>
+/*
- 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;
- for (id = __irqchip_acpi_table; id->id[0]; id++)
acpi_table_parse(id->id, (acpi_tbl_table_handler)id->data);
+} diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h index 0f6486d..1949546 100644 --- a/drivers/irqchip/irqchip.h +++ b/drivers/irqchip/irqchip.h @@ -11,6 +11,7 @@ #ifndef _IRQCHIP_H #define _IRQCHIP_H +#include <linux/acpi.h> #include <linux/of.h> /* @@ -25,4 +26,15 @@ */ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) +/*
- This macro must be used by the different irqchip drivers to declare
- the association between their ACPI table and their initialization function.
- @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the
- same file.
- @table_id: name of the ACPI table signature
- @fn: initialization function
- */
+#define IRQCHIP_ACPI_DECLARE(name, table_id, fn) \
- ACPI_DECLARE(irqchip, name, table_id, fn)
#endif 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 90e4ed1e..b904af3 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -820,4 +820,18 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev, #endif +#ifdef CONFIG_ACPI +#define ACPI_DECLARE(table, name, table_id, fn) \
- static const struct acpi_table_id __acpi_table_##name \
__used __section(__##table##_acpi_table) \
= { .id = table_id, \
.data = (void *)fn }
+#else +#define ACPI_DECLARE(table, name, table_id, fn) \
- static const struct acpi_table_id __acpi_table_##name \
__attribute__((unused)) \
= { .id = table_id, \
.data = (void*)fn }
+#endif
#endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 3bfd567..47c1ea1 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -199,6 +199,13 @@ struct pnp_device_id { kernel_ulong_t driver_data; }; +#define ACPI_TABLE_ID_LEN 5
+struct acpi_table_id {
- __u8 id[ACPI_TABLE_ID_LEN];
- const void *data;
+};
struct pnp_card_device_id { __u8 id[PNP_ID_LEN]; kernel_ulong_t driver_data;
Hi Marc,
On 06/10/2015 11:33 PM, Marc Zyngier wrote:
Hi Hanjun,
On 18/05/15 13:59, Hanjun Guo wrote:
From: Tomasz Nowicki tomasz.nowicki@linaro.org
This self-probe infrastructure works in the similar way as OF, but there is some different in the mechanism:
For OF, the init fn will be called once it finds comptiable strings in DT, but for ACPI, we init irqchips by static tables, and in static ACPI tables, there are no comptiable strings to indicate irqchips, so every init function with IRQCHIP_ACPI_DECLARE in the same table will be called, but thanks to the GIC version presented in ACPI table, we can init different GIC irqchips with this framework.
This triggers an immediate question: If we can find out the GIC version in the ACPI tables, which can't we just call the irqchips that implement the support for this version?
This is really a good question and triggers me to rethink about the implementation.
i.e: the GICv2 irqchip code would have a line like:
IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_GIC_VER_V2, gic_v2_acpi_init);
and the probing code would simply call the drivers that have declared their interest for this version code.
if we want to achieve this, we can redefine the strut for acpi_table_id:
#define ACPI_TABLE_ID_LEN 5
struct acpi_table_id { __u8 id[ACPI_TABLE_ID_LEN]; const void *handler; kernel_ulong_t driver_data; };
then pass the ACPI_MADT_GIC_VER_V2 as the driver_data, it will work as you suggested.
Having code that tests for the version in each driver is not an option (this is exactly what we're trying to avoid).
I also think it's awkward to do that in each driver, thanks for the suggestion!
Thanks Hanjun
There is a field added in ACPI 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.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/Kconfig | 1 + drivers/acpi/irq.c | 3 + drivers/irqchip/Kconfig | 3 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-gic-acpi.c | 111 +++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-acpi.h | 2 + 6 files changed, 121 insertions(+) create mode 100644 drivers/irqchip/irq-gic-acpi.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7796af4..9b80428 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -15,6 +15,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/acpi/irq.c b/drivers/acpi/irq.c index 65d6b93..855ead9 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -32,6 +32,9 @@ void __init acpi_irqchip_init(void) if (acpi_disabled) return;
+ if (acpi_gic_version_init()) + return; + for (id = __irqchip_acpi_table; id->id[0]; id++) acpi_table_parse(id->id, (acpi_tbl_table_handler)id->data); } diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 6de62a9..0dd64c5 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -46,6 +46,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 dda4927..0bd8e49 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 +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..53a86ef --- /dev/null +++ b/drivers/irqchip/irq-gic-acpi.c @@ -0,0 +1,111 @@ +/* + * 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_VER_UNKNOWN; + +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->gic_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); + + /* has at least one GIC redistributor entry */ + if (count > 0) + return true; + else + return false; +} + +int __init acpi_gic_version_init(void) +{ + int count; + void __iomem *dist_base; + u32 reg; + + 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_VER_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_VER_UNKNOWN) { + /* 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_VER_V3; + else + gic_version = ACPI_MADT_GIC_VER_V4; + + iounmap(dist_base); + } else { + gic_version = ACPI_MADT_GIC_VER_V2; + } + } + + return 0; +} diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index de3419e..0d5f204 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -19,11 +19,13 @@ */ #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;
int gic_v2_acpi_init(struct acpi_table_header *table); void acpi_gic_init(void); +int acpi_gic_version_init(void); #else static inline void acpi_gic_init(void) { } #endif
On Mon, 18 May 2015, Hanjun Guo wrote:
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index 65d6b93..855ead9 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -32,6 +32,9 @@ void __init acpi_irqchip_init(void) if (acpi_disabled) return;
- if (acpi_gic_version_init())
return;
This looks just wrong. acpi_irqchip_init() is a generic ACPI function and now you stick a GIC specific callback into it?
What calls acpi_irqchip_init?
Thanks,
tglx
On 2015年05月21日 04:02, Thomas Gleixner wrote:
On Mon, 18 May 2015, Hanjun Guo wrote:
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index 65d6b93..855ead9 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -32,6 +32,9 @@ void __init acpi_irqchip_init(void) if (acpi_disabled) return;
- if (acpi_gic_version_init())
return;
This looks just wrong. acpi_irqchip_init() is a generic ACPI function and now you stick a GIC specific callback into it?
For now, acpi_irqchip_init() just introduced for GIC init, not for APIC init for x86, and I don't see the usage in the near future.
What calls acpi_irqchip_init?
I renamed it as acpi_irq_init() in the later patch, which is called in irqchip_init() in drivers/irqchip/irqchip.c to init irqchip when DT is not available.
This is not a nice way, but the kernel should stay functional for each patch goes in, so I separate the patch to smaller one for easy review under that rule, does it make sense?
Thanks Hanjun
On Thu, 21 May 2015, Hanjun Guo wrote:
On 2015年05月21日 04:02, Thomas Gleixner wrote:
On Mon, 18 May 2015, Hanjun Guo wrote:
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index 65d6b93..855ead9 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -32,6 +32,9 @@ void __init acpi_irqchip_init(void) if (acpi_disabled) return;
- if (acpi_gic_version_init())
return;
This looks just wrong. acpi_irqchip_init() is a generic ACPI function and now you stick a GIC specific callback into it?
For now, acpi_irqchip_init() just introduced for GIC init, not for APIC init for x86, and I don't see the usage in the near future.
What calls acpi_irqchip_init?
I renamed it as acpi_irq_init() in the later patch, which is called in irqchip_init() in drivers/irqchip/irqchip.c to init irqchip when DT is not available.
Neither of those names is a good choice as they suggest that this is a generic acpi mechanism while in fact it is a GIC specific ACPI extension. And its therefor wrong to put that code into drivers/acpi.
It belongs into drivers/irqchip/gic-acpi.c or some other descriptive name.
Thanks,
tglx
On 2015年05月21日 22:39, Thomas Gleixner wrote:
On Thu, 21 May 2015, Hanjun Guo wrote:
On 2015年05月21日 04:02, Thomas Gleixner wrote:
On Mon, 18 May 2015, Hanjun Guo wrote:
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index 65d6b93..855ead9 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -32,6 +32,9 @@ void __init acpi_irqchip_init(void) if (acpi_disabled) return;
- if (acpi_gic_version_init())
return;
This looks just wrong. acpi_irqchip_init() is a generic ACPI function and now you stick a GIC specific callback into it?
For now, acpi_irqchip_init() just introduced for GIC init, not for APIC init for x86, and I don't see the usage in the near future.
What calls acpi_irqchip_init?
I renamed it as acpi_irq_init() in the later patch, which is called in irqchip_init() in drivers/irqchip/irqchip.c to init irqchip when DT is not available.
Neither of those names is a good choice as they suggest that this is a generic acpi mechanism while in fact it is a GIC specific ACPI extension. And its therefor wrong to put that code into drivers/acpi.
OK, thanks for the suggestion.
It belongs into drivers/irqchip/gic-acpi.c or some other descriptive name.
I already introduced a similar file named irq-gic-acpi.c under drivers/irqchip/, will move the code to there in next version.
Thanks Hanjun
As the ACPI self-probe infrastructure for irqchip is ready, we use the infrastructure and the GIC version to simplify GICv2 init code.
From now on, GIC init calls reside in theirs 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/acpi/irq.c | 2 +- drivers/irqchip/irq-gic-acpi.c | 5 +++++ drivers/irqchip/irq-gic.c | 6 +++++- include/linux/acpi_irq.h | 4 +++- include/linux/irqchip/arm-gic-acpi.h | 10 ++-------- 7 files changed, 16 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 8b83955..69809e7 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -318,28 +318,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/acpi/irq.c b/drivers/acpi/irq.c index 855ead9..7bd1ef6 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -25,7 +25,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-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 53a86ef..1388d9e 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_VER_UNKNOWN;
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) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 01999d7..fefbcb5 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1085,12 +1085,15 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, return 0; }
-int __init +static int __init gic_v2_acpi_init(struct acpi_table_header *table) { void __iomem *cpu_base, *dist_base; int count;
+ if (acpi_gic_version() >= ACPI_MADT_GIC_VER_V3) + return -ENODEV; + /* Collect CPU base addresses */ count = acpi_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), @@ -1141,4 +1144,5 @@ gic_v2_acpi_init(struct acpi_table_header *table) acpi_irq_model = ACPI_IRQ_MODEL_GIC; return 0; } +IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, 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 0d5f204..021e8e8 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -21,13 +21,7 @@ #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); int acpi_gic_version_init(void); -#else -static inline void acpi_gic_init(void) { } -#endif - +u8 acpi_gic_version(void); +#endif /* CONFIG_ACPI */ #endif /* ARM_GIC_ACPI_H_ */
Introduce acpi_irq_domain for GICv2 core domain instead of referring to the irq_default_domain, based on that, pass gsi as the argument and get the gsi in gic_irq_domain_alloc() to add stacked irqdomain support for ACPI based GICv2 init.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/gsi.c | 28 +++++++++++++--------------- drivers/irqchip/irq-gic.c | 32 +++++++++++++++++--------------- include/linux/irqchip/arm-gic-acpi.h | 2 ++ 3 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 38208f2..55b5f31 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -3,6 +3,7 @@ * * Copyright (C) 2015 ARM Ltd. * Author: Lorenzo Pieralisi lorenzo.pieralisi@arm.com + * Hanjun Guo hanjun.guo@linaro.org for stacked irqdomains support * * 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 @@ -13,6 +14,8 @@ #include <linux/irqdomain.h>
enum acpi_irq_model_id acpi_irq_model; +/* ACPI core domian pointing to GICv2/3 core domain */ +struct irq_domain *acpi_irq_domain __read_mostly;
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -45,12 +48,7 @@ static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) */ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { - /* - * Only default domain is supported at present, always find - * the mapping corresponding to default domain by passing NULL - * as irq_domain parameter - */ - *irq = irq_find_mapping(NULL, gsi); + *irq = irq_find_mapping(acpi_irq_domain, gsi); /* * *irq == 0 means no mapping, that should * be reported as a failure @@ -72,16 +70,16 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { - unsigned int irq; + int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- /* - * There is no way at present to look-up the IRQ domain on ACPI, - * hence always create mapping referring to the default domain - * by passing NULL as irq_domain parameter - */ - irq = irq_create_mapping(NULL, gsi); - if (!irq) + irq = irq_find_mapping(acpi_irq_domain, gsi); + if (irq > 0) + return irq; + + irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), + &gsi); + if (irq <= 0) return -EINVAL;
/* Set irq type if specified and different than the current one */ @@ -98,7 +96,7 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) { - int irq = irq_find_mapping(NULL, gsi); + int irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fefbcb5..869a69f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -851,15 +851,22 @@ static struct notifier_block gic_cpu_notifier = { static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { - int i, ret; + int i; irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg;
- ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); - if (ret) - return ret; + if (domain->of_node) { /* DT case */ + int ret; + unsigned int type = IRQ_TYPE_NONE; + struct of_phandle_args *irq_data = arg; + + ret = gic_irq_domain_xlate(domain, irq_data->np, + irq_data->args, + irq_data->args_count, &hwirq, &type); + if (ret) + return ret; + } else { /* ACPI case */ + hwirq = (irq_hw_number_t)*(u32 *)arg; + }
for (i = 0; i < nr_irqs; i++) gic_irq_domain_map(domain, virq + i, hwirq + i); @@ -945,11 +952,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs;
- if (node) { /* DT case */ + if (node || !acpi_disabled) { /* DT or ACPI case */ gic->domain = irq_domain_add_linear(node, gic_irqs, &gic_irq_domain_hierarchy_ops, gic); - } else { /* Non-DT case */ + } else { /* Non-DT and ACPI case */ /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. @@ -1133,13 +1140,8 @@ gic_v2_acpi_init(struct acpi_table_header *table) return -ENOMEM; }
- /* - * Initialize zero GIC instance (no multi-GIC support). Also, set GIC - * as default IRQ domain to allow for GSI registration and GSI to IRQ - * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). - */ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); - irq_set_default_host(gic_data[0].domain); + acpi_irq_domain = gic_data[0].domain;
acpi_irq_model = ACPI_IRQ_MODEL_GIC; return 0; diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index 021e8e8..245386d 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -21,6 +21,8 @@ #define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
+extern struct irq_domain *acpi_irq_domain; + int acpi_gic_version_init(void); u8 acpi_gic_version(void); #endif /* CONFIG_ACPI */
On 18/05/15 13:59, Hanjun Guo wrote:
Introduce acpi_irq_domain for GICv2 core domain instead of referring to the irq_default_domain, based on that, pass gsi as the argument and get the gsi in gic_irq_domain_alloc() to add stacked irqdomain support for ACPI based GICv2 init.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 28 +++++++++++++--------------- drivers/irqchip/irq-gic.c | 32 +++++++++++++++++--------------- include/linux/irqchip/arm-gic-acpi.h | 2 ++ 3 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 38208f2..55b5f31 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -3,6 +3,7 @@
- Copyright (C) 2015 ARM Ltd.
- Author: Lorenzo Pieralisi lorenzo.pieralisi@arm.com
Hanjun Guo <hanjun.guo@linaro.org> for stacked irqdomains support
- 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
@@ -13,6 +14,8 @@ #include <linux/irqdomain.h> enum acpi_irq_model_id acpi_irq_model; +/* ACPI core domian pointing to GICv2/3 core domain */ +struct irq_domain *acpi_irq_domain __read_mostly;
How is a single domain pointer going to work when you will have several domains (GICv2m, ITS)? Crucially, how are you going to perform the matching of a device with its irq domain?
M.
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -45,12 +48,7 @@ static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) */ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) {
- /*
* Only default domain is supported at present, always find
* the mapping corresponding to default domain by passing NULL
* as irq_domain parameter
*/
- *irq = irq_find_mapping(NULL, gsi);
- *irq = irq_find_mapping(acpi_irq_domain, gsi); /*
- *irq == 0 means no mapping, that should
- be reported as a failure
@@ -72,16 +70,16 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) {
- unsigned int irq;
- int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- /*
* There is no way at present to look-up the IRQ domain on ACPI,
* hence always create mapping referring to the default domain
* by passing NULL as irq_domain parameter
*/
- irq = irq_create_mapping(NULL, gsi);
- if (!irq)
- irq = irq_find_mapping(acpi_irq_domain, gsi);
- if (irq > 0)
return irq;
- irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev),
&gsi);
- if (irq <= 0) return -EINVAL;
/* Set irq type if specified and different than the current one */ @@ -98,7 +96,7 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) {
- int irq = irq_find_mapping(NULL, gsi);
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fefbcb5..869a69f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -851,15 +851,22 @@ static struct notifier_block gic_cpu_notifier = { static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) {
- int i, ret;
- int i; irq_hw_number_t hwirq;
- unsigned int type = IRQ_TYPE_NONE;
- struct of_phandle_args *irq_data = arg;
- ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args,
irq_data->args_count, &hwirq, &type);
- if (ret)
return ret;
- if (domain->of_node) { /* DT case */
int ret;
unsigned int type = IRQ_TYPE_NONE;
struct of_phandle_args *irq_data = arg;
ret = gic_irq_domain_xlate(domain, irq_data->np,
irq_data->args,
irq_data->args_count, &hwirq, &type);
if (ret)
return ret;
- } else { /* ACPI case */
hwirq = (irq_hw_number_t)*(u32 *)arg;
- }
for (i = 0; i < nr_irqs; i++) gic_irq_domain_map(domain, virq + i, hwirq + i); @@ -945,11 +952,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs;
- if (node) { /* DT case */
- if (node || !acpi_disabled) { /* DT or ACPI case */ gic->domain = irq_domain_add_linear(node, gic_irqs, &gic_irq_domain_hierarchy_ops, gic);
- } else { /* Non-DT case */
- } else { /* Non-DT and ACPI case */ /*
- For primary GICs, skip over SGIs.
- For secondary GICs, skip over PPIs, too.
@@ -1133,13 +1140,8 @@ gic_v2_acpi_init(struct acpi_table_header *table) return -ENOMEM; }
- /*
* Initialize zero GIC instance (no multi-GIC support). Also, set GIC
* as default IRQ domain to allow for GSI registration and GSI to IRQ
* number translation (see acpi_register_gsi() and acpi_gsi_to_irq()).
gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);*/
- irq_set_default_host(gic_data[0].domain);
- acpi_irq_domain = gic_data[0].domain;
acpi_irq_model = ACPI_IRQ_MODEL_GIC; return 0; diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index 021e8e8..245386d 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -21,6 +21,8 @@ #define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K) +extern struct irq_domain *acpi_irq_domain;
int acpi_gic_version_init(void); u8 acpi_gic_version(void); #endif /* CONFIG_ACPI */
On 06/11/2015 12:27 AM, Marc Zyngier wrote:
On 18/05/15 13:59, Hanjun Guo wrote:
Introduce acpi_irq_domain for GICv2 core domain instead of referring to the irq_default_domain, based on that, pass gsi as the argument and get the gsi in gic_irq_domain_alloc() to add stacked irqdomain support for ACPI based GICv2 init.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 28 +++++++++++++--------------- drivers/irqchip/irq-gic.c | 32 +++++++++++++++++--------------- include/linux/irqchip/arm-gic-acpi.h | 2 ++ 3 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 38208f2..55b5f31 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -3,6 +3,7 @@
- Copyright (C) 2015 ARM Ltd.
- Author: Lorenzo Pieralisi lorenzo.pieralisi@arm.com
Hanjun Guo <hanjun.guo@linaro.org> for stacked irqdomains support
- 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
@@ -13,6 +14,8 @@ #include <linux/irqdomain.h>
enum acpi_irq_model_id acpi_irq_model; +/* ACPI core domian pointing to GICv2/3 core domain */ +struct irq_domain *acpi_irq_domain __read_mostly;
How is a single domain pointer going to work when you will have several domains (GICv2m, ITS)?
This acpi_irq_domain is the core domain which is the parent domain of GICv2m or ITS.
acpi_irq_domain points to GICv2 or GICv3 domain when the GIC is initialized.
Crucially, how are you going to perform the matching of a device with its irq domain?
since every ITS will have a domain, and there is a mapping from device id to ITS ID in IORT table, then we can match the device with the ITS irq domain, does it make sense?
Thanks Hanjun
On 06/11/2015 09:22 PM, Hanjun Guo wrote:
On 06/11/2015 12:27 AM, Marc Zyngier wrote:
On 18/05/15 13:59, Hanjun Guo wrote:
Introduce acpi_irq_domain for GICv2 core domain instead of referring to the irq_default_domain, based on that, pass gsi as the argument and get the gsi in gic_irq_domain_alloc() to add stacked irqdomain support for ACPI based GICv2 init.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 28 +++++++++++++--------------- drivers/irqchip/irq-gic.c | 32 +++++++++++++++++--------------- include/linux/irqchip/arm-gic-acpi.h | 2 ++ 3 files changed, 32 insertions(+), 30 deletions(-)
[...]
enum acpi_irq_model_id acpi_irq_model; +/* ACPI core domian pointing to GICv2/3 core domain */ +struct irq_domain *acpi_irq_domain __read_mostly;
How is a single domain pointer going to work when you will have several domains (GICv2m, ITS)?
This acpi_irq_domain is the core domain which is the parent domain of GICv2m or ITS.
acpi_irq_domain points to GICv2 or GICv3 domain when the GIC is initialized.
Crucially, how are you going to perform the matching of a device with its irq domain?
since every ITS will have a domain, and there is a mapping from device id to ITS ID in IORT table, then we can match the device with the ITS irq domain, does it make sense?
Sorry, I misunderstood the question here, I thought "its" here means ITS (interrupt translation service), but actually I think you mean how to match a device to the device's irq domain.
So the stacked irq domain will be:
acpi_irq_domain == gicv2 or gicv3 core domain ^ | (parent) | ITS domain or GIv2m domain ^ | | MSI chip irq domain
Since there is one GICD supported for now, so there will be only one irqdomain created for all the wired hardware irqs for PPI, SGI and SPI, and PPI, SGI and SPI will have unique hardware irq number (GSI), so we can match the device to the acpi_irq_domain with unique GSI and it will works. If there will be multi GICD in the future, this will still works to follow the solution for x86 of ACPI (mutil IOAPICs).
MSI will match itself (device id) to its MSI irqdomain and it will handled by core code (dynamicly allocated hw irq number), so all the interrupts will be handled probably in ACPI way.
Thanks Hanjun
Add a mutex for acpi_register_gsi()/acpi_unregister_gsi() to avoid concurrency issues.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/gsi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 55b5f31..ab0dcb4 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -16,6 +16,7 @@ enum acpi_irq_model_id acpi_irq_model; /* ACPI core domian pointing to GICv2/3 core domain */ struct irq_domain *acpi_irq_domain __read_mostly; +static DEFINE_MUTEX(gsi_mutex);
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -73,20 +74,24 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
+ mutex_lock(&gsi_mutex); irq = irq_find_mapping(acpi_irq_domain, gsi); if (irq > 0) - return irq; + goto out;
irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), &gsi); if (irq <= 0) - return -EINVAL; + goto out;
/* Set irq type if specified and different than the current one */ if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) irq_set_irq_type(irq, irq_type); - return irq; + +out: + mutex_unlock(&gsi_mutex); + return irq > 0 ? irq : -EINVAL; } EXPORT_SYMBOL_GPL(acpi_register_gsi);
@@ -96,8 +101,12 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) { - int irq = irq_find_mapping(acpi_irq_domain, gsi); + int irq; + + mutex_lock(&gsi_mutex); + irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq); + mutex_unlock(&gsi_mutex); } EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
On 18/05/15 13:59, Hanjun Guo wrote:
Add a mutex for acpi_register_gsi()/acpi_unregister_gsi() to avoid concurrency issues.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 55b5f31..ab0dcb4 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -16,6 +16,7 @@ enum acpi_irq_model_id acpi_irq_model; /* ACPI core domian pointing to GICv2/3 core domain */ struct irq_domain *acpi_irq_domain __read_mostly; +static DEFINE_MUTEX(gsi_mutex); static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -73,20 +74,24 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- mutex_lock(&gsi_mutex); irq = irq_find_mapping(acpi_irq_domain, gsi); if (irq > 0)
return irq;
goto out;
irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), &gsi); if (irq <= 0)
return -EINVAL;
goto out;
/* Set irq type if specified and different than the current one */ if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) irq_set_irq_type(irq, irq_type);
- return irq;
+out:
- mutex_unlock(&gsi_mutex);
- return irq > 0 ? irq : -EINVAL;
} EXPORT_SYMBOL_GPL(acpi_register_gsi); @@ -96,8 +101,12 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) {
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
- int irq;
- mutex_lock(&gsi_mutex);
- irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq);
- mutex_unlock(&gsi_mutex);
} EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
Can you point out why we need this locking? The rest of the kernel seems to live without it pretty well. And if we really have an issue, I'd prefer seeing it fixed in the core code rather than in something that is very much firmware-specific.
Thanks,
M.
On 06/10/2015 11:58 PM, Marc Zyngier wrote:
On 18/05/15 13:59, Hanjun Guo wrote:
Add a mutex for acpi_register_gsi()/acpi_unregister_gsi() to avoid concurrency issues.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 55b5f31..ab0dcb4 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -16,6 +16,7 @@ enum acpi_irq_model_id acpi_irq_model; /* ACPI core domian pointing to GICv2/3 core domain */ struct irq_domain *acpi_irq_domain __read_mostly; +static DEFINE_MUTEX(gsi_mutex);
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -73,20 +74,24 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- mutex_lock(&gsi_mutex); irq = irq_find_mapping(acpi_irq_domain, gsi); if (irq > 0)
return irq;
goto out;
irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), &gsi); if (irq <= 0)
return -EINVAL;
goto out;
/* Set irq type if specified and different than the current one */ if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) irq_set_irq_type(irq, irq_type);
- return irq;
+out:
- mutex_unlock(&gsi_mutex);
- return irq > 0 ? irq : -EINVAL; } EXPORT_SYMBOL_GPL(acpi_register_gsi);
@@ -96,8 +101,12 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) {
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
int irq;
mutex_lock(&gsi_mutex);
irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq);
mutex_unlock(&gsi_mutex); } EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
Can you point out why we need this locking? The rest of the kernel seems to live without it pretty well. And if we really have an issue, I'd
Hmm, I'm not so sure, I will look deep into that and come back later.
prefer seeing it fixed in the core code rather than in something that is very much firmware-specific.
I agree if there are real issues.
Thanks Hanjun
On 06/11/2015 09:16 PM, Hanjun Guo wrote:
On 06/10/2015 11:58 PM, Marc Zyngier wrote:
On 18/05/15 13:59, Hanjun Guo wrote:
Add a mutex for acpi_register_gsi()/acpi_unregister_gsi() to avoid concurrency issues.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 55b5f31..ab0dcb4 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -16,6 +16,7 @@ enum acpi_irq_model_id acpi_irq_model; /* ACPI core domian pointing to GICv2/3 core domain */ struct irq_domain *acpi_irq_domain __read_mostly; +static DEFINE_MUTEX(gsi_mutex);
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -73,20 +74,24 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- mutex_lock(&gsi_mutex); irq = irq_find_mapping(acpi_irq_domain, gsi); if (irq > 0)
return irq;
goto out; irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), &gsi); if (irq <= 0)
return -EINVAL;
goto out; /* Set irq type if specified and different than the current one */ if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) irq_set_irq_type(irq, irq_type);
- return irq;
+out:
- mutex_unlock(&gsi_mutex);
- return irq > 0 ? irq : -EINVAL; } EXPORT_SYMBOL_GPL(acpi_register_gsi);
@@ -96,8 +101,12 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) {
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
int irq;
mutex_lock(&gsi_mutex);
irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq);
mutex_unlock(&gsi_mutex); } EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
Can you point out why we need this locking? The rest of the kernel seems to live without it pretty well. And if we really have an issue, I'd
Hmm, I'm not so sure, I will look deep into that and come back later.
Sorry for the late reply, I finally recalled that why I introduced the lock here.
The lock introduced here is because of I assume ACPI based container (such as CPU socket) hotplug will be available on ARM64 in the future, then we may online/offline a irqchip at the same time (similar way of IOAPIC hotplug which introduced by Jiang Liu), it turns out that only one GICD for now so it's not the case for ARM64 in the near future, I will drop this patch in next version.
Thanks Hanjun
On 19/06/15 08:31, Hanjun Guo wrote:
On 06/11/2015 09:16 PM, Hanjun Guo wrote:
On 06/10/2015 11:58 PM, Marc Zyngier wrote:
On 18/05/15 13:59, Hanjun Guo wrote:
Add a mutex for acpi_register_gsi()/acpi_unregister_gsi() to avoid concurrency issues.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/gsi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 55b5f31..ab0dcb4 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -16,6 +16,7 @@ enum acpi_irq_model_id acpi_irq_model; /* ACPI core domian pointing to GICv2/3 core domain */ struct irq_domain *acpi_irq_domain __read_mostly; +static DEFINE_MUTEX(gsi_mutex);
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) { @@ -73,20 +74,24 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
- mutex_lock(&gsi_mutex); irq = irq_find_mapping(acpi_irq_domain, gsi); if (irq > 0)
return irq;
goto out; irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev), &gsi); if (irq <= 0)
return -EINVAL;
goto out; /* Set irq type if specified and different than the current one */ if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) irq_set_irq_type(irq, irq_type);
- return irq;
+out:
- mutex_unlock(&gsi_mutex);
- return irq > 0 ? irq : -EINVAL; } EXPORT_SYMBOL_GPL(acpi_register_gsi);
@@ -96,8 +101,12 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); */ void acpi_unregister_gsi(u32 gsi) {
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
int irq;
mutex_lock(&gsi_mutex);
irq = irq_find_mapping(acpi_irq_domain, gsi);
irq_dispose_mapping(irq);
mutex_unlock(&gsi_mutex); } EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
Can you point out why we need this locking? The rest of the kernel seems to live without it pretty well. And if we really have an issue, I'd
Hmm, I'm not so sure, I will look deep into that and come back later.
Sorry for the late reply, I finally recalled that why I introduced the lock here.
The lock introduced here is because of I assume ACPI based container (such as CPU socket) hotplug will be available on ARM64 in the future, then we may online/offline a irqchip at the same time (similar way of IOAPIC hotplug which introduced by Jiang Liu), it turns out that only one GICD for now so it's not the case for ARM64 in the near future,
Well, there can only be one GICD, or at least only one that is visible. If the HW uses multiple GICDs (one per socket?), it must make ensure that they are all synchronized transparently. That's a strong requirement from the architecture. Otherwise, we enter the FrankeinGIC realm, and ACPI has no business with it.
I will drop this patch in next version.
Thanks,
M.
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 49875ad..87cf81b 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -765,17 +765,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, + struct device_node *node) +{ + 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(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); + 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) { @@ -819,47 +871,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; - - /* - * 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; + err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, + redist_stride, node); + if (!err) + return 0;
- 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) @@ -871,3 +887,4 @@ out_unmap_dist: }
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); +#endif
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.
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 | 146 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 4 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 87cf81b..11946a6 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> @@ -819,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) { @@ -826,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); @@ -836,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; }
@@ -888,3 +898,131 @@ 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_phy_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_phy_base = dist->base_address; + return 0; +} + +static int __init +gic_v3_acpi_init(struct acpi_table_header *table) +{ + int count, i, err = 0; + void __iomem *dist_base; + + if (acpi_gic_version() < ACPI_MADT_GIC_VER_V3) + return -ENODEV; + + /* 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_phy_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, NULL); + if (err) + goto out_redist_unmap; + + irq_set_default_host(gic_data.domain); + 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_SIG_MADT, gic_v3_acpi_init); +#endif
Similar as stacked domain support for ACPI based GICv2 init, let acpi_irq_domain point to the core domain of GICv3 and pass the gsi as the arg to support stacked irqdomain.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-v3.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 11946a6..e7f134e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -733,15 +733,21 @@ static int gic_irq_domain_xlate(struct irq_domain *d, static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { - int i, ret; + int i; irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg;
- ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); - if (ret) - return ret; + if (domain->of_node) { /* DT case */ + int ret; + unsigned int type = IRQ_TYPE_NONE; + struct of_phandle_args *irq_data = arg; + + ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, + irq_data->args_count, &hwirq, &type); + if (ret) + return ret; + } else { /* ACPI case */ + hwirq = (irq_hw_number_t)*(u32 *)arg; + }
for (i = 0; i < nr_irqs; i++) gic_irq_domain_map(domain, virq + i, hwirq + i); @@ -1012,7 +1018,7 @@ gic_v3_acpi_init(struct acpi_table_header *table) if (err) goto out_redist_unmap;
- irq_set_default_host(gic_data.domain); + acpi_irq_domain = gic_data.domain; return 0;
out_redist_unmap:
Move GICv2 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained.
Introduce set_acpi_core_irqdomain() to set acpi_irqdomain then it will be no need to make gic_data[] as a global value, and it will save the confilcts with GICv3's gic_data in the later patch.
acpi_gic_parse_distributor() have the same function as gic_acpi_parse_madt_distributor() to get the GIC distributor physical base address, so just remove the duplicate one, and only get the GIC version when it is unknown.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-acpi.c | 95 +++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 103 +---------------------------------- include/linux/irqchip/arm-gic-acpi.h | 5 ++ 3 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 1388d9e..8463e48 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -13,12 +13,16 @@
#include <linux/acpi.h> #include <linux/init.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-acpi.h> #include <linux/irqchip/arm-gic-v3.h>
+#include "irqchip.h" + /* GIC version presented in MADT GIC distributor structure */ static u8 gic_version __initdata = ACPI_MADT_GIC_VER_UNKNOWN;
+/* GIC distributor physical base address, which is needed for both GICv2/3 */ static phys_addr_t dist_phy_base __initdata;
u8 __init acpi_gic_version(void) @@ -26,6 +30,11 @@ u8 __init acpi_gic_version(void) return gic_version; }
+void __init set_acpi_core_irqdomain(struct irq_domain *domain) +{ + acpi_irq_domain = domain; +} + static int __init acpi_gic_parse_distributor(struct acpi_subtable_header *header, const unsigned long end) @@ -37,8 +46,9 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header, if (BAD_MADT_ENTRY(dist, end)) return -EINVAL;
- gic_version = dist->gic_version; dist_phy_base = dist->base_address; + if (gic_version == ACPI_MADT_GIC_VER_UNKNOWN) + gic_version = dist->gic_version; return 0; }
@@ -114,3 +124,86 @@ int __init acpi_gic_version_init(void)
return 0; } + +static phys_addr_t cpu_phy_base __initdata; + +static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + phys_addr_t gic_cpu_base; + static int cpu_base_assigned; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + /* + * There is no support for non-banked GICv1/2 register in ACPI spec. + * All CPU interface addresses have to be the same. + */ + gic_cpu_base = processor->base_address; + if (cpu_base_assigned && gic_cpu_base != cpu_phy_base) + return -EINVAL; + + cpu_phy_base = gic_cpu_base; + cpu_base_assigned = 1; + return 0; +} + +static int __init +gic_v2_acpi_init(struct acpi_table_header *table) +{ + void __iomem *cpu_base, *dist_base; + int count; + + if (acpi_gic_version() >= ACPI_MADT_GIC_VER_V3) + return -ENODEV; + + /* Collect CPU base addresses */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_cpu, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + if (count <= 0) { + pr_err("No valid GICC entries exist\n"); + return -EINVAL; + } + + /* + * Find distributor base address. We expect one distributor entry since + * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade. + */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + acpi_gic_parse_distributor, table, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0); + if (count <= 0) { + pr_err("No valid GICD entries exist\n"); + return -EINVAL; + } else if (count > 1) { + pr_err("More than one GICD entry detected\n"); + return -EINVAL; + } + + cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); + if (!cpu_base) { + pr_err("Unable to map GICC registers\n"); + return -ENOMEM; + } + + dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE); + if (!dist_base) { + pr_err("Unable to map GICD registers\n"); + iounmap(cpu_base); + return -ENOMEM; + } + + gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); + + acpi_irq_model = ACPI_IRQ_MODEL_GIC; + return 0; +} +IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, gic_v2_acpi_init); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 869a69f..2f934fe 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -986,6 +986,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, if (WARN_ON(!gic->domain)) return;
+ set_acpi_core_irqdomain(gic->domain); + if (gic_nr == 0) { #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq); @@ -1047,104 +1049,3 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
#endif - -#ifdef CONFIG_ACPI -static phys_addr_t dist_phy_base, cpu_phy_base __initdata; - -static int __init -gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, - const unsigned long end) -{ - struct acpi_madt_generic_interrupt *processor; - phys_addr_t gic_cpu_base; - static int cpu_base_assigned; - - processor = (struct acpi_madt_generic_interrupt *)header; - - if (BAD_MADT_ENTRY(processor, end)) - return -EINVAL; - - /* - * There is no support for non-banked GICv1/2 register in ACPI spec. - * All CPU interface addresses have to be the same. - */ - gic_cpu_base = processor->base_address; - if (cpu_base_assigned && gic_cpu_base != cpu_phy_base) - return -EINVAL; - - cpu_phy_base = gic_cpu_base; - cpu_base_assigned = 1; - return 0; -} - -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_phy_base = dist->base_address; - return 0; -} - -static int __init -gic_v2_acpi_init(struct acpi_table_header *table) -{ - void __iomem *cpu_base, *dist_base; - int count; - - if (acpi_gic_version() >= ACPI_MADT_GIC_VER_V3) - return -ENODEV; - - /* Collect CPU base addresses */ - count = acpi_parse_entries(ACPI_SIG_MADT, - sizeof(struct acpi_table_madt), - gic_acpi_parse_madt_cpu, table, - ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); - if (count <= 0) { - pr_err("No valid GICC entries exist\n"); - return -EINVAL; - } - - /* - * Find distributor base address. We expect one distributor entry since - * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade. - */ - 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 entries exist\n"); - return -EINVAL; - } else if (count > 1) { - pr_err("More than one GICD entry detected\n"); - return -EINVAL; - } - - cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); - if (!cpu_base) { - pr_err("Unable to map GICC registers\n"); - return -ENOMEM; - } - - dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE); - if (!dist_base) { - pr_err("Unable to map GICD registers\n"); - iounmap(cpu_base); - return -ENOMEM; - } - - gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); - acpi_irq_domain = gic_data[0].domain; - - acpi_irq_model = ACPI_IRQ_MODEL_GIC; - return 0; -} -IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, gic_v2_acpi_init); -#endif diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index 245386d..f4a17c7 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -25,5 +25,10 @@ extern struct irq_domain *acpi_irq_domain;
int acpi_gic_version_init(void); u8 acpi_gic_version(void); + +void set_acpi_core_irqdomain(struct irq_domain *domain); +#else +#define set_acpi_core_irqdomain(domain) #endif /* CONFIG_ACPI */ + #endif /* ARM_GIC_ACPI_H_ */
Hi Hanjun,
On 05/18/2015 02:59 PM, Hanjun Guo wrote:
Move GICv2 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained.
Introduce set_acpi_core_irqdomain() to set acpi_irqdomain then it will be no need to make gic_data[] as a global value, and it will save the confilcts with GICv3's gic_data in the later patch.
acpi_gic_parse_distributor() have the same function as gic_acpi_parse_madt_distributor() to get the GIC distributor physical base address, so just remove the duplicate one, and only get the GIC version when it is unknown.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-acpi.c | 95 +++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 103 +---------------------------------- include/linux/irqchip/arm-gic-acpi.h | 5 ++ 3 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 1388d9e..8463e48 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -13,12 +13,16 @@
#include <linux/acpi.h> #include <linux/init.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-acpi.h> #include <linux/irqchip/arm-gic-v3.h>
arm-gic.h and arm-gic-v3.h describe register map for respective drivers and should be used separately within parent driver only.
Tomasz
+#include "irqchip.h"
- /* GIC version presented in MADT GIC distributor structure */ static u8 gic_version __initdata = ACPI_MADT_GIC_VER_UNKNOWN;
+/* GIC distributor physical base address, which is needed for both GICv2/3 */ static phys_addr_t dist_phy_base __initdata;
u8 __init acpi_gic_version(void) @@ -26,6 +30,11 @@ u8 __init acpi_gic_version(void) return gic_version; }
+void __init set_acpi_core_irqdomain(struct irq_domain *domain) +{
- acpi_irq_domain = domain;
+}
- static int __init acpi_gic_parse_distributor(struct acpi_subtable_header *header, const unsigned long end)
@@ -37,8 +46,9 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header, if (BAD_MADT_ENTRY(dist, end)) return -EINVAL;
- gic_version = dist->gic_version; dist_phy_base = dist->base_address;
- if (gic_version == ACPI_MADT_GIC_VER_UNKNOWN)
return 0; }gic_version = dist->gic_version;
@@ -114,3 +124,86 @@ int __init acpi_gic_version_init(void)
return 0; }
+static phys_addr_t cpu_phy_base __initdata;
+static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_interrupt *processor;
- phys_addr_t gic_cpu_base;
- static int cpu_base_assigned;
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- gic_cpu_base = processor->base_address;
- if (cpu_base_assigned && gic_cpu_base != cpu_phy_base)
return -EINVAL;
- cpu_phy_base = gic_cpu_base;
- cpu_base_assigned = 1;
- return 0;
+}
+static int __init +gic_v2_acpi_init(struct acpi_table_header *table) +{
- void __iomem *cpu_base, *dist_base;
- int count;
- if (acpi_gic_version() >= ACPI_MADT_GIC_VER_V3)
return -ENODEV;
- /* Collect CPU base addresses */
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
- if (count <= 0) {
pr_err("No valid GICC entries exist\n");
return -EINVAL;
- }
- /*
* Find distributor base address. We expect one distributor entry since
* ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
*/
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
acpi_gic_parse_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
- if (count <= 0) {
pr_err("No valid GICD entries exist\n");
return -EINVAL;
- } else if (count > 1) {
pr_err("More than one GICD entry detected\n");
return -EINVAL;
- }
- cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
- if (!cpu_base) {
pr_err("Unable to map GICC registers\n");
return -ENOMEM;
- }
- dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
- if (!dist_base) {
pr_err("Unable to map GICD registers\n");
iounmap(cpu_base);
return -ENOMEM;
- }
- gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
- acpi_irq_model = ACPI_IRQ_MODEL_GIC;
- return 0;
+} +IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, gic_v2_acpi_init); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 869a69f..2f934fe 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -986,6 +986,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, if (WARN_ON(!gic->domain)) return;
- set_acpi_core_irqdomain(gic->domain);
- if (gic_nr == 0) { #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq);
@@ -1047,104 +1049,3 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
#endif
-#ifdef CONFIG_ACPI -static phys_addr_t dist_phy_base, cpu_phy_base __initdata;
-static int __init -gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
const unsigned long end)
-{
- struct acpi_madt_generic_interrupt *processor;
- phys_addr_t gic_cpu_base;
- static int cpu_base_assigned;
- processor = (struct acpi_madt_generic_interrupt *)header;
- if (BAD_MADT_ENTRY(processor, end))
return -EINVAL;
- /*
* There is no support for non-banked GICv1/2 register in ACPI spec.
* All CPU interface addresses have to be the same.
*/
- gic_cpu_base = processor->base_address;
- if (cpu_base_assigned && gic_cpu_base != cpu_phy_base)
return -EINVAL;
- cpu_phy_base = gic_cpu_base;
- cpu_base_assigned = 1;
- return 0;
-}
-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_phy_base = dist->base_address;
- return 0;
-}
-static int __init -gic_v2_acpi_init(struct acpi_table_header *table) -{
- void __iomem *cpu_base, *dist_base;
- int count;
- if (acpi_gic_version() >= ACPI_MADT_GIC_VER_V3)
return -ENODEV;
- /* Collect CPU base addresses */
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_cpu, table,
ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
- if (count <= 0) {
pr_err("No valid GICC entries exist\n");
return -EINVAL;
- }
- /*
* Find distributor base address. We expect one distributor entry since
* ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
*/
- 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 entries exist\n");
return -EINVAL;
- } else if (count > 1) {
pr_err("More than one GICD entry detected\n");
return -EINVAL;
- }
- cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
- if (!cpu_base) {
pr_err("Unable to map GICC registers\n");
return -ENOMEM;
- }
- dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
- if (!dist_base) {
pr_err("Unable to map GICD registers\n");
iounmap(cpu_base);
return -ENOMEM;
- }
- gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
- acpi_irq_domain = gic_data[0].domain;
- acpi_irq_model = ACPI_IRQ_MODEL_GIC;
- return 0;
-} -IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, gic_v2_acpi_init); -#endif diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index 245386d..f4a17c7 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -25,5 +25,10 @@ extern struct irq_domain *acpi_irq_domain;
int acpi_gic_version_init(void); u8 acpi_gic_version(void);
+void set_acpi_core_irqdomain(struct irq_domain *domain); +#else +#define set_acpi_core_irqdomain(domain) #endif /* CONFIG_ACPI */
- #endif /* ARM_GIC_ACPI_H_ */
On 2015年05月21日 04:44, Tomasz Nowicki wrote:
Hi Hanjun,
On 05/18/2015 02:59 PM, Hanjun Guo wrote:
Move GICv2 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained.
Introduce set_acpi_core_irqdomain() to set acpi_irqdomain then it will be no need to make gic_data[] as a global value, and it will save the confilcts with GICv3's gic_data in the later patch.
acpi_gic_parse_distributor() have the same function as gic_acpi_parse_madt_distributor() to get the GIC distributor physical base address, so just remove the duplicate one, and only get the GIC version when it is unknown.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-acpi.c | 95 +++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 103 +---------------------------------- include/linux/irqchip/arm-gic-acpi.h | 5 ++ 3 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 1388d9e..8463e48 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -13,12 +13,16 @@
#include <linux/acpi.h> #include <linux/init.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-acpi.h> #include <linux/irqchip/arm-gic-v3.h>
arm-gic.h and arm-gic-v3.h describe register map for respective drivers and should be used separately within parent driver only.
Seems that there is no duplicate macros in that two head file, but yes, it will confuse people.
Consolidating all ACPI GIC code is an improvement to make ACPI related code self-contained, but also have some drawbacks,
Marc, what do you think?
Thanks Hanjun
On 21/05/15 15:27, Hanjun Guo wrote:
On 2015年05月21日 04:44, Tomasz Nowicki wrote:
Hi Hanjun,
On 05/18/2015 02:59 PM, Hanjun Guo wrote:
Move GICv2 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained.
Introduce set_acpi_core_irqdomain() to set acpi_irqdomain then it will be no need to make gic_data[] as a global value, and it will save the confilcts with GICv3's gic_data in the later patch.
acpi_gic_parse_distributor() have the same function as gic_acpi_parse_madt_distributor() to get the GIC distributor physical base address, so just remove the duplicate one, and only get the GIC version when it is unknown.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-acpi.c | 95 +++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 103 +---------------------------------- include/linux/irqchip/arm-gic-acpi.h | 5 ++ 3 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 1388d9e..8463e48 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -13,12 +13,16 @@
#include <linux/acpi.h> #include <linux/init.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-acpi.h> #include <linux/irqchip/arm-gic-v3.h>
arm-gic.h and arm-gic-v3.h describe register map for respective drivers and should be used separately within parent driver only.
Seems that there is no duplicate macros in that two head file, but yes, it will confuse people.
Consolidating all ACPI GIC code is an improvement to make ACPI related code self-contained, but also have some drawbacks,
Marc, what do you think?
What I think is "Over my dead body".
These include files are private to the respective interrupt controller code, and the only reason they are in linux/irqchip is because the corresponding KVM support code uses them too.
Thanks,
M.
Hi Marc,
On 06/11/2015 12:29 AM, Marc Zyngier wrote:
On 21/05/15 15:27, Hanjun Guo wrote:
On 2015年05月21日 04:44, Tomasz Nowicki wrote:
Hi Hanjun,
On 05/18/2015 02:59 PM, Hanjun Guo wrote:
Move GICv2 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained.
Introduce set_acpi_core_irqdomain() to set acpi_irqdomain then it will be no need to make gic_data[] as a global value, and it will save the confilcts with GICv3's gic_data in the later patch.
acpi_gic_parse_distributor() have the same function as gic_acpi_parse_madt_distributor() to get the GIC distributor physical base address, so just remove the duplicate one, and only get the GIC version when it is unknown.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-acpi.c | 95 +++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 103 +---------------------------------- include/linux/irqchip/arm-gic-acpi.h | 5 ++ 3 files changed, 101 insertions(+), 102 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 1388d9e..8463e48 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -13,12 +13,16 @@
#include <linux/acpi.h> #include <linux/init.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic-acpi.h> #include <linux/irqchip/arm-gic-v3.h>
arm-gic.h and arm-gic-v3.h describe register map for respective drivers and should be used separately within parent driver only.
Seems that there is no duplicate macros in that two head file, but yes, it will confuse people.
Consolidating all ACPI GIC code is an improvement to make ACPI related code self-contained, but also have some drawbacks,
Marc, what do you think?
What I think is "Over my dead body".
These include files are private to the respective interrupt controller code, and the only reason they are in linux/irqchip is because the corresponding KVM support code uses them too.
So for this patch, we are totally in the wrong direction, I will remove the last two patches in next version.
Thanks for your constructive comments, much appreciated :)
Thanks Hanjun
Move GICv3 ACPI related init code in irq-gic.c to irq-gic-acpi.c, this can make the ACPI related GIC init code slef-contained as GICV2 did.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-acpi.c | 109 +++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3.c | 140 ++----------------------------------- include/linux/irqchip/arm-gic-v3.h | 10 +++ 3 files changed, 123 insertions(+), 136 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 8463e48..75c4893 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -207,3 +207,112 @@ gic_v2_acpi_init(struct acpi_table_header *table) return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_SIG_MADT, gic_v2_acpi_init); + +static struct redist_region *redist_regs __initdata; +static u32 nr_redist_regions __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_v3_acpi_init(struct acpi_table_header *table) +{ + int count, i, err = 0; + void __iomem *dist_base; + + if (acpi_gic_version() < ACPI_MADT_GIC_VER_V3) + return -ENODEV; + + /* Get distributor base address */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + acpi_gic_parse_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_phy_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 = gicv3_init_bases(dist_base, redist_regs, nr_redist_regions, 0, NULL); + if (err) + goto out_redist_unmap; + + 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_SIG_MADT, gic_v3_acpi_init); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e7f134e..a8382f4 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -36,11 +36,6 @@ #include "irq-gic-common.h" #include "irqchip.h"
-struct redist_region { - void __iomem *redist_base; - phys_addr_t phys_base; -}; - struct gic_chip_data { void __iomem *dist_base; struct redist_region *redist_regions; @@ -773,7 +768,7 @@ 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, +int __init gicv3_init_bases(void __iomem *dist_base, struct redist_region *rdist_regs, u32 nr_redist_regions, u64 redist_stride, @@ -808,6 +803,7 @@ static int __init gic_init_bases(void __iomem *dist_base, goto out_free; }
+ set_acpi_core_irqdomain(gic_data.domain); set_handle_irq(gic_handle_irq);
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) @@ -827,7 +823,7 @@ out_free: return err; }
-static int __init detect_distributor(void __iomem *dist_base) +int __init detect_distributor(void __iomem *dist_base) { u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
@@ -887,7 +883,7 @@ 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;
- err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, + err = gicv3_init_bases(dist_base, rdist_regs, nr_redist_regions, redist_stride, node); if (!err) return 0; @@ -904,131 +900,3 @@ 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_phy_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_phy_base = dist->base_address; - return 0; -} - -static int __init -gic_v3_acpi_init(struct acpi_table_header *table) -{ - int count, i, err = 0; - void __iomem *dist_base; - - if (acpi_gic_version() < ACPI_MADT_GIC_VER_V3) - return -ENODEV; - - /* 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_phy_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, NULL); - if (err) - goto out_redist_unmap; - - acpi_irq_domain = gic_data.domain; - 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_SIG_MADT, gic_v3_acpi_init); -#endif diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ffbc034..37ef420 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -378,6 +378,11 @@ struct rdists { u64 flags; };
+struct redist_region { + void __iomem *redist_base; + phys_addr_t phys_base; +}; + static inline void gic_write_eoir(u64 irq) { asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq)); @@ -389,6 +394,11 @@ int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain);
+int gicv3_init_bases(void __iomem *dist_base, struct redist_region *rdist_regs, + u32 nr_redist_regions, u64 redist_stride, + struct device_node *node); + +int detect_distributor(void __iomem *dist_base); #endif
#endif
Hi Marc,
Ping, could you comment on if we are on the right direction for this patch set? much appreciated.
Thanks Hanjun
On 2015年05月18日 20:59, Hanjun Guo wrote:
This patch set introduce self-probe infrastructure to init IRQ controllers and stacked irqdomain support for ACPI based GICv2/3 init.
The self-probe infrastructure for ACPI GIC init is similar as IRQCHIP_DECLARE() and based on the GIC version support in ACPI MADT table.
We introduce acpi_irq_domain for GICv2/3 core domain to support stacked irqdomain, and pass the gsi (global system interrupt) as the agument (void *arg) for gic_irq_domain_alloc(), then we can alloc virqs via acpi_register_gsi() with stacked irqdomain.
In order to make ACPI related GIC init code slef-contained, I consolidated all the GIC init code into drivers/irqchip/irq-gic-acpi.c.
update from RFC version:
- Consolidate all the GIC init code into drivers/irqchip/irq-gic-acpi.c
Hanjun Guo (8): irqchip / GIC: Add GIC version support in ACPI MADT irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code irqchip / gic: Add stacked irqdomain support for ACPI based GICv2 init ACPI / gsi: Add gsi_mutex to synchronize acpi_register_gsi()/acpi_unregister_gsi() irqchip / GICv3: Add ACPI support for GICv3+ initialization irqchip / GICv3: Add stacked irqdomain support for ACPI based init irqchip / GICv2 / ACPI: Consolidate GICv2 ACPI related init code irqchip / GICv3 / ACPI: Consolidate GICv3 ACPI related init code
Tomasz Nowicki (3): ACPICA: Introduce GIC version for arm based system ACPI / irqchip: Add self-probe infrastructure to initialize IRQ controller irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
arch/arm64/Kconfig | 1 + arch/arm64/include/asm/irq.h | 13 -- arch/arm64/kernel/acpi.c | 25 --- drivers/acpi/Makefile | 1 + drivers/acpi/gsi.c | 41 +++-- drivers/acpi/irq.c | 40 +++++ drivers/irqchip/Kconfig | 3 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-gic-acpi.c | 318 +++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3.c | 149 +++++++++------- drivers/irqchip/irq-gic.c | 129 ++------------ drivers/irqchip/irqchip.h | 12 ++ include/acpi/actbl1.h | 17 +- include/asm-generic/vmlinux.lds.h | 13 ++ include/linux/acpi.h | 14 ++ include/linux/acpi_irq.h | 4 +- include/linux/irqchip/arm-gic-acpi.h | 13 +- include/linux/irqchip/arm-gic-v3.h | 10 ++ include/linux/mod_devicetable.h | 7 + 19 files changed, 577 insertions(+), 234 deletions(-) create mode 100644 drivers/acpi/irq.c create mode 100644 drivers/irqchip/irq-gic-acpi.c