arm_pmu: acpi: spe: Add initial MADT/SPE probing
ACPI 6.3 adds additional fields to the MADT GICC structure to describe SPE PPI's. We pick these out of the cached reference to the madt_gicc structure similarly to the core PMU code. We then create a platform device referring to the IRQ and let the user/module loader decide whether to load the SPE driver. Tested-by: Hanjun Guo <hanjun.guo@linaro.org> Reviewed-by: Sudeep Holla <sudeep.holla@arm.com> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com> Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
56855a99f3
commit
d24a0c7099
|
@ -41,6 +41,9 @@
|
|||
(!(entry) || (entry)->header.length < ACPI_MADT_GICC_MIN_LENGTH || \
|
||||
(unsigned long)(entry) + (entry)->header.length > (end))
|
||||
|
||||
#define ACPI_MADT_GICC_SPE (ACPI_OFFSET(struct acpi_madt_generic_interrupt, \
|
||||
spe_interrupt) + sizeof(u16))
|
||||
|
||||
/* Basic configuration for ACPI */
|
||||
#ifdef CONFIG_ACPI
|
||||
pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
|
||||
|
|
|
@ -74,6 +74,76 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
|
|||
acpi_unregister_gsi(gsi);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARM_SPE_PMU)
|
||||
static struct resource spe_resources[] = {
|
||||
{
|
||||
/* irq */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device spe_dev = {
|
||||
.name = ARMV8_SPE_PDEV_NAME,
|
||||
.id = -1,
|
||||
.resource = spe_resources,
|
||||
.num_resources = ARRAY_SIZE(spe_resources)
|
||||
};
|
||||
|
||||
/*
|
||||
* For lack of a better place, hook the normal PMU MADT walk
|
||||
* and create a SPE device if we detect a recent MADT with
|
||||
* a homogeneous PPI mapping.
|
||||
*/
|
||||
static void arm_spe_acpi_register_device(void)
|
||||
{
|
||||
int cpu, hetid, irq, ret;
|
||||
bool first = true;
|
||||
u16 gsi = 0;
|
||||
|
||||
/*
|
||||
* Sanity check all the GICC tables for the same interrupt number.
|
||||
* For now, we only support homogeneous ACPI/SPE machines.
|
||||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct acpi_madt_generic_interrupt *gicc;
|
||||
|
||||
gicc = acpi_cpu_get_madt_gicc(cpu);
|
||||
if (gicc->header.length < ACPI_MADT_GICC_SPE)
|
||||
return;
|
||||
|
||||
if (first) {
|
||||
gsi = gicc->spe_interrupt;
|
||||
if (!gsi)
|
||||
return;
|
||||
hetid = find_acpi_cpu_topology_hetero_id(cpu);
|
||||
first = false;
|
||||
} else if ((gsi != gicc->spe_interrupt) ||
|
||||
(hetid != find_acpi_cpu_topology_hetero_id(cpu))) {
|
||||
pr_warn("ACPI: SPE must be homogeneous\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE,
|
||||
ACPI_ACTIVE_HIGH);
|
||||
if (irq < 0) {
|
||||
pr_warn("ACPI: SPE Unable to register interrupt: %d\n", gsi);
|
||||
return;
|
||||
}
|
||||
|
||||
spe_resources[0].start = irq;
|
||||
ret = platform_device_register(&spe_dev);
|
||||
if (ret < 0) {
|
||||
pr_warn("ACPI: SPE: Unable to register device\n");
|
||||
acpi_unregister_gsi(gsi);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void arm_spe_acpi_register_device(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ARM_SPE_PMU */
|
||||
|
||||
static int arm_pmu_acpi_parse_irqs(void)
|
||||
{
|
||||
int irq, cpu, irq_cpu, err;
|
||||
|
@ -279,6 +349,8 @@ static int arm_pmu_acpi_init(void)
|
|||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
arm_spe_acpi_register_device();
|
||||
|
||||
ret = arm_pmu_acpi_parse_irqs();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -175,4 +175,6 @@ void armpmu_free_irq(int irq, int cpu);
|
|||
|
||||
#endif /* CONFIG_ARM_PMU */
|
||||
|
||||
#define ARMV8_SPE_PDEV_NAME "arm,spe-v1"
|
||||
|
||||
#endif /* __ARM_PMU_H__ */
|
||||
|
|
Loading…
Reference in New Issue