aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Nowicki <tomasz.nowicki@linaro.org>2014-02-13 18:20:54 +0100
committerGraeme Gregory <graeme.gregory@linaro.org>2014-06-03 09:24:22 +0100
commit7bf086c5589d8a0b58a17580609b833beb448b31 (patch)
treedcebcd29d3f74e6f4b679dcaffc648ed9bd8affb
parente16d20531ad50593cb8c09f8a934659be950a33e (diff)
downloadleg-kernel-7bf086c5589d8a0b58a17580609b833beb448b31.tar.gz
ARM64, ACPI, core: Move GIC specific code to irq-gic.c driver.
This commit allows us to initialize the ACPI core on ARM64 using the GIC IRQ controller. Due to current MADT specification, the GIC is the only controller we can use for ARM64 in ACPI initialization. Listed changes: 1. Move all functions related to GIC structures to GIC driver. 2. Make BAD_MADT_ENTRY accessible from other files as well, future usage. 3. Move gic prototypes to ACPI arch specific header. 4. Rename acpi_gic_init to gic_acpi_init to be aligned with GIC drivers function names. Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
-rw-r--r--arch/arm64/include/asm/acpi.h14
-rw-r--r--arch/arm64/kernel/irq.c11
-rw-r--r--drivers/acpi/plat/arm-core.c118
-rw-r--r--drivers/irqchip/irq-gic.c130
-rw-r--r--include/linux/acpi.h6
5 files changed, 150 insertions, 129 deletions
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 856a2e770960..409a8892d9ea 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -42,6 +42,11 @@
/* Asm macros */
#define ACPI_FLUSH_CPU_CACHE() flush_cache_all()
+/* MADT table validation macro */
+#define BAD_MADT_ENTRY(entry, end) ( \
+ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
+ ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+
/* Basic configuration for ACPI */
#ifdef CONFIG_ACPI
extern int acpi_disabled;
@@ -80,9 +85,6 @@ void arch_fix_phys_package_id(int num, u32 slot);
extern int (*acpi_suspend_lowlevel)(void);
#define acpi_wakeup_address (0)
-#define MAX_GIC_CPU_INTERFACE 256
-#define MAX_GIC_DISTRIBUTOR 1 /* should be the same as MAX_GIC_NR */
-
/* map logic cpu id to physical GIC id */
extern int arm_cpu_to_apicid[NR_CPUS];
#define cpu_physical_id(cpu) arm_cpu_to_apicid[cpu]
@@ -90,6 +92,7 @@ extern int arm_cpu_to_apicid[NR_CPUS];
extern const char *acpi_get_enable_method(int cpu);
extern int acpi_get_cpu_release_address(int cpu, u64 *release_address);
+extern int gic_acpi_init(void);
#else /* !CONFIG_ACPI */
#define acpi_disabled 1 /* ACPI sometimes enabled on ARM */
@@ -97,6 +100,11 @@ extern int acpi_get_cpu_release_address(int cpu, u64 *release_address);
#define acpi_pci_disabled 1 /* ACPI PCI sometimes enabled on ARM */
#define acpi_strict 1 /* no ACPI spec workarounds on ARM */
+static inline int gic_acpi_init(void)
+{
+ return -ENODEV;
+}
+
static inline const char *acpi_get_enable_method(int cpu)
{
return NULL;
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index e4e0df32e9e7..46dc555bb8a7 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -80,9 +80,16 @@ void __init init_IRQ(void)
{
irqchip_init();
- /* FIXME: need to fix GIC hardcoded here */
+ /*
+ * FIXME: need to fix GIC hardcoded here and find a scalable way.
+ * GIC is the only one IRQ controller for ARM64 which is
+ * supported by MADT and is accessible at early stage.
+ *
+ * FIXME: MADT presence is needed for UP scenario, otherwise there is
+ * no info for GIC initialization.
+ */
if (!handle_arch_irq)
- acpi_gic_init();
+ gic_acpi_init();
if (!handle_arch_irq)
panic("No interrupt controller found.");
diff --git a/drivers/acpi/plat/arm-core.c b/drivers/acpi/plat/arm-core.c
index 95e2edb7b3c3..b825a9601515 100644
--- a/drivers/acpi/plat/arm-core.c
+++ b/drivers/acpi/plat/arm-core.c
@@ -48,12 +48,6 @@ EXPORT_SYMBOL(acpi_disabled);
int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);
-/*
- * Local interrupt controller address,
- * GIC cpu interface base address on ARM/ARM64
- */
-static u64 acpi_lapic_addr __initdata;
-
/* available_cpus here means enabled cpu in MADT */
static int available_cpus;
@@ -64,10 +58,6 @@ static int boot_cpu_apic_id = -1;
/* Parked Address in ACPI GIC structure */
static u64 parked_address[NR_CPUS];
-#define BAD_MADT_ENTRY(entry, end) ( \
- (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
#define PREFIX "ACPI: "
/* FIXME: this function should be moved to topology.c when it is ready */
@@ -128,26 +118,9 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
return -ENODEV;
}
- if (madt->address) {
- acpi_lapic_addr = (u64) madt->address;
-
- pr_info(PREFIX "Local APIC address 0x%08x\n", madt->address);
- }
-
return 0;
}
-/*
- * GIC structures on ARM are somthing like Local APIC structures on x86,
- * which means GIC cpu interfaces for GICv2/v3. Every GIC structure in
- * MADT table represents a cpu in the system.
- *
- * GIC distributor structures are somthing like IOAPIC on x86. GIC can
- * be initialized with information in this structure.
- *
- * Please refer to chapter5.2.12.14/15 of ACPI 5.0
- */
-
/**
* acpi_register_gic_cpu_interface - register a gic cpu interface and
* generates a logic cpu number
@@ -211,15 +184,6 @@ acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end)
acpi_table_print_madt_entry(header);
/*
- * As ACPI 5.0 said, the 64-bit physical address in GIC struct at
- * which the processor can access this GIC. If provided, the
- * ???Local Interruptp controller Address??? field in the MADT
- * is ignored by OSPM.
- */
- if (processor->base_address)
- acpi_lapic_addr = processor->base_address;
-
- /*
* We need to register disabled CPU as well to permit
* counting disabled CPUs. This allows us to size
* cpus_possible_map more accurately, to permit
@@ -240,58 +204,6 @@ acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end)
}
/*
- * Hard code here, we can not get memory size from MADT (but FDT does),
- * this size can be refered from GICv2 spec
- */
-#define GIC_DISTRIBUTOR_MEMORY_SIZE (SZ_4K)
-#define GIC_CPU_INTERFACE_MEMORY_SIZE (SZ_8K)
-
-/*
- * ACPI 5.0 only provides information of GICC and GICD, use them
- * to initialize GIC
- */
-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, *cpu_base;
-
- if (!IS_ENABLED(CONFIG_ARM_GIC))
- return;
-
- distributor = (struct acpi_madt_generic_distributor *)header;
-
- if (BAD_MADT_ENTRY(distributor, end))
- return -EINVAL;
-
- acpi_table_print_madt_entry(header);
-
- /* GIC is initialised after page_init(), no need for early_ioremap */
- dist_base = ioremap(distributor->base_address,
- GIC_DISTRIBUTOR_MEMORY_SIZE);
- if (!dist_base) {
- pr_warn(PREFIX "unable to map gic dist registers\n");
- return -ENOMEM;
- }
-
- /*
- * acpi_lapic_addr is stored in acpi_parse_madt() or acpi_parse_gic(),
- * so we can use it here for GIC init
- */
- cpu_base = ioremap(acpi_lapic_addr, GIC_CPU_INTERFACE_MEMORY_SIZE);
- if (!cpu_base) {
- iounmap(dist_base);
- pr_warn(PREFIX "unable to map gic cpu registers\n");
- return -ENOMEM;
- }
-
- gic_init(distributor->gic_id, -1, dist_base, cpu_base);
-
- return 0;
-}
-
-/*
* Parse GIC cpu interface related entries in MADT
* returns 0 on success, < 0 on error
*/
@@ -341,28 +253,6 @@ int acpi_get_cpu_release_address(int cpu, u64 *release_address)
return 0;
}
-/*
- * Parse GIC distributor related entries in MADT
- * returns 0 on success, < 0 on error
- */
-static int __init acpi_parse_madt_gic_distributor_entries(void)
-{
- int count;
-
- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
- acpi_parse_gic_distributor, MAX_GIC_DISTRIBUTOR);
-
- if (!count) {
- pr_err(PREFIX "No GIC distributor entries present\n");
- return -ENODEV;
- } else if (count < 0) {
- pr_err(PREFIX "Error parsing GIC distributor entry\n");
- return count;
- }
-
- return 0;
-}
-
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
*irq = gsi_to_irq(gsi);
@@ -474,14 +364,6 @@ static void __init acpi_process_madt(void)
return;
}
-int __init acpi_gic_init(void)
-{
- /*
- * Parse MADT GIC distributor entries
- */
- return acpi_parse_madt_gic_distributor_entries();
-}
-
/*
* To see PCSI is enabled or not.
*
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index e03e3c157264..4cc76771a0ee 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -35,6 +35,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/acpi.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
@@ -1084,3 +1085,132 @@ 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
+
+/*
+ * Hard code here, we can not get memory size from MADT (but FDT does),
+ * this size can be inferred from GICv2 spec
+ */
+#define GIC_DISTRIBUTOR_MEMORY_SIZE (SZ_4K)
+#define GIC_CPU_INTERFACE_MEMORY_SIZE (SZ_8K)
+
+static u64 gic_cpu_addr __initdata;
+
+static int __init
+gic_parse_madt_cpu(struct acpi_subtable_header *header, const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *processor;
+
+ processor = (struct acpi_madt_generic_interrupt *)header;
+
+ if (BAD_MADT_ENTRY(processor, end))
+ return -EINVAL;
+
+ if (cpu_logical_map(0) != (u64)processor->uid) {
+ pr_err("Wrong boot cpu placement in MADT\n");
+ return -ENOENT;
+ }
+
+ acpi_table_print_madt_entry(header);
+
+ /*
+ * As ACPI 5.0 said, the 64-bit physical address in GIC structure at
+ * which the processor can access this GIC. If provided, the
+ * “Local Interrupt controller Address” field in the MADT
+ * is ignored by OSPM.
+ */
+ if (processor->base_address)
+ gic_cpu_addr = processor->base_address;
+
+ return 0;
+}
+
+
+static int __init
+gic_parse_madt_distributor(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_distributor *distributor;
+ void __iomem *dist_base, *cpu_base;
+
+ cpu_base = ioremap(gic_cpu_addr, GIC_CPU_INTERFACE_MEMORY_SIZE);
+ if (!cpu_base) {
+ pr_err("Unable to map gic cpu registers\n");
+ return -ENOMEM;
+ }
+
+ distributor = (struct acpi_madt_generic_distributor *)header;
+
+ if (BAD_MADT_ENTRY(distributor, end))
+ return -EINVAL;
+
+ acpi_table_print_madt_entry(header);
+
+ dist_base = ioremap(distributor->base_address,
+ GIC_DISTRIBUTOR_MEMORY_SIZE);
+ if (!dist_base) {
+ iounmap(cpu_base);
+ pr_warn("Unable to map gic dist registers\n");
+ return -ENOMEM;
+ }
+
+
+ gic_init(distributor->gic_id, -1, dist_base, cpu_base);
+
+ return 0;
+}
+
+/* ACPI 5.0 provides information of GICC and GICD, use them to initialize GIC.
+ * Please refer to chapter 5.2.12.14/15 of ACPI 5.0
+ */
+int __init gic_acpi_init(void)
+{
+ struct acpi_table_header *table;
+ struct acpi_table_madt *madt;
+ acpi_status status;
+ acpi_size tbl_size;
+ int count;
+
+ 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 -ENODEV;
+ }
+
+ /* First read GIC CPU address from MADT header */
+ madt = (struct acpi_table_madt *)table;
+ if (madt->address)
+ gic_cpu_addr = (u64)madt->address;
+ early_acpi_os_unmap_memory((char *)table, tbl_size);
+
+ /*
+ * FIXME: No support for per cpu offset in MADT. Get gic_cpu_addr from
+ * boot cpu MADT entries. It causes the same address for all GIC CPU
+ * interfaces.
+ */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+ gic_parse_madt_cpu, 1);
+ if (count <= 0) {
+ pr_err("No GICC entries present in MADT\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Once we find GICC address, we are ready to parse GICD and
+ * do the essential part of GIC initialization.
+ * FIXME: We assume to parse one distributor entry since ACPI 5.0 spec
+ * does not support multi-GIC instances and cascade.
+ */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+ gic_parse_madt_distributor, 1);
+ if (count <= 0) {
+ pr_err("Failed to parse GICD entries\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index beee07815bbb..f9143c8f3f18 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -116,7 +116,6 @@ static inline void acpi_initrd_override(void *data, size_t size)
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
void __acpi_unmap_table(char *map, unsigned long size);
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);
@@ -445,11 +444,6 @@ 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;