Commit 6e4b74e4690dd03b5664fa4895c3db0607d64742
Committed by
Felipe Balbi
1 parent
d526128694
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
usb: renesas: fix scheduling in atomic context bug
The current renesas_usbhs driver triggers BUG: scheduling while atomic: ksoftirqd/0/3/0x00000102 with enabled CONFIG_DEBUG_ATOMIC_SLEEP, by submitting DMA transfers from an atomic (tasklet) context, which is not supported by the shdma dmaengine driver. Fix it by switching to a work. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Felipe Balbi <balbi@ti.com>
Showing 2 changed files with 8 additions and 13 deletions Side-by-side Diff
drivers/usb/renesas_usbhs/fifo.c
... | ... | @@ -765,9 +765,9 @@ |
765 | 765 | } |
766 | 766 | |
767 | 767 | static void usbhsf_dma_complete(void *arg); |
768 | -static void usbhsf_dma_prepare_tasklet(unsigned long data) | |
768 | +static void xfer_work(struct work_struct *work) | |
769 | 769 | { |
770 | - struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; | |
770 | + struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); | |
771 | 771 | struct usbhs_pipe *pipe = pkt->pipe; |
772 | 772 | struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); |
773 | 773 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
774 | 774 | |
... | ... | @@ -847,12 +847,9 @@ |
847 | 847 | |
848 | 848 | pkt->trans = len; |
849 | 849 | |
850 | - tasklet_init(&fifo->tasklet, | |
851 | - usbhsf_dma_prepare_tasklet, | |
852 | - (unsigned long)pkt); | |
850 | + INIT_WORK(&pkt->work, xfer_work); | |
851 | + schedule_work(&pkt->work); | |
853 | 852 | |
854 | - tasklet_schedule(&fifo->tasklet); | |
855 | - | |
856 | 853 | return 0; |
857 | 854 | |
858 | 855 | usbhsf_pio_prepare_push_unmap: |
... | ... | @@ -941,11 +938,8 @@ |
941 | 938 | |
942 | 939 | pkt->trans = len; |
943 | 940 | |
944 | - tasklet_init(&fifo->tasklet, | |
945 | - usbhsf_dma_prepare_tasklet, | |
946 | - (unsigned long)pkt); | |
947 | - | |
948 | - tasklet_schedule(&fifo->tasklet); | |
941 | + INIT_WORK(&pkt->work, xfer_work); | |
942 | + schedule_work(&pkt->work); | |
949 | 943 | |
950 | 944 | return 0; |
951 | 945 |
drivers/usb/renesas_usbhs/fifo.h
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | |
20 | 20 | #include <linux/interrupt.h> |
21 | 21 | #include <linux/sh_dma.h> |
22 | +#include <linux/workqueue.h> | |
22 | 23 | #include <asm/dma.h> |
23 | 24 | #include "pipe.h" |
24 | 25 | |
... | ... | @@ -31,7 +32,6 @@ |
31 | 32 | u32 ctr; /* xFIFOCTR */ |
32 | 33 | |
33 | 34 | struct usbhs_pipe *pipe; |
34 | - struct tasklet_struct tasklet; | |
35 | 35 | |
36 | 36 | struct dma_chan *tx_chan; |
37 | 37 | struct dma_chan *rx_chan; |
... | ... | @@ -53,6 +53,7 @@ |
53 | 53 | struct usbhs_pkt_handle *handler; |
54 | 54 | void (*done)(struct usbhs_priv *priv, |
55 | 55 | struct usbhs_pkt *pkt); |
56 | + struct work_struct work; | |
56 | 57 | dma_addr_t dma; |
57 | 58 | void *buf; |
58 | 59 | int length; |