diff options
| -rw-r--r-- | drivers/dma/omap-dma.c | 78 |
1 files changed, 14 insertions, 64 deletions
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 48f77c289cd3..9794b073d7d7 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c | |||
| @@ -28,8 +28,6 @@ | |||
| 28 | struct omap_dmadev { | 28 | struct omap_dmadev { |
| 29 | struct dma_device ddev; | 29 | struct dma_device ddev; |
| 30 | spinlock_t lock; | 30 | spinlock_t lock; |
| 31 | struct tasklet_struct task; | ||
| 32 | struct list_head pending; | ||
| 33 | void __iomem *base; | 31 | void __iomem *base; |
| 34 | const struct omap_dma_reg *reg_map; | 32 | const struct omap_dma_reg *reg_map; |
| 35 | struct omap_system_dma_plat_info *plat; | 33 | struct omap_system_dma_plat_info *plat; |
| @@ -42,7 +40,6 @@ struct omap_dmadev { | |||
| 42 | 40 | ||
| 43 | struct omap_chan { | 41 | struct omap_chan { |
| 44 | struct virt_dma_chan vc; | 42 | struct virt_dma_chan vc; |
| 45 | struct list_head node; | ||
| 46 | void __iomem *channel_base; | 43 | void __iomem *channel_base; |
| 47 | const struct omap_dma_reg *reg_map; | 44 | const struct omap_dma_reg *reg_map; |
| 48 | uint32_t ccr; | 45 | uint32_t ccr; |
| @@ -454,33 +451,6 @@ static void omap_dma_callback(int ch, u16 status, void *data) | |||
| 454 | spin_unlock_irqrestore(&c->vc.lock, flags); | 451 | spin_unlock_irqrestore(&c->vc.lock, flags); |
| 455 | } | 452 | } |
| 456 | 453 | ||
| 457 | /* | ||
| 458 | * This callback schedules all pending channels. We could be more | ||
| 459 | * clever here by postponing allocation of the real DMA channels to | ||
| 460 | * this point, and freeing them when our virtual channel becomes idle. | ||
| 461 | * | ||
| 462 | * We would then need to deal with 'all channels in-use' | ||
| 463 | */ | ||
| 464 | static void omap_dma_sched(unsigned long data) | ||
| 465 | { | ||
| 466 | struct omap_dmadev *d = (struct omap_dmadev *)data; | ||
| 467 | LIST_HEAD(head); | ||
| 468 | |||
| 469 | spin_lock_irq(&d->lock); | ||
| 470 | list_splice_tail_init(&d->pending, &head); | ||
| 471 | spin_unlock_irq(&d->lock); | ||
| 472 | |||
| 473 | while (!list_empty(&head)) { | ||
| 474 | struct omap_chan *c = list_first_entry(&head, | ||
| 475 | struct omap_chan, node); | ||
| 476 | |||
| 477 | spin_lock_irq(&c->vc.lock); | ||
| 478 | list_del_init(&c->node); | ||
| 479 | omap_dma_start_desc(c); | ||
| 480 | spin_unlock_irq(&c->vc.lock); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | static irqreturn_t omap_dma_irq(int irq, void *devid) | 454 | static irqreturn_t omap_dma_irq(int irq, void *devid) |
| 485 | { | 455 | { |
| 486 | struct omap_dmadev *od = devid; | 456 | struct omap_dmadev *od = devid; |
| @@ -703,8 +673,14 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, | |||
| 703 | struct omap_chan *c = to_omap_dma_chan(chan); | 673 | struct omap_chan *c = to_omap_dma_chan(chan); |
| 704 | struct virt_dma_desc *vd; | 674 | struct virt_dma_desc *vd; |
| 705 | enum dma_status ret; | 675 | enum dma_status ret; |
| 676 | uint32_t ccr; | ||
| 706 | unsigned long flags; | 677 | unsigned long flags; |
| 707 | 678 | ||
| 679 | ccr = omap_dma_chan_read(c, CCR); | ||
| 680 | /* The channel is no longer active, handle the completion right away */ | ||
| 681 | if (!(ccr & CCR_ENABLE)) | ||
| 682 | omap_dma_callback(c->dma_ch, 0, c); | ||
| 683 | |||
| 708 | ret = dma_cookie_status(chan, cookie, txstate); | 684 | ret = dma_cookie_status(chan, cookie, txstate); |
| 709 | if (ret == DMA_COMPLETE || !txstate) | 685 | if (ret == DMA_COMPLETE || !txstate) |
| 710 | return ret; | 686 | return ret; |
| @@ -719,7 +695,7 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, | |||
| 719 | 695 | ||
| 720 | if (d->dir == DMA_MEM_TO_DEV) | 696 | if (d->dir == DMA_MEM_TO_DEV) |
| 721 | pos = omap_dma_get_src_pos(c); | 697 | pos = omap_dma_get_src_pos(c); |
| 722 | else if (d->dir == DMA_DEV_TO_MEM) | 698 | else if (d->dir == DMA_DEV_TO_MEM || d->dir == DMA_MEM_TO_MEM) |
| 723 | pos = omap_dma_get_dst_pos(c); | 699 | pos = omap_dma_get_dst_pos(c); |
| 724 | else | 700 | else |
| 725 | pos = 0; | 701 | pos = 0; |
| @@ -739,22 +715,8 @@ static void omap_dma_issue_pending(struct dma_chan *chan) | |||
| 739 | unsigned long flags; | 715 | unsigned long flags; |
| 740 | 716 | ||
| 741 | spin_lock_irqsave(&c->vc.lock, flags); | 717 | spin_lock_irqsave(&c->vc.lock, flags); |
| 742 | if (vchan_issue_pending(&c->vc) && !c->desc) { | 718 | if (vchan_issue_pending(&c->vc) && !c->desc) |
| 743 | /* | 719 | omap_dma_start_desc(c); |
| 744 | * c->cyclic is used only by audio and in this case the DMA need | ||
| 745 | * to be started without delay. | ||
| 746 | */ | ||
| 747 | if (!c->cyclic) { | ||
| 748 | struct omap_dmadev *d = to_omap_dma_dev(chan->device); | ||
| 749 | spin_lock(&d->lock); | ||
| 750 | if (list_empty(&c->node)) | ||
| 751 | list_add_tail(&c->node, &d->pending); | ||
| 752 | spin_unlock(&d->lock); | ||
| 753 | tasklet_schedule(&d->task); | ||
| 754 | } else { | ||
| 755 | omap_dma_start_desc(c); | ||
| 756 | } | ||
| 757 | } | ||
| 758 | spin_unlock_irqrestore(&c->vc.lock, flags); | 720 | spin_unlock_irqrestore(&c->vc.lock, flags); |
| 759 | } | 721 | } |
| 760 | 722 | ||
| @@ -768,7 +730,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( | |||
| 768 | struct scatterlist *sgent; | 730 | struct scatterlist *sgent; |
| 769 | struct omap_desc *d; | 731 | struct omap_desc *d; |
| 770 | dma_addr_t dev_addr; | 732 | dma_addr_t dev_addr; |
| 771 | unsigned i, j = 0, es, en, frame_bytes; | 733 | unsigned i, es, en, frame_bytes; |
| 772 | u32 burst; | 734 | u32 burst; |
| 773 | 735 | ||
| 774 | if (dir == DMA_DEV_TO_MEM) { | 736 | if (dir == DMA_DEV_TO_MEM) { |
| @@ -845,13 +807,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( | |||
| 845 | en = burst; | 807 | en = burst; |
| 846 | frame_bytes = es_bytes[es] * en; | 808 | frame_bytes = es_bytes[es] * en; |
| 847 | for_each_sg(sgl, sgent, sglen, i) { | 809 | for_each_sg(sgl, sgent, sglen, i) { |
| 848 | d->sg[j].addr = sg_dma_address(sgent); | 810 | d->sg[i].addr = sg_dma_address(sgent); |
| 849 | d->sg[j].en = en; | 811 | d->sg[i].en = en; |
| 850 | d->sg[j].fn = sg_dma_len(sgent) / frame_bytes; | 812 | d->sg[i].fn = sg_dma_len(sgent) / frame_bytes; |
| 851 | j++; | ||
| 852 | } | 813 | } |
| 853 | 814 | ||
| 854 | d->sglen = j; | 815 | d->sglen = sglen; |
| 855 | 816 | ||
| 856 | return vchan_tx_prep(&c->vc, &d->vd, tx_flags); | 817 | return vchan_tx_prep(&c->vc, &d->vd, tx_flags); |
| 857 | } | 818 | } |
| @@ -1018,17 +979,11 @@ static int omap_dma_slave_config(struct dma_chan *chan, struct dma_slave_config | |||
| 1018 | static int omap_dma_terminate_all(struct dma_chan *chan) | 979 | static int omap_dma_terminate_all(struct dma_chan *chan) |
| 1019 | { | 980 | { |
| 1020 | struct omap_chan *c = to_omap_dma_chan(chan); | 981 | struct omap_chan *c = to_omap_dma_chan(chan); |
| 1021 | struct omap_dmadev *d = to_omap_dma_dev(c->vc.chan.device); | ||
| 1022 | unsigned long flags; | 982 | unsigned long flags; |
| 1023 | LIST_HEAD(head); | 983 | LIST_HEAD(head); |
| 1024 | 984 | ||
| 1025 | spin_lock_irqsave(&c->vc.lock, flags); | 985 | spin_lock_irqsave(&c->vc.lock, flags); |
| 1026 | 986 | ||
| 1027 | /* Prevent this channel being scheduled */ | ||
| 1028 | spin_lock(&d->lock); | ||
| 1029 | list_del_init(&c->node); | ||
| 1030 | spin_unlock(&d->lock); | ||
| 1031 | |||
| 1032 | /* | 987 | /* |
| 1033 | * Stop DMA activity: we assume the callback will not be called | 988 | * Stop DMA activity: we assume the callback will not be called |
| 1034 | * after omap_dma_stop() returns (even if it does, it will see | 989 | * after omap_dma_stop() returns (even if it does, it will see |
| @@ -1102,14 +1057,12 @@ static int omap_dma_chan_init(struct omap_dmadev *od) | |||
| 1102 | c->reg_map = od->reg_map; | 1057 | c->reg_map = od->reg_map; |
| 1103 | c->vc.desc_free = omap_dma_desc_free; | 1058 | c->vc.desc_free = omap_dma_desc_free; |
| 1104 | vchan_init(&c->vc, &od->ddev); | 1059 | vchan_init(&c->vc, &od->ddev); |
| 1105 | INIT_LIST_HEAD(&c->node); | ||
| 1106 | 1060 | ||
| 1107 | return 0; | 1061 | return 0; |
| 1108 | } | 1062 | } |
| 1109 | 1063 | ||
| 1110 | static void omap_dma_free(struct omap_dmadev *od) | 1064 | static void omap_dma_free(struct omap_dmadev *od) |
| 1111 | { | 1065 | { |
| 1112 | tasklet_kill(&od->task); | ||
| 1113 | while (!list_empty(&od->ddev.channels)) { | 1066 | while (!list_empty(&od->ddev.channels)) { |
| 1114 | struct omap_chan *c = list_first_entry(&od->ddev.channels, | 1067 | struct omap_chan *c = list_first_entry(&od->ddev.channels, |
| 1115 | struct omap_chan, vc.chan.device_node); | 1068 | struct omap_chan, vc.chan.device_node); |
| @@ -1165,12 +1118,9 @@ static int omap_dma_probe(struct platform_device *pdev) | |||
| 1165 | od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; | 1118 | od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; |
| 1166 | od->ddev.dev = &pdev->dev; | 1119 | od->ddev.dev = &pdev->dev; |
| 1167 | INIT_LIST_HEAD(&od->ddev.channels); | 1120 | INIT_LIST_HEAD(&od->ddev.channels); |
| 1168 | INIT_LIST_HEAD(&od->pending); | ||
| 1169 | spin_lock_init(&od->lock); | 1121 | spin_lock_init(&od->lock); |
| 1170 | spin_lock_init(&od->irq_lock); | 1122 | spin_lock_init(&od->irq_lock); |
| 1171 | 1123 | ||
| 1172 | tasklet_init(&od->task, omap_dma_sched, (unsigned long)od); | ||
| 1173 | |||
| 1174 | od->dma_requests = OMAP_SDMA_REQUESTS; | 1124 | od->dma_requests = OMAP_SDMA_REQUESTS; |
| 1175 | if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node, | 1125 | if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node, |
| 1176 | "dma-requests", | 1126 | "dma-requests", |
