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

[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
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
* Changed to support scatter gather DMA * Changed to support scatter gather DMA
* by taking Russell's code from RiscPC * by taking Russell's code from RiscPC
* *
* 2006-05-31 Pavel Pisa <pisa@cmp.felk.cvut.cz>
* Corrected error handling code.
*
*/ */
#undef DEBUG #undef DEBUG
...@@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, ...@@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int int
imx_dma_setup_handlers(imx_dmach_t dma_ch, imx_dma_setup_handlers(imx_dmach_t dma_ch,
void (*irq_handler) (int, void *, struct pt_regs *), 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) void *data)
{ {
struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 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) ...@@ -463,43 +466,53 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
int i, disr = DISR; int i, disr = DISR;
struct imx_dma_channel *channel; struct imx_dma_channel *channel;
unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
int errcode;
DISR = disr; DISR = disr & err_mask;
for (i = 0; i < IMX_DMA_CHANNELS; i++) { for (i = 0; i < IMX_DMA_CHANNELS; i++) {
channel = &imx_dma_channels[i]; if(!(err_mask & (1 << i)))
if ((err_mask & 1 << i) && channel->name
&& channel->err_handler) {
channel->err_handler(i, channel->data, regs);
continue; continue;
} channel = &imx_dma_channels[i];
errcode = 0;
imx_dma_channels[i].sg = NULL;
if (DBTOSR & (1 << i)) { if (DBTOSR & (1 << i)) {
printk(KERN_WARNING DBTOSR = (1 << i);
"Burst timeout on channel %d (%s)\n", errcode |= IMX_DMA_ERR_BURST;
i, channel->name);
DBTOSR |= (1 << i);
} }
if (DRTOSR & (1 << i)) { if (DRTOSR & (1 << i)) {
printk(KERN_WARNING DRTOSR = (1 << i);
"Request timeout on channel %d (%s)\n", errcode |= IMX_DMA_ERR_REQUEST;
i, channel->name);
DRTOSR |= (1 << i);
} }
if (DSESR & (1 << i)) { if (DSESR & (1 << i)) {
printk(KERN_WARNING DSESR = (1 << i);
"Transfer timeout on channel %d (%s)\n", errcode |= IMX_DMA_ERR_TRANSFER;
i, channel->name);
DSESR |= (1 << i);
} }
if (DBOSR & (1 << i)) { if (DBOSR & (1 << i)) {
printk(KERN_WARNING DBOSR = (1 << i);
"Buffer overflow timeout on channel %d (%s)\n", errcode |= IMX_DMA_ERR_BUFFER;
i, channel->name);
DBOSR |= (1 << i);
} }
/*
* 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; return IRQ_HANDLED;
} }
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
struct imx_dma_channel { struct imx_dma_channel {
const char *name; const char *name;
void (*irq_handler) (int, void *, struct pt_regs *); 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; void *data;
dmamode_t dma_mode; dmamode_t dma_mode;
struct scatterlist *sg; struct scatterlist *sg;
...@@ -58,6 +58,10 @@ struct imx_dma_channel { ...@@ -58,6 +58,10 @@ struct imx_dma_channel {
extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; 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 */ /* The type to distinguish channel numbers parameter from ordinal int type */
typedef int imx_dmach_t; typedef int imx_dmach_t;
...@@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, ...@@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int int
imx_dma_setup_handlers(imx_dmach_t dma_ch, imx_dma_setup_handlers(imx_dmach_t dma_ch,
void (*irq_handler) (int, void *, struct pt_regs *), 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); void imx_dma_enable(imx_dmach_t dma_ch);
......
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