mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
arm_pmu: acpi: Refactor arm_spe_acpi_register_device()
Sanity checking all the GICC tables for same interrupt number, and ensuring a homogeneous ACPI based machine, could be used for other platform devices as well. Hence this refactors arm_spe_acpi_register_device() into a common helper arm_acpi_register_pmu_device(). Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Co-developed-by: Will Deacon <will@kernel.org> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Link: https://lore.kernel.org/r/20230817055405.249630-2-anshuman.khandual@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
d11a69873d
commit
81e5ee4716
@@ -69,6 +69,62 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
|
|||||||
acpi_unregister_gsi(gsi);
|
acpi_unregister_gsi(gsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused
|
||||||
|
arm_acpi_register_pmu_device(struct platform_device *pdev, u8 len,
|
||||||
|
u16 (*parse_gsi)(struct acpi_madt_generic_interrupt *))
|
||||||
|
{
|
||||||
|
int cpu, this_hetid, hetid, irq, ret;
|
||||||
|
u16 this_gsi = 0, gsi = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that platform device must have IORESOURCE_IRQ
|
||||||
|
* resource to hold gsi interrupt.
|
||||||
|
*/
|
||||||
|
if (pdev->num_resources != 1)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
if (pdev->resource[0].flags != IORESOURCE_IRQ)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check all the GICC tables for the same interrupt
|
||||||
|
* number. For now, only support homogeneous ACPI machines.
|
||||||
|
*/
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
struct acpi_madt_generic_interrupt *gicc;
|
||||||
|
|
||||||
|
gicc = acpi_cpu_get_madt_gicc(cpu);
|
||||||
|
if (gicc->header.length < len)
|
||||||
|
return gsi ? -ENXIO : 0;
|
||||||
|
|
||||||
|
this_gsi = parse_gsi(gicc);
|
||||||
|
this_hetid = find_acpi_cpu_topology_hetero_id(cpu);
|
||||||
|
if (!gsi) {
|
||||||
|
hetid = this_hetid;
|
||||||
|
gsi = this_gsi;
|
||||||
|
} else if (hetid != this_hetid || gsi != this_gsi) {
|
||||||
|
pr_warn("ACPI: %s: must be homogeneous\n", pdev->name);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this_gsi)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
|
||||||
|
if (irq < 0) {
|
||||||
|
pr_warn("ACPI: %s Unable to register interrupt: %d\n", pdev->name, gsi);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdev->resource[0].start = irq;
|
||||||
|
ret = platform_device_register(pdev);
|
||||||
|
if (ret)
|
||||||
|
acpi_unregister_gsi(gsi);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ARM_SPE_PMU)
|
#if IS_ENABLED(CONFIG_ARM_SPE_PMU)
|
||||||
static struct resource spe_resources[] = {
|
static struct resource spe_resources[] = {
|
||||||
{
|
{
|
||||||
@@ -84,6 +140,11 @@ static struct platform_device spe_dev = {
|
|||||||
.num_resources = ARRAY_SIZE(spe_resources)
|
.num_resources = ARRAY_SIZE(spe_resources)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u16 arm_spe_parse_gsi(struct acpi_madt_generic_interrupt *gicc)
|
||||||
|
{
|
||||||
|
return gicc->spe_interrupt;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For lack of a better place, hook the normal PMU MADT walk
|
* For lack of a better place, hook the normal PMU MADT walk
|
||||||
* and create a SPE device if we detect a recent MADT with
|
* and create a SPE device if we detect a recent MADT with
|
||||||
@@ -91,47 +152,10 @@ static struct platform_device spe_dev = {
|
|||||||
*/
|
*/
|
||||||
static void arm_spe_acpi_register_device(void)
|
static void arm_spe_acpi_register_device(void)
|
||||||
{
|
{
|
||||||
int cpu, hetid, irq, ret;
|
int ret = arm_acpi_register_pmu_device(&spe_dev, ACPI_MADT_GICC_SPE,
|
||||||
bool first = true;
|
arm_spe_parse_gsi);
|
||||||
u16 gsi = 0;
|
if (ret)
|
||||||
|
|
||||||
/*
|
|
||||||
* 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");
|
pr_warn("ACPI: SPE: Unable to register device\n");
|
||||||
acpi_unregister_gsi(gsi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void arm_spe_acpi_register_device(void)
|
static inline void arm_spe_acpi_register_device(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user