Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d24a0c70 authored by Jeremy Linton's avatar Jeremy Linton Committed by Will Deacon
Browse files

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: default avatarHanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: default avatarSudeep Holla <sudeep.holla@arm.com>
Reviewed-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarJeremy Linton <jeremy.linton@arm.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 56855a99
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
+72 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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__ */