]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/irqchip/irq-gic.c
Merge remote-tracking branch 'pm/linux-next'
[karo-tx-linux.git] / drivers / irqchip / irq-gic.c
index 1d0e76855106cf946627dcc5c5aaa728a38c6bc8..515c823c1c95cee63b46c18bed35bb70260ae9a9 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/irqchip.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
-#include <linux/irqchip/arm-gic-acpi.h>
 
 #include <asm/cputype.h>
 #include <asm/irq.h>
@@ -1219,7 +1218,7 @@ IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init);
 #endif
 
 #ifdef CONFIG_ACPI
-static phys_addr_t dist_phy_base, cpu_phy_base __initdata;
+static phys_addr_t cpu_phy_base __initdata;
 
 static int __init
 gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
@@ -1247,61 +1246,57 @@ 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)
+/* The things you have to do to just *count* something... */
+static int __init acpi_dummy_func(struct acpi_subtable_header *header,
+                                 const unsigned long end)
 {
-       struct acpi_madt_generic_distributor *dist;
+       return 0;
+}
 
-       dist = (struct acpi_madt_generic_distributor *)header;
+static bool __init acpi_gic_redist_is_present(void)
+{
+       return acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
+                                    acpi_dummy_func, 0) > 0;
+}
 
-       if (BAD_MADT_ENTRY(dist, end))
-               return -EINVAL;
+static bool __init gic_validate_dist(struct acpi_subtable_header *header,
+                                    struct acpi_probe_entry *ape)
+{
+       struct acpi_madt_generic_distributor *dist;
+       dist = (struct acpi_madt_generic_distributor *)header;
 
-       dist_phy_base = dist->base_address;
-       return 0;
+       return (dist->version == ape->driver_data &&
+               (dist->version != ACPI_MADT_GIC_VERSION_NONE ||
+                !acpi_gic_redist_is_present()));
 }
 
-int __init
-gic_v2_acpi_init(struct acpi_table_header *table)
+#define ACPI_GICV2_DIST_MEM_SIZE       (SZ_4K)
+#define ACPI_GIC_CPU_IF_MEM_SIZE       (SZ_8K)
+
+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;
        struct fwnode_handle *domain_handle;
        int count;
 
        /* 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;
-       }
-
        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);
+       dist = (struct acpi_madt_generic_distributor *)header;
+       dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
        if (!dist_base) {
                pr_err("Unable to map GICD registers\n");
                iounmap(cpu_base);
@@ -1332,4 +1327,10 @@ gic_v2_acpi_init(struct acpi_table_header *table)
        acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
        return 0;
 }
+IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
+                    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