mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 11:06:03 +02:00
On Marvel the CMOS clock is only reachable from the boot cpu, so
remote_read_time() and remote_set_time() bounce the access there with
smp_call_function_single(), whose callback runs in hard interrupt
context.
alpha_rtc_read_time() calls mc146818_get_time() with a 10 ms timeout.
That waits out the RTC update cycle in mc146818_avoid_UIP(), which drops
rtc_lock and udelay()s 100 us at a time until the update completes or
the timeout expires:
for (i = 0; UIP_RECHECK_LOOPS_MS(i) < timeout; i++) {
spin_lock_irqsave(&rtc_lock, flags);
...
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
udelay(UIP_RECHECK_DELAY);
continue;
}
So a clock read from a non-boot cpu can spin for up to 10 ms in hard
interrupt context on the boot cpu, while the cpu that sent the request
spins in smp_call_function_single() waiting for it to finish.
mc146818_set_time() does not poll, but it takes rtc_lock too, and
rtc_lock is a spinlock_t. Only raw spinlocks may be taken in hard
interrupt context, so lockdep reports the write path as soon as a
non-boot cpu sets the clock:
[ BUG: Invalid wait context ]
-----------------------------
swapper/0/0 is trying to lock:
fffffc0003690470 (rtc_lock){....}-{3:3}, at: mc146818_set_time+0x74/0x450
other info that might help us debug this:
context-{2:2}
no locks held by swapper/0/0.
stack backtrace:
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.2.0-rc1 #1 NONE
Trace:
[<fffffc000102ebb0>] dump_stack+0x28/0x44
[<fffffc000110efcc>] __lock_acquire+0xb0c/0x1060
[<fffffc000110f5f0>] lock_acquire.part.0+0xd0/0x300
[...]
[<fffffc0001b0d834>] mc146818_set_time+0x74/0x450
[<fffffc0001f090cc>] _raw_spin_lock_irqsave+0x7c/0xc0
[<fffffc0001042f90>] do_remote_set+0x90/0xc0
[<fffffc000119c1a4>] __flush_smp_call_function_queue+0x314/0x5c0
[<fffffc000119c474>] generic_smp_call_function_single_interrupt+0x24/0x40
[<fffffc000103d984>] handle_ipi+0xa4/0x230
[<fffffc0001037044>] do_entInt+0x1a4/0x2e0
The rtc class ops are always called from process context, so there is no
reason to run the access from an interrupt at all. Use work_on_cpu() to
run it in a worker on the boot cpu. Alpha does not support cpu hotplug,
so the boot cpu cannot go offline while the work is pending.
Tested on an AlphaServer ES47 (Marvel/EV7): hwclock read and write
pinned to a non-boot cpu, twenty times, with no splat.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Magnus Lindholm <linmag7@gmail.com>
Link: https://lore.kernel.org/r/20260810202835.3592833-1-mattst88@gmail.com
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
|
||
|---|---|---|
| .. | ||
| syscalls | ||
| .gitignore | ||
| asm-offsets.c | ||
| audit.c | ||
| bugs.c | ||
| console.c | ||
| core_cia.c | ||
| core_irongate.c | ||
| core_marvel.c | ||
| core_mcpcia.c | ||
| core_polaris.c | ||
| core_t2.c | ||
| core_titan.c | ||
| core_tsunami.c | ||
| core_wildfire.c | ||
| entry.S | ||
| err_common.c | ||
| err_ev6.c | ||
| err_ev7.c | ||
| err_impl.h | ||
| err_marvel.c | ||
| err_titan.c | ||
| es1888.c | ||
| gct.c | ||
| head.S | ||
| io.c | ||
| irq_alpha.c | ||
| irq_i8259.c | ||
| irq_impl.h | ||
| irq_pyxis.c | ||
| irq_srm.c | ||
| irq.c | ||
| machvec_impl.h | ||
| Makefile | ||
| module.c | ||
| osf_sys.c | ||
| pc873xx.c | ||
| pc873xx.h | ||
| pci_impl.h | ||
| pci_iommu.c | ||
| pci-sysfs.c | ||
| pci.c | ||
| perf_event.c | ||
| process.c | ||
| proto.h | ||
| ptrace.c | ||
| rtc.c | ||
| setup.c | ||
| signal.c | ||
| smc37c93x.c | ||
| smc37c669.c | ||
| smp.c | ||
| srm_env.c | ||
| srmcons.c | ||
| stacktrace.c | ||
| sys_alcor.c | ||
| sys_cabriolet.c | ||
| sys_dp264.c | ||
| sys_eiger.c | ||
| sys_marvel.c | ||
| sys_miata.c | ||
| sys_mikasa.c | ||
| sys_nautilus.c | ||
| sys_noritake.c | ||
| sys_rawhide.c | ||
| sys_ruffian.c | ||
| sys_rx164.c | ||
| sys_sable.c | ||
| sys_sx164.c | ||
| sys_takara.c | ||
| sys_titan.c | ||
| sys_wildfire.c | ||
| systbls.S | ||
| termios.c | ||
| time.c | ||
| traps.c | ||
| vmlinux.lds.S | ||