mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									d526128694
								
							
						
					
					
						commit
						6e4b74e469
					
				
					 2 changed files with 8 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue