Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −12
Original line number Diff line number Diff line
@@ -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_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_fifo *fifo = usbhs_pipe_to_fifo(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)

	pkt->trans = len;

	tasklet_init(&fifo->tasklet,
		     usbhsf_dma_prepare_tasklet,
		     (unsigned long)pkt);

	tasklet_schedule(&fifo->tasklet);
	INIT_WORK(&pkt->work, xfer_work);
	schedule_work(&pkt->work);

	return 0;

@@ -941,11 +938,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)

	pkt->trans = len;

	tasklet_init(&fifo->tasklet,
		     usbhsf_dma_prepare_tasklet,
		     (unsigned long)pkt);

	tasklet_schedule(&fifo->tasklet);
	INIT_WORK(&pkt->work, xfer_work);
	schedule_work(&pkt->work);

	return 0;

+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <linux/interrupt.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <asm/dma.h>
#include "pipe.h"

@@ -31,7 +32,6 @@ struct usbhs_fifo {
	u32 ctr;	/* xFIFOCTR */

	struct usbhs_pipe	*pipe;
	struct tasklet_struct	tasklet;

	struct dma_chan		*tx_chan;
	struct dma_chan		*rx_chan;
@@ -53,6 +53,7 @@ struct usbhs_pkt {
	struct usbhs_pkt_handle *handler;
	void (*done)(struct usbhs_priv *priv,
		     struct usbhs_pkt *pkt);
	struct work_struct work;
	dma_addr_t dma;
	void *buf;
	int length;