aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/Kconfig4
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/sa11x0-dma.c249
-rw-r--r--drivers/dma/virt-dma.c99
-rw-r--r--drivers/dma/virt-dma.h138
5 files changed, 320 insertions, 171 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index aadeb5be9dba..eb2b60e8e1cb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -255,6 +255,7 @@ config DMA_SA11X0
255 tristate "SA-11x0 DMA support" 255 tristate "SA-11x0 DMA support"
256 depends on ARCH_SA1100 256 depends on ARCH_SA1100
257 select DMA_ENGINE 257 select DMA_ENGINE
258 select DMA_VIRTUAL_CHANNELS
258 help 259 help
259 Support the DMA engine found on Intel StrongARM SA-1100 and 260 Support the DMA engine found on Intel StrongARM SA-1100 and
260 SA-1110 SoCs. This DMA engine can only be used with on-chip 261 SA-1110 SoCs. This DMA engine can only be used with on-chip
@@ -263,6 +264,9 @@ config DMA_SA11X0
263config DMA_ENGINE 264config DMA_ENGINE
264 bool 265 bool
265 266
267config DMA_VIRTUAL_CHANNELS
268 tristate
269
266comment "DMA Clients" 270comment "DMA Clients"
267 depends on DMA_ENGINE 271 depends on DMA_ENGINE
268 272
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 86b795baba98..fc05f7ddac7e 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -2,6 +2,7 @@ ccflags-$(CONFIG_DMADEVICES_DEBUG) := -DDEBUG
2ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG 2ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG
3 3
4obj-$(CONFIG_DMA_ENGINE) += dmaengine.o 4obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
5obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
5obj-$(CONFIG_NET_DMA) += iovlock.o 6obj-$(CONFIG_NET_DMA) += iovlock.o
6obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o 7obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
7obj-$(CONFIG_DMATEST) += dmatest.o 8obj-$(CONFIG_DMATEST) += dmatest.o
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index ec78ccef9132..5f1d2e670837 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -21,6 +21,8 @@
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/spinlock.h> 22#include <linux/spinlock.h>
23 23
24#include "virt-dma.h"
25
24#define NR_PHY_CHAN 6 26#define NR_PHY_CHAN 6
25#define DMA_ALIGN 3 27#define DMA_ALIGN 3
26#define DMA_MAX_SIZE 0x1fff 28#define DMA_MAX_SIZE 0x1fff
@@ -72,12 +74,11 @@ struct sa11x0_dma_sg {
72}; 74};
73 75
74struct sa11x0_dma_desc { 76struct sa11x0_dma_desc {
75 struct dma_async_tx_descriptor tx; 77 struct virt_dma_desc vd;
78
76 u32 ddar; 79 u32 ddar;
77 size_t size; 80 size_t size;
78 81
79 /* maybe protected by c->lock */
80 struct list_head node;
81 unsigned sglen; 82 unsigned sglen;
82 struct sa11x0_dma_sg sg[0]; 83 struct sa11x0_dma_sg sg[0];
83}; 84};
@@ -85,15 +86,11 @@ struct sa11x0_dma_desc {
85struct sa11x0_dma_phy; 86struct sa11x0_dma_phy;
86 87
87struct sa11x0_dma_chan { 88struct sa11x0_dma_chan {
88 struct dma_chan chan; 89 struct virt_dma_chan vc;
89 spinlock_t lock;
90 dma_cookie_t lc;
91 90
92 /* protected by c->lock */ 91 /* protected by c->vc.lock */
93 struct sa11x0_dma_phy *phy; 92 struct sa11x0_dma_phy *phy;
94 enum dma_status status; 93 enum dma_status status;
95 struct list_head desc_submitted;
96 struct list_head desc_issued;
97 94
98 /* protected by d->lock */ 95 /* protected by d->lock */
99 struct list_head node; 96 struct list_head node;
@@ -109,7 +106,7 @@ struct sa11x0_dma_phy {
109 106
110 struct sa11x0_dma_chan *vchan; 107 struct sa11x0_dma_chan *vchan;
111 108
112 /* Protected by c->lock */ 109 /* Protected by c->vc.lock */
113 unsigned sg_load; 110 unsigned sg_load;
114 struct sa11x0_dma_desc *txd_load; 111 struct sa11x0_dma_desc *txd_load;
115 unsigned sg_done; 112 unsigned sg_done;
@@ -127,13 +124,12 @@ struct sa11x0_dma_dev {
127 spinlock_t lock; 124 spinlock_t lock;
128 struct tasklet_struct task; 125 struct tasklet_struct task;
129 struct list_head chan_pending; 126 struct list_head chan_pending;
130 struct list_head desc_complete;
131 struct sa11x0_dma_phy phy[NR_PHY_CHAN]; 127 struct sa11x0_dma_phy phy[NR_PHY_CHAN];
132}; 128};
133 129
134static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan) 130static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
135{ 131{
136 return container_of(chan, struct sa11x0_dma_chan, chan); 132 return container_of(chan, struct sa11x0_dma_chan, vc.chan);
137} 133}
138 134
139static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev) 135static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
@@ -141,27 +137,26 @@ static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
141 return container_of(dmadev, struct sa11x0_dma_dev, slave); 137 return container_of(dmadev, struct sa11x0_dma_dev, slave);
142} 138}
143 139
144static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx) 140static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
145{ 141{
146 return container_of(tx, struct sa11x0_dma_desc, tx); 142 struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
143
144 return vd ? container_of(vd, struct sa11x0_dma_desc, vd) : NULL;
147} 145}
148 146
149static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c) 147static void sa11x0_dma_free_desc(struct virt_dma_desc *vd)
150{ 148{
151 if (list_empty(&c->desc_issued)) 149 kfree(container_of(vd, struct sa11x0_dma_desc, vd));
152 return NULL;
153
154 return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
155} 150}
156 151
157static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd) 152static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
158{ 153{
159 list_del(&txd->node); 154 list_del(&txd->vd.node);
160 p->txd_load = txd; 155 p->txd_load = txd;
161 p->sg_load = 0; 156 p->sg_load = 0;
162 157
163 dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n", 158 dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
164 p->num, txd, txd->tx.cookie, txd->ddar); 159 p->num, &txd->vd, txd->vd.tx.cookie, txd->ddar);
165} 160}
166 161
167static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p, 162static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
@@ -229,21 +224,13 @@ static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
229 struct sa11x0_dma_desc *txd = p->txd_done; 224 struct sa11x0_dma_desc *txd = p->txd_done;
230 225
231 if (++p->sg_done == txd->sglen) { 226 if (++p->sg_done == txd->sglen) {
232 struct sa11x0_dma_dev *d = p->dev; 227 vchan_cookie_complete(&txd->vd);
233
234 dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
235 p->num, p->txd_done, p->txd_done->tx.cookie);
236
237 c->lc = txd->tx.cookie;
238
239 spin_lock(&d->lock);
240 list_add_tail(&txd->node, &d->desc_complete);
241 spin_unlock(&d->lock);
242 228
243 p->sg_done = 0; 229 p->sg_done = 0;
244 p->txd_done = p->txd_load; 230 p->txd_done = p->txd_load;
245 231
246 tasklet_schedule(&d->task); 232 if (!p->txd_done)
233 tasklet_schedule(&p->dev->task);
247 } 234 }
248 235
249 sa11x0_dma_start_sg(p, c); 236 sa11x0_dma_start_sg(p, c);
@@ -280,7 +267,7 @@ static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
280 if (c) { 267 if (c) {
281 unsigned long flags; 268 unsigned long flags;
282 269
283 spin_lock_irqsave(&c->lock, flags); 270 spin_lock_irqsave(&c->vc.lock, flags);
284 /* 271 /*
285 * Now that we're holding the lock, check that the vchan 272 * Now that we're holding the lock, check that the vchan
286 * really is associated with this pchan before touching the 273 * really is associated with this pchan before touching the
@@ -294,7 +281,7 @@ static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
294 if (dcsr & DCSR_DONEB) 281 if (dcsr & DCSR_DONEB)
295 sa11x0_dma_complete(p, c); 282 sa11x0_dma_complete(p, c);
296 } 283 }
297 spin_unlock_irqrestore(&c->lock, flags); 284 spin_unlock_irqrestore(&c->vc.lock, flags);
298 } 285 }
299 286
300 return IRQ_HANDLED; 287 return IRQ_HANDLED;
@@ -332,28 +319,15 @@ static void sa11x0_dma_tasklet(unsigned long arg)
332 struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg; 319 struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
333 struct sa11x0_dma_phy *p; 320 struct sa11x0_dma_phy *p;
334 struct sa11x0_dma_chan *c; 321 struct sa11x0_dma_chan *c;
335 struct sa11x0_dma_desc *txd, *txn;
336 LIST_HEAD(head);
337 unsigned pch, pch_alloc = 0; 322 unsigned pch, pch_alloc = 0;
338 323
339 dev_dbg(d->slave.dev, "tasklet enter\n"); 324 dev_dbg(d->slave.dev, "tasklet enter\n");
340 325
341 /* Get the completed tx descriptors */ 326 list_for_each_entry(c, &d->slave.channels, vc.chan.device_node) {
342 spin_lock_irq(&d->lock); 327 spin_lock_irq(&c->vc.lock);
343 list_splice_init(&d->desc_complete, &head);
344 spin_unlock_irq(&d->lock);
345
346 list_for_each_entry(txd, &head, node) {
347 c = to_sa11x0_dma_chan(txd->tx.chan);
348
349 dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
350 c, txd, txd->tx.cookie);
351
352 spin_lock_irq(&c->lock);
353 p = c->phy; 328 p = c->phy;
354 if (p) { 329 if (p && !p->txd_done) {
355 if (!p->txd_done) 330 sa11x0_dma_start_txd(c);
356 sa11x0_dma_start_txd(c);
357 if (!p->txd_done) { 331 if (!p->txd_done) {
358 /* No current txd associated with this channel */ 332 /* No current txd associated with this channel */
359 dev_dbg(d->slave.dev, "pchan %u: free\n", p->num); 333 dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
@@ -363,7 +337,7 @@ static void sa11x0_dma_tasklet(unsigned long arg)
363 p->vchan = NULL; 337 p->vchan = NULL;
364 } 338 }
365 } 339 }
366 spin_unlock_irq(&c->lock); 340 spin_unlock_irq(&c->vc.lock);
367 } 341 }
368 342
369 spin_lock_irq(&d->lock); 343 spin_lock_irq(&d->lock);
@@ -380,7 +354,7 @@ static void sa11x0_dma_tasklet(unsigned long arg)
380 /* Mark this channel allocated */ 354 /* Mark this channel allocated */
381 p->vchan = c; 355 p->vchan = c;
382 356
383 dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c); 357 dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
384 } 358 }
385 } 359 }
386 spin_unlock_irq(&d->lock); 360 spin_unlock_irq(&d->lock);
@@ -390,42 +364,18 @@ static void sa11x0_dma_tasklet(unsigned long arg)
390 p = &d->phy[pch]; 364 p = &d->phy[pch];
391 c = p->vchan; 365 c = p->vchan;
392 366
393 spin_lock_irq(&c->lock); 367 spin_lock_irq(&c->vc.lock);
394 c->phy = p; 368 c->phy = p;
395 369
396 sa11x0_dma_start_txd(c); 370 sa11x0_dma_start_txd(c);
397 spin_unlock_irq(&c->lock); 371 spin_unlock_irq(&c->vc.lock);
398 } 372 }
399 } 373 }
400 374
401 /* Now free the completed tx descriptor, and call their callbacks */
402 list_for_each_entry_safe(txd, txn, &head, node) {
403 dma_async_tx_callback callback = txd->tx.callback;
404 void *callback_param = txd->tx.callback_param;
405
406 dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
407 txd, txd->tx.cookie);
408
409 kfree(txd);
410
411 if (callback)
412 callback(callback_param);
413 }
414
415 dev_dbg(d->slave.dev, "tasklet exit\n"); 375 dev_dbg(d->slave.dev, "tasklet exit\n");
416} 376}
417 377
418 378
419static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
420{
421 struct sa11x0_dma_desc *txd, *txn;
422
423 list_for_each_entry_safe(txd, txn, head, node) {
424 dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
425 kfree(txd);
426 }
427}
428
429static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan) 379static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
430{ 380{
431 return 0; 381 return 0;
@@ -436,18 +386,12 @@ static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
436 struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 386 struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
437 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 387 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
438 unsigned long flags; 388 unsigned long flags;
439 LIST_HEAD(head);
440 389
441 spin_lock_irqsave(&c->lock, flags); 390 spin_lock_irqsave(&d->lock, flags);
442 spin_lock(&d->lock);
443 list_del_init(&c->node); 391 list_del_init(&c->node);
444 spin_unlock(&d->lock); 392 spin_unlock_irqrestore(&d->lock, flags);
445
446 list_splice_tail_init(&c->desc_submitted, &head);
447 list_splice_tail_init(&c->desc_issued, &head);
448 spin_unlock_irqrestore(&c->lock, flags);
449 393
450 sa11x0_dma_desc_free(d, &head); 394 vchan_free_chan_resources(&c->vc);
451} 395}
452 396
453static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p) 397static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
@@ -473,21 +417,15 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
473 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 417 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
474 struct sa11x0_dma_phy *p; 418 struct sa11x0_dma_phy *p;
475 struct sa11x0_dma_desc *txd; 419 struct sa11x0_dma_desc *txd;
476 dma_cookie_t last_used, last_complete;
477 unsigned long flags; 420 unsigned long flags;
478 enum dma_status ret; 421 enum dma_status ret;
479 size_t bytes = 0; 422 size_t bytes = 0;
480 423
481 last_used = c->chan.cookie; 424 ret = dma_cookie_status(&c->vc.chan, cookie, state);
482 last_complete = c->lc; 425 if (ret == DMA_SUCCESS)
483
484 ret = dma_async_is_complete(cookie, last_complete, last_used);
485 if (ret == DMA_SUCCESS) {
486 dma_set_tx_state(state, last_complete, last_used, 0);
487 return ret; 426 return ret;
488 }
489 427
490 spin_lock_irqsave(&c->lock, flags); 428 spin_lock_irqsave(&c->vc.lock, flags);
491 p = c->phy; 429 p = c->phy;
492 ret = c->status; 430 ret = c->status;
493 if (p) { 431 if (p) {
@@ -524,12 +462,13 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
524 if (txd != p->txd_load && p->txd_load) 462 if (txd != p->txd_load && p->txd_load)
525 bytes += p->txd_load->size; 463 bytes += p->txd_load->size;
526 } 464 }
527 list_for_each_entry(txd, &c->desc_issued, node) { 465 list_for_each_entry(txd, &c->vc.desc_issued, vd.node) {
528 bytes += txd->size; 466 bytes += txd->size;
529 } 467 }
530 spin_unlock_irqrestore(&c->lock, flags); 468 spin_unlock_irqrestore(&c->vc.lock, flags);
531 469
532 dma_set_tx_state(state, last_complete, last_used, bytes); 470 if (state)
471 state->residue = bytes;
533 472
534 dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes); 473 dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
535 474
@@ -547,40 +486,20 @@ static void sa11x0_dma_issue_pending(struct dma_chan *chan)
547 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 486 struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
548 unsigned long flags; 487 unsigned long flags;
549 488
550 spin_lock_irqsave(&c->lock, flags); 489 spin_lock_irqsave(&c->vc.lock, flags);
551 list_splice_tail_init(&c->desc_submitted, &c->desc_issued); 490 if (vchan_issue_pending(&c->vc)) {
552 if (!list_empty(&c->desc_issued)) { 491 if (!c->phy) {
553 spin_lock(&d->lock); 492 spin_lock(&d->lock);
554 if (!c->phy && list_empty(&c->node)) { 493 if (list_empty(&c->node)) {
555 list_add_tail(&c->node, &d->chan_pending); 494 list_add_tail(&c->node, &d->chan_pending);
556 tasklet_schedule(&d->task); 495 tasklet_schedule(&d->task);
557 dev_dbg(d->slave.dev, "vchan %p: issued\n", c); 496 dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
497 }
498 spin_unlock(&d->lock);
558 } 499 }
559 spin_unlock(&d->lock);
560 } else 500 } else
561 dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c); 501 dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
562 spin_unlock_irqrestore(&c->lock, flags); 502 spin_unlock_irqrestore(&c->vc.lock, flags);
563}
564
565static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
566{
567 struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
568 struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
569 unsigned long flags;
570
571 spin_lock_irqsave(&c->lock, flags);
572 c->chan.cookie += 1;
573 if (c->chan.cookie < 0)
574 c->chan.cookie = 1;
575 txd->tx.cookie = c->chan.cookie;
576
577 list_add_tail(&txd->node, &c->desc_submitted);
578 spin_unlock_irqrestore(&c->lock, flags);
579
580 dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
581 c, txd, txd->tx.cookie);
582
583 return txd->tx.cookie;
584} 503}
585 504
586static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( 505static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
@@ -596,7 +515,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
596 /* SA11x0 channels can only operate in their native direction */ 515 /* SA11x0 channels can only operate in their native direction */
597 if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) { 516 if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
598 dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n", 517 dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
599 c, c->ddar, dir); 518 &c->vc, c->ddar, dir);
600 return NULL; 519 return NULL;
601 } 520 }
602 521
@@ -612,14 +531,14 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
612 j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1; 531 j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
613 if (addr & DMA_ALIGN) { 532 if (addr & DMA_ALIGN) {
614 dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n", 533 dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
615 c, addr); 534 &c->vc, addr);
616 return NULL; 535 return NULL;
617 } 536 }
618 } 537 }
619 538
620 txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC); 539 txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
621 if (!txd) { 540 if (!txd) {
622 dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c); 541 dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
623 return NULL; 542 return NULL;
624 } 543 }
625 544
@@ -655,17 +574,14 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
655 } while (len); 574 } while (len);
656 } 575 }
657 576
658 dma_async_tx_descriptor_init(&txd->tx, &c->chan);
659 txd->tx.flags = flags;
660 txd->tx.tx_submit = sa11x0_dma_tx_submit;
661 txd->ddar = c->ddar; 577 txd->ddar = c->ddar;
662 txd->size = size; 578 txd->size = size;
663 txd->sglen = j; 579 txd->sglen = j;
664 580
665 dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n", 581 dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
666 c, txd, txd->size, txd->sglen); 582 &c->vc, &txd->vd, txd->size, txd->sglen);
667 583
668 return &txd->tx; 584 return vchan_tx_prep(&c->vc, &txd->vd, flags);
669} 585}
670 586
671static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg) 587static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
@@ -695,8 +611,8 @@ static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_c
695 if (maxburst == 8) 611 if (maxburst == 8)
696 ddar |= DDAR_BS; 612 ddar |= DDAR_BS;
697 613
698 dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n", 614 dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
699 c, addr, width, maxburst); 615 &c->vc, addr, width, maxburst);
700 616
701 c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6; 617 c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
702 618
@@ -718,16 +634,13 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
718 return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg); 634 return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
719 635
720 case DMA_TERMINATE_ALL: 636 case DMA_TERMINATE_ALL:
721 dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c); 637 dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
722 /* Clear the tx descriptor lists */ 638 /* Clear the tx descriptor lists */
723 spin_lock_irqsave(&c->lock, flags); 639 spin_lock_irqsave(&c->vc.lock, flags);
724 list_splice_tail_init(&c->desc_submitted, &head); 640 vchan_get_all_descriptors(&c->vc, &head);
725 list_splice_tail_init(&c->desc_issued, &head);
726 641
727 p = c->phy; 642 p = c->phy;
728 if (p) { 643 if (p) {
729 struct sa11x0_dma_desc *txd, *txn;
730
731 dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num); 644 dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
732 /* vchan is assigned to a pchan - stop the channel */ 645 /* vchan is assigned to a pchan - stop the channel */
733 writel(DCSR_RUN | DCSR_IE | 646 writel(DCSR_RUN | DCSR_IE |
@@ -735,17 +648,13 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
735 DCSR_STRTB | DCSR_DONEB, 648 DCSR_STRTB | DCSR_DONEB,
736 p->base + DMA_DCSR_C); 649 p->base + DMA_DCSR_C);
737 650
738 list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
739 if (txd->tx.chan == &c->chan)
740 list_move(&txd->node, &head);
741
742 if (p->txd_load) { 651 if (p->txd_load) {
743 if (p->txd_load != p->txd_done) 652 if (p->txd_load != p->txd_done)
744 list_add_tail(&p->txd_load->node, &head); 653 list_add_tail(&p->txd_load->vd.node, &head);
745 p->txd_load = NULL; 654 p->txd_load = NULL;
746 } 655 }
747 if (p->txd_done) { 656 if (p->txd_done) {
748 list_add_tail(&p->txd_done->node, &head); 657 list_add_tail(&p->txd_done->vd.node, &head);
749 p->txd_done = NULL; 658 p->txd_done = NULL;
750 } 659 }
751 c->phy = NULL; 660 c->phy = NULL;
@@ -754,14 +663,14 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
754 spin_unlock(&d->lock); 663 spin_unlock(&d->lock);
755 tasklet_schedule(&d->task); 664 tasklet_schedule(&d->task);
756 } 665 }
757 spin_unlock_irqrestore(&c->lock, flags); 666 spin_unlock_irqrestore(&c->vc.lock, flags);
758 sa11x0_dma_desc_free(d, &head); 667 vchan_dma_desc_free_list(&c->vc, &head);
759 ret = 0; 668 ret = 0;
760 break; 669 break;
761 670
762 case DMA_PAUSE: 671 case DMA_PAUSE:
763 dev_dbg(d->slave.dev, "vchan %p: pause\n", c); 672 dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
764 spin_lock_irqsave(&c->lock, flags); 673 spin_lock_irqsave(&c->vc.lock, flags);
765 if (c->status == DMA_IN_PROGRESS) { 674 if (c->status == DMA_IN_PROGRESS) {
766 c->status = DMA_PAUSED; 675 c->status = DMA_PAUSED;
767 676
@@ -774,26 +683,26 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
774 spin_unlock(&d->lock); 683 spin_unlock(&d->lock);
775 } 684 }
776 } 685 }
777 spin_unlock_irqrestore(&c->lock, flags); 686 spin_unlock_irqrestore(&c->vc.lock, flags);
778 ret = 0; 687 ret = 0;
779 break; 688 break;
780 689
781 case DMA_RESUME: 690 case DMA_RESUME:
782 dev_dbg(d->slave.dev, "vchan %p: resume\n", c); 691 dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
783 spin_lock_irqsave(&c->lock, flags); 692 spin_lock_irqsave(&c->vc.lock, flags);
784 if (c->status == DMA_PAUSED) { 693 if (c->status == DMA_PAUSED) {
785 c->status = DMA_IN_PROGRESS; 694 c->status = DMA_IN_PROGRESS;
786 695
787 p = c->phy; 696 p = c->phy;
788 if (p) { 697 if (p) {
789 writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S); 698 writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
790 } else if (!list_empty(&c->desc_issued)) { 699 } else if (!list_empty(&c->vc.desc_issued)) {
791 spin_lock(&d->lock); 700 spin_lock(&d->lock);
792 list_add_tail(&c->node, &d->chan_pending); 701 list_add_tail(&c->node, &d->chan_pending);
793 spin_unlock(&d->lock); 702 spin_unlock(&d->lock);
794 } 703 }
795 } 704 }
796 spin_unlock_irqrestore(&c->lock, flags); 705 spin_unlock_irqrestore(&c->vc.lock, flags);
797 ret = 0; 706 ret = 0;
798 break; 707 break;
799 708
@@ -853,15 +762,13 @@ static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
853 return -ENOMEM; 762 return -ENOMEM;
854 } 763 }
855 764
856 c->chan.device = dmadev;
857 c->status = DMA_IN_PROGRESS; 765 c->status = DMA_IN_PROGRESS;
858 c->ddar = chan_desc[i].ddar; 766 c->ddar = chan_desc[i].ddar;
859 c->name = chan_desc[i].name; 767 c->name = chan_desc[i].name;
860 spin_lock_init(&c->lock);
861 INIT_LIST_HEAD(&c->desc_submitted);
862 INIT_LIST_HEAD(&c->desc_issued);
863 INIT_LIST_HEAD(&c->node); 768 INIT_LIST_HEAD(&c->node);
864 list_add_tail(&c->chan.device_node, &dmadev->channels); 769
770 c->vc.desc_free = sa11x0_dma_free_desc;
771 vchan_init(&c->vc, dmadev);
865 } 772 }
866 773
867 return dma_async_device_register(dmadev); 774 return dma_async_device_register(dmadev);
@@ -890,8 +797,9 @@ static void sa11x0_dma_free_channels(struct dma_device *dmadev)
890{ 797{
891 struct sa11x0_dma_chan *c, *cn; 798 struct sa11x0_dma_chan *c, *cn;
892 799
893 list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) { 800 list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
894 list_del(&c->chan.device_node); 801 list_del(&c->vc.chan.device_node);
802 tasklet_kill(&c->vc.task);
895 kfree(c); 803 kfree(c);
896 } 804 }
897} 805}
@@ -915,7 +823,6 @@ static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
915 823
916 spin_lock_init(&d->lock); 824 spin_lock_init(&d->lock);
917 INIT_LIST_HEAD(&d->chan_pending); 825 INIT_LIST_HEAD(&d->chan_pending);
918 INIT_LIST_HEAD(&d->desc_complete);
919 826
920 d->base = ioremap(res->start, resource_size(res)); 827 d->base = ioremap(res->start, resource_size(res));
921 if (!d->base) { 828 if (!d->base) {
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
new file mode 100644
index 000000000000..bd85b052b481
--- /dev/null
+++ b/drivers/dma/virt-dma.c
@@ -0,0 +1,99 @@
1/*
2 * Virtual DMA channel support for DMAengine
3 *
4 * Copyright (C) 2012 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/device.h>
11#include <linux/dmaengine.h>
12#include <linux/module.h>
13#include <linux/spinlock.h>
14
15#include "virt-dma.h"
16
17static struct virt_dma_desc *to_virt_desc(struct dma_async_tx_descriptor *tx)
18{
19 return container_of(tx, struct virt_dma_desc, tx);
20}
21
22dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
23{
24 struct virt_dma_chan *vc = to_virt_chan(tx->chan);
25 struct virt_dma_desc *vd = to_virt_desc(tx);
26 unsigned long flags;
27 dma_cookie_t cookie;
28
29 spin_lock_irqsave(&vc->lock, flags);
30 cookie = dma_cookie_assign(tx);
31
32 list_add_tail(&vd->node, &vc->desc_submitted);
33 spin_unlock_irqrestore(&vc->lock, flags);
34
35 dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
36 vc, vd, cookie);
37
38 return cookie;
39}
40EXPORT_SYMBOL_GPL(vchan_tx_submit);
41
42/*
43 * This tasklet handles the completion of a DMA descriptor by
44 * calling its callback and freeing it.
45 */
46static void vchan_complete(unsigned long arg)
47{
48 struct virt_dma_chan *vc = (struct virt_dma_chan *)arg;
49 LIST_HEAD(head);
50
51 spin_lock_irq(&vc->lock);
52 list_splice_tail_init(&vc->desc_completed, &head);
53 spin_unlock_irq(&vc->lock);
54
55 while (!list_empty(&head)) {
56 struct virt_dma_desc *vd = list_first_entry(&head,
57 struct virt_dma_desc, node);
58 dma_async_tx_callback cb = vd->tx.callback;
59 void *cb_data = vd->tx.callback_param;
60
61 list_del(&vd->node);
62
63 vc->desc_free(vd);
64
65 if (cb)
66 cb(cb_data);
67 }
68}
69
70void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
71{
72 while (!list_empty(head)) {
73 struct virt_dma_desc *vd = list_first_entry(head,
74 struct virt_dma_desc, node);
75 list_del(&vd->node);
76 dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
77 vc->desc_free(vd);
78 }
79}
80EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
81
82void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
83{
84 dma_cookie_init(&vc->chan);
85
86 spin_lock_init(&vc->lock);
87 INIT_LIST_HEAD(&vc->desc_submitted);
88 INIT_LIST_HEAD(&vc->desc_issued);
89 INIT_LIST_HEAD(&vc->desc_completed);
90
91 tasklet_init(&vc->task, vchan_complete, (unsigned long)vc);
92
93 vc->chan.device = dmadev;
94 list_add_tail(&vc->chan.device_node, &dmadev->channels);
95}
96EXPORT_SYMBOL_GPL(vchan_init);
97
98MODULE_AUTHOR("Russell King");
99MODULE_LICENSE("GPL");
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
new file mode 100644
index 000000000000..825bb9623175
--- /dev/null
+++ b/drivers/dma/virt-dma.h
@@ -0,0 +1,138 @@
1/*
2 * Virtual DMA channel support for DMAengine
3 *
4 * Copyright (C) 2012 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#ifndef VIRT_DMA_H
11#define VIRT_DMA_H
12
13#include <linux/dmaengine.h>
14#include <linux/interrupt.h>
15
16#include "dmaengine.h"
17
18struct virt_dma_desc {
19 struct dma_async_tx_descriptor tx;
20 /* protected by vc.lock */
21 struct list_head node;
22};
23
24struct virt_dma_chan {
25 struct dma_chan chan;
26 struct tasklet_struct task;
27 void (*desc_free)(struct virt_dma_desc *);
28
29 spinlock_t lock;
30
31 /* protected by vc.lock */
32 struct list_head desc_submitted;
33 struct list_head desc_issued;
34 struct list_head desc_completed;
35};
36
37static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
38{
39 return container_of(chan, struct virt_dma_chan, chan);
40}
41
42void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head);
43
44void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev);
45
46/**
47 * vchan_tx_prep - prepare a descriptor
48 * vc: virtual channel allocating this descriptor
49 * vd: virtual descriptor to prepare
50 * tx_flags: flags argument passed in to prepare function
51 */
52static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan *vc,
53 struct virt_dma_desc *vd, unsigned long tx_flags)
54{
55 extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
56
57 dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
58 vd->tx.flags = tx_flags;
59 vd->tx.tx_submit = vchan_tx_submit;
60
61 return &vd->tx;
62}
63
64/**
65 * vchan_issue_pending - move submitted descriptors to issued list
66 * vc: virtual channel to update
67 *
68 * vc.lock must be held by caller
69 */
70static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
71{
72 list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued);
73 return !list_empty(&vc->desc_issued);
74}
75
76/**
77 * vchan_cookie_complete - report completion of a descriptor
78 * vd: virtual descriptor to update
79 *
80 * vc.lock must be held by caller
81 */
82static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
83{
84 struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
85
86 dma_cookie_complete(&vd->tx);
87 dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
88 vd, vd->tx.cookie);
89 list_add_tail(&vd->node, &vc->desc_completed);
90
91 tasklet_schedule(&vc->task);
92}
93
94/**
95 * vchan_next_desc - peek at the next descriptor to be processed
96 * vc: virtual channel to obtain descriptor from
97 *
98 * vc.lock must be held by caller
99 */
100static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
101{
102 if (list_empty(&vc->desc_issued))
103 return NULL;
104
105 return list_first_entry(&vc->desc_issued, struct virt_dma_desc, node);
106}
107
108/**
109 * vchan_get_all_descriptors - obtain all submitted and issued descriptors
110 * vc: virtual channel to get descriptors from
111 * head: list of descriptors found
112 *
113 * vc.lock must be held by caller
114 *
115 * Removes all submitted and issued descriptors from internal lists, and
116 * provides a list of all descriptors found
117 */
118static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
119 struct list_head *head)
120{
121 list_splice_tail_init(&vc->desc_submitted, head);
122 list_splice_tail_init(&vc->desc_issued, head);
123 list_splice_tail_init(&vc->desc_completed, head);
124}
125
126static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
127{
128 unsigned long flags;
129 LIST_HEAD(head);
130
131 spin_lock_irqsave(&vc->lock, flags);
132 vchan_get_all_descriptors(vc, &head);
133 spin_unlock_irqrestore(&vc->lock, flags);
134
135 vchan_dma_desc_free_list(vc, &head);
136}
137
138#endif