Commit 5256d493 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/dwc'

- Release previously-requested DW eDMA IRQs if request_irq() fails (Serge
  Semin)

- Convert DW eDMA linked-list (ll) and data target (dt) from CPU-relative
  addresses to PCI bus addresses (Serge Semin)

- Fix missing src/dst address for interleaved transfers (Serge Semin)

- Enforce the DW eDMA restriction that interleaved transfers must increment
  src and dst addresses (Serge Semin)

- Fix some invalid interleaved transfer semantics (Serge Semin)

- Convert CPU-relative addresses to PCI bus addresses for eDMA engine
  (Serge Semin)

- Drop chancnt initialization from dw-edma-core, since it is managed by the
  dmaengine core, e.g., in dma_async_device_channel_register() (Serge Semin)

- Clean up bogus casting of debugfs_entries.reg addresses (Serge Semin)

- Ignore debugfs file/directory creation errors (Serge Semin)

- Allocate debugfs entries from the heap to prepare for multi-eDMA
  platforms (Serge Semin)

- Simplify and rework register accessors to remove another obstacle to
  multi-eDMA platforms (Serge Semin)

- Consolidate eDMA read/write channels in a single dma_device to simplify,
  better reflect the hardware design, and avoid a debugfs complaint (Serge
  Semin)

- Move eDMA-specific debugfs nodes into existing dmaengine subdirectory
  (Serge Semin)

- Fix a readq_ch() truncation from 64 to 32 bits (Serge Semin)

- Use existing readq()/writeq rather than hand-coding new ones (Serge
  Semin)

- Drop unnecessary data target region allocation in favor of existing
  dw_edma_chip members (Serge Semin)

- Use parent device in eDMA controller name to prepare for multi-eDMA
  platforms (Serge Semin)

- In addition to the existing MMIO accessors for linked list entries, add
  support for ioremapped entries for use by eDMA in Root Ports or local
  Endpoints (Serge Semin)

- Convert DW_EDMA_PCIE so it depends on DW_EDMA instead of selecting it
  (Serge Semin)

- Allow DWC drivers to set streaming DMA masks larger than 32 bits;
  previously both streaming and coherent DMA were limited to 32 bits
  because some PCI devices only support coherent 32-bit DMA for MSI (Serge
  Semin)

- Set 64-bit streaming and coherent DMA mask for the bt1 driver (Serge
  Semin)

- Add DW Root Port and Endpoint controller support for eDMA (Serge Semin)

* pci/controller/dwc:
  PCI: dwc: Add Root Port and Endpoint controller eDMA engine support
  PCI: bt1: Set 64-bit DMA mask
  PCI: dwc: Restrict only coherent DMA mask for MSI address allocation
  dmaengine: dw-edma: Prepare dw_edma_probe() for builtin callers
  dmaengine: dw-edma: Depend on DW_EDMA instead of selecting it
  dmaengine: dw-edma: Add mem-mapped LL-entries support
  dmaengine: dw-edma: Skip cleanup procedure if no private data found
  dmaengine: dw-edma: Replace chip ID number with device name
  dmaengine: dw-edma: Drop DT-region allocation
  dmaengine: dw-edma: Use non-atomic io-64 methods
  dmaengine: dw-edma: Fix readq_ch() return value truncation
  dmaengine: dw-edma: Use DMA engine device debugfs subdirectory
  dmaengine: dw-edma: Join read/write channels into a single device
  dmaengine: dw-edma: Move eDMA data pointer to debugfs node descriptor
  dmaengine: dw-edma: Simplify debugfs context CSRs init procedure
  dmaengine: dw-edma: Rename debugfs dentry variables to 'dent'
  dmaengine: dw-edma: Convert debugfs descs to being heap-allocated
  dmaengine: dw-edma: Add dw_edma prefix to debugfs nodes descriptor
  dmaengine: dw-edma: Stop checking debugfs_create_*() return value
  dmaengine: dw-edma: Drop unnecessary debugfs reg casts
  dmaengine: dw-edma: Drop chancnt initialization
  dmaengine: dw-edma: Add PCI bus address getter to the remote EP glue driver
  dmaengine: dw-edma: Add CPU to PCI bus address translation
  dmaengine: dw-edma: Fix invalid interleaved xfers semantics
  dmaengine: dw-edma: Don't permit non-inc interleaved xfers
  dmaengine: dw-edma: Fix missing src/dst address of interleaved xfers
  dmaengine: dw-edma: Convert ll/dt phys address to PCI bus/DMA address
  dmaengine: dw-edma: Release requested IRQs on failure
  dmaengine: Fix dma_slave_config.dst_addr description
parents 33abd97c 939fbcd5
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -9,11 +9,14 @@ config DW_EDMA
	  Support the Synopsys DesignWare eDMA controller, normally
	  implemented on endpoints SoCs.

if DW_EDMA

config DW_EDMA_PCIE
	tristate "Synopsys DesignWare eDMA PCIe driver"
	depends on PCI && PCI_MSI
	select DW_EDMA
	help
	  Provides a glue-logic between the Synopsys DesignWare
	  eDMA controller and an endpoint PCIe device. This also serves
	  as a reference design to whom desires to use this IP.

endif # DW_EDMA
+104 −92
Original line number Diff line number Diff line
@@ -39,6 +39,17 @@ struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
	return container_of(vd, struct dw_edma_desc, vd);
}

static inline
u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
{
	struct dw_edma_chip *chip = chan->dw->chip;

	if (chip->ops->pci_address)
		return chip->ops->pci_address(chip->dev, cpu_addr);

	return cpu_addr;
}

static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
{
	struct dw_edma_burst *burst;
@@ -197,6 +208,24 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
	desc->chunks_alloc--;
}

static void dw_edma_device_caps(struct dma_chan *dchan,
				struct dma_slave_caps *caps)
{
	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);

	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
		if (chan->dir == EDMA_DIR_READ)
			caps->directions = BIT(DMA_DEV_TO_MEM);
		else
			caps->directions = BIT(DMA_MEM_TO_DEV);
	} else {
		if (chan->dir == EDMA_DIR_WRITE)
			caps->directions = BIT(DMA_DEV_TO_MEM);
		else
			caps->directions = BIT(DMA_MEM_TO_DEV);
	}
}

static int dw_edma_device_config(struct dma_chan *dchan,
				 struct dma_slave_config *config)
{
@@ -327,11 +356,12 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
{
	struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
	enum dma_transfer_direction dir = xfer->direction;
	phys_addr_t src_addr, dst_addr;
	struct scatterlist *sg = NULL;
	struct dw_edma_chunk *chunk;
	struct dw_edma_burst *burst;
	struct dw_edma_desc *desc;
	u64 src_addr, dst_addr;
	size_t fsz = 0;
	u32 cnt = 0;
	int i;

@@ -381,9 +411,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
		if (xfer->xfer.sg.len < 1)
			return NULL;
	} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
		if (!xfer->xfer.il->numf)
		if (!xfer->xfer.il->numf || xfer->xfer.il->frame_size < 1)
			return NULL;
		if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
		if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
			return NULL;
	} else {
		return NULL;
@@ -405,16 +435,19 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
		dst_addr = chan->config.dst_addr;
	}

	if (dir == DMA_DEV_TO_MEM)
		src_addr = dw_edma_get_pci_address(chan, (phys_addr_t)src_addr);
	else
		dst_addr = dw_edma_get_pci_address(chan, (phys_addr_t)dst_addr);

	if (xfer->type == EDMA_XFER_CYCLIC) {
		cnt = xfer->xfer.cyclic.cnt;
	} else if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
		cnt = xfer->xfer.sg.len;
		sg = xfer->xfer.sg.sgl;
	} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
		if (xfer->xfer.il->numf > 0)
			cnt = xfer->xfer.il->numf;
		else
			cnt = xfer->xfer.il->frame_size;
		cnt = xfer->xfer.il->numf * xfer->xfer.il->frame_size;
		fsz = xfer->xfer.il->frame_size;
	}

	for (i = 0; i < cnt; i++) {
@@ -436,7 +469,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
		else if (xfer->type == EDMA_XFER_SCATTER_GATHER)
			burst->sz = sg_dma_len(sg);
		else if (xfer->type == EDMA_XFER_INTERLEAVED)
			burst->sz = xfer->xfer.il->sgl[i].size;
			burst->sz = xfer->xfer.il->sgl[i % fsz].size;

		chunk->ll_region.sz += burst->sz;
		desc->alloc_sz += burst->sz;
@@ -455,6 +488,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
				 * and destination addresses are increased
				 * by the same portion (data length)
				 */
			} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
				burst->dar = dst_addr;
			}
		} else {
			burst->dar = dst_addr;
@@ -470,27 +505,26 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
				 * and destination addresses are increased
				 * by the same portion (data length)
				 */
			}  else if (xfer->type == EDMA_XFER_INTERLEAVED) {
				burst->sar = src_addr;
			}
		}

		if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
			sg = sg_next(sg);
		} else if (xfer->type == EDMA_XFER_INTERLEAVED &&
			   xfer->xfer.il->frame_size > 0) {
		} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
			struct dma_interleaved_template *il = xfer->xfer.il;
			struct data_chunk *dc = &il->sgl[i];
			struct data_chunk *dc = &il->sgl[i % fsz];

			if (il->src_sgl) {
			src_addr += burst->sz;
			if (il->src_sgl)
				src_addr += dmaengine_get_src_icg(il, dc);
			}

			if (il->dst_sgl) {
			dst_addr += burst->sz;
			if (il->dst_sgl)
				dst_addr += dmaengine_get_dst_icg(il, dc);
		}
	}
	}

	return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);

@@ -701,92 +735,76 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
	}
}

static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
				 u32 wr_alloc, u32 rd_alloc)
static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
{
	struct dw_edma_chip *chip = dw->chip;
	struct dw_edma_region *dt_region;
	struct device *dev = chip->dev;
	struct dw_edma_chan *chan;
	struct dw_edma_irq *irq;
	struct dma_device *dma;
	u32 alloc, off_alloc;
	u32 i, j, cnt;
	int err = 0;
	u32 i, ch_cnt;
	u32 pos;

	if (write) {
		i = 0;
		cnt = dw->wr_ch_cnt;
		dma = &dw->wr_edma;
		alloc = wr_alloc;
		off_alloc = 0;
	} else {
		i = dw->wr_ch_cnt;
		cnt = dw->rd_ch_cnt;
		dma = &dw->rd_edma;
		alloc = rd_alloc;
		off_alloc = wr_alloc;
	}
	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
	dma = &dw->dma;

	INIT_LIST_HEAD(&dma->channels);
	for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {

	for (i = 0; i < ch_cnt; i++) {
		chan = &dw->chan[i];

		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
		if (!dt_region)
			return -ENOMEM;
		chan->dw = dw;

		chan->vc.chan.private = dt_region;
		if (i < dw->wr_ch_cnt) {
			chan->id = i;
			chan->dir = EDMA_DIR_WRITE;
		} else {
			chan->id = i - dw->wr_ch_cnt;
			chan->dir = EDMA_DIR_READ;
		}

		chan->dw = dw;
		chan->id = j;
		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
		chan->configured = false;
		chan->request = EDMA_REQ_NONE;
		chan->status = EDMA_ST_IDLE;

		if (write)
			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
		if (chan->dir == EDMA_DIR_WRITE)
			chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
		else
			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
			chan->ll_max = (chip->ll_region_rd[chan->id].sz / EDMA_LL_SZ);
		chan->ll_max -= 1;

		dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
			 write ? "write" : "read", j, chan->ll_max);
			 chan->dir == EDMA_DIR_WRITE ? "write" : "read",
			 chan->id, chan->ll_max);

		if (dw->nr_irqs == 1)
			pos = 0;
		else if (chan->dir == EDMA_DIR_WRITE)
			pos = chan->id % wr_alloc;
		else
			pos = off_alloc + (j % alloc);
			pos = wr_alloc + chan->id % rd_alloc;

		irq = &dw->irq[pos];

		if (write)
			irq->wr_mask |= BIT(j);
		if (chan->dir == EDMA_DIR_WRITE)
			irq->wr_mask |= BIT(chan->id);
		else
			irq->rd_mask |= BIT(j);
			irq->rd_mask |= BIT(chan->id);

		irq->dw = dw;
		memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));

		dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
			 write ? "write" : "read", j,
			 chan->dir == EDMA_DIR_WRITE  ? "write" : "read", chan->id,
			 chan->msi.address_hi, chan->msi.address_lo,
			 chan->msi.data);

		chan->vc.desc_free = vchan_free_desc;
		vchan_init(&chan->vc, dma);
		chan->vc.chan.private = chan->dir == EDMA_DIR_WRITE ?
					&dw->chip->dt_region_wr[chan->id] :
					&dw->chip->dt_region_rd[chan->id];

		if (write) {
			dt_region->paddr = chip->dt_region_wr[j].paddr;
			dt_region->vaddr = chip->dt_region_wr[j].vaddr;
			dt_region->sz = chip->dt_region_wr[j].sz;
		} else {
			dt_region->paddr = chip->dt_region_rd[j].paddr;
			dt_region->vaddr = chip->dt_region_rd[j].vaddr;
			dt_region->sz = chip->dt_region_rd[j].sz;
		}
		vchan_init(&chan->vc, dma);

		dw_edma_v0_core_device_config(chan);
	}
@@ -797,16 +815,16 @@ static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
	dma_cap_set(DMA_CYCLIC, dma->cap_mask);
	dma_cap_set(DMA_PRIVATE, dma->cap_mask);
	dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
	dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
	dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
	dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
	dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
	dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
	dma->chancnt = cnt;

	/* Set DMA channel callbacks */
	dma->dev = chip->dev;
	dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
	dma->device_free_chan_resources = dw_edma_free_chan_resources;
	dma->device_caps = dw_edma_device_caps;
	dma->device_config = dw_edma_device_config;
	dma->device_pause = dw_edma_device_pause;
	dma->device_resume = dw_edma_device_resume;
@@ -820,9 +838,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
	dma_set_max_seg_size(dma->dev, U32_MAX);

	/* Register DMA device */
	err = dma_async_device_register(dma);

	return err;
	return dma_async_device_register(dma);
}

static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
@@ -893,10 +909,8 @@ static int dw_edma_irq_request(struct dw_edma *dw,
						dw_edma_interrupt_read,
					  IRQF_SHARED, dw->name,
					  &dw->irq[i]);
			if (err) {
				dw->nr_irqs = i;
				return err;
			}
			if (err)
				goto err_irq_free;

			if (irq_get_msi_desc(irq))
				get_cached_msi_msg(irq, &dw->irq[i].msi);
@@ -905,6 +919,14 @@ static int dw_edma_irq_request(struct dw_edma *dw,
		dw->nr_irqs = i;
	}

	return 0;

err_irq_free:
	for  (i--; i >= 0; i--) {
		irq = chip->ops->irq_vector(dev, i);
		free_irq(irq, &dw->irq[i]);
	}

	return err;
}

@@ -951,7 +973,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
	if (!dw->chan)
		return -ENOMEM;

	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
		 dev_name(chip->dev));

	/* Disable eDMA, only to establish the ideal initial conditions */
	dw_edma_v0_core_off(dw);
@@ -961,13 +984,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
	if (err)
		return err;

	/* Setup write channels */
	err = dw_edma_channel_setup(dw, true, wr_alloc, rd_alloc);
	if (err)
		goto err_irq_free;

	/* Setup read channels */
	err = dw_edma_channel_setup(dw, false, wr_alloc, rd_alloc);
	/* Setup write/read channels */
	err = dw_edma_channel_setup(dw, wr_alloc, rd_alloc);
	if (err)
		goto err_irq_free;

@@ -993,6 +1011,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
	struct dw_edma *dw = chip->dw;
	int i;

	/* Skip removal if no private data found */
	if (!dw)
		return -ENODEV;

	/* Disable eDMA */
	dw_edma_v0_core_off(dw);

@@ -1001,23 +1023,13 @@ int dw_edma_remove(struct dw_edma_chip *chip)
		free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);

	/* Deregister eDMA device */
	dma_async_device_unregister(&dw->wr_edma);
	list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
				 vc.chan.device_node) {
		tasklet_kill(&chan->vc.task);
		list_del(&chan->vc.chan.device_node);
	}

	dma_async_device_unregister(&dw->rd_edma);
	list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
	dma_async_device_unregister(&dw->dma);
	list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
				 vc.chan.device_node) {
		tasklet_kill(&chan->vc.task);
		list_del(&chan->vc.chan.device_node);
	}

	/* Turn debugfs off */
	dw_edma_v0_core_debugfs_off(dw);

	return 0;
}
EXPORT_SYMBOL_GPL(dw_edma_remove);
+3 −7
Original line number Diff line number Diff line
@@ -96,12 +96,11 @@ struct dw_edma_irq {
};

struct dw_edma {
	char				name[20];
	char				name[32];

	struct dma_device		wr_edma;
	u16				wr_ch_cnt;
	struct dma_device		dma;

	struct dma_device		rd_edma;
	u16				wr_ch_cnt;
	u16				rd_ch_cnt;

	struct dw_edma_irq		*irq;
@@ -112,9 +111,6 @@ struct dw_edma {
	raw_spinlock_t			lock;		/* Only for legacy */

	struct dw_edma_chip             *chip;
#ifdef CONFIG_DEBUG_FS
	struct dentry			*debugfs;
#endif /* CONFIG_DEBUG_FS */
};

struct dw_edma_sg {
+35 −21
Original line number Diff line number Diff line
@@ -95,8 +95,23 @@ static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
	return pci_irq_vector(to_pci_dev(dev), nr);
}

static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	struct pci_bus_region region;
	struct resource res = {
		.flags = IORESOURCE_MEM,
		.start = cpu_addr,
		.end = cpu_addr,
	};

	pcibios_resource_to_bus(pdev->bus, &region, &res);
	return region.start;
}

static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
	.irq_vector = dw_edma_pcie_irq_vector,
	.pci_address = dw_edma_pcie_address,
};

static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
@@ -207,7 +222,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,

	/* Data structure initialization */
	chip->dev = dev;
	chip->id = pdev->devfn;

	chip->mf = vsec_data.mf;
	chip->nr_irqs = nr_irqs;
@@ -226,21 +240,21 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
		struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];

		ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
		if (!ll_region->vaddr)
		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
		if (!ll_region->vaddr.io)
			return -ENOMEM;

		ll_region->vaddr += ll_block->off;
		ll_region->paddr = pdev->resource[ll_block->bar].start;
		ll_region->vaddr.io += ll_block->off;
		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
		ll_region->paddr += ll_block->off;
		ll_region->sz = ll_block->sz;

		dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
		if (!dt_region->vaddr)
		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
		if (!dt_region->vaddr.io)
			return -ENOMEM;

		dt_region->vaddr += dt_block->off;
		dt_region->paddr = pdev->resource[dt_block->bar].start;
		dt_region->vaddr.io += dt_block->off;
		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
		dt_region->paddr += dt_block->off;
		dt_region->sz = dt_block->sz;
	}
@@ -251,21 +265,21 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
		struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];
		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];

		ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
		if (!ll_region->vaddr)
		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
		if (!ll_region->vaddr.io)
			return -ENOMEM;

		ll_region->vaddr += ll_block->off;
		ll_region->paddr = pdev->resource[ll_block->bar].start;
		ll_region->vaddr.io += ll_block->off;
		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
		ll_region->paddr += ll_block->off;
		ll_region->sz = ll_block->sz;

		dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
		if (!dt_region->vaddr)
		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
		if (!dt_region->vaddr.io)
			return -ENOMEM;

		dt_region->vaddr += dt_block->off;
		dt_region->paddr = pdev->resource[dt_block->bar].start;
		dt_region->vaddr.io += dt_block->off;
		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
		dt_region->paddr += dt_block->off;
		dt_region->sz = dt_block->sz;
	}
@@ -289,24 +303,24 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
			i, vsec_data.ll_wr[i].bar,
			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
			chip->ll_region_wr[i].vaddr, &chip->ll_region_wr[i].paddr);
			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);

		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
			i, vsec_data.dt_wr[i].bar,
			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
			chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
	}

	for (i = 0; i < chip->ll_rd_cnt; i++) {
		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
			i, vsec_data.ll_rd[i].bar,
			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
			chip->ll_region_rd[i].vaddr, &chip->ll_region_rd[i].paddr);
			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);

		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
			i, vsec_data.dt_rd[i].bar,
			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
			chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
	}

	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
+47 −53
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

#include <linux/bitfield.h>

#include <linux/io-64-nonatomic-lo-hi.h>

#include "dw-edma-core.h"
#include "dw-edma-v0-core.h"
#include "dw-edma-v0-regs.h"
@@ -53,8 +55,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
		SET_32(dw, rd_##name, value);		\
	} while (0)

#ifdef CONFIG_64BIT

#define SET_64(dw, name, value)				\
	writeq(value, &(__dw_regs(dw)->name))

@@ -80,8 +80,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
		SET_64(dw, rd_##name, value);		\
	} while (0)

#endif /* CONFIG_64BIT */

#define SET_COMPAT(dw, name, value)			\
	writel(value, &(__dw_regs(dw)->type.unroll.name))

@@ -161,11 +159,6 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
#define GET_CH_32(dw, dir, ch, name) \
	readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))

#define SET_LL_32(ll, value) \
	writel(value, ll)

#ifdef CONFIG_64BIT

static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
			     u64 value, void __iomem *addr)
{
@@ -192,7 +185,7 @@ static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
			   const void __iomem *addr)
{
	u32 value;
	u64 value;

	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
		u32 viewport_sel;
@@ -222,11 +215,6 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
#define GET_CH_64(dw, dir, ch, name) \
	readq_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))

#define SET_LL_64(ll, value) \
	writeq(value, ll)

#endif /* CONFIG_64BIT */

/* eDMA management callbacks */
void dw_edma_v0_core_off(struct dw_edma *dw)
{
@@ -298,17 +286,53 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
			 GET_RW_32(dw, dir, int_status));
}

static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
				     u32 control, u32 size, u64 sar, u64 dar)
{
	ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);

	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
		struct dw_edma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;

		lli->control = control;
		lli->transfer_size = size;
		lli->sar.reg = sar;
		lli->dar.reg = dar;
	} else {
		struct dw_edma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;

		writel(control, &lli->control);
		writel(size, &lli->transfer_size);
		writeq(sar, &lli->sar.reg);
		writeq(dar, &lli->dar.reg);
	}
}

static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
				     int i, u32 control, u64 pointer)
{
	ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);

	if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
		struct dw_edma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;

		llp->control = control;
		llp->llp.reg = pointer;
	} else {
		struct dw_edma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;

		writel(control, &llp->control);
		writeq(pointer, &llp->llp.reg);
	}
}

static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
	struct dw_edma_burst *child;
	struct dw_edma_chan *chan = chunk->chan;
	struct dw_edma_v0_lli __iomem *lli;
	struct dw_edma_v0_llp __iomem *llp;
	u32 control = 0, i = 0;
	int j;

	lli = chunk->ll_region.vaddr;

	if (chunk->cb)
		control = DW_EDMA_V0_CB;

@@ -320,41 +344,16 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
			if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
				control |= DW_EDMA_V0_RIE;
		}
		/* Channel control */
		SET_LL_32(&lli[i].control, control);
		/* Transfer size */
		SET_LL_32(&lli[i].transfer_size, child->sz);
		/* SAR */
		#ifdef CONFIG_64BIT
			SET_LL_64(&lli[i].sar.reg, child->sar);
		#else /* CONFIG_64BIT */
			SET_LL_32(&lli[i].sar.lsb, lower_32_bits(child->sar));
			SET_LL_32(&lli[i].sar.msb, upper_32_bits(child->sar));
		#endif /* CONFIG_64BIT */
		/* DAR */
		#ifdef CONFIG_64BIT
			SET_LL_64(&lli[i].dar.reg, child->dar);
		#else /* CONFIG_64BIT */
			SET_LL_32(&lli[i].dar.lsb, lower_32_bits(child->dar));
			SET_LL_32(&lli[i].dar.msb, upper_32_bits(child->dar));
		#endif /* CONFIG_64BIT */
		i++;
	}

	llp = (void __iomem *)&lli[i];

		dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
					 child->sar, child->dar);
	}

	control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
	if (!chunk->cb)
		control |= DW_EDMA_V0_CB;

	/* Channel control */
	SET_LL_32(&llp->control, control);
	/* Linked list */
	#ifdef CONFIG_64BIT
		SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
	#else /* CONFIG_64BIT */
		SET_LL_32(&llp->llp.lsb, lower_32_bits(chunk->ll_region.paddr));
		SET_LL_32(&llp->llp.msb, upper_32_bits(chunk->ll_region.paddr));
	#endif /* CONFIG_64BIT */
	dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
}

void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -504,8 +503,3 @@ void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
{
	dw_edma_v0_debugfs_on(dw);
}

void dw_edma_v0_core_debugfs_off(struct dw_edma *dw)
{
	dw_edma_v0_debugfs_off(dw);
}
Loading