Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI: CPPC: Make rmw_lock a raw_spin_lock

The following BUG was triggered:

=============================
[ BUG: Invalid wait context ]
6.12.0-rc2-XXX #406 Not tainted
-----------------------------
kworker/1:1/62 is trying to lock:
ffffff8801593030 (&cpc_ptr->rmw_lock){+.+.}-{3:3}, at: cpc_write+0xcc/0x370
other info that might help us debug this:
context-{5:5}
2 locks held by kworker/1:1/62:
#0: ffffff897ef5ec98 (&rq->__lock){-.-.}-{2:2}, at: raw_spin_rq_lock_nested+0x2c/0x50
#1: ffffff880154e238 (&sg_policy->update_lock){....}-{2:2}, at: sugov_update_shared+0x3c/0x280
stack backtrace:
CPU: 1 UID: 0 PID: 62 Comm: kworker/1:1 Not tainted 6.12.0-rc2-g9654bd3e8806 #406
Workqueue: 0x0 (events)
Call trace:
dump_backtrace+0xa4/0x130
show_stack+0x20/0x38
dump_stack_lvl+0x90/0xd0
dump_stack+0x18/0x28
__lock_acquire+0x480/0x1ad8
lock_acquire+0x114/0x310
_raw_spin_lock+0x50/0x70
cpc_write+0xcc/0x370
cppc_set_perf+0xa0/0x3a8
cppc_cpufreq_fast_switch+0x40/0xc0
cpufreq_driver_fast_switch+0x4c/0x218
sugov_update_shared+0x234/0x280
update_load_avg+0x6ec/0x7b8
dequeue_entities+0x108/0x830
dequeue_task_fair+0x58/0x408
__schedule+0x4f0/0x1070
schedule+0x54/0x130
worker_thread+0xc0/0x2e8
kthread+0x130/0x148
ret_from_fork+0x10/0x20

sugov_update_shared() locks a raw_spinlock while cpc_write() locks a
spinlock.

To have a correct wait-type order, update rmw_lock to a raw spinlock and
ensure that interrupts will be disabled on the CPU holding it.

Fixes: 60949b7b8054 ("ACPI: CPPC: Fix MASK_VAL() usage")
Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Link: https://patch.msgid.link/20241028125657.1271512-1-pierre.gondois@arm.com
[ rjw: Changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Pierre Gondois and committed by
Rafael J. Wysocki
1c10941e 81983758

+6 -5
+5 -4
drivers/acpi/cppc_acpi.c
··· 867 867 868 868 /* Store CPU Logical ID */ 869 869 cpc_ptr->cpu_id = pr->id; 870 - spin_lock_init(&cpc_ptr->rmw_lock); 870 + raw_spin_lock_init(&cpc_ptr->rmw_lock); 871 871 872 872 /* Parse PSD data for this CPU */ 873 873 ret = acpi_get_psd(cpc_ptr, handle); ··· 1087 1087 int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); 1088 1088 struct cpc_reg *reg = &reg_res->cpc_entry.reg; 1089 1089 struct cpc_desc *cpc_desc; 1090 + unsigned long flags; 1090 1091 1091 1092 size = GET_BIT_WIDTH(reg); 1092 1093 ··· 1127 1126 return -ENODEV; 1128 1127 } 1129 1128 1130 - spin_lock(&cpc_desc->rmw_lock); 1129 + raw_spin_lock_irqsave(&cpc_desc->rmw_lock, flags); 1131 1130 switch (size) { 1132 1131 case 8: 1133 1132 prev_val = readb_relaxed(vaddr); ··· 1142 1141 prev_val = readq_relaxed(vaddr); 1143 1142 break; 1144 1143 default: 1145 - spin_unlock(&cpc_desc->rmw_lock); 1144 + raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags); 1146 1145 return -EFAULT; 1147 1146 } 1148 1147 val = MASK_VAL_WRITE(reg, prev_val, val); ··· 1175 1174 } 1176 1175 1177 1176 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) 1178 - spin_unlock(&cpc_desc->rmw_lock); 1177 + raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags); 1179 1178 1180 1179 return ret_val; 1181 1180 }
+1 -1
include/acpi/cppc_acpi.h
··· 65 65 int write_cmd_status; 66 66 int write_cmd_id; 67 67 /* Lock used for RMW operations in cpc_write() */ 68 - spinlock_t rmw_lock; 68 + raw_spinlock_t rmw_lock; 69 69 struct cpc_register_resource cpc_regs[MAX_CPC_REG_ENT]; 70 70 struct acpi_psd_package domain_info; 71 71 struct kobject kobj;