Commit 6e4b74e4690dd03b5664fa4895c3db0607d64742

Authored by Guennadi Liakhovetski
Committed by Felipe Balbi
1 parent d526128694

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;