Hi Marc,
Tomasz and I reworked this patch set to address your comments, mainly about the self-probe infrastructure and the way to init GIC redistributor in GICC structures.
For the self-probe infrastructure, we introduce a new file in drivers/acpi/ which can be reused for ioapic in the future;
For init GIC redistributor in GICC structures, I introduced a flag in struct redist_region just as you suggested, and get the redist base from GICC strucutes if no redistributor regions are available from GICR strucutes. I think the naming of the flag and functions are not good, please comment on them :)
For the proper namespace of domain token for ACPI, I think we can use the Interrupt Controller Structure Types as the token, (just some ideas, not implemented in the patch, trying to discuss with you that if it makes sense to you), for Structure Types, we got: 1 - I/O APIC 0xB - GICC CPU Interface Structure 0xC - GICD GIC Distributor Structure 0xD - GICv2m MSI Frame 0xE - GICR Redistributor Structure 0xF - ITS Structure
so except the GICD 0xC both for GICv2/3, others can used as proper namespace for different domain tokens, what do you think?
Please comments on if we are on right direction, thanks.
Hanjun
Hanjun Guo (4): irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code irqchip / GICv3: remove the useless comparision of device node in xlate irqchip / GICv3: Add ACPI support for GICv3+ initialization irqchip / GICv3 / ACPI: Add GICR support via GICC structures
Tomasz Nowicki (2): acpi, irqchip: Add self-probe infrastructure to initialize IRQ controller irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
arch/arm64/include/asm/irq.h | 13 -- arch/arm64/kernel/acpi.c | 25 --- drivers/acpi/Makefile | 2 + drivers/acpi/irq.c | 136 +++++++++++++ drivers/irqchip/irq-gic-v3.c | 360 ++++++++++++++++++++++++++++++----- drivers/irqchip/irq-gic.c | 4 +- include/asm-generic/vmlinux.lds.h | 13 ++ include/linux/acpi.h | 18 ++ include/linux/acpi_irq.h | 4 +- include/linux/irqchip.h | 13 ++ include/linux/irqchip/arm-gic-acpi.h | 9 +- include/linux/mod_devicetable.h | 9 + 12 files changed, 512 insertions(+), 94 deletions(-) create mode 100644 drivers/acpi/irq.c
From: Tomasz Nowicki tn@semihalf.com
From the top level prospective this self-probe infrastructure works
in the similar way as OF, however there are some internal differences.
For DT, the init fn is called once it finds compatible strings, but for ACPI there are no such thing. Instead, we initialize irqchips using static MADT table. Doing that, we need to relay on subtables presence which define details to corresponding IRQ controller. Also, for some subtable we can do additional matching, like for GIC distributor version. See patch for more detailed information.
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 tn@semihalf.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/Makefile | 2 + drivers/acpi/irq.c | 110 ++++++++++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++ include/linux/acpi.h | 18 +++++++ include/linux/irqchip.h | 13 +++++ include/linux/mod_devicetable.h | 9 ++++ 6 files changed, 165 insertions(+) create mode 100644 drivers/acpi/irq.c
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430..599f1df 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -27,6 +27,8 @@ acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o
+# IRQ controller probe +acpi-y += irq.o
# # ACPI Bus and Device Drivers diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 0000000..4216b34 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015, Linaro Ltd. + * Author: Tomasz Nowicki tomasz.nowicki@linaro.org + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include <linux/acpi.h> +#include <linux/init.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[]; +static struct acpi_table_id *iterator; + +static int __init +acpi_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; + + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, + acpi_match_gic_redist, 0); + return count > 0; +} + +static int __init +acpi_match_madt_subtable(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_distributor *dist; + u8 gic_version = ACPI_MADT_GIC_VERSION_NONE; + + /* Found appropriated subtable, now try to do additional matching */ + switch (header->type) { + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + + dist = (struct acpi_madt_generic_distributor *)header; + gic_version = dist->version; + + /* + * This is for backward compatibility with ACPI 5.1, + * which has no gic_version field. + */ + if (gic_version == ACPI_MADT_GIC_VERSION_NONE) { + /* It is GICv3/v4 if redistributor is present */ + if (acpi_gic_redist_is_present()) + gic_version = ACPI_MADT_GIC_VERSION_V3; + else + gic_version = ACPI_MADT_GIC_VERSION_V2; + + return 0; + } + + /* + * GICv4 has meaning to KVM, for host IRQ controller we can + * treat it as GICv3 to avoid another IRQCHIP_ACPI_DECLARE + * entry. + */ + if (gic_version == ACPI_MADT_GIC_VERSION_V4) + gic_version = ACPI_MADT_GIC_VERSION_V3; + + if (gic_version == iterator->driver_data) + return 0; + + return -AE_NOT_FOUND; + } + + /* No additional matching for the rest of subtable types for now */ + return 0; +} + +void __init acpi_irqchip_init(void) +{ + + if (acpi_disabled) + return; + + for (iterator = __irqchip_acpi_table; iterator->id[0]; iterator++) { + if (acpi_table_parse_madt(iterator->type, + acpi_match_madt_subtable, 0) <= 0) + continue; /* No match or invalid subtables */ + + acpi_table_parse(ACPI_SIG_MADT, + (acpi_tbl_table_handler)iterator->handler); + } +} diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8bd374d..625776c 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -181,6 +181,18 @@ #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) #define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
+#ifdef CONFIG_ACPI +#define ACPI_TABLE(name) \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__##name##_acpi_table) = .; \ + *(__##name##_acpi_table) \ + *(__##name##_acpi_table_end) + +#define IRQCHIP_ACPI_MATCH_TABLE() ACPI_TABLE(irqchip) +#else +#define IRQCHIP_ACPI_MATCH_TABLE() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .; \ @@ -516,6 +528,7 @@ CPUIDLE_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ + IRQCHIP_ACPI_MATCH_TABLE() \ EARLYCON_TABLE() \ EARLYCON_OF_TABLES()
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 0820cb1..a30b969 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -829,4 +829,22 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev,
#endif
+#ifdef CONFIG_ACPI +#define ACPI_DECLARE(table, name, table_id, subtable, data, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __used __section(__##table##_acpi_table) \ + = { .id = table_id, \ + .type = subtable, \ + .handler = (void *)fn, \ + .driver_data = data } +#else +#define ACPI_DECLARE(table, name, table_id, subtable, data, fn) \ + static const struct acpi_table_id __acpi_table_##name \ + __attribute__((unused)) \ + = { .id = table_id, \ + .type = subtable, \ + .handler = (void *)fn, \ + .driver_data = data } +#endif + #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 6388873..a7573fd 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -11,6 +11,7 @@ #ifndef _LINUX_IRQCHIP_H #define _LINUX_IRQCHIP_H
+#include <linux/acpi.h> #include <linux/of.h>
/* @@ -25,6 +26,18 @@ */ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
+/* + * This macro must be used by the different ARM GIC drivers to declare + * the association between their version and their initialization function. + * + * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the + * same file. + * @gic_version: version of GIC + * @fn: initialization function + */ +#define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \ + ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, subtable, version, fn) + #ifdef CONFIG_IRQCHIP void irqchip_init(void); #else diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 34f25b7..ebedaa7 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -193,6 +193,15 @@ struct acpi_device_id { __u32 cls_msk; };
+#define ACPI_TABLE_ID_LEN 5 + +struct acpi_table_id { + __u8 id[ACPI_TABLE_ID_LEN]; + __u8 type; + const void *handler; + kernel_ulong_t driver_data; +}; + #define PNP_ID_LEN 8 #define PNP_MAX_DEVICES 8
On 17/08/15 14:23, Hanjun Guo wrote:
From: Tomasz Nowicki tn@semihalf.com
From the top level prospective this self-probe infrastructure works in the similar way as OF, however there are some internal differences.
For DT, the init fn is called once it finds compatible strings, but for ACPI there are no such thing. Instead, we initialize irqchips using static MADT table. Doing that, we need to relay on subtables presence which define details to corresponding IRQ controller. Also, for some subtable we can do additional matching, like for GIC distributor version. See patch for more detailed information.
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 tn@semihalf.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/Makefile | 2 + drivers/acpi/irq.c | 110 ++++++++++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++ include/linux/acpi.h | 18 +++++++ include/linux/irqchip.h | 13 +++++ include/linux/mod_devicetable.h | 9 ++++ 6 files changed, 165 insertions(+) create mode 100644 drivers/acpi/irq.c
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430..599f1df 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -27,6 +27,8 @@ acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o +# IRQ controller probe +acpi-y += irq.o # # ACPI Bus and Device Drivers diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 0000000..4216b34 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,110 @@ +/*
- Copyright (C) 2015, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
- */
+#include <linux/acpi.h> +#include <linux/init.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[]; +static struct acpi_table_id *iterator;
+static int __init +acpi_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;
- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
acpi_match_gic_redist, 0);
- return count > 0;
+}
I was really dreading to review this series, and I was right... What are these two functions doing here? This file is supposed to be irqchip agnostic and only provide a generic framework for ACPI-based ipchips.
So NAK. You can do some filtering on a per irqchip basis so that we don't have to pollute the firmware abstraction with properties that only matter to a given irqchip.
+static int __init +acpi_match_madt_subtable(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_distributor *dist;
- u8 gic_version = ACPI_MADT_GIC_VERSION_NONE;
- /* Found appropriated subtable, now try to do additional matching */
- switch (header->type) {
- case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
dist = (struct acpi_madt_generic_distributor *)header;
gic_version = dist->version;
/*
* This is for backward compatibility with ACPI 5.1,
* which has no gic_version field.
*/
if (gic_version == ACPI_MADT_GIC_VERSION_NONE) {
/* It is GICv3/v4 if redistributor is present */
if (acpi_gic_redist_is_present())
gic_version = ACPI_MADT_GIC_VERSION_V3;
else
gic_version = ACPI_MADT_GIC_VERSION_V2;
return 0;
Seriously? Can you explain the exact effect of that code? You can't possibly have tested it.
I've stopped reading, this is a waste of my time.
Thanks,
M.
On 28.08.2015 15:25, Marc Zyngier wrote:
On 17/08/15 14:23, Hanjun Guo wrote:
From: Tomasz Nowicki tn@semihalf.com
From the top level prospective this self-probe infrastructure works in the similar way as OF, however there are some internal differences.
For DT, the init fn is called once it finds compatible strings, but for ACPI there are no such thing. Instead, we initialize irqchips using static MADT table. Doing that, we need to relay on subtables presence which define details to corresponding IRQ controller. Also, for some subtable we can do additional matching, like for GIC distributor version. See patch for more detailed information.
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 tn@semihalf.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/acpi/Makefile | 2 + drivers/acpi/irq.c | 110 ++++++++++++++++++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++ include/linux/acpi.h | 18 +++++++ include/linux/irqchip.h | 13 +++++ include/linux/mod_devicetable.h | 9 ++++ 6 files changed, 165 insertions(+) create mode 100644 drivers/acpi/irq.c
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430..599f1df 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -27,6 +27,8 @@ acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o
+# IRQ controller probe +acpi-y += irq.o
# # ACPI Bus and Device Drivers diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 0000000..4216b34 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,110 @@ +/*
- Copyright (C) 2015, Linaro Ltd.
- Author: Tomasz Nowicki tomasz.nowicki@linaro.org
- 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.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
- */
+#include <linux/acpi.h> +#include <linux/init.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[]; +static struct acpi_table_id *iterator;
+static int __init +acpi_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;
- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
acpi_match_gic_redist, 0);
- return count > 0;
+}
I was really dreading to review this series, and I was right... What are these two functions doing here? This file is supposed to be irqchip agnostic and only provide a generic framework for ACPI-based ipchips.
So NAK. You can do some filtering on a per irqchip basis so that we don't have to pollute the firmware abstraction with properties that only matter to a given irqchip.
+static int __init +acpi_match_madt_subtable(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_distributor *dist;
- u8 gic_version = ACPI_MADT_GIC_VERSION_NONE;
- /* Found appropriated subtable, now try to do additional matching */
- switch (header->type) {
- case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
dist = (struct acpi_madt_generic_distributor *)header;
gic_version = dist->version;
/*
* This is for backward compatibility with ACPI 5.1,
* which has no gic_version field.
*/
if (gic_version == ACPI_MADT_GIC_VERSION_NONE) {
/* It is GICv3/v4 if redistributor is present */
if (acpi_gic_redist_is_present())
gic_version = ACPI_MADT_GIC_VERSION_V3;
else
gic_version = ACPI_MADT_GIC_VERSION_V2;
return 0;
Seriously? Can you explain the exact effect of that code? You can't possibly have tested it.
Apologies for this silly code. We tested it, but obviously not with ACPI 5.1.
Anyway I agree with your comments and your clean up looks much better.
Tomasz
As the ACPI self-probe infrastructure for irqchip is ready, we use the infrastructure to simplify GICv2 init code.
acpi_irqchip_init() is renamed as acpi_irq_init() to replace the previous hardcode version of acpi_irq_init() in asm/irq.h, also cleanup the code which previously calling the GIC driver manually in arch/arm64/kernel/acpi.c.
From now on, GIC init calls reside in their drivers only.
This means the code becomes cleaner and it is not spread outside irqchip driver.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki tn@semihalf.com --- arch/arm64/include/asm/irq.h | 13 ------------- arch/arm64/kernel/acpi.c | 25 ------------------------- drivers/acpi/irq.c | 2 +- drivers/irqchip/irq-gic.c | 4 +++- include/linux/acpi_irq.h | 4 +++- include/linux/irqchip/arm-gic-acpi.h | 9 +-------- 6 files changed, 8 insertions(+), 49 deletions(-)
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index bbb251b..94c5367 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -1,8 +1,6 @@ #ifndef __ASM_IRQ_H #define __ASM_IRQ_H
-#include <linux/irqchip/arm-gic-acpi.h> - #include <asm-generic/irq.h>
struct pt_regs; @@ -10,15 +8,4 @@ struct pt_regs; extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
-static inline void acpi_irq_init(void) -{ - /* - * Hardcode ACPI IRQ chip initialization to GICv2 for now. - * Proper irqchip infrastructure will be implemented along with - * incoming GICv2m|GICv3|ITS bits. - */ - acpi_gic_init(); -} -#define acpi_irq_init acpi_irq_init - #endif diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 19de753..d6463bb 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -205,28 +205,3 @@ void __init acpi_boot_table_init(void) disable_acpi(); } } - -void __init acpi_gic_init(void) -{ - struct acpi_table_header *table; - acpi_status status; - acpi_size tbl_size; - int err; - - if (acpi_disabled) - return; - - status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size); - if (ACPI_FAILURE(status)) { - const char *msg = acpi_format_exception(status); - - pr_err("Failed to get MADT table, %s\n", msg); - return; - } - - err = gic_v2_acpi_init(table); - if (err) - pr_err("Failed to initialize GIC IRQ controller"); - - early_acpi_os_unmap_memory((char *)table, tbl_size); -} diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index 4216b34..cb23cb2 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -93,7 +93,7 @@ acpi_match_madt_subtable(struct acpi_subtable_header *header, return 0; }
-void __init acpi_irqchip_init(void) +void __init acpi_irq_init(void) {
if (acpi_disabled) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index ce531e6..03adec8 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1109,7 +1109,7 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data, return 0; }
-int __init +static int __init gic_v2_acpi_init(struct acpi_table_header *table) { void __iomem *cpu_base, *dist_base; @@ -1163,4 +1163,6 @@ gic_v2_acpi_init(struct acpi_table_header *table) gic_acpi_gsi_desc_populate); return 0; } +IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, + ACPI_MADT_GIC_VERSION_V2, gic_v2_acpi_init); #endif diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h index f10c872..4c0e108 100644 --- a/include/linux/acpi_irq.h +++ b/include/linux/acpi_irq.h @@ -3,7 +3,9 @@
#include <linux/irq.h>
-#ifndef acpi_irq_init +#ifdef CONFIG_ACPI +void acpi_irq_init(void); +#else static inline void acpi_irq_init(void) { } #endif
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h index de3419e..9add59b 100644 --- a/include/linux/irqchip/arm-gic-acpi.h +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -20,12 +20,5 @@ #define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K) #define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
-struct acpi_table_header; - -int gic_v2_acpi_init(struct acpi_table_header *table); -void acpi_gic_init(void); -#else -static inline void acpi_gic_init(void) { } -#endif - +#endif /* CONFIG_ACPI */ #endif /* ARM_GIC_ACPI_H_ */
From: Tomasz Nowicki tomasz.nowicki@linaro.org
Isolate hardware abstraction (FDT) code to gic_of_init(). Rest of the logic goes to gic_init_bases() and expects well defined data to initialize GIC properly. The same solution is used for GICv2 driver.
This is needed for ACPI initialization later.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-v3.c | 105 +++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 44 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 5492f4e..19a65de 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -766,17 +766,69 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .free = gic_irq_domain_free, };
+static int __init gic_init_bases(void __iomem *dist_base, + struct redist_region *rdist_regs, + u32 nr_redist_regions, + u64 redist_stride, + void *domain_token) +{ + u32 typer; + int gic_irqs; + int err; + + gic_data.dist_base = dist_base; + gic_data.redist_regions = rdist_regs; + gic_data.nr_redist_regions = nr_redist_regions; + gic_data.redist_stride = redist_stride; + + /* + * Find out how many interrupts are supported. + * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) + */ + typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); + gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer); + gic_irqs = GICD_TYPER_IRQS(typer); + if (gic_irqs > 1020) + gic_irqs = 1020; + gic_data.irq_nr = gic_irqs; + + gic_data.domain = irq_domain_add_tree(domain_token, &gic_irq_domain_ops, + &gic_data); + gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); + + if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { + err = -ENOMEM; + goto out_free; + } + + set_handle_irq(gic_handle_irq); + + if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) + its_init(domain_token, &gic_data.rdists, gic_data.domain); + + gic_smp_init(); + gic_dist_init(); + gic_cpu_init(); + gic_cpu_pm_init(); + + return 0; + +out_free: + if (gic_data.domain) + irq_domain_remove(gic_data.domain); + free_percpu(gic_data.rdists.rdist); + return err; +} + +#ifdef CONFIG_OF static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *dist_base; struct redist_region *rdist_regs; u64 redist_stride; u32 nr_redist_regions; - u32 typer; u32 reg; - int gic_irqs; - int err; - int i; + int err, i;
dist_base = of_iomap(node, 0); if (!dist_base) { @@ -820,47 +872,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) redist_stride = 0;
- gic_data.dist_base = dist_base; - gic_data.redist_regions = rdist_regs; - gic_data.nr_redist_regions = nr_redist_regions; - gic_data.redist_stride = redist_stride; + err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, + redist_stride, node); + if (!err) + return 0;
- /* - * Find out how many interrupts are supported. - * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) - */ - typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); - gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer); - gic_irqs = GICD_TYPER_IRQS(typer); - if (gic_irqs > 1020) - gic_irqs = 1020; - gic_data.irq_nr = gic_irqs; - - gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops, - &gic_data); - gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); - - if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { - err = -ENOMEM; - goto out_free; - } - - set_handle_irq(gic_handle_irq); - - if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) - its_init(node, &gic_data.rdists, gic_data.domain); - - gic_smp_init(); - gic_dist_init(); - gic_cpu_init(); - gic_cpu_pm_init(); - - return 0; - -out_free: - if (gic_data.domain) - irq_domain_remove(gic_data.domain); - free_percpu(gic_data.rdists.rdist); out_unmap_rdist: for (i = 0; i < nr_redist_regions; i++) if (rdist_regs[i].redist_base) @@ -872,3 +888,4 @@ out_unmap_dist: }
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); +#endif
In gic_irq_domain_xlate(), we match the domain's device node to the controller and it turns out pretty useless, because we're always registering the GIC domain with its device_node on DT, this is really guaranteed to match.
Since we unify the way of matching irqdomain in DT and ACPI, this is also a blocker of making this function usable in the context of ACPI, so just remove it.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-v3.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 19a65de..c0b96c6 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -706,8 +706,6 @@ static int gic_irq_domain_xlate(struct irq_domain *d, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { - if (irq_domain_get_of_node(d) != controller) - return -EINVAL; if (intsize < 3) return -EINVAL;
With the refator of gic_of_init(), GICv3/4 can be initialized by gic_init_bases() with gic distributor base address and gic redistributor region(s).
So get the redistributor region base addresses from MADT GIC redistributor subtable, and the distributor base address from GICD subtable to init GICv3 irqchip in ACPI way.
Note: GIC redistributor base address may also be provided in GICC structures on systems supporting GICv3 and above if the GIC Redistributors are not in the always-on power domain, this patch didn't implement such feature yet.
This patch is based on Tomasz's work.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-v3.c | 189 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c0b96c6..51547c9 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> @@ -801,7 +803,8 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq);
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) + if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() + && irq_domain_token_to_of_node(domain_token)) its_init(domain_token, &gic_data.rdists, gic_data.domain);
gic_smp_init(); @@ -818,6 +821,16 @@ out_free: return err; }
+static int __init gic_validate_dist_version(void __iomem *dist_base) +{ + u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; + + if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) + return -ENODEV; + + return 0; +} + #ifdef CONFIG_OF static int __init gic_of_init(struct device_node *node, struct device_node *parent) { @@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare struct redist_region *rdist_regs; u64 redist_stride; u32 nr_redist_regions; - u32 reg; int err, i;
dist_base = of_iomap(node, 0); @@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare return -ENXIO; }
- reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; - if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) { + err = gic_validate_dist_version(dist_base); + if (err) { pr_err("%s: no distributor detected, giving up\n", node->full_name); - err = -ENODEV; goto out_unmap_dist; }
@@ -887,3 +898,171 @@ out_unmap_dist:
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #endif + +#ifdef CONFIG_ACPI +static struct redist_region *redist_regs __initdata; +static u32 nr_redist_regions __initdata; +static phys_addr_t dist_phys_base __initdata; + +static int __init +gic_acpi_match_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 0; +} + +static int __init +gic_acpi_register_redist(phys_addr_t phys_base, u64 size) +{ + void __iomem *redist_base; + + 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; + + redist = (struct acpi_madt_generic_redistributor *)header; + return gic_acpi_register_redist(redist->base_address, redist->length); +} + +static int __init +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_distributor *dist; + + dist = (struct acpi_madt_generic_distributor *)header; + + if (BAD_MADT_ENTRY(dist, end)) + return -EINVAL; + + dist_phys_base = dist->base_address; + return 0; +} + +static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data, + u32 gsi, unsigned int irq_type) +{ + /* + * Encode GSI and triggering information the way the GIC likes + * them. + */ + if (WARN_ON(gsi < 16)) + return -EINVAL; + + if (gsi >= 32) { + data->param[0] = 0; /* SPI */ + data->param[1] = gsi - 32; + data->param[2] = irq_type; + } else { + data->param[0] = 1; /* PPI */ + data->param[1] = gsi - 16; + data->param[2] = 0xff << 4 | irq_type; + } + + data->param_count = 3; + + return 0; +} + +static int __init +gic_acpi_init(struct acpi_table_header *table) +{ + int count, i, err = 0; + void __iomem *dist_base; + + /* Get distributor base address */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_distributor, table, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0); + if (count <= 0) { + pr_err("No valid GICD entry exist\n"); + return -EINVAL; + } else if (count > 1) { + pr_err("More than one GICD entry detected\n"); + return -EINVAL; + } + + dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE); + if (!dist_base) { + pr_err("Unable to map GICD registers\n"); + return -ENOMEM; + } + + err = gic_validate_dist_version(dist_base); + if (err) { + pr_err("No distributor detected at @%p, giving up", dist_base); + goto out_dist_unmap; + } + + /* Count how many redistributor regions we have */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_match_redist, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); + if (count <= 0) { + pr_err("No valid GICR entries\n"); + err = -EINVAL; + goto out_dist_unmap; + } + + redist_regs = kzalloc(sizeof(*redist_regs) * count, GFP_KERNEL); + if (!redist_regs) { + err = -ENOMEM; + goto out_dist_unmap; + } + + /* Collect redistributor base addresses */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redist, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); + if (count <= 0) { + pr_info("No valid GICR entries exist\n"); + err = -EINVAL; + goto out_redist_unmap; + } + + err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0, + (void *)dist_phys_base); + if (err) + goto out_redist_unmap; + + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, dist_phys_base, + gic_acpi_gsi_desc_populate); + return 0; + +out_redist_unmap: + for (i = 0; i < nr_redist_regions; i++) + if (redist_regs[i].redist_base) + iounmap(redist_regs[i].redist_base); + kfree(redist_regs); +out_dist_unmap: + iounmap(dist_base); + return err; +} +IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init); +#endif
On 17.08.2015 15:23, Hanjun Guo wrote:
With the refator of gic_of_init(), GICv3/4 can be initialized by gic_init_bases() with gic distributor base address and gic redistributor region(s).
So get the redistributor region base addresses from MADT GIC redistributor subtable, and the distributor base address from GICD subtable to init GICv3 irqchip in ACPI way.
Note: GIC redistributor base address may also be provided in GICC structures on systems supporting GICv3 and above if the GIC Redistributors are not in the always-on power domain, this patch didn't implement such feature yet.
This patch is based on Tomasz's work.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-v3.c | 189 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 5 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c0b96c6..51547c9 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> @@ -801,7 +803,8 @@ static int __init gic_init_bases(void __iomem *dist_base,
set_handle_irq(gic_handle_irq);
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()
&& irq_domain_token_to_of_node(domain_token))
its_init(domain_token, &gic_data.rdists, gic_data.domain);
gic_smp_init();
@@ -818,6 +821,16 @@ out_free: return err; }
+static int __init gic_validate_dist_version(void __iomem *dist_base) +{
- u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
- if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
return -ENODEV;
- return 0;
+}
- #ifdef CONFIG_OF static int __init gic_of_init(struct device_node *node, struct device_node *parent) {
@@ -825,7 +838,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare struct redist_region *rdist_regs; u64 redist_stride; u32 nr_redist_regions;
u32 reg; int err, i;
dist_base = of_iomap(node, 0);
@@ -835,11 +847,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare return -ENXIO; }
- reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
- if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
- err = gic_validate_dist_version(dist_base);
- if (err) { pr_err("%s: no distributor detected, giving up\n", node->full_name);
goto out_unmap_dist; }err = -ENODEV;
@@ -887,3 +898,171 @@ out_unmap_dist:
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #endif
+#ifdef CONFIG_ACPI +static struct redist_region *redist_regs __initdata; +static u32 nr_redist_regions __initdata; +static phys_addr_t dist_phys_base __initdata;
+static int __init +gic_acpi_match_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 0;
+}
+static int __init +gic_acpi_register_redist(phys_addr_t phys_base, u64 size) +{
- void __iomem *redist_base;
- 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;
- redist = (struct acpi_madt_generic_redistributor *)header;
- return gic_acpi_register_redist(redist->base_address, redist->length);
+}
+static int __init +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
const unsigned long end)
+{
- struct acpi_madt_generic_distributor *dist;
- dist = (struct acpi_madt_generic_distributor *)header;
- if (BAD_MADT_ENTRY(dist, end))
return -EINVAL;
- dist_phys_base = dist->base_address;
- return 0;
+}
+static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data,
u32 gsi, unsigned int irq_type)
+{
- /*
* Encode GSI and triggering information the way the GIC likes
* them.
*/
- if (WARN_ON(gsi < 16))
return -EINVAL;
- if (gsi >= 32) {
data->param[0] = 0; /* SPI */
data->param[1] = gsi - 32;
data->param[2] = irq_type;
- } else {
data->param[0] = 1; /* PPI */
data->param[1] = gsi - 16;
data->param[2] = 0xff << 4 | irq_type;
- }
- data->param_count = 3;
- return 0;
+}
+static int __init +gic_acpi_init(struct acpi_table_header *table) +{
- int count, i, err = 0;
- void __iomem *dist_base;
- /* Get distributor base address */
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_distributor, table,
ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
- if (count <= 0) {
pr_err("No valid GICD entry exist\n");
return -EINVAL;
- } else if (count > 1) {
pr_err("More than one GICD entry detected\n");
return -EINVAL;
- }
- dist_base = ioremap(dist_phys_base, ACPI_GICV3_DIST_MEM_SIZE);
- if (!dist_base) {
pr_err("Unable to map GICD registers\n");
return -ENOMEM;
- }
- err = gic_validate_dist_version(dist_base);
- if (err) {
pr_err("No distributor detected at @%p, giving up", dist_base);
goto out_dist_unmap;
- }
- /* Count how many redistributor regions we have */
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
gic_acpi_match_redist, table,
ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
- if (count <= 0) {
pr_err("No valid GICR entries\n");
err = -EINVAL;
goto out_dist_unmap;
- }
- redist_regs = kzalloc(sizeof(*redist_regs) * count, GFP_KERNEL);
- if (!redist_regs) {
err = -ENOMEM;
goto out_dist_unmap;
- }
- /* Collect redistributor base addresses */
- count = acpi_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt),
gic_acpi_parse_madt_redist, table,
ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0);
- if (count <= 0) {
pr_info("No valid GICR entries exist\n");
err = -EINVAL;
goto out_redist_unmap;
- }
- err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
(void *)dist_phys_base);
- if (err)
goto out_redist_unmap;
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, dist_phys_base,
gic_acpi_gsi_desc_populate);
- return 0;
+out_redist_unmap:
- for (i = 0; i < nr_redist_regions; i++)
if (redist_regs[i].redist_base)
iounmap(redist_regs[i].redist_base);
- kfree(redist_regs);
+out_dist_unmap:
- iounmap(dist_base);
- return err;
+} +IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init); +#endif
Giving the new approach, this should look like this: IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init);
Regards, Tomasz
On 08/24/2015 05:03 PM, Tomasz Nowicki wrote:
On 17.08.2015 15:23, Hanjun Guo wrote:
With the refator of gic_of_init(), GICv3/4 can be initialized
[...]
+IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init); +#endif
Giving the new approach, this should look like this: IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, ACPI_MADT_GIC_VERSION_V3, gic_acpi_init);
Yes, you are right, I already fixed this and pushed to linaro acpi git repo.
Marc, do you prefer a updated version for review or just this patchset? it has minor updates and majority of this patch set was unchanged.
Thanks Hanjun
On systems supporting GICv3 and above, in MADT GICC structures, the field of GICR Base Address holds the 64-bit physical address of the associated Redistributor if the GIC Redistributors are not in the always-on power domain, so instead of init GICR regions via GIC redistributor structure(s), init it with GICR base address in GICC structures in that case.
As GICR base in MADT GICC is another way to indicate the GIC version is 3 or 4, add its support to find out the GIC versions.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/irq.c | 26 +++++++++ drivers/irqchip/irq-gic-v3.c | 122 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 124 insertions(+), 24 deletions(-)
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index cb23cb2..bc963f7 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -37,6 +37,27 @@ acpi_match_gic_redist(struct acpi_subtable_header *header, return 0; }
+static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc; + + gicc = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_GICC_ENTRY(gicc, end)) + return -EINVAL; + + /* + * If GICC is enabled but has no valid gicr base address, then it + * means GICR base is not presented via GICC + */ + if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address) + return -ENODEV; + + return 0; +} + static bool __init acpi_gic_redist_is_present(void) { @@ -44,6 +65,11 @@ acpi_gic_redist_is_present(void)
count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, acpi_match_gic_redist, 0); + if (count > 0) + return true; + + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_parse_madt_gicc, 0); return count > 0; }
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 51547c9..5596846 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -39,6 +39,7 @@ struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; + bool single_redist; };
struct gic_chip_data { @@ -429,6 +430,9 @@ static int gic_populate_rdist(void) return 0; }
+ if (gic_data.redist_regions[i].single_redist) + break; + if (gic_data.redist_stride) { ptr += gic_data.redist_stride; } else { @@ -906,22 +910,35 @@ static phys_addr_t dist_phys_base __initdata;
static int __init gic_acpi_match_redist(struct acpi_subtable_header *header, - const unsigned long end) + const unsigned long end) { struct acpi_madt_generic_redistributor *redist;
- if (BAD_MADT_ENTRY(header, end)) + redist = (struct acpi_madt_generic_redistributor *)header; + if (BAD_MADT_ENTRY(redist, end) || !redist->base_address) return -EINVAL;
- redist = (struct acpi_madt_generic_redistributor *)header; - if (!redist->base_address) + return 0; +} + +static int __init +gic_acpi_match_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc; + + gicc = (struct acpi_madt_generic_interrupt *)header; + if (BAD_MADT_GICC_ENTRY(gicc, end)) return -EINVAL;
+ if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address) + return -ENODEV; + return 0; }
static int __init -gic_acpi_register_redist(phys_addr_t phys_base, u64 size) +gic_acpi_register_redist(phys_addr_t phys_base, u64 size, bool flag) { void __iomem *redist_base;
@@ -933,6 +950,7 @@ gic_acpi_register_redist(phys_addr_t phys_base, u64 size)
redist_regs[nr_redist_regions].phys_base = phys_base; redist_regs[nr_redist_regions].redist_base = redist_base; + redist_regs[nr_redist_regions].single_redist = flag; nr_redist_regions++; return 0; } @@ -944,7 +962,29 @@ gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, struct acpi_madt_generic_redistributor *redist;
redist = (struct acpi_madt_generic_redistributor *)header; - return gic_acpi_register_redist(redist->base_address, redist->length); + return gic_acpi_register_redist(redist->base_address, redist->length, + false); +} + +static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc; + void __iomem *redist_base; + u64 typer; + u32 size; + + gicc = (struct acpi_madt_generic_interrupt *)header; + redist_base = ioremap(gicc->gicr_base_address, SZ_64K * 2); + if (!redist_base) + return -ENOMEM; + + typer = readq_relaxed(redist_base + GICR_TYPER); + /* don't map reserved page as it's buggy to access it */ + size = (typer & GICR_TYPER_VLPIS) ? SZ_64K * 3 : SZ_64K * 2; + iounmap(redist_base); + return gic_acpi_register_redist(gicc->gicr_base_address, size, true); }
static int __init @@ -988,6 +1028,54 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data, }
static int __init +gic_acpi_count_gicr_regions(struct acpi_table_header *table, int *count) +{ + /* Count how many redistributor regions we have */ + *count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_match_redist, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); + if (*count > 0) + return 0; + + *count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_match_gicc, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + + if (*count > 0) + return 0; + + pr_err("No valid GICR entries\n"); + return -ENODEV; +} + +static int __init +gic_acpi_collect_gicr_base(struct acpi_table_header *table) +{ + int count; + + /* Collect redistributor base addresses in GICR entries */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_redist, table, + ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); + if (count > 0) + return 0; + + /* Collect redistributor base addresses in GICC entries */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_gicc, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + if (count > 0) + return 0; + + pr_info("No valid GICR entries exist\n"); + return -ENODEV; +} + +static int __init gic_acpi_init(struct acpi_table_header *table) { int count, i, err = 0; @@ -1018,16 +1106,9 @@ gic_acpi_init(struct acpi_table_header *table) goto out_dist_unmap; }
- /* Count how many redistributor regions we have */ - count = acpi_parse_entries(ACPI_SIG_MADT, - sizeof(struct acpi_table_madt), - gic_acpi_match_redist, table, - ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, 0); - if (count <= 0) { - pr_err("No valid GICR entries\n"); - err = -EINVAL; + err = gic_acpi_count_gicr_regions(table, &count); + if (err) goto out_dist_unmap; - }
redist_regs = kzalloc(sizeof(*redist_regs) * count, GFP_KERNEL); if (!redist_regs) { @@ -1035,16 +1116,9 @@ gic_acpi_init(struct acpi_table_header *table) 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; + err = gic_acpi_collect_gicr_base(table); + if (err) goto out_redist_unmap; - }
err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0, (void *)dist_phys_base);
Marc, really sorry for the delay, I think you may need to load the context from disk instead of memory :)
Please give your guidance and I will address them fast this week.
Thanks Hanjun
On 08/17/2015 09:23 PM, Hanjun Guo wrote:
Hi Marc,
Tomasz and I reworked this patch set to address your comments, mainly about the self-probe infrastructure and the way to init GIC redistributor in GICC structures.
For the self-probe infrastructure, we introduce a new file in drivers/acpi/ which can be reused for ioapic in the future;
For init GIC redistributor in GICC structures, I introduced a flag in struct redist_region just as you suggested, and get the redist base from GICC strucutes if no redistributor regions are available from GICR strucutes. I think the naming of the flag and functions are not good, please comment on them :)
For the proper namespace of domain token for ACPI, I think we can use the Interrupt Controller Structure Types as the token, (just some ideas, not implemented in the patch, trying to discuss with you that if it makes sense to you), for Structure Types, we got: 1 - I/O APIC 0xB - GICC CPU Interface Structure 0xC - GICD GIC Distributor Structure 0xD - GICv2m MSI Frame 0xE - GICR Redistributor Structure 0xF - ITS Structure
so except the GICD 0xC both for GICv2/3, others can used as proper namespace for different domain tokens, what do you think?
Please comments on if we are on right direction, thanks.
Hanjun
Hanjun Guo (4): irqchip / GIC / ACPI: Use IRQCHIP_ACPI_DECLARE to simplify GICv2 init code irqchip / GICv3: remove the useless comparision of device node in xlate irqchip / GICv3: Add ACPI support for GICv3+ initialization irqchip / GICv3 / ACPI: Add GICR support via GICC structures
Tomasz Nowicki (2): acpi, irqchip: Add self-probe infrastructure to initialize IRQ controller irqchip / GICv3: Refactor gic_of_init() for GICv3 driver
arch/arm64/include/asm/irq.h | 13 -- arch/arm64/kernel/acpi.c | 25 --- drivers/acpi/Makefile | 2 + drivers/acpi/irq.c | 136 +++++++++++++ drivers/irqchip/irq-gic-v3.c | 360 ++++++++++++++++++++++++++++++----- drivers/irqchip/irq-gic.c | 4 +- include/asm-generic/vmlinux.lds.h | 13 ++ include/linux/acpi.h | 18 ++ include/linux/acpi_irq.h | 4 +- include/linux/irqchip.h | 13 ++ include/linux/irqchip/arm-gic-acpi.h | 9 +- include/linux/mod_devicetable.h | 9 + 12 files changed, 512 insertions(+), 94 deletions(-) create mode 100644 drivers/acpi/irq.c
On Mon, 17 Aug 2015 14:30:43 +0100 Hanjun Guo hanjun.guo@linaro.org wrote:
Marc, really sorry for the delay, I think you may need to load the context from disk instead of memory :)
Please give your guidance and I will address them fast this week.
Hi Hanjun,
I'm attending a number of conferences in Seattle this week, so my reviewing bandwidth is going to be pretty limited (and I already have a queue of about 50 patches to go through, including some from Suravee).
I'll do my best, but no promises...
M.
On 08/17/2015 10:49 PM, Marc Zyngier wrote:
On Mon, 17 Aug 2015 14:30:43 +0100 Hanjun Guo hanjun.guo@linaro.org wrote:
Marc, really sorry for the delay, I think you may need to load the context from disk instead of memory :)
Please give your guidance and I will address them fast this week.
Hi Hanjun,
I'm attending a number of conferences in Seattle this week, so my reviewing bandwidth is going to be pretty limited (and I already have a queue of about 50 patches to go through, including some from Suravee).
I'll do my best, but no promises...
No problem, I can work on other stuff and wait for your response when you are not occupied.
Thanks Hanjun
On 17/08/15 14:23, Hanjun Guo wrote:
Hi Marc,
Tomasz and I reworked this patch set to address your comments, mainly about the self-probe infrastructure and the way to init GIC redistributor in GICC structures.
For the self-probe infrastructure, we introduce a new file in drivers/acpi/ which can be reused for ioapic in the future;
For init GIC redistributor in GICC structures, I introduced a flag in struct redist_region just as you suggested, and get the redist base from GICC strucutes if no redistributor regions are available from GICR strucutes. I think the naming of the flag and functions are not good, please comment on them :)
For the proper namespace of domain token for ACPI, I think we can use the Interrupt Controller Structure Types as the token, (just some ideas, not implemented in the patch, trying to discuss with you that if it makes sense to you), for Structure Types, we got: 1 - I/O APIC 0xB - GICC CPU Interface Structure 0xC - GICD GIC Distributor Structure 0xD - GICv2m MSI Frame 0xE - GICR Redistributor Structure 0xF - ITS Structure
so except the GICD 0xC both for GICv2/3, others can used as proper namespace for different domain tokens, what do you think?
Please comments on if we are on right direction, thanks.
And after my earlier rant, I did what I should have done the first place, which is to do it myself. I started from your first two patches, and cleaned it up.
Hardly any code left at all. Tested on Juno.
From e80ce48c7449429f3191000244d6b94ab92b7f40 Mon Sep 17 00:00:00 2001
From: Marc Zyngier marc.zyngier@arm.com Date: Fri, 28 Aug 2015 18:48:19 +0100 Subject: [PATCH] irqchip/acpi: Fix the bloody mess
Signed-off-by: Marc Zyngier marc.zyngier@arm.com --- drivers/acpi/Makefile | 3 -- drivers/acpi/irq.c | 110 ---------------------------------------- drivers/irqchip/irq-gic.c | 73 +++++++++++++------------- drivers/irqchip/irqchip.c | 35 ++++++++++++- include/linux/acpi.h | 32 +++++++++--- include/linux/acpi_irq.h | 12 ----- include/linux/irqchip.h | 11 ++-- include/linux/mod_devicetable.h | 9 ---- 8 files changed, 100 insertions(+), 185 deletions(-) delete mode 100644 drivers/acpi/irq.c delete mode 100644 include/linux/acpi_irq.h
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 599f1df..a742a83 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -27,9 +27,6 @@ acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o
-# IRQ controller probe -acpi-y += irq.o - # # ACPI Bus and Device Drivers # diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c deleted file mode 100644 index cb23cb2..0000000 --- a/drivers/acpi/irq.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2015, Linaro Ltd. - * Author: Tomasz Nowicki tomasz.nowicki@linaro.org - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -#include <linux/acpi.h> -#include <linux/init.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[]; -static struct acpi_table_id *iterator; - -static int __init -acpi_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; - - count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - acpi_match_gic_redist, 0); - return count > 0; -} - -static int __init -acpi_match_madt_subtable(struct acpi_subtable_header *header, - const unsigned long end) -{ - struct acpi_madt_generic_distributor *dist; - u8 gic_version = ACPI_MADT_GIC_VERSION_NONE; - - /* Found appropriated subtable, now try to do additional matching */ - switch (header->type) { - case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: - - dist = (struct acpi_madt_generic_distributor *)header; - gic_version = dist->version; - - /* - * This is for backward compatibility with ACPI 5.1, - * which has no gic_version field. - */ - if (gic_version == ACPI_MADT_GIC_VERSION_NONE) { - /* It is GICv3/v4 if redistributor is present */ - if (acpi_gic_redist_is_present()) - gic_version = ACPI_MADT_GIC_VERSION_V3; - else - gic_version = ACPI_MADT_GIC_VERSION_V2; - - return 0; - } - - /* - * GICv4 has meaning to KVM, for host IRQ controller we can - * treat it as GICv3 to avoid another IRQCHIP_ACPI_DECLARE - * entry. - */ - if (gic_version == ACPI_MADT_GIC_VERSION_V4) - gic_version = ACPI_MADT_GIC_VERSION_V3; - - if (gic_version == iterator->driver_data) - return 0; - - return -AE_NOT_FOUND; - } - - /* No additional matching for the rest of subtable types for now */ - return 0; -} - -void __init acpi_irq_init(void) -{ - - if (acpi_disabled) - return; - - for (iterator = __irqchip_acpi_table; iterator->id[0]; iterator++) { - if (acpi_table_parse_madt(iterator->type, - acpi_match_madt_subtable, 0) <= 0) - continue; /* No match or invalid subtables */ - - acpi_table_parse(ACPI_SIG_MADT, - (acpi_tbl_table_handler)iterator->handler); - } -} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 03adec8..5a9f586 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1069,21 +1069,6 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, 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 gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data, u32 gsi, unsigned int irq_type) { @@ -1109,37 +1094,47 @@ static int gic_acpi_gsi_desc_populate(struct acpi_gsi_descriptor *data, return 0; }
-static int __init -gic_v2_acpi_init(struct acpi_table_header *table) +static int __init acpi_match_gic_redist(struct acpi_subtable_header *header, + const unsigned long end) { + return 0; +} + +static bool __init acpi_gic_redist_is_present(void) +{ + return acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, + acpi_match_gic_redist, 0) > 0; +} + +static bool __init gic_validate_dist(struct acpi_subtable_header *header, + struct acpi_table_id *id) +{ + struct acpi_madt_generic_distributor *dist; + dist = (struct acpi_madt_generic_distributor *)header; + + return (dist->version == id->driver_data); +} + +static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_distributor *dist; void __iomem *cpu_base, *dist_base; int count;
+ if (acpi_gic_redist_is_present()) + return -EINVAL; + /* 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); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_parse_madt_cpu, 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; - } + dist = (struct acpi_madt_generic_distributor *)header; + dist_phy_base = dist->base_address;
cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); if (!cpu_base) { @@ -1164,5 +1159,9 @@ gic_v2_acpi_init(struct acpi_table_header *table) return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, - ACPI_MADT_GIC_VERSION_V2, gic_v2_acpi_init); + gic_validate_dist, ACPI_MADT_GIC_VERSION_V2, + gic_v2_acpi_init); +IRQCHIP_ACPI_DECLARE(gic_v2_maybe, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, + gic_validate_dist, ACPI_MADT_GIC_VERSION_NONE, + gic_v2_acpi_init); #endif diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index afd1af3..8a49385 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -8,7 +8,7 @@ * warranty of any kind, whether express or implied. */
-#include <linux/acpi_irq.h> +#include <linux/acpi.h> #include <linux/init.h> #include <linux/of_irq.h> #include <linux/irqchip.h> @@ -24,9 +24,40 @@ irqchip_of_match_end __used __section(__irqchip_of_table_end);
extern struct of_device_id __irqchip_of_table[];
+#ifdef CONFIG_ACPI +/* Same dance for ACPI */ +static const struct acpi_table_id +irqchip_acpi_match_end __used __section(__irqchip_acpi_table_end); +extern struct acpi_table_id __irqchip_acpi_table[]; +static struct acpi_table_id *iterator; + +static int __init acpi_match_irqchip(struct acpi_subtable_header *header, + const unsigned long end) +{ + acpi_table_id_validate validate = iterator->validate; + acpi_tbl_entry_handler handler = iterator->handler; + + if (validate && !validate(header, iterator)) + return 0; + + handler(header, end); + return 0; +} + +static void __init acpi_irq_init(void) +{ + if (!acpi_disabled) + for (iterator = __irqchip_acpi_table; + iterator->id[0]; iterator++) + acpi_table_parse_madt(iterator->type, + acpi_match_irqchip, 0); +} +#else +#define acpi_irq_init() do {} while(0) +#endif + void __init irqchip_init(void) { of_irq_init(__irqchip_of_table); - acpi_irq_init(); } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index a30b969..f2f4887 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -830,21 +830,37 @@ static inline struct acpi_device *acpi_get_next_child(struct device *dev, #endif
#ifdef CONFIG_ACPI -#define ACPI_DECLARE(table, name, table_id, subtable, data, fn) \ +struct acpi_table_id; +typedef bool (*acpi_table_id_validate)(struct acpi_subtable_header *, + struct acpi_table_id *); + +#define ACPI_TABLE_ID_LEN 5 + +struct acpi_table_id { + __u8 id[ACPI_TABLE_ID_LEN]; + __u8 type; + acpi_tbl_entry_handler handler; + acpi_table_id_validate validate; + kernel_ulong_t driver_data; +}; + +#define ACPI_DECLARE(table, name, table_id, subtable, valid, data, fn) \ static const struct acpi_table_id __acpi_table_##name \ __used __section(__##table##_acpi_table) \ = { .id = table_id, \ .type = subtable, \ - .handler = (void *)fn, \ + .validate = valid, \ + .handler = fn, \ .driver_data = data } #else -#define ACPI_DECLARE(table, name, table_id, subtable, data, fn) \ - static const struct acpi_table_id __acpi_table_##name \ +#define ACPI_DECLARE(table, name, table_id, subtable, validate, data, fn) \ + static const void * __acpi_table_##name[] \ __attribute__((unused)) \ - = { .id = table_id, \ - .type = subtable, \ - .handler = (void *)fn, \ - .driver_data = data } + = { (void *) table_id, \ + (void *) subtable, \ + (void *) valid, \ + (void *) fn, \ + (void *) data } #endif
#endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h deleted file mode 100644 index 4c0e108..0000000 --- a/include/linux/acpi_irq.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _LINUX_ACPI_IRQ_H -#define _LINUX_ACPI_IRQ_H - -#include <linux/irq.h> - -#ifdef CONFIG_ACPI -void acpi_irq_init(void); -#else -static inline void acpi_irq_init(void) { } -#endif - -#endif /* _LINUX_ACPI_IRQ_H */ diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index a7573fd..7e956d0 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -27,16 +27,19 @@ #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
/* - * This macro must be used by the different ARM GIC drivers to declare + * This macro must be used by the different irqchip drivers to declare * the association between their version and their initialization function. * * @name: name that must be unique accross all IRQCHIP_ACPI_DECLARE of the * same file. - * @gic_version: version of GIC + * @subtable: Subtable to be identified in MADT + * @validate: Function to be called on that subtable to check its validity. + * Can be NULL. + * @data: data to be checked by the validate function. * @fn: initialization function */ -#define IRQCHIP_ACPI_DECLARE(name, subtable, version, fn) \ - ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, subtable, version, fn) +#define IRQCHIP_ACPI_DECLARE(name, subtable, validate, data, fn) \ + ACPI_DECLARE(irqchip, name, ACPI_SIG_MADT, subtable, validate, data, fn)
#ifdef CONFIG_IRQCHIP void irqchip_init(void); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index ebedaa7..34f25b7 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -193,15 +193,6 @@ struct acpi_device_id { __u32 cls_msk; };
-#define ACPI_TABLE_ID_LEN 5 - -struct acpi_table_id { - __u8 id[ACPI_TABLE_ID_LEN]; - __u8 type; - const void *handler; - kernel_ulong_t driver_data; -}; - #define PNP_ID_LEN 8 #define PNP_MAX_DEVICES 8