aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/mpc512x_dma.c
diff options
context:
space:
mode:
authorIlya Yanok <yanok@emcraft.com>2010-10-26 19:52:55 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-12-30 00:27:31 -0500
commit6504cf3412373f42b53a675363c056901c1596cf (patch)
tree920b990614e44a692057a2a75d6110ca501579cc /drivers/dma/mpc512x_dma.c
parentd392da5207352f09030e95d9ea335a4225667ec0 (diff)
powerpc/512x: scatter/gather dma fix
While testing mpc512x-dma driver with dmatest module I've found that I can hang the mpc512x-dma issuing request from multiple threads to the single channel. insmod dmatest.ko max_channels=1 threads_per_chan=16 After investigating this case I've managed to find that this happens if and only if we have more than one queued requests. In this case the driver tries to make use of hardware scatter/gather functionality. I've found two problems with scatter/gather: 1. When TCD is copied form RAM to the TCD register space with memcpy_io() e_sg bit eventually gets cleared. This results in only first TCD being executed. I've added setting of e_sg bit explicitly in the TCD registers. BTW, what is the correct way to do this? (How can I use setbits with bitfield structure?) After that hardware loads consecutive TCDs and we hit the second issue. 2. Existing code clears int_maj bit in the last TCD so we never get an interrupt on transfer completion. With these fixes my tests with many threads of single channel succeed but tests that use many channels simultaneously still don't work reliable. Signed-off-by: Ilya Yanok <yanok@emcraft.com> Acked-by: Wolfgang Denk <wd@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/dma/mpc512x_dma.c')
-rw-r--r--drivers/dma/mpc512x_dma.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 4e9cbf300594..1bc04aa27b14 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -252,11 +252,13 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
252 prev = mdesc; 252 prev = mdesc;
253 } 253 }
254 254
255 prev->tcd->start = 0;
256 prev->tcd->int_maj = 1; 255 prev->tcd->int_maj = 1;
257 256
258 /* Send first descriptor in chain into hardware */ 257 /* Send first descriptor in chain into hardware */
259 memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd)); 258 memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd));
259
260 if (first != prev)
261 mdma->tcd[cid].e_sg = 1;
260 out_8(&mdma->regs->dmassrt, cid); 262 out_8(&mdma->regs->dmassrt, cid);
261} 263}
262 264