Commit 6e4b74e4 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Felipe Balbi

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: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent d5261286
...@@ -765,9 +765,9 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) ...@@ -765,9 +765,9 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
} }
static void usbhsf_dma_complete(void *arg); static void usbhsf_dma_complete(void *arg);
static void usbhsf_dma_prepare_tasklet(unsigned long data) static void xfer_work(struct work_struct *work)
{ {
struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 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,11 +847,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len; pkt->trans = len;
tasklet_init(&fifo->tasklet, INIT_WORK(&pkt->work, xfer_work);
usbhsf_dma_prepare_tasklet, schedule_work(&pkt->work);
(unsigned long)pkt);
tasklet_schedule(&fifo->tasklet);
return 0; return 0;
...@@ -941,11 +938,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) ...@@ -941,11 +938,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len; pkt->trans = len;
tasklet_init(&fifo->tasklet, INIT_WORK(&pkt->work, xfer_work);
usbhsf_dma_prepare_tasklet, schedule_work(&pkt->work);
(unsigned long)pkt);
tasklet_schedule(&fifo->tasklet);
return 0; return 0;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sh_dma.h> #include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <asm/dma.h> #include <asm/dma.h>
#include "pipe.h" #include "pipe.h"
...@@ -31,7 +32,6 @@ struct usbhs_fifo { ...@@ -31,7 +32,6 @@ struct usbhs_fifo {
u32 ctr; /* xFIFOCTR */ u32 ctr; /* xFIFOCTR */
struct usbhs_pipe *pipe; struct usbhs_pipe *pipe;
struct tasklet_struct tasklet;
struct dma_chan *tx_chan; struct dma_chan *tx_chan;
struct dma_chan *rx_chan; struct dma_chan *rx_chan;
...@@ -53,6 +53,7 @@ struct usbhs_pkt { ...@@ -53,6 +53,7 @@ struct usbhs_pkt {
struct usbhs_pkt_handle *handler; struct usbhs_pkt_handle *handler;
void (*done)(struct usbhs_priv *priv, void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt); struct usbhs_pkt *pkt);
struct work_struct work;
dma_addr_t dma; dma_addr_t dma;
void *buf; void *buf;
int length; int length;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment