Kernel dump with mxs-auart.c in DMA mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Kernel dump with mxs-auart.c in DMA mode

1,324 Views
YS
Contributor IV

I experienced "BUG: scheduling while atomic:" Kernel dump with mxs-auart.c (after Freescale patch applied) in DMA mode. I tracked down the cause - in DMA mode, mxs-auart.c sets ASYNC_LOW_LATENCY flags on uart_port structure which eventually turn tty->low_latency flag in serial_core.c.

The patched mxs-auart.c uses tasklet to process bottom-half of DMA interrupt. In the end the tasklet callses tty_flip_buffer_push() to pass received data to user process. However tty_flip_buffer_push() is strictly prohibited to be called from IRQ hander with low_latency flag=1, since it will directly calls flush_to_ldisc() API, which includes mutex lock to tty->termios_mutex. Interrupt could happen any time, even when application access to the /dev/ttySPx and locks the mutex. If this happens, Linux kernel dumps with "BUG: scheduling while atomic" error.

I'm not sure if I should eliminate ASYNC_LOW_LATENCY flag completely. At this point I'm testing mxs-auart.c driver with my patch to temporally disable low_latency flag while calling tty_flip_buffer_push() from dma_rx_do_tasklet.

static void dma_rx_do_tasklet(unsigned long arg)
{
        .
        .
        .
        int low_latency_backup;
        .
        .
        .
        /* tty_flip_buffer_push strictly prohibits to be called
         * from IRQ handler with low_latency=1 to avoid
         * task scheduling (mutex lock) */
        low_latency_backup = tty->low_latency;
        tty->low_latency = 0;
        tty_flip_buffer_push(tty);
        tty->low_latency = low_latency_backup;
}

Labels (1)
0 Kudos
Reply
2 Replies

806 Views
YS
Contributor IV

Okay, my patch seems like working. AUART can now handle up to 2Mbps throughput (not bitrate) with DMA mode. No kernel dump observed so far.

0 Kudos
Reply

806 Views
guillaume_lecoc
Contributor I

Hi,

I think your patch is not complete, because you did not correct the normal mode. Shouldn't you do the same at the end of mxs_auart_rx_chars(struct mxs_auart_port *s), because it is also called in irq context.

Also, after reading tty_flip_buffer() from atomic context when low_latency==1 (Linux Serial), it seems to me that the flag ASYNC_LOW_LATENCY has to be removed. After some investigation, its seems to be used in different context.

It is mostly (and commonly) set by userland software which want to reduce the latency when receiving characters. In this case, it is used by driver to change the way they drive the hardware depending on what the user want.

It is only set by some few driver (like CDC-ACM for example). In this case, not that the userland have no way to disable this flag.

Imho (but correct me if I'm wrong), it should never be set by the driver directly but the driver should take care of it (like your patch did), and not throw an ugly exception if this flag is requested by the user.

By the way, I was going here because I saw some latency problem, and that flag felt really strange to me and caught my attention.

I figure out that my problem was related to the "really high" value of the rxtimeout flag which is configured to 0x80 in DMA mode (1031 bits), whereas the reference manual wrote that the default value is 0x03 (31 bits).

0 Kudos
Reply