Skip to content

[BUG] DSP panic when stopping arecord while aplay is running #2233

Closed

Description

@paulstelian97

Describe the bug
A clear and concise description of what the bug is.
Whenever I'm running aplay and arecord in parallel and then stop arecord I will get a DSP crash.

What have you tried to diagnose or workaround this issue?
Tried bisecting, found that 07bf590 breaks it and with the parent commit the playback continues just fine.

To Reproduce
Steps to reproduce the behavior: (e.g. list commands or actions used to reproduce the bug)
-> One terminal, begin arecord. Simplest command is arecord -Dhw:0,0 -f S24_LE -c 2 -r 48000 (to agree with the pipeline and not do any host-side processing but only on DSP if any I used the hw instead of default which is plughw:0,0)
-> The other terminal, begin playback. aplay Sample.wav. My file is S24_3LE which is not supported by SOF so a conversion is necessary, thus I just go with the default. It's also 2 channel, 48k.
-> First terminal, cancel arecord.
-> Listen in the headphones while the song suddenly stops progressing. No errors on aplay but it just hangs in there and I will get IPC errors when attempting to stop.

Reproduction Rate
Consistent (100% of attempts). After each attempt a reboot is required since the DSP is rendered unusable (I presume panic, however my platform doesn't report to the kernel yet; sof-coredump-reader.py reports code 63 which means it's a software initiated panic)

Expected behavior
A clear and concise description of what you expected to happen.
Being able to continue playback.

Impact
What impact does this issue have on your progress (e.g., annoyance, showstopper)
Showstopper.

Environment

  1. Branch name and commit hash of the 2 repositories: sof (firmware/topology) and linux (kernel driver).
  2. Name of the topology file
    • Topology: sof-imx8qxp-cs42888.m4
  3. Name of the platform(s) on which the bug is observed.
    • Platform: imx8

Screenshots or console output

No particular logs except on the kernel side I get IPC timeout when arecord is stopped, then again when I try to stop aplay.

[   56.441639] sof-audio-of 596e8000.dsp: error: ipc timed out for 0x60030000 size 12
[   56.441654] sof-audio-of 596e8000.dsp: error: waking up any trace sleepers
[   56.441663]  Port0: ASoC: trigger FE failed -110
[   56.953641] sof-audio-of 596e8000.dsp: error: ipc timed out for 0x60030000 size 12
[   56.953654] sof-audio-of 596e8000.dsp: error: waking up any trace sleepers
[  114.265642] sof-audio-of 596e8000.dsp: error: ipc timed out for 0x60050000 size 12
[  114.265657] sof-audio-of 596e8000.dsp: error: waking up any trace sleepers
[  114.265666]  Port0: ASoC: trigger FE failed -110
[  114.777652] sof-audio-of 596e8000.dsp: error: ipc timed out for 0x60030000 size 12
[  114.777665] sof-audio-of 596e8000.dsp: error: waking up any trace sleepers

Those with the timestamp of 56 seconds happened when I stopped arecord, those with timestamp 114 were when I also stopped aplay after listening to the tone of 1ms repeating over and over and the song not progressing.

On stopping either aplay or arecord no new logs go through DMA trace. Will edit as soon as I get mailbox trace data.

    0      2          IPC          57426298.082583   7879420.500000    src/ipc/handler.c:449 	ipc: comp 6 -> trigger cmd 0x50000
    0      2         PIPE 2.11     57426307.861862         9.779280 src/audio/pipeline.c:713 	pipeline_trigger()
    0      2         HOST 2.6      57426313.106607         5.244745     src/audio/host.c:299 	host_trigger()
    0      2       VOLUME 2.7      57426329.267267        16.160660 udio/volume/volume.c:563 	volume_trigger()
    0      2          DAI 2.10     57426334.537538         5.270270      src/audio/dai.c:536 	dai_comp_trigger(), command = 0
    0      2          DMA          57426352.768769  57426352.000000 c/drivers/imx/edma.c:176 	EDMA: stop(6)
    0      2  SCHEDULE_LL          57426365.312312        12.543544 _multi_chan_domain.c:197 	dma_multi_chan_domain_unregister()
    0      2  SCHEDULE_LL          57426371.672673         6.360360 _multi_chan_domain.c:173 	dma_multi_chan_domain_irq_unregister()
    0      2          IPC          57426415.924925        44.252251    src/ipc/handler.c:338 	ipc: comp 6 -> free
    0      2         PIPE 2.11     57426422.794294         6.869370 src/audio/pipeline.c:788 	pipeline_reset()
    0      2         HOST 2.6      57426428.617117         5.822823     src/audio/host.c:661 	host_reset()

This is the last trace visible in the mailbox; after that I get the timer_domain_register with a timestamp of 852 which is due to wraparound of the trace mailbox itself and is deemed irrelevant.

Attaching full, unfiltered output of sof-logger -l /sof-imx8.ldc -c 666:
etrace.log

Activity

  1. paulstelian97 commented on Dec 19, 2019

    @paulstelian97
    CollaboratorAuthor

    Additionally, stopping aplay while letting arecord running has the same effect.

  2. dbaluta commented on Dec 19, 2019

    @dbaluta
    Collaborator

    @paulstelian97 @akloniex @jajanusz

    Actually there is no panic. I suspect there is a deadlock / race introduced by the notifier changes. Can someone at intel try to following simple use case:

    1. Start record
    2. Start aplay
    3. Interrupt record (Ctrl + C).
    4. See if aplay is still able to run properly.
  3. jajanusz commented on Dec 19, 2019

    @jajanusz
    Contributor

    @tlauda @akloniex is it related to that bug with notifier sending msg to wrong core?

  4. paulstelian97 commented on Dec 19, 2019

    @paulstelian97
    CollaboratorAuthor

    @jajanusz On further investigation, I have noticed that I get stuck in an infinite loop in the list_for_item_safe loop inside notifier_register. Which is odd to me. I'm watching over the mailbox and I keep seeing a custom trace from that loop filling it up and the timestamps everchanging.

    I don't see what could corrupt the list to that level. notifier_register and notifier_unregister use spinlocks (without _irq) and are the only things that can modify the list, right? Thus all that I'd expect would be a deadlock instead of this.

  5. paulstelian97 commented on Dec 19, 2019

    @paulstelian97
    CollaboratorAuthor

    On other combinations I have managed to have it actually deadlock on the spinlock notify->lock. That is besides the infinite list BS (where I have wlist->next == wlist but wlist->prev != wlist -- yes I'm getting that).

    i.MX is single core btw (at least for now).

  6. paulstelian97 commented on Dec 20, 2019

    @paulstelian97
    CollaboratorAuthor

    I have new data which I still need to investigate: I think rzalloc returns to the notifier the same address twice without a rfree call inbetween. The only rfree happens in the next block between these. An expert on that, anyone?

    etrace dump (DMA trace won't flush due to the while(1) loop inserted upon list corruption being detected)

  7. paulstelian97 commented on Dec 20, 2019

    @paulstelian97
    CollaboratorAuthor

    Found the bug and it's in the memory allocator. Will attempt to push today before leaving for vacation but, if I don't manage, I'll leave the info for someone else to pick up -- apparently the field first_free becomes stale for some reason. Do we have (failing) unit tests related to this field?

  8. lgirdwood commented on Dec 20, 2019

    @lgirdwood
    Member

    @jajanusz possible missing/failing UT for allocator ? See previous message.

  9. paulstelian97 commented on Dec 20, 2019

    @paulstelian97
    CollaboratorAuthor

    An explanation of what I understood of alloc_block and free_block and their usage of first_free.

    Let's say we have a heap with two blocks. Initially they are both free:

    +--------+
    |  FREE  |  <-- first_free
    +--------+
    |  FREE  |
    +--------+
    

    Now allocate one of the blocks. It will give out the first free block, from where "first_free" points, and will search for the next free block. Nothing wrong with this. It becomes:

    +--------+
    |  USED  |
    +--------+
    |  FREE  |  <-- first_free
    +--------+
    

    Let's also allocate the second block now. No free blocks are found, first_free remains stuck in place. Also, free_count is set to 0 now so get_ptr_from_heap will not even check this heap anymore, so first_free doesn't need to be valid anymore.

    +--------+
    |  USED  |
    +--------+
    |  USED  |  <-- first_free
    +--------+
    

    Let's free the first block:

    +--------+
    |  FREE  |  <-- first_free
    +--------+
    |  USED  |
    +--------+
    

    Nothing wrong with that, first_free is set correctly in free_block. Now allocate it again:

    +--------+
    |  USED  |  <-- first_free
    +--------+
    |  USED  |
    +--------+
    

    Fair game, it doesn't need to be valid. Let's free the second block now:

    +--------+
    |  USED  |  <-- first_free
    +--------+
    |  FREE  |
    +--------+
    

    Oops? Since the block is later than where first_free is pointing, this pointer is not updated and suddenly we are in an invalid situation.

    If we try to allocate again the FIRST block will now be returned from this heap, which causes havoc.

    #2238 is a hacky attempt at fixing it, however from this very explanation I may have uncovered a simpler fix. Will push.

    EDIT: Replaced with non-hacky fix which tackles the problem directly. Please review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working as expected

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions