.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * ACPI probing code for ARM performance counters. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2017 ARM Ltd. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | 8 | #include <linux/acpi.h> |
---|
.. | .. |
---|
70 | 67 | if (gsi) |
---|
71 | 68 | acpi_unregister_gsi(gsi); |
---|
72 | 69 | } |
---|
| 70 | + |
---|
| 71 | +#if IS_ENABLED(CONFIG_ARM_SPE_PMU) |
---|
| 72 | +static struct resource spe_resources[] = { |
---|
| 73 | + { |
---|
| 74 | + /* irq */ |
---|
| 75 | + .flags = IORESOURCE_IRQ, |
---|
| 76 | + } |
---|
| 77 | +}; |
---|
| 78 | + |
---|
| 79 | +static struct platform_device spe_dev = { |
---|
| 80 | + .name = ARMV8_SPE_PDEV_NAME, |
---|
| 81 | + .id = -1, |
---|
| 82 | + .resource = spe_resources, |
---|
| 83 | + .num_resources = ARRAY_SIZE(spe_resources) |
---|
| 84 | +}; |
---|
| 85 | + |
---|
| 86 | +/* |
---|
| 87 | + * For lack of a better place, hook the normal PMU MADT walk |
---|
| 88 | + * and create a SPE device if we detect a recent MADT with |
---|
| 89 | + * a homogeneous PPI mapping. |
---|
| 90 | + */ |
---|
| 91 | +static void arm_spe_acpi_register_device(void) |
---|
| 92 | +{ |
---|
| 93 | + int cpu, hetid, irq, ret; |
---|
| 94 | + bool first = true; |
---|
| 95 | + u16 gsi = 0; |
---|
| 96 | + |
---|
| 97 | + /* |
---|
| 98 | + * Sanity check all the GICC tables for the same interrupt number. |
---|
| 99 | + * For now, we only support homogeneous ACPI/SPE machines. |
---|
| 100 | + */ |
---|
| 101 | + for_each_possible_cpu(cpu) { |
---|
| 102 | + struct acpi_madt_generic_interrupt *gicc; |
---|
| 103 | + |
---|
| 104 | + gicc = acpi_cpu_get_madt_gicc(cpu); |
---|
| 105 | + if (gicc->header.length < ACPI_MADT_GICC_SPE) |
---|
| 106 | + return; |
---|
| 107 | + |
---|
| 108 | + if (first) { |
---|
| 109 | + gsi = gicc->spe_interrupt; |
---|
| 110 | + if (!gsi) |
---|
| 111 | + return; |
---|
| 112 | + hetid = find_acpi_cpu_topology_hetero_id(cpu); |
---|
| 113 | + first = false; |
---|
| 114 | + } else if ((gsi != gicc->spe_interrupt) || |
---|
| 115 | + (hetid != find_acpi_cpu_topology_hetero_id(cpu))) { |
---|
| 116 | + pr_warn("ACPI: SPE must be homogeneous\n"); |
---|
| 117 | + return; |
---|
| 118 | + } |
---|
| 119 | + } |
---|
| 120 | + |
---|
| 121 | + irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, |
---|
| 122 | + ACPI_ACTIVE_HIGH); |
---|
| 123 | + if (irq < 0) { |
---|
| 124 | + pr_warn("ACPI: SPE Unable to register interrupt: %d\n", gsi); |
---|
| 125 | + return; |
---|
| 126 | + } |
---|
| 127 | + |
---|
| 128 | + spe_resources[0].start = irq; |
---|
| 129 | + ret = platform_device_register(&spe_dev); |
---|
| 130 | + if (ret < 0) { |
---|
| 131 | + pr_warn("ACPI: SPE: Unable to register device\n"); |
---|
| 132 | + acpi_unregister_gsi(gsi); |
---|
| 133 | + } |
---|
| 134 | +} |
---|
| 135 | +#else |
---|
| 136 | +static inline void arm_spe_acpi_register_device(void) |
---|
| 137 | +{ |
---|
| 138 | +} |
---|
| 139 | +#endif /* CONFIG_ARM_SPE_PMU */ |
---|
73 | 140 | |
---|
74 | 141 | static int arm_pmu_acpi_parse_irqs(void) |
---|
75 | 142 | { |
---|
.. | .. |
---|
276 | 343 | if (acpi_disabled) |
---|
277 | 344 | return 0; |
---|
278 | 345 | |
---|
| 346 | + arm_spe_acpi_register_device(); |
---|
| 347 | + |
---|
279 | 348 | ret = arm_pmu_acpi_parse_irqs(); |
---|
280 | 349 | if (ret) |
---|
281 | 350 | return ret; |
---|