summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Morse <james.morse@arm.com>2021-07-02 16:48:41 +0100
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2023-08-29 15:30:08 +0100
commit8a34ac66449388a2e3cd1825bd9ea59c5e72b17a (patch)
treeb870fe1499b28df0d3501873cfc2ce67b685e737
parent13bd3033d6e6f502da61bedd480891988f43813d (diff)
ACPI: Check _STA present bit before making CPUs not present
When called acpi_processor_post_eject() unconditionally make a CPU not-present and unregisters it. To add support for AML events where the CPU has become disabled, but remains present, the _STA method should be checked before calling acpi_processor_remove(). Rename acpi_processor_post_eject() acpi_processor_remove_possible(), and check the _STA before calling. Adding the function prototype for arch_unregister_cpu() allows the preprocessor guards to be removed. After this change CPUs will remain registered and visible to user-space as offline if buggy firmware triggers an eject-request, but doesn't clear the corresponding _STA bits after _EJ0 has been called. Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/acpi/acpi_processor.c31
-rw-r--r--include/linux/cpu.h1
2 files changed, 26 insertions, 6 deletions
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index a02ee80db50e..a8f5d25b2015 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -446,13 +446,12 @@ static int acpi_processor_add(struct acpi_device *device,
return result;
}
-#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU
/* Removal */
-static void acpi_processor_post_eject(struct acpi_device *device)
+static void acpi_processor_make_not_present(struct acpi_device *device)
{
struct acpi_processor *pr;
- if (!device || !acpi_driver_data(device))
+ if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU))
return;
pr = acpi_driver_data(device);
@@ -490,7 +489,29 @@ static void acpi_processor_post_eject(struct acpi_device *device)
free_cpumask_var(pr->throttling.shared_cpu_map);
kfree(pr);
}
-#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */
+
+static void acpi_processor_post_eject(struct acpi_device *device)
+{
+ struct acpi_processor *pr;
+ unsigned long long sta;
+ acpi_status status;
+
+ if (!device)
+ return;
+
+ pr = acpi_driver_data(device);
+ if (!pr || pr->id >= nr_cpu_ids || invalid_phys_cpuid(pr->phys_id))
+ return;
+
+ status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return;
+
+ if (cpu_present(pr->id) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
+ acpi_processor_make_not_present(device);
+ return;
+ }
+}
#ifdef CONFIG_X86
static bool acpi_hwp_native_thermal_lvt_set;
@@ -559,9 +580,7 @@ static const struct acpi_device_id processor_device_ids[] = {
static struct acpi_scan_handler processor_handler = {
.ids = processor_device_ids,
.attach = acpi_processor_add,
-#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU
.post_eject = acpi_processor_post_eject,
-#endif
.hotplug = {
.enabled = true,
},
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 7efa3adc65a2..cb09e7ca1d95 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -80,6 +80,7 @@ struct device *cpu_device_create(struct device *parent, void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...);
extern int arch_register_cpu(int cpu);
+extern void arch_unregister_cpu(int cpu);
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *cpu);
extern ssize_t arch_cpu_probe(const char *, size_t);