ACPI GPE handler: mtx_lock() by idle thread

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

ACPI GPE handler: mtx_lock() by idle thread

yuripv
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
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: ACPI GPE handler: mtx_lock() by idle thread

Konstantin Belousov
On Tue, Sep 11, 2018 at 08:19:26AM +0300, Yuri Pankov wrote:
> 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.

>
>
> 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
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: ACPI GPE handler: mtx_lock() by idle thread

yuripv
Konstantin Belousov wrote:

> On Tue, Sep 11, 2018 at 08:19:26AM +0300, Yuri Pankov wrote:
>> 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.
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[hidden email]"