Commit 5331d9ca authored by Lorenzo Pieralisi's avatar Lorenzo Pieralisi Committed by Rafael J. Wysocki

ACPI / drivers: replace acpi_probe_lock spinlock with mutex

Commit e647b532 ("ACPI: Add early device probing infrastructure")
introduced code that allows inserting driver specific
struct acpi_probe_entry probe entries into ACPI linker sections
(one per-subsystem, eg irqchip, clocksource) that are then walked
to retrieve the data and function hooks required to probe the
respective kernel components.

Probing for all entries in a section is triggered through
the __acpi_probe_device_table() function, that in turn, according
to the table ID a given probe entry reports parses the table
with the function retrieved from the respective section structures
(ie struct acpi_probe_entry). Owing to the current ACPI table
parsing implementation, the __acpi_probe_device_table() function
has to share global variables with the acpi_match_madt() function, so
in order to guarantee mutual exclusion locking is required
between the two functions.

Current kernel code implements the locking through the acpi_probe_lock
spinlock; this has the side effect of requiring all code called
within the lock (ie struct acpi_probe_entry.probe_{table/subtbl} hooks)
not to sleep.

However, kernel subsystems that make use of the early probing
infrastructure are relying on kernel APIs that may sleep (eg
irq_domain_alloc_fwnode(), among others) in the function calls
pointed at by struct acpi_probe_entry.{probe_table/subtbl} entries
(eg gic_v2_acpi_init()), which is a bug.

Since __acpi_probe_device_table() is called from context
that is allowed to sleep the acpi_probe_lock spinlock can be replaced
with a mutex; this fixes the issue whilst still guaranteeing
mutual exclusion.
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Fixes: e647b532 (ACPI: Add early device probing infrastructure)
Cc: 4.4+ <stable@vger.kernel.org> # 4.4+
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 3feab13c
...@@ -2054,7 +2054,7 @@ int __init acpi_scan_init(void) ...@@ -2054,7 +2054,7 @@ int __init acpi_scan_init(void)
static struct acpi_probe_entry *ape; static struct acpi_probe_entry *ape;
static int acpi_probe_count; static int acpi_probe_count;
static DEFINE_SPINLOCK(acpi_probe_lock); static DEFINE_MUTEX(acpi_probe_mutex);
static int __init acpi_match_madt(struct acpi_subtable_header *header, static int __init acpi_match_madt(struct acpi_subtable_header *header,
const unsigned long end) const unsigned long end)
...@@ -2073,7 +2073,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) ...@@ -2073,7 +2073,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
if (acpi_disabled) if (acpi_disabled)
return 0; return 0;
spin_lock(&acpi_probe_lock); mutex_lock(&acpi_probe_mutex);
for (ape = ap_head; nr; ape++, nr--) { for (ape = ap_head; nr; ape++, nr--) {
if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) { if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) {
acpi_probe_count = 0; acpi_probe_count = 0;
...@@ -2086,7 +2086,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) ...@@ -2086,7 +2086,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
count++; count++;
} }
} }
spin_unlock(&acpi_probe_lock); mutex_unlock(&acpi_probe_mutex);
return count; return count;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment