aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2016-07-20 04:50:32 -0400
committerVinod Koul <vinod.koul@intel.com>2016-08-10 13:29:13 -0400
commit1c2e8e6b6429688e6b1096db1a89a60faaa6d8dc (patch)
tree3eecc7c4eab678e3da49696126dfe056019b26d7
parentcb7958dfa9bc4a69f94eaa8bbc9d21a291a2a560 (diff)
dmaengine: omap-dma: Support for LinkedList transfer of slave_sg
sDMA in OMAP3630 or newer SoC have support for LinkedList transfer. When LinkedList or Descriptor load feature is present we can create the descriptors for each and program sDMA to walk through the list of descriptors instead of the current way of sDMA stop, sDMA reconfiguration and sDMA start after each SG transfer. By using LinkedList transfer in sDMA the number of DMA interrupts will decrease dramatically. Booting up the board with filesystem on SD card for example: W/o LinkedList support: 27: 4436 0 WUGEN 13 Level omap-dma-engine Same board/filesystem with this patch: 27: 1027 0 WUGEN 13 Level omap-dma-engine Or copying files from SD card to eMCC: 2.1G /usr/ 232001 W/o LinkedList we see ~761069 DMA interrupts. With LinkedList support it is down to ~269314 DMA interrupts. With the decreased DMA interrupt number the CPU load is dropping significantly as well. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/omap-dma.c183
1 files changed, 177 insertions, 6 deletions
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 6e8e28955ca6..aef52011d7c0 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -8,6 +8,7 @@
8#include <linux/delay.h> 8#include <linux/delay.h>
9#include <linux/dmaengine.h> 9#include <linux/dmaengine.h>
10#include <linux/dma-mapping.h> 10#include <linux/dma-mapping.h>
11#include <linux/dmapool.h>
11#include <linux/err.h> 12#include <linux/err.h>
12#include <linux/init.h> 13#include <linux/init.h>
13#include <linux/interrupt.h> 14#include <linux/interrupt.h>
@@ -32,6 +33,8 @@ struct omap_dmadev {
32 const struct omap_dma_reg *reg_map; 33 const struct omap_dma_reg *reg_map;
33 struct omap_system_dma_plat_info *plat; 34 struct omap_system_dma_plat_info *plat;
34 bool legacy; 35 bool legacy;
36 bool ll123_supported;
37 struct dma_pool *desc_pool;
35 unsigned dma_requests; 38 unsigned dma_requests;
36 spinlock_t irq_lock; 39 spinlock_t irq_lock;
37 uint32_t irq_enable_mask; 40 uint32_t irq_enable_mask;
@@ -55,16 +58,40 @@ struct omap_chan {
55 unsigned sgidx; 58 unsigned sgidx;
56}; 59};
57 60
61#define DESC_NXT_SV_REFRESH (0x1 << 24)
62#define DESC_NXT_SV_REUSE (0x2 << 24)
63#define DESC_NXT_DV_REFRESH (0x1 << 26)
64#define DESC_NXT_DV_REUSE (0x2 << 26)
65#define DESC_NTYPE_TYPE2 (0x2 << 29)
66
67/* Type 2 descriptor with Source or Destination address update */
68struct omap_type2_desc {
69 uint32_t next_desc;
70 uint32_t en;
71 uint32_t addr; /* src or dst */
72 uint16_t fn;
73 uint16_t cicr;
74 uint16_t cdei;
75 uint16_t csei;
76 uint32_t cdfi;
77 uint32_t csfi;
78} __packed;
79
58struct omap_sg { 80struct omap_sg {
59 dma_addr_t addr; 81 dma_addr_t addr;
60 uint32_t en; /* number of elements (24-bit) */ 82 uint32_t en; /* number of elements (24-bit) */
61 uint32_t fn; /* number of frames (16-bit) */ 83 uint32_t fn; /* number of frames (16-bit) */
62 int32_t fi; /* for double indexing */ 84 int32_t fi; /* for double indexing */
63 int16_t ei; /* for double indexing */ 85 int16_t ei; /* for double indexing */
86
87 /* Linked list */
88 struct omap_type2_desc *t2_desc;
89 dma_addr_t t2_desc_paddr;
64}; 90};
65 91
66struct omap_desc { 92struct omap_desc {
67 struct virt_dma_desc vd; 93 struct virt_dma_desc vd;
94 bool using_ll;
68 enum dma_transfer_direction dir; 95 enum dma_transfer_direction dir;
69 dma_addr_t dev_addr; 96 dma_addr_t dev_addr;
70 97
@@ -81,6 +108,9 @@ struct omap_desc {
81}; 108};
82 109
83enum { 110enum {
111 CAPS_0_SUPPORT_LL123 = BIT(20), /* Linked List type1/2/3 */
112 CAPS_0_SUPPORT_LL4 = BIT(21), /* Linked List type4 */
113
84 CCR_FS = BIT(5), 114 CCR_FS = BIT(5),
85 CCR_READ_PRIORITY = BIT(6), 115 CCR_READ_PRIORITY = BIT(6),
86 CCR_ENABLE = BIT(7), 116 CCR_ENABLE = BIT(7),
@@ -151,6 +181,19 @@ enum {
151 CICR_SUPER_BLOCK_IE = BIT(14), /* OMAP2+ only */ 181 CICR_SUPER_BLOCK_IE = BIT(14), /* OMAP2+ only */
152 182
153 CLNK_CTRL_ENABLE_LNK = BIT(15), 183 CLNK_CTRL_ENABLE_LNK = BIT(15),
184
185 CDP_DST_VALID_INC = 0 << 0,
186 CDP_DST_VALID_RELOAD = 1 << 0,
187 CDP_DST_VALID_REUSE = 2 << 0,
188 CDP_SRC_VALID_INC = 0 << 2,
189 CDP_SRC_VALID_RELOAD = 1 << 2,
190 CDP_SRC_VALID_REUSE = 2 << 2,
191 CDP_NTYPE_TYPE1 = 1 << 4,
192 CDP_NTYPE_TYPE2 = 2 << 4,
193 CDP_NTYPE_TYPE3 = 3 << 4,
194 CDP_TMODE_NORMAL = 0 << 8,
195 CDP_TMODE_LLIST = 1 << 8,
196 CDP_FAST = BIT(10),
154}; 197};
155 198
156static const unsigned es_bytes[] = { 199static const unsigned es_bytes[] = {
@@ -180,7 +223,64 @@ static inline struct omap_desc *to_omap_dma_desc(struct dma_async_tx_descriptor
180 223
181static void omap_dma_desc_free(struct virt_dma_desc *vd) 224static void omap_dma_desc_free(struct virt_dma_desc *vd)
182{ 225{
183 kfree(container_of(vd, struct omap_desc, vd)); 226 struct omap_desc *d = to_omap_dma_desc(&vd->tx);
227
228 if (d->using_ll) {
229 struct omap_dmadev *od = to_omap_dma_dev(vd->tx.chan->device);
230 int i;
231
232 for (i = 0; i < d->sglen; i++) {
233 if (d->sg[i].t2_desc)
234 dma_pool_free(od->desc_pool, d->sg[i].t2_desc,
235 d->sg[i].t2_desc_paddr);
236 }
237 }
238
239 kfree(d);
240}
241
242static void omap_dma_fill_type2_desc(struct omap_desc *d, int idx,
243 enum dma_transfer_direction dir, bool last)
244{
245 struct omap_sg *sg = &d->sg[idx];
246 struct omap_type2_desc *t2_desc = sg->t2_desc;
247
248 if (idx)
249 d->sg[idx - 1].t2_desc->next_desc = sg->t2_desc_paddr;
250 if (last)
251 t2_desc->next_desc = 0xfffffffc;
252
253 t2_desc->en = sg->en;
254 t2_desc->addr = sg->addr;
255 t2_desc->fn = sg->fn & 0xffff;
256 t2_desc->cicr = d->cicr;
257 if (!last)
258 t2_desc->cicr &= ~CICR_BLOCK_IE;
259
260 switch (dir) {
261 case DMA_DEV_TO_MEM:
262 t2_desc->cdei = sg->ei;
263 t2_desc->csei = d->ei;
264 t2_desc->cdfi = sg->fi;
265 t2_desc->csfi = d->fi;
266
267 t2_desc->en |= DESC_NXT_DV_REFRESH;
268 t2_desc->en |= DESC_NXT_SV_REUSE;
269 break;
270 case DMA_MEM_TO_DEV:
271 t2_desc->cdei = d->ei;
272 t2_desc->csei = sg->ei;
273 t2_desc->cdfi = d->fi;
274 t2_desc->csfi = sg->fi;
275
276 t2_desc->en |= DESC_NXT_SV_REFRESH;
277 t2_desc->en |= DESC_NXT_DV_REUSE;
278 break;
279 default:
280 return;
281 }
282
283 t2_desc->en |= DESC_NTYPE_TYPE2;
184} 284}
185 285
186static void omap_dma_write(uint32_t val, unsigned type, void __iomem *addr) 286static void omap_dma_write(uint32_t val, unsigned type, void __iomem *addr)
@@ -285,6 +385,7 @@ static void omap_dma_assign(struct omap_dmadev *od, struct omap_chan *c,
285static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) 385static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
286{ 386{
287 struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); 387 struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
388 uint16_t cicr = d->cicr;
288 389
289 if (__dma_omap15xx(od->plat->dma_attr)) 390 if (__dma_omap15xx(od->plat->dma_attr))
290 omap_dma_chan_write(c, CPC, 0); 391 omap_dma_chan_write(c, CPC, 0);
@@ -293,8 +394,27 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
293 394
294 omap_dma_clear_csr(c); 395 omap_dma_clear_csr(c);
295 396
397 if (d->using_ll) {
398 uint32_t cdp = CDP_TMODE_LLIST | CDP_NTYPE_TYPE2 | CDP_FAST;
399
400 if (d->dir == DMA_DEV_TO_MEM)
401 cdp |= (CDP_DST_VALID_RELOAD | CDP_SRC_VALID_REUSE);
402 else
403 cdp |= (CDP_DST_VALID_REUSE | CDP_SRC_VALID_RELOAD);
404 omap_dma_chan_write(c, CDP, cdp);
405
406 omap_dma_chan_write(c, CNDP, d->sg[0].t2_desc_paddr);
407 omap_dma_chan_write(c, CCDN, 0);
408 omap_dma_chan_write(c, CCFN, 0xffff);
409 omap_dma_chan_write(c, CCEN, 0xffffff);
410
411 cicr &= ~CICR_BLOCK_IE;
412 } else if (od->ll123_supported) {
413 omap_dma_chan_write(c, CDP, 0);
414 }
415
296 /* Enable interrupts */ 416 /* Enable interrupts */
297 omap_dma_chan_write(c, CICR, d->cicr); 417 omap_dma_chan_write(c, CICR, cicr);
298 418
299 /* Enable channel */ 419 /* Enable channel */
300 omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE); 420 omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
@@ -447,7 +567,7 @@ static void omap_dma_callback(int ch, u16 status, void *data)
447 if (d) { 567 if (d) {
448 if (c->cyclic) { 568 if (c->cyclic) {
449 vchan_cyclic_callback(&d->vd); 569 vchan_cyclic_callback(&d->vd);
450 } else if (c->sgidx == d->sglen) { 570 } else if (d->using_ll || c->sgidx == d->sglen) {
451 omap_dma_start_desc(c); 571 omap_dma_start_desc(c);
452 vchan_cookie_complete(&d->vd); 572 vchan_cookie_complete(&d->vd);
453 } else { 573 } else {
@@ -501,6 +621,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
501{ 621{
502 struct omap_dmadev *od = to_omap_dma_dev(chan->device); 622 struct omap_dmadev *od = to_omap_dma_dev(chan->device);
503 struct omap_chan *c = to_omap_dma_chan(chan); 623 struct omap_chan *c = to_omap_dma_chan(chan);
624 struct device *dev = od->ddev.dev;
504 int ret; 625 int ret;
505 626
506 if (od->legacy) { 627 if (od->legacy) {
@@ -511,8 +632,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
511 &c->dma_ch); 632 &c->dma_ch);
512 } 633 }
513 634
514 dev_dbg(od->ddev.dev, "allocating channel %u for %u\n", 635 dev_dbg(dev, "allocating channel %u for %u\n", c->dma_ch, c->dma_sig);
515 c->dma_ch, c->dma_sig);
516 636
517 if (ret >= 0) { 637 if (ret >= 0) {
518 omap_dma_assign(od, c, c->dma_ch); 638 omap_dma_assign(od, c, c->dma_ch);
@@ -743,6 +863,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
743 struct omap_desc *d; 863 struct omap_desc *d;
744 dma_addr_t dev_addr; 864 dma_addr_t dev_addr;
745 unsigned i, es, en, frame_bytes; 865 unsigned i, es, en, frame_bytes;
866 bool ll_failed = false;
746 u32 burst; 867 u32 burst;
747 868
748 if (dir == DMA_DEV_TO_MEM) { 869 if (dir == DMA_DEV_TO_MEM) {
@@ -818,16 +939,47 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
818 */ 939 */
819 en = burst; 940 en = burst;
820 frame_bytes = es_bytes[es] * en; 941 frame_bytes = es_bytes[es] * en;
942
943 if (sglen >= 2)
944 d->using_ll = od->ll123_supported;
945
821 for_each_sg(sgl, sgent, sglen, i) { 946 for_each_sg(sgl, sgent, sglen, i) {
822 struct omap_sg *osg = &d->sg[i]; 947 struct omap_sg *osg = &d->sg[i];
823 948
824 osg->addr = sg_dma_address(sgent); 949 osg->addr = sg_dma_address(sgent);
825 osg->en = en; 950 osg->en = en;
826 osg->fn = sg_dma_len(sgent) / frame_bytes; 951 osg->fn = sg_dma_len(sgent) / frame_bytes;
952
953 if (d->using_ll) {
954 osg->t2_desc = dma_pool_alloc(od->desc_pool, GFP_ATOMIC,
955 &osg->t2_desc_paddr);
956 if (!osg->t2_desc) {
957 dev_err(chan->device->dev,
958 "t2_desc[%d] allocation failed\n", i);
959 ll_failed = true;
960 d->using_ll = false;
961 continue;
962 }
963
964 omap_dma_fill_type2_desc(d, i, dir, (i == sglen - 1));
965 }
827 } 966 }
828 967
829 d->sglen = sglen; 968 d->sglen = sglen;
830 969
970 /* Release the dma_pool entries if one allocation failed */
971 if (ll_failed) {
972 for (i = 0; i < d->sglen; i++) {
973 struct omap_sg *osg = &d->sg[i];
974
975 if (osg->t2_desc) {
976 dma_pool_free(od->desc_pool, osg->t2_desc,
977 osg->t2_desc_paddr);
978 osg->t2_desc = NULL;
979 }
980 }
981 }
982
831 return vchan_tx_prep(&c->vc, &d->vd, tx_flags); 983 return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
832} 984}
833 985
@@ -1266,10 +1418,25 @@ static int omap_dma_probe(struct platform_device *pdev)
1266 return rc; 1418 return rc;
1267 } 1419 }
1268 1420
1421 if (omap_dma_glbl_read(od, CAPS_0) & CAPS_0_SUPPORT_LL123)
1422 od->ll123_supported = true;
1423
1269 od->ddev.filter.map = od->plat->slave_map; 1424 od->ddev.filter.map = od->plat->slave_map;
1270 od->ddev.filter.mapcnt = od->plat->slavecnt; 1425 od->ddev.filter.mapcnt = od->plat->slavecnt;
1271 od->ddev.filter.fn = omap_dma_filter_fn; 1426 od->ddev.filter.fn = omap_dma_filter_fn;
1272 1427
1428 if (od->ll123_supported) {
1429 od->desc_pool = dma_pool_create(dev_name(&pdev->dev),
1430 &pdev->dev,
1431 sizeof(struct omap_type2_desc),
1432 4, 0);
1433 if (!od->desc_pool) {
1434 dev_err(&pdev->dev,
1435 "unable to allocate descriptor pool\n");
1436 od->ll123_supported = false;
1437 }
1438 }
1439
1273 rc = dma_async_device_register(&od->ddev); 1440 rc = dma_async_device_register(&od->ddev);
1274 if (rc) { 1441 if (rc) {
1275 pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n", 1442 pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n",
@@ -1293,7 +1460,8 @@ static int omap_dma_probe(struct platform_device *pdev)
1293 } 1460 }
1294 } 1461 }
1295 1462
1296 dev_info(&pdev->dev, "OMAP DMA engine driver\n"); 1463 dev_info(&pdev->dev, "OMAP DMA engine driver%s\n",
1464 od->ll123_supported ? " (LinkedList1/2/3 supported)" : "");
1297 1465
1298 return rc; 1466 return rc;
1299} 1467}
@@ -1316,6 +1484,9 @@ static int omap_dma_remove(struct platform_device *pdev)
1316 omap_dma_glbl_write(od, IRQENABLE_L0, 0); 1484 omap_dma_glbl_write(od, IRQENABLE_L0, 0);
1317 } 1485 }
1318 1486
1487 if (od->ll123_supported)
1488 dma_pool_destroy(od->desc_pool);
1489
1319 omap_dma_free(od); 1490 omap_dma_free(od);
1320 1491
1321 return 0; 1492 return 0;