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

Commit fa3e686a authored by Pavel Pisa's avatar Pavel Pisa Committed by Russell King
Browse files

[ARM] 3601/1: i.MX/MX1 DMA error handling for signaled channels only



Patch from Pavel Pisa

There has been bug, that dma_err_handler() touches even
channels not signaling error condition.

Problem noticed by Andrea Paterniani.

Signed-off-by: default avatarPavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e22b04fb
Loading
Loading
Loading
Loading
+39 −26
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
 *             Changed to support scatter gather DMA
 *             by taking Russell's code from RiscPC
 *
 *  2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
 *             Corrected error handling code.
 *
 */

#undef DEBUG
@@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
		       void (*irq_handler) (int, void *, struct pt_regs *),
		       void (*err_handler) (int, void *, struct pt_regs *),
		       void (*err_handler) (int, void *, struct pt_regs *, int),
		       void *data)
{
	struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
@@ -463,43 +466,53 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
	int i, disr = DISR;
	struct imx_dma_channel *channel;
	unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
	int errcode;

	DISR = disr;
	DISR = disr & err_mask;
	for (i = 0; i < IMX_DMA_CHANNELS; i++) {
		channel = &imx_dma_channels[i];

		if ((err_mask & 1 << i) && channel->name
		    && channel->err_handler) {
			channel->err_handler(i, channel->data, regs);
		if(!(err_mask & (1 << i)))
			continue;
		}

		imx_dma_channels[i].sg = NULL;
		channel = &imx_dma_channels[i];
		errcode = 0;

		if (DBTOSR & (1 << i)) {
			printk(KERN_WARNING
			       "Burst timeout on channel %d (%s)\n",
			       i, channel->name);
			DBTOSR |= (1 << i);
			DBTOSR = (1 << i);
			errcode |= IMX_DMA_ERR_BURST;
		}
		if (DRTOSR & (1 << i)) {
			printk(KERN_WARNING
			       "Request timeout on channel %d (%s)\n",
			       i, channel->name);
			DRTOSR |= (1 << i);
			DRTOSR = (1 << i);
			errcode |= IMX_DMA_ERR_REQUEST;
		}
		if (DSESR & (1 << i)) {
			printk(KERN_WARNING
			       "Transfer timeout on channel %d (%s)\n",
			       i, channel->name);
			DSESR |= (1 << i);
			DSESR = (1 << i);
			errcode |= IMX_DMA_ERR_TRANSFER;
		}
		if (DBOSR & (1 << i)) {
			printk(KERN_WARNING
			       "Buffer overflow timeout on channel %d (%s)\n",
			       i, channel->name);
			DBOSR |= (1 << i);
			DBOSR = (1 << i);
			errcode |= IMX_DMA_ERR_BUFFER;
		}

		/*
		 * The cleaning of @sg field would be questionable
		 * there, because its value can help to compute
		 * remaining/transfered bytes count in the handler
		 */
		/*imx_dma_channels[i].sg = NULL;*/

		if (channel->name && channel->err_handler) {
			channel->err_handler(i, channel->data, regs, errcode);
			continue;
		}

		imx_dma_channels[i].sg = NULL;

		printk(KERN_WARNING
		       "DMA timeout on channel %d (%s) -%s%s%s%s\n",
		       i, channel->name,
		       errcode&IMX_DMA_ERR_BURST?    " burst":"",
		       errcode&IMX_DMA_ERR_REQUEST?  " request":"",
		       errcode&IMX_DMA_ERR_TRANSFER? " transfer":"",
		       errcode&IMX_DMA_ERR_BUFFER?   " buffer":"");
	}
	return IRQ_HANDLED;
}
+6 −2
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@
struct imx_dma_channel {
	const char *name;
	void (*irq_handler) (int, void *, struct pt_regs *);
	void (*err_handler) (int, void *, struct pt_regs *);
	void (*err_handler) (int, void *, struct pt_regs *, int errcode);
	void *data;
	dmamode_t  dma_mode;
	struct scatterlist *sg;
@@ -58,6 +58,10 @@ struct imx_dma_channel {

extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];

#define IMX_DMA_ERR_BURST     1
#define IMX_DMA_ERR_REQUEST   2
#define IMX_DMA_ERR_TRANSFER  4
#define IMX_DMA_ERR_BUFFER    8

/* The type to distinguish channel numbers parameter from ordinal int type */
typedef int imx_dmach_t;
@@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
		void (*irq_handler) (int, void *, struct pt_regs *),
		void (*err_handler) (int, void *, struct pt_regs *), void *data);
		void (*err_handler) (int, void *, struct pt_regs *, int), void *data);

void imx_dma_enable(imx_dmach_t dma_ch);