#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
+static struct cpumask broken_rdists __read_mostly;
+
struct redist_region {
void __iomem *redist_base;
phys_addr_t phys_base;
#define MPIDR_TO_SGI_RS(mpidr) (MPIDR_RS(mpidr) << ICC_SGI1R_RS_SHIFT)
#define MPIDR_TO_SGI_CLUSTER_ID(mpidr) ((mpidr) & ~0xFUL)
+/*
+ * gic_starting_cpu() is called after the last point where cpuhp is allowed
+ * to fail. So pre check for problems earlier.
+ */
+static int gic_check_rdist(unsigned int cpu)
+{
+ if (cpumask_test_cpu(cpu, &broken_rdists))
+ return -EINVAL;
+
+ return 0;
+}
+
static int gic_starting_cpu(unsigned int cpu)
{
gic_cpu_init();
};
int base_sgi;
+ cpuhp_setup_state_nocalls(CPUHP_BP_PREPARE_DYN,
+ "irqchip/arm/gicv3:checkrdist",
+ gic_check_rdist, NULL);
+
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
"irqchip/arm/gicv3:starting",
gic_starting_cpu, NULL);
u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
void __iomem *redist_base;
- if (!acpi_gicc_is_usable(gicc))
+ /* Neither enabled or online capable means it doesn't exist, skip it */
+ if (!(gicc->flags & (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
+ return 0;
+
+ /*
+ * Capable but disabled CPUs can be brought online later. What about
+ * the redistributor? ACPI doesn't want to say!
+ * Virtual hotplug systems can use the MADT's "always-on" GICR entries.
+ * Otherwise, prevent such CPUs from being brought online.
+ */
+ if (!(gicc->flags & ACPI_MADT_ENABLED)) {
+ int cpu = get_cpu_for_acpi_id(gicc->uid);
+
+ pr_warn("CPU %u's redistributor is inaccessible: this CPU can't be brought online\n", cpu);
+ if (cpu >= 0)
+ cpumask_set_cpu(cpu, &broken_rdists);
return 0;
+ }
redist_base = ioremap(gicc->gicr_base_address, size);
if (!redist_base)
/*
* If GICC is enabled and has valid gicr base address, then it means
- * GICR base is presented via GICC
+ * GICR base is presented via GICC. The redistributor is only known to
+ * be accessible if the GICC is marked as enabled. If this bit is not
+ * set, we'd need to add the redistributor at runtime, which isn't
+ * supported.
*/
- if (acpi_gicc_is_usable(gicc) && gicc->gicr_base_address)
+ if (gicc->flags & ACPI_MADT_ENABLED && gicc->gicr_base_address)
acpi_data.enabled_rdists++;
return 0;
int maint_irq_mode;
static int first_madt = true;
- if (!acpi_gicc_is_usable(gicc))
+ if (!(gicc->flags &
+ (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
return 0;
maint_irq_mode = (gicc->flags & ACPI_MADT_VGIC_IRQ_MODE) ?