Discussion:
ACPI GPE handler: mtx_lock() by idle thread
Yuri Pankov
2018-09-11 05:19:26 UTC
Permalink
I have the panic shown below with a simple device driver that installs
GPE handler in the attach routine, and does nothing else than waiting
for GPEs. No matter if I try to handle it sync (calling
SPIBUS_TRANSFER() from the handler), or async (calling
taskqueue_enqueue()), once one of those functions called from the
handler does mtx_lock(), it panics. Any hints?


panic: mtx_lock() by idle thread 0xfffff800035bb000 on sleep mutex spi1
@ /home/yuri/ws/mbp/sys/dev/intel/spi.c:382
cpuid = 0
time = 1536642645
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame
0xfffffe00764761b0
vpanic() at vpanic+0x1a3/frame 0xfffffe0076476210
panic() at panic+0x43/frame 0xfffffe0076476270
__mtx_lock_flags() at __mtx_lock_flags+0x15a/frame 0xfffffe00764762c0
intelspi_transfer() at intelspi_transfer+0x3d/frame 0xfffffe0076476310
spimbp_gpe_handler() at spimbp_gpe_handler+0x102/frame 0xfffffe0076476580
AcpiEvGpeDispatch() at AcpiEvGpeDispatch+0xc0/frame 0xfffffe00764765b0
AcpiEvDetectGpe() at AcpiEvDetectGpe+0x10a/frame 0xfffffe0076476600
AcpiEvGpeDetect() at AcpiEvGpeDetect+0x323/frame 0xfffffe0076476670
AcpiEvSciXruptHandler() at AcpiEvSciXruptHandler+0x1e/frame
0xfffffe00764766a0
acpi_intr_handler() at acpi_intr_handler+0x18/frame 0xfffffe00764766b0
intr_event_handle() at intr_event_handle+0xcb/frame 0xfffffe0076476700
intr_execute_handlers() at intr_execute_handlers+0x58/frame
0xfffffe0076476730
lapic_handle_intr() at lapic_handle_intr+0x5f/frame 0xfffffe0076476750
Xapic_isr1() at Xapic_isr1+0xd9/frame 0xfffffe0076476750
--- interrupt, rip = 0xffffffff80461191, rsp = 0xfffffe0076476820, rbp =
0xfffffe0076476860 ---
acpi_cpu_idle() at acpi_cpu_idle+0x2a1/frame 0xfffffe0076476860
cpu_idle_acpi() at cpu_idle_acpi+0x3f/frame 0xfffffe0076476880
cpu_idle() at cpu_idle+0xa7/frame 0xfffffe00764768a0
sched_idletd() at sched_idletd+0x517/frame 0xfffffe0076476970
fork_exit() at fork_exit+0x84/frame 0xfffffe00764769b0
fork_trampoline() at fork_trampoline+0xe/frame 0xfffffe00764769b0
--- trap 0, rip = 0, rsp = 0, rbp = 0 ---
KDB: enter: panic
Konstantin Belousov
2018-09-11 08:43:57 UTC
Permalink
Post by Yuri Pankov
I have the panic shown below with a simple device driver that installs
GPE handler in the attach routine, and does nothing else than waiting
for GPEs. No matter if I try to handle it sync (calling
SPIBUS_TRANSFER() from the handler), or async (calling
taskqueue_enqueue()), once one of those functions called from the
handler does mtx_lock(), it panics. Any hints?
If you look at the backtrace below, you would note that ACPI GPE event
handler is executed in the context of an interrupt. It means that it
borrows the context of whatever thread was executed on the CPU when the
interrupt occured. One of the consequences is that an interrupt handler
(fast interrupt handler in the FreeBSD terminology) cannot block or
sleep, see locking(9).

There is a different way to handle interrupts in FreeBSD, by normal (not
fast) interrupt handlers. There, the code executing in the context of
interrupt only wakes up the interrupt thread, which executes the handler
in its dedicated context. As the consequence, mutexes do work for such
handlers. Still, sleep is prohibited.

I briefly looked at the dev/intel/spi.c code and I see that
intelspi_transfer() sleeps waiting for the hardware event. In other
words, even normal interrupt handler cannot help your problem.

Is it required to do the transfers in the interrupt handler code, for
your work ? If not, then the usual solution is to delegate the work
that requires resource acquision, to the fast taskqueue. Your code in
GPE event handler would only schedule a task, and the running task can
do whatever slow operations it needs. See taskqueue(9), there are
enough examples of the fast taskqueue use in the tree.
Post by Yuri Pankov
panic: mtx_lock() by idle thread 0xfffff800035bb000 on sleep mutex spi1
@ /home/yuri/ws/mbp/sys/dev/intel/spi.c:382
cpuid = 0
time = 1536642645
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame
0xfffffe00764761b0
vpanic() at vpanic+0x1a3/frame 0xfffffe0076476210
panic() at panic+0x43/frame 0xfffffe0076476270
__mtx_lock_flags() at __mtx_lock_flags+0x15a/frame 0xfffffe00764762c0
intelspi_transfer() at intelspi_transfer+0x3d/frame 0xfffffe0076476310
spimbp_gpe_handler() at spimbp_gpe_handler+0x102/frame 0xfffffe0076476580
AcpiEvGpeDispatch() at AcpiEvGpeDispatch+0xc0/frame 0xfffffe00764765b0
AcpiEvDetectGpe() at AcpiEvDetectGpe+0x10a/frame 0xfffffe0076476600
AcpiEvGpeDetect() at AcpiEvGpeDetect+0x323/frame 0xfffffe0076476670
AcpiEvSciXruptHandler() at AcpiEvSciXruptHandler+0x1e/frame
0xfffffe00764766a0
acpi_intr_handler() at acpi_intr_handler+0x18/frame 0xfffffe00764766b0
intr_event_handle() at intr_event_handle+0xcb/frame 0xfffffe0076476700
intr_execute_handlers() at intr_execute_handlers+0x58/frame
0xfffffe0076476730
lapic_handle_intr() at lapic_handle_intr+0x5f/frame 0xfffffe0076476750
Xapic_isr1() at Xapic_isr1+0xd9/frame 0xfffffe0076476750
--- interrupt, rip = 0xffffffff80461191, rsp = 0xfffffe0076476820, rbp =
0xfffffe0076476860 ---
acpi_cpu_idle() at acpi_cpu_idle+0x2a1/frame 0xfffffe0076476860
cpu_idle_acpi() at cpu_idle_acpi+0x3f/frame 0xfffffe0076476880
cpu_idle() at cpu_idle+0xa7/frame 0xfffffe00764768a0
sched_idletd() at sched_idletd+0x517/frame 0xfffffe0076476970
fork_exit() at fork_exit+0x84/frame 0xfffffe00764769b0
fork_trampoline() at fork_trampoline+0xe/frame 0xfffffe00764769b0
--- trap 0, rip = 0, rsp = 0, rbp = 0 ---
KDB: enter: panic
Yuri Pankov
2018-09-11 17:39:45 UTC
Permalink
Post by Konstantin Belousov
Post by Yuri Pankov
I have the panic shown below with a simple device driver that installs
GPE handler in the attach routine, and does nothing else than waiting
for GPEs. No matter if I try to handle it sync (calling
SPIBUS_TRANSFER() from the handler), or async (calling
taskqueue_enqueue()), once one of those functions called from the
handler does mtx_lock(), it panics. Any hints?
If you look at the backtrace below, you would note that ACPI GPE event
handler is executed in the context of an interrupt. It means that it
borrows the context of whatever thread was executed on the CPU when the
interrupt occured. One of the consequences is that an interrupt handler
(fast interrupt handler in the FreeBSD terminology) cannot block or
sleep, see locking(9).
There is a different way to handle interrupts in FreeBSD, by normal (not
fast) interrupt handlers. There, the code executing in the context of
interrupt only wakes up the interrupt thread, which executes the handler
in its dedicated context. As the consequence, mutexes do work for such
handlers. Still, sleep is prohibited.
I briefly looked at the dev/intel/spi.c code and I see that
intelspi_transfer() sleeps waiting for the hardware event. In other
words, even normal interrupt handler cannot help your problem.
Is it required to do the transfers in the interrupt handler code, for
your work ? If not, then the usual solution is to delegate the work
that requires resource acquision, to the fast taskqueue. Your code in
GPE event handler would only schedule a task, and the running task can
do whatever slow operations it needs. See taskqueue(9), there are
enough examples of the fast taskqueue use in the tree.
Of course, I don't need to process the event in the GPE handler, and
just noted that I tried to compare with taskqueue_enqueue()'d async
handler, which produced the same results mainly because I was stupid and
didn't notice that there's a separate predefined taskqueue for interrupt
processing, taskqueue_fast. Now all looks good, I have the chance to do
spi transfer in async handler.

Thank you for all your help.

Loading...