]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'dmaengine-fix-4.6-rc4' of git://git.infradead.org/users/vkoul/slave-dma
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Apr 2016 22:52:38 +0000 (15:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Apr 2016 22:52:38 +0000 (15:52 -0700)
Pull dmaengine fixes from Vinod Koul:
 "This time we have some odd fixes in hsu, edma, omap and xilinx.

  Usual fixes and nothing special"

* tag 'dmaengine-fix-4.6-rc4' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: dw: fix master selection
  dmaengine: edma: special case slot limit workaround
  dmaengine: edma: Remove dynamic TPTC power management feature
  dmaengine: vdma: don't crash when bad channel is requested
  dmaengine: omap-dma: Do not suppress interrupts for memcpy
  dmaengine: omap-dma: Fix polled channel completion detection and handling
  dmaengine: hsu: correct use of channel status register
  dmaengine: hsu: correct residue calculation of active descriptor
  dmaengine: hsu: set HSU_CH_MTSR to memory width

drivers/dma/dw/core.c
drivers/dma/edma.c
drivers/dma/hsu/hsu.c
drivers/dma/hsu/hsu.h
drivers/dma/omap-dma.c
drivers/dma/xilinx/xilinx_vdma.c

index 5ad0ec1f0e29f750eee5c70889df5427d7413556..97199b3c25a22cd907c1a73648c76a96a594b370 100644 (file)
@@ -130,26 +130,14 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
 static void dwc_initialize(struct dw_dma_chan *dwc)
 {
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-       struct dw_dma_slave *dws = dwc->chan.private;
        u32 cfghi = DWC_CFGH_FIFO_MODE;
        u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
 
        if (dwc->initialized == true)
                return;
 
-       if (dws) {
-               /*
-                * We need controller-specific data to set up slave
-                * transfers.
-                */
-               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
-
-               cfghi |= DWC_CFGH_DST_PER(dws->dst_id);
-               cfghi |= DWC_CFGH_SRC_PER(dws->src_id);
-       } else {
-               cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
-               cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
-       }
+       cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
+       cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
 
        channel_writel(dwc, CFG_LO, cfglo);
        channel_writel(dwc, CFG_HI, cfghi);
@@ -941,7 +929,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
        struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
        struct dw_dma_slave *dws = param;
 
-       if (!dws || dws->dma_dev != chan->device->dev)
+       if (dws->dma_dev != chan->device->dev)
                return false;
 
        /* We have to copy data since dws can be temporary storage */
@@ -1165,6 +1153,14 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
         * doesn't mean what you think it means), and status writeback.
         */
 
+       /*
+        * We need controller-specific data to set up slave transfers.
+        */
+       if (chan->private && !dw_dma_filter(chan, chan->private)) {
+               dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
+               return -EINVAL;
+       }
+
        /* Enable controller here if needed */
        if (!dw->in_use)
                dw_dma_on(dw);
@@ -1226,6 +1222,14 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_irqsave(&dwc->lock, flags);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
+
+       /* Clear custom channel configuration */
+       dwc->src_id = 0;
+       dwc->dst_id = 0;
+
+       dwc->src_master = 0;
+       dwc->dst_master = 0;
+
        dwc->initialized = false;
 
        /* Disable interrupts */
index ee3463e774f8e4dc5c46e2614719f9d0723cfd06..04070baab78ab0cc7772085dd70828741317dd5a 100644 (file)
@@ -1238,6 +1238,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
        struct edma_desc *edesc;
        dma_addr_t src_addr, dst_addr;
        enum dma_slave_buswidth dev_width;
+       bool use_intermediate = false;
        u32 burst;
        int i, ret, nslots;
 
@@ -1279,8 +1280,21 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
         * but the synchronization is difficult to achieve with Cyclic and
         * cannot be guaranteed, so we error out early.
         */
-       if (nslots > MAX_NR_SG)
-               return NULL;
+       if (nslots > MAX_NR_SG) {
+               /*
+                * If the burst and period sizes are the same, we can put
+                * the full buffer into a single period and activate
+                * intermediate interrupts. This will produce interrupts
+                * after each burst, which is also after each desired period.
+                */
+               if (burst == period_len) {
+                       period_len = buf_len;
+                       nslots = 2;
+                       use_intermediate = true;
+               } else {
+                       return NULL;
+               }
+       }
 
        edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
                        GFP_ATOMIC);
@@ -1358,8 +1372,13 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                /*
                 * Enable period interrupt only if it is requested
                 */
-               if (tx_flags & DMA_PREP_INTERRUPT)
+               if (tx_flags & DMA_PREP_INTERRUPT) {
                        edesc->pset[i].param.opt |= TCINTEN;
+
+                       /* Also enable intermediate interrupts if necessary */
+                       if (use_intermediate)
+                               edesc->pset[i].param.opt |= ITCINTEN;
+               }
        }
 
        /* Place the cyclic channel to highest priority queue */
@@ -1570,32 +1589,6 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void edma_tc_set_pm_state(struct edma_tc *tc, bool enable)
-{
-       struct platform_device *tc_pdev;
-       int ret;
-
-       if (!IS_ENABLED(CONFIG_OF) || !tc)
-               return;
-
-       tc_pdev = of_find_device_by_node(tc->node);
-       if (!tc_pdev) {
-               pr_err("%s: TPTC device is not found\n", __func__);
-               return;
-       }
-       if (!pm_runtime_enabled(&tc_pdev->dev))
-               pm_runtime_enable(&tc_pdev->dev);
-
-       if (enable)
-               ret = pm_runtime_get_sync(&tc_pdev->dev);
-       else
-               ret = pm_runtime_put_sync(&tc_pdev->dev);
-
-       if (ret < 0)
-               pr_err("%s: pm_runtime_%s_sync() failed for %s\n", __func__,
-                      enable ? "get" : "put", dev_name(&tc_pdev->dev));
-}
-
 /* Alloc channel resources */
 static int edma_alloc_chan_resources(struct dma_chan *chan)
 {
@@ -1632,8 +1625,6 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
                EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id,
                echan->hw_triggered ? "HW" : "SW");
 
-       edma_tc_set_pm_state(echan->tc, true);
-
        return 0;
 
 err_slot:
@@ -1670,7 +1661,6 @@ static void edma_free_chan_resources(struct dma_chan *chan)
                echan->alloced = false;
        }
 
-       edma_tc_set_pm_state(echan->tc, false);
        echan->tc = NULL;
        echan->hw_triggered = false;
 
@@ -2417,10 +2407,8 @@ static int edma_pm_suspend(struct device *dev)
        int i;
 
        for (i = 0; i < ecc->num_channels; i++) {
-               if (echan[i].alloced) {
+               if (echan[i].alloced)
                        edma_setup_interrupt(&echan[i], false);
-                       edma_tc_set_pm_state(echan[i].tc, false);
-               }
        }
 
        return 0;
@@ -2450,8 +2438,6 @@ static int edma_pm_resume(struct device *dev)
 
                        /* Set up channel -> slot mapping for the entry slot */
                        edma_set_chmap(&echan[i], echan[i].slot[0]);
-
-                       edma_tc_set_pm_state(echan[i].tc, true);
                }
        }
 
@@ -2475,7 +2461,8 @@ static struct platform_driver edma_driver = {
 
 static int edma_tptc_probe(struct platform_device *pdev)
 {
-       return 0;
+       pm_runtime_enable(&pdev->dev);
+       return pm_runtime_get_sync(&pdev->dev);
 }
 
 static struct platform_driver edma_tptc_driver = {
index eef145edb936816f3686d343742a709392a5dffa..ee510515ce187af75d3ba873b65d5de26cc3acb4 100644 (file)
@@ -64,10 +64,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc)
 
        if (hsuc->direction == DMA_MEM_TO_DEV) {
                bsr = config->dst_maxburst;
-               mtsr = config->dst_addr_width;
+               mtsr = config->src_addr_width;
        } else if (hsuc->direction == DMA_DEV_TO_MEM) {
                bsr = config->src_maxburst;
-               mtsr = config->src_addr_width;
+               mtsr = config->dst_addr_width;
        }
 
        hsu_chan_disable(hsuc);
@@ -135,7 +135,7 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc)
        sr = hsu_chan_readl(hsuc, HSU_CH_SR);
        spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
 
-       return sr;
+       return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
 }
 
 irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
@@ -254,10 +254,13 @@ static void hsu_dma_issue_pending(struct dma_chan *chan)
 static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc)
 {
        struct hsu_dma_desc *desc = hsuc->desc;
-       size_t bytes = desc->length;
+       size_t bytes = 0;
        int i;
 
-       i = desc->active % HSU_DMA_CHAN_NR_DESC;
+       for (i = desc->active; i < desc->nents; i++)
+               bytes += desc->sg[i].len;
+
+       i = HSU_DMA_CHAN_NR_DESC - 1;
        do {
                bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i));
        } while (--i >= 0);
index 578a8ee8cd054429b3e3fd6da2341b49020721cc..6b070c22b1dfc2bca1dc04ca12218de17d1f0d70 100644 (file)
@@ -41,6 +41,9 @@
 #define HSU_CH_SR_DESCTO(x)    BIT(8 + (x))
 #define HSU_CH_SR_DESCTO_ANY   (BIT(11) | BIT(10) | BIT(9) | BIT(8))
 #define HSU_CH_SR_CHE          BIT(15)
+#define HSU_CH_SR_DESCE(x)     BIT(16 + (x))
+#define HSU_CH_SR_DESCE_ANY    (BIT(19) | BIT(18) | BIT(17) | BIT(16))
+#define HSU_CH_SR_CDESC_ANY    (BIT(31) | BIT(30))
 
 /* Bits in HSU_CH_CR */
 #define HSU_CH_CR_CHA          BIT(0)
index 43bd5aee7ffe093d78e6f8c1f43b75084f8f1c8e..1e984e18c1266b74fc01c247fad36f3e132ad587 100644 (file)
@@ -48,6 +48,7 @@ struct omap_chan {
        unsigned dma_sig;
        bool cyclic;
        bool paused;
+       bool running;
 
        int dma_ch;
        struct omap_desc *desc;
@@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
 
        /* Enable channel */
        omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
+
+       c->running = true;
 }
 
 static void omap_dma_stop(struct omap_chan *c)
@@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c)
 
                omap_dma_chan_write(c, CLNK_CTRL, val);
        }
+
+       c->running = false;
 }
 
 static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
@@ -673,15 +678,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
        struct omap_chan *c = to_omap_dma_chan(chan);
        struct virt_dma_desc *vd;
        enum dma_status ret;
-       uint32_t ccr;
        unsigned long flags;
 
-       ccr = omap_dma_chan_read(c, CCR);
-       /* The channel is no longer active, handle the completion right away */
-       if (!(ccr & CCR_ENABLE))
-               omap_dma_callback(c->dma_ch, 0, c);
-
        ret = dma_cookie_status(chan, cookie, txstate);
+
+       if (!c->paused && c->running) {
+               uint32_t ccr = omap_dma_chan_read(c, CCR);
+               /*
+                * The channel is no longer active, set the return value
+                * accordingly
+                */
+               if (!(ccr & CCR_ENABLE))
+                       ret = DMA_COMPLETE;
+       }
+
        if (ret == DMA_COMPLETE || !txstate)
                return ret;
 
@@ -945,9 +955,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy(
        d->ccr = c->ccr;
        d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC;
 
-       d->cicr = CICR_DROP_IE;
-       if (tx_flags & DMA_PREP_INTERRUPT)
-               d->cicr |= CICR_FRAME_IE;
+       d->cicr = CICR_DROP_IE | CICR_FRAME_IE;
 
        d->csdp = data_type;
 
index 0ee0321868d36b3054acac0a02356e09cc0749a1..ef67f278e076da61c3e08428a70bffd0d8f9341c 100644 (file)
@@ -1236,7 +1236,7 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
        struct xilinx_vdma_device *xdev = ofdma->of_dma_data;
        int chan_id = dma_spec->args[0];
 
-       if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE)
+       if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE || !xdev->chan[chan_id])
                return NULL;
 
        return dma_get_slave_channel(&xdev->chan[chan_id]->common);