In MADT table, there are GIC cpu interface base address and GIC distributor base address, use them to convert GIC to ACPI.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/kernel/irq.c | 4 +++ drivers/acpi/plat/arm/boot.c | 65 +++++++++++++++++++++++++++++++++++------- include/linux/acpi.h | 6 ++++ 3 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 473e5db..f27af5f 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -25,6 +25,7 @@ #include <linux/irq.h> #include <linux/smp.h> #include <linux/init.h> +#include <linux/acpi.h> #include <linux/irqchip.h> #include <linux/seq_file.h> #include <linux/ratelimit.h> @@ -79,6 +80,9 @@ void __init init_IRQ(void) { irqchip_init(); if (!handle_arch_irq) + acpi_gic_init(); + + if (!handle_arch_irq) panic("No interrupt controller found."); }
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 70262a2..a9f313d 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -37,6 +37,7 @@ #include <linux/bootmem.h> #include <linux/ioport.h> #include <linux/pci.h> +#include <linux/irqchip/arm-gic.h>
#include <asm/pgtable.h> #include <asm/io.h> @@ -80,6 +81,8 @@ int acpi_sci_override_gsi __initdata; int acpi_skip_timer_override __initdata; int acpi_use_timer_override __initdata; int acpi_fix_pin2_polarity __initdata; + +/* GIC cpu interface base address on ARM */ static u64 acpi_lapic_addr __initdata;
struct acpi_arm_root acpi_arm_rsdp_info; /* info about RSDP from FDT */ @@ -198,11 +201,22 @@ acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end) return 0; }
+#ifdef CONFIG_ARM_GIC +/* + * Hard code here, we can not get memory size from MADT (but FDT does), + * this size is described in ARMv8 foudation model's User Guide + */ +#define GIC_DISTRIBUTOR_MEMORY_SIZE (SZ_8K) +#define GIC_CPU_INTERFACE_MEMORY_SIZE (SZ_4K) + +/* GIC distributor is something like IOAPIC on x86 */ static int __init acpi_parse_gic_distributor(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_generic_distributor *distributor = NULL; + void __iomem *dist_base = NULL; + void __iomem *cpu_base = NULL;
distributor = (struct acpi_madt_generic_distributor *)header;
@@ -211,10 +225,35 @@ acpi_parse_gic_distributor(struct acpi_subtable_header *header,
acpi_table_print_madt_entry(header);
- /* TODO: handle with the base_address and irq_base for irq system */ + dist_base = ioremap(distributor->base_address, + GIC_CPU_INTERFACE_MEMORY_SIZE); + if (!dist_base) { + pr_warn("unable to map gic dist registers\n"); + return -ENOMEM; + } + + /* acpi_lapic_addr is stored in early_acpi_boot_init(), + * we can use it here with no worries + */ + cpu_base = ioremap(acpi_lapic_addr, GIC_CPU_INTERFACE_MEMORY_SIZE); + if (!cpu_base) { + iounmap(dist_base); + pr_warn("unable to map gic cpu registers\n"); + return -ENOMEM; + } + + gic_init(distributor->gic_id, -1, dist_base, cpu_base);
return 0; } +#else +static int __init +acpi_parse_gic_distributor(struct acpi_subtable_header *header, + const unsigned long end) +{ + return -ENODEV; +} +#endif /* CONFIG_ARM_GIC */
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) { @@ -569,16 +608,8 @@ static void __init acpi_process_madt(void) * Parse MADT LAPIC entries */ error = acpi_parse_madt_lapic_entries(); - if (!error) { + if (!error) acpi_lapic = 1; - - /* - * Parse MADT IO-APIC entries - */ - error = acpi_parse_madt_ioapic_entries(); - if (!error) - acpi_set_irq_model_gic(); - } }
/* @@ -702,6 +733,20 @@ void __init arm_acpi_reserve_memory() memblock_remove(addr - section_offset, num_sections * SECTION_SIZE); }
+int __init acpi_gic_init(void) +{ + int error; + + /* + * Parse MADT GIC distributor entries + */ + error = acpi_parse_madt_ioapic_entries(); + if (!error) + acpi_set_irq_model_gic(); + + return error; +} + static int __init parse_acpi(char *arg) { if (!arg) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1dbfa2c..5af1674 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -92,6 +92,7 @@ char *__acpi_map_table(phys_addr_t phys_addr, unsigned long size); void __acpi_unmap_table(char *map, unsigned long size); int early_acpi_boot_init(void); int acpi_boot_init (void); +int acpi_gic_init(void); void acpi_boot_table_init (void); int acpi_mps_check (void); int acpi_numa_init (void); @@ -421,6 +422,11 @@ static inline int acpi_boot_init(void) return 0; }
+static inline int acpi_gic_init(void) +{ + return -ENODEV; +} + static inline void acpi_boot_table_init(void) { return;