Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83dc311c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'dmaengine-fix-4.3-rc4' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine fixes from Vinod Koul:
 "This contains fixes spread throughout the drivers, and also fixes one
  more instance of privatecnt in dmaengine.

  Driver fixes summary:
   - bunch of pxa_dma fixes for reuse of descriptor issue, residue and
     no-requestor
   - odd fixes in xgene, idma, sun4i and zxdma
   - at_xdmac fixes for cleaning descriptor and block addr mode"

* tag 'dmaengine-fix-4.3-rc4' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: pxa_dma: fix residue corner case
  dmaengine: pxa_dma: fix the no-requestor case
  dmaengine: zxdma: Fix off-by-one for testing valid pchan request
  dmaengine: at_xdmac: clean used descriptor
  dmaengine: at_xdmac: change block increment addressing mode
  dmaengine: dw: properly read DWC_PARAMS register
  dmaengine: xgene-dma: Fix overwritting DMA tx ring
  dmaengine: fix balance of privatecnt
  dmaengine: sun4i: fix unsafe list iteration
  dmaengine: idma64: improve residue estimation
  dmaengine: xgene-dma: fix handling xgene_dma_get_ring_size result
  dmaengine: pxa_dma: fix initial list move
parents 27728bf0 7b09a1bb
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -455,6 +455,15 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan,
	return desc;
}

void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
{
	memset(&desc->lld, 0, sizeof(desc->lld));
	INIT_LIST_HEAD(&desc->descs_list);
	desc->direction = DMA_TRANS_NONE;
	desc->xfer_size = 0;
	desc->active_xfer = false;
}

/* Call must be protected by lock. */
static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan)
{
@@ -466,7 +475,7 @@ static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan)
		desc = list_first_entry(&atchan->free_descs_list,
					struct at_xdmac_desc, desc_node);
		list_del(&desc->desc_node);
		desc->active_xfer = false;
		at_xdmac_init_used_desc(desc);
	}

	return desc;
@@ -875,14 +884,14 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,

	if (xt->src_inc) {
		if (xt->src_sgl)
			chan_cc |=  AT_XDMAC_CC_SAM_UBS_DS_AM;
			chan_cc |=  AT_XDMAC_CC_SAM_UBS_AM;
		else
			chan_cc |=  AT_XDMAC_CC_SAM_INCREMENTED_AM;
	}

	if (xt->dst_inc) {
		if (xt->dst_sgl)
			chan_cc |=  AT_XDMAC_CC_DAM_UBS_DS_AM;
			chan_cc |=  AT_XDMAC_CC_DAM_UBS_AM;
		else
			chan_cc |=  AT_XDMAC_CC_DAM_INCREMENTED_AM;
	}
+9 −1
Original line number Diff line number Diff line
@@ -554,10 +554,18 @@ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan)
	mutex_lock(&dma_list_mutex);

	if (chan->client_count == 0) {
		struct dma_device *device = chan->device;

		dma_cap_set(DMA_PRIVATE, device->cap_mask);
		device->privatecnt++;
		err = dma_chan_get(chan);
		if (err)
		if (err) {
			pr_debug("%s: failed to get %s: (%d)\n",
				__func__, dma_chan_name(chan), err);
			chan = NULL;
			if (--device->privatecnt == 0)
				dma_cap_clear(DMA_PRIVATE, device->cap_mask);
		}
	} else
		chan = NULL;

+2 −2
Original line number Diff line number Diff line
@@ -1591,7 +1591,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
	INIT_LIST_HEAD(&dw->dma.channels);
	for (i = 0; i < nr_channels; i++) {
		struct dw_dma_chan	*dwc = &dw->chan[i];
		int			r = nr_channels - i - 1;

		dwc->chan.device = &dw->dma;
		dma_cookie_init(&dwc->chan);
@@ -1603,7 +1602,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)

		/* 7 is highest priority & 0 is lowest. */
		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
			dwc->priority = r;
			dwc->priority = nr_channels - i - 1;
		else
			dwc->priority = i;

@@ -1622,6 +1621,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
		/* Hardware configuration */
		if (autocfg) {
			unsigned int dwc_params;
			unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1;
			void __iomem *addr = chip->regs + r * sizeof(u32);

			dwc_params = dma_read_byaddr(addr, DWC_PARAMS);
+8 −8
Original line number Diff line number Diff line
@@ -355,23 +355,23 @@ static size_t idma64_active_desc_size(struct idma64_chan *idma64c)
	struct idma64_desc *desc = idma64c->desc;
	struct idma64_hw_desc *hw;
	size_t bytes = desc->length;
	u64 llp;
	u32 ctlhi;
	u64 llp = channel_readq(idma64c, LLP);
	u32 ctlhi = channel_readl(idma64c, CTL_HI);
	unsigned int i = 0;

	llp = channel_readq(idma64c, LLP);
	do {
		hw = &desc->hw[i];
	} while ((hw->llp != llp) && (++i < desc->ndesc));
		if (hw->llp == llp)
			break;
		bytes -= hw->len;
	} while (++i < desc->ndesc);

	if (!i)
		return bytes;

	do {
		bytes -= desc->hw[--i].len;
	} while (i);
	/* The current chunk is not fully transfered yet */
	bytes += desc->hw[--i].len;

	ctlhi = channel_readl(idma64c, CTL_HI);
	return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi);
}

+25 −6
Original line number Diff line number Diff line
@@ -473,8 +473,10 @@ static void pxad_free_phy(struct pxad_chan *chan)
		return;

	/* clear the channel mapping in DRCMR */
	if (chan->drcmr <= DRCMR_CHLNUM) {
		reg = pxad_drcmr(chan->drcmr);
		writel_relaxed(0, chan->phy->base + reg);
	}

	spin_lock_irqsave(&pdev->phy_lock, flags);
	for (i = 0; i < 32; i++)
@@ -516,8 +518,10 @@ static void phy_enable(struct pxad_phy *phy, bool misaligned)
		"%s(); phy=%p(%d) misaligned=%d\n", __func__,
		phy, phy->idx, misaligned);

	if (phy->vchan->drcmr <= DRCMR_CHLNUM) {
		reg = pxad_drcmr(phy->vchan->drcmr);
		writel_relaxed(DRCMR_MAPVLD | phy->idx, phy->base + reg);
	}

	dalgn = phy_readl_relaxed(phy, DALGN);
	if (misaligned)
@@ -887,6 +891,7 @@ pxad_tx_prep(struct virt_dma_chan *vc, struct virt_dma_desc *vd,
	struct dma_async_tx_descriptor *tx;
	struct pxad_chan *chan = container_of(vc, struct pxad_chan, vc);

	INIT_LIST_HEAD(&vd->node);
	tx = vchan_tx_prep(vc, vd, tx_flags);
	tx->tx_submit = pxad_tx_submit;
	dev_dbg(&chan->vc.chan.dev->device,
@@ -910,14 +915,18 @@ static void pxad_get_config(struct pxad_chan *chan,
		width = chan->cfg.src_addr_width;
		dev_addr = chan->cfg.src_addr;
		*dev_src = dev_addr;
		*dcmd |= PXA_DCMD_INCTRGADDR | PXA_DCMD_FLOWSRC;
		*dcmd |= PXA_DCMD_INCTRGADDR;
		if (chan->drcmr <= DRCMR_CHLNUM)
			*dcmd |= PXA_DCMD_FLOWSRC;
	}
	if (dir == DMA_MEM_TO_DEV) {
		maxburst = chan->cfg.dst_maxburst;
		width = chan->cfg.dst_addr_width;
		dev_addr = chan->cfg.dst_addr;
		*dev_dst = dev_addr;
		*dcmd |= PXA_DCMD_INCSRCADDR | PXA_DCMD_FLOWTRG;
		*dcmd |= PXA_DCMD_INCSRCADDR;
		if (chan->drcmr <= DRCMR_CHLNUM)
			*dcmd |= PXA_DCMD_FLOWTRG;
	}
	if (dir == DMA_MEM_TO_MEM)
		*dcmd |= PXA_DCMD_BURST32 | PXA_DCMD_INCTRGADDR |
@@ -1177,6 +1186,16 @@ static unsigned int pxad_residue(struct pxad_chan *chan,
	else
		curr = phy_readl_relaxed(chan->phy, DTADR);

	/*
	 * curr has to be actually read before checking descriptor
	 * completion, so that a curr inside a status updater
	 * descriptor implies the following test returns true, and
	 * preventing reordering of curr load and the test.
	 */
	rmb();
	if (is_desc_completed(vd))
		goto out;

	for (i = 0; i < sw_desc->nb_desc - 1; i++) {
		hw_desc = sw_desc->hw_desc[i];
		if (sw_desc->hw_desc[0]->dcmd & PXA_DCMD_INCSRCADDR)
Loading