aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2012-02-14 05:37:21 -0500
committerFelipe Balbi <balbi@ti.com>2012-02-14 06:44:53 -0500
commit6e4b74e4690dd03b5664fa4895c3db0607d64742 (patch)
tree607c5bd1c23be029b589971e512458fde91ed0fa /drivers
parentd5261286949fc9ada701c7e30bf89e08a6dbf4de (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c18
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h3
2 files changed, 8 insertions, 13 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index fb2a88c5c210..3648c82a17fe 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -765,9 +765,9 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
765} 765}
766 766
767static void usbhsf_dma_complete(void *arg); 767static void usbhsf_dma_complete(void *arg);
768static void usbhsf_dma_prepare_tasklet(unsigned long data) 768static 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 struct usbhs_pipe *pipe = pkt->pipe; 771 struct usbhs_pipe *pipe = pkt->pipe;
772 struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); 772 struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
773 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 773 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -847,11 +847,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
847 847
848 pkt->trans = len; 848 pkt->trans = len;
849 849
850 tasklet_init(&fifo->tasklet, 850 INIT_WORK(&pkt->work, xfer_work);
851 usbhsf_dma_prepare_tasklet, 851 schedule_work(&pkt->work);
852 (unsigned long)pkt);
853
854 tasklet_schedule(&fifo->tasklet);
855 852
856 return 0; 853 return 0;
857 854
@@ -941,11 +938,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
941 938
942 pkt->trans = len; 939 pkt->trans = len;
943 940
944 tasklet_init(&fifo->tasklet, 941 INIT_WORK(&pkt->work, xfer_work);
945 usbhsf_dma_prepare_tasklet, 942 schedule_work(&pkt->work);
946 (unsigned long)pkt);
947
948 tasklet_schedule(&fifo->tasklet);
949 943
950 return 0; 944 return 0;
951 945
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index f68609c0f489..c31731a843d1 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -19,6 +19,7 @@
19 19
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/sh_dma.h> 21#include <linux/sh_dma.h>
22#include <linux/workqueue.h>
22#include <asm/dma.h> 23#include <asm/dma.h>
23#include "pipe.h" 24#include "pipe.h"
24 25
@@ -31,7 +32,6 @@ struct usbhs_fifo {
31 u32 ctr; /* xFIFOCTR */ 32 u32 ctr; /* xFIFOCTR */
32 33
33 struct usbhs_pipe *pipe; 34 struct usbhs_pipe *pipe;
34 struct tasklet_struct tasklet;
35 35
36 struct dma_chan *tx_chan; 36 struct dma_chan *tx_chan;
37 struct dma_chan *rx_chan; 37 struct dma_chan *rx_chan;
@@ -53,6 +53,7 @@ struct usbhs_pkt {
53 struct usbhs_pkt_handle *handler; 53 struct usbhs_pkt_handle *handler;
54 void (*done)(struct usbhs_priv *priv, 54 void (*done)(struct usbhs_priv *priv,
55 struct usbhs_pkt *pkt); 55 struct usbhs_pkt *pkt);
56 struct work_struct work;
56 dma_addr_t dma; 57 dma_addr_t dma;
57 void *buf; 58 void *buf;
58 int length; 59 int length;