hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/perf/arm_pmu_acpi.c
....@@ -1,11 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * ACPI probing code for ARM performance counters.
34 *
45 * 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.
96 */
107
118 #include <linux/acpi.h>
....@@ -70,6 +67,76 @@
7067 if (gsi)
7168 acpi_unregister_gsi(gsi);
7269 }
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 */
73140
74141 static int arm_pmu_acpi_parse_irqs(void)
75142 {
....@@ -276,6 +343,8 @@
276343 if (acpi_disabled)
277344 return 0;
278345
346
+ arm_spe_acpi_register_device();
347
+
279348 ret = arm_pmu_acpi_parse_irqs();
280349 if (ret)
281350 return ret;