[Arm-dev] [PATCH v1 59/87] arm64, acpi: Implement new "GIC version" field of MADT GIC entry.

Thu Aug 13 13:18:56 UTC 2015
Vadim Lomovtsev <Vadim.Lomovtsev at caviumnetworks.com>

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

There is no need to probe GICv2 and GICv3 sequentially. From now on,
we know GIC version in advance. Note this patch does not break backward
compatibility for machines which are compliant with ACPI spec. 5.1.

Signed-off-by: Tomasz Nowicki <tomasz.nowicki at linaro.org>
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev at caviumnetworks.com>
---
 arch/arm64/include/asm/acpi.h |  2 ++
 arch/arm64/kernel/acpi.c      | 31 +++++++++++++++++++++++++++++--
 include/acpi/actbl1.h         | 12 +++++++++++-
 3 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 406485e..a80f3af 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -47,6 +47,7 @@ typedef u64 phys_cpuid_t;
 extern int acpi_disabled;
 extern int acpi_noirq;
 extern int acpi_pci_disabled;
+extern int acpi_gic_ver;
 
 static inline void disable_acpi(void)
 {
@@ -85,6 +86,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }
 void __init acpi_init_cpus(void);
 
 #else
+#define acpi_gic_ver	0
 static inline void acpi_init_cpus(void) { }
 #endif /* CONFIG_ACPI */
 
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 19de753..26928c4 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -36,6 +36,8 @@ EXPORT_SYMBOL(acpi_disabled);
 int acpi_pci_disabled = 1;	/* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
+int acpi_gic_ver;
+
 static bool param_acpi_off __initdata;
 static bool param_acpi_force __initdata;
 
@@ -206,12 +208,27 @@ void __init acpi_boot_table_init(void)
 	}
 }
 
+static int __init
+gic_acpi_find_ver(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;
+
+	acpi_gic_ver = dist->gic_version;
+	return 0;
+}
+
 void __init acpi_gic_init(void)
 {
 	struct acpi_table_header *table;
 	acpi_status status;
 	acpi_size tbl_size;
-	int err;
+	int err, count;;
 
 	if (acpi_disabled)
 		return;
@@ -224,7 +241,17 @@ void __init acpi_gic_init(void)
 		return;
 	}
 
-	err = gic_v2_acpi_init(table);
+	count = acpi_parse_entries(ACPI_SIG_MADT,
+				   sizeof(struct acpi_table_madt),
+				   gic_acpi_find_ver, table,
+				   ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
+	if (count <= 0) {
+		pr_info("Error during GICD entries parsing, assuming GICv2\n");
+		acpi_gic_ver = ACPI_MADT_GIC_VER_V2;
+	}
+
+	err = acpi_gic_ver < ACPI_MADT_GIC_VER_V3 ?
+			gic_v2_acpi_init(table) : -ENXIO;
 	if (err)
 		pr_err("Failed to initialize GIC IRQ controller");
 
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index fcd5709..606f657 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -823,6 +823,16 @@ 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 */
 
+enum acpi_madt_gic_ver_type
+{
+    ACPI_MADT_GIC_VER_UNKNOWN       = 0,
+    ACPI_MADT_GIC_VER_V2            = 1,
+    ACPI_MADT_GIC_VER_V2m           = 2,
+    ACPI_MADT_GIC_VER_V3            = 3,
+    ACPI_MADT_GIC_VER_V4            = 4,
+    ACPI_MADT_GIC_VER_RESERVED      = 5     /* 15 and greater are reserved */
+};
+
 /* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */
 
 struct acpi_madt_generic_distributor {
@@ -831,7 +841,7 @@ struct acpi_madt_generic_distributor {
 	u32 gic_id;
 	u64 base_address;
 	u32 global_irq_base;
-	u8 version;
+	u8 gic_version;
 	u8 reserved2[3];	/* reserved - must be zero */
 };
 
-- 
2.4.3