File Index
Files and directories
Sign in
FILE

dw-edma-pcie.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dma/dw-edma/dw-edma-pcie.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
  4 * Synopsys DesignWare eDMA PCIe driver
  5 *
  6 * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
  7 */
  8
  9#include <linux/kernel.h>
 10#include <linux/module.h>
 11#include <linux/pci.h>
 12#include <linux/device.h>
 13#include <linux/dma/edma.h>
 14#include <linux/pci-epf.h>
 15#include <linux/msi.h>
 16#include <linux/bitfield.h>
 17
 18#include "dw-edma-core.h"
 19
 20#define DW_PCIE_VSEC_DMA_ID			0x6
 21#define DW_PCIE_VSEC_DMA_BAR			GENMASK(10, 8)
 22#define DW_PCIE_VSEC_DMA_MAP			GENMASK(2, 0)
 23#define DW_PCIE_VSEC_DMA_WR_CH			GENMASK(9, 0)
 24#define DW_PCIE_VSEC_DMA_RD_CH			GENMASK(25, 16)
 25
 26#define DW_BLOCK(a, b, c) \
 27	{ \
 28		.bar = a, \
 29		.off = b, \
 30		.sz = c, \
 31	},
 32
 33struct dw_edma_block {
 34	enum pci_barno			bar;
 35	off_t				off;
 36	size_t				sz;
 37};
 38
 39struct dw_edma_pcie_data {
 40	/* eDMA registers location */
 41	struct dw_edma_block		rg;
 42	/* eDMA memory linked list location */
 43	struct dw_edma_block		ll_wr[EDMA_MAX_WR_CH];
 44	struct dw_edma_block		ll_rd[EDMA_MAX_RD_CH];
 45	/* eDMA memory data location */
 46	struct dw_edma_block		dt_wr[EDMA_MAX_WR_CH];
 47	struct dw_edma_block		dt_rd[EDMA_MAX_RD_CH];
 48	/* Other */
 49	enum dw_edma_map_format		mf;
 50	u8				irqs;
 51	u16				wr_ch_cnt;
 52	u16				rd_ch_cnt;
 53};
 54
 55static const struct dw_edma_pcie_data snps_edda_data = {
 56	/* eDMA registers location */
 57	.rg.bar				= BAR_0,
 58	.rg.off				= 0x00001000,	/*  4 Kbytes */
 59	.rg.sz				= 0x00002000,	/*  8 Kbytes */
 60	/* eDMA memory linked list location */
 61	.ll_wr = {
 62		/* Channel 0 - BAR 2, offset 0 Mbytes, size 2 Kbytes */
 63		DW_BLOCK(BAR_2, 0x00000000, 0x00000800)
 64		/* Channel 1 - BAR 2, offset 2 Mbytes, size 2 Kbytes */
 65		DW_BLOCK(BAR_2, 0x00200000, 0x00000800)
 66	},
 67	.ll_rd = {
 68		/* Channel 0 - BAR 2, offset 4 Mbytes, size 2 Kbytes */
 69		DW_BLOCK(BAR_2, 0x00400000, 0x00000800)
 70		/* Channel 1 - BAR 2, offset 6 Mbytes, size 2 Kbytes */
 71		DW_BLOCK(BAR_2, 0x00600000, 0x00000800)
 72	},
 73	/* eDMA memory data location */
 74	.dt_wr = {
 75		/* Channel 0 - BAR 2, offset 8 Mbytes, size 2 Kbytes */
 76		DW_BLOCK(BAR_2, 0x00800000, 0x00000800)
 77		/* Channel 1 - BAR 2, offset 9 Mbytes, size 2 Kbytes */
 78		DW_BLOCK(BAR_2, 0x00900000, 0x00000800)
 79	},
 80	.dt_rd = {
 81		/* Channel 0 - BAR 2, offset 10 Mbytes, size 2 Kbytes */
 82		DW_BLOCK(BAR_2, 0x00a00000, 0x00000800)
 83		/* Channel 1 - BAR 2, offset 11 Mbytes, size 2 Kbytes */
 84		DW_BLOCK(BAR_2, 0x00b00000, 0x00000800)
 85	},
 86	/* Other */
 87	.mf				= EDMA_MF_EDMA_UNROLL,
 88	.irqs				= 1,
 89	.wr_ch_cnt			= 2,
 90	.rd_ch_cnt			= 2,
 91};
 92
 93static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
 94{
 95	return pci_irq_vector(to_pci_dev(dev), nr);
 96}
 97
 98static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
 99{
100	struct pci_dev *pdev = to_pci_dev(dev);
101	struct pci_bus_region region;
102	struct resource res = {
103		.flags = IORESOURCE_MEM,
104		.start = cpu_addr,
105		.end = cpu_addr,
106	};
107
108	pcibios_resource_to_bus(pdev->bus, &region, &res);
109	return region.start;
110}
111
112static const struct dw_edma_plat_ops dw_edma_pcie_plat_ops = {
113	.irq_vector = dw_edma_pcie_irq_vector,
114	.pci_address = dw_edma_pcie_address,
115};
116
117static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
118					   struct dw_edma_pcie_data *pdata)
119{
120	u32 val, map;
121	u16 vsec;
122	u64 off;
123
124	vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_SYNOPSYS,
125					DW_PCIE_VSEC_DMA_ID);
126	if (!vsec)
127		return;
128
129	pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
130	if (PCI_VNDR_HEADER_REV(val) != 0x00 ||
131	    PCI_VNDR_HEADER_LEN(val) != 0x18)
132		return;
133
134	pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability DMA\n");
135	pci_read_config_dword(pdev, vsec + 0x8, &val);
136	map = FIELD_GET(DW_PCIE_VSEC_DMA_MAP, val);
137	if (map != EDMA_MF_EDMA_LEGACY &&
138	    map != EDMA_MF_EDMA_UNROLL &&
139	    map != EDMA_MF_HDMA_COMPAT &&
140	    map != EDMA_MF_HDMA_NATIVE)
141		return;
142
143	pdata->mf = map;
144	pdata->rg.bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val);
145
146	pci_read_config_dword(pdev, vsec + 0xc, &val);
147	pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,
148				 FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val));
149	pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt,
150				 FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val));
151
152	pci_read_config_dword(pdev, vsec + 0x14, &val);
153	off = val;
154	pci_read_config_dword(pdev, vsec + 0x10, &val);
155	off <<= 32;
156	off |= val;
157	pdata->rg.off = off;
158}
159
160static int dw_edma_pcie_probe(struct pci_dev *pdev,
161			      const struct pci_device_id *pid)
162{
163	struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
164	struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL;
165	struct device *dev = &pdev->dev;
166	struct dw_edma_chip *chip;
167	int err, nr_irqs;
168	int i, mask;
169
170	vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL);
171	if (!vsec_data)
172		return -ENOMEM;
173
174	/* Enable PCI device */
175	err = pcim_enable_device(pdev);
176	if (err) {
177		pci_err(pdev, "enabling device failed\n");
178		return err;
179	}
180
181	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
182
183	/*
184	 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
185	 * for the DMA, if one exists, then reconfigures it.
186	 */
187	dw_edma_pcie_get_vsec_dma_data(pdev, vsec_data);
188
189	/* Mapping PCI BAR regions */
190	mask = BIT(vsec_data->rg.bar);
191	for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
192		mask |= BIT(vsec_data->ll_wr[i].bar);
193		mask |= BIT(vsec_data->dt_wr[i].bar);
194	}
195	for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
196		mask |= BIT(vsec_data->ll_rd[i].bar);
197		mask |= BIT(vsec_data->dt_rd[i].bar);
198	}
199	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
200	if (err) {
201		pci_err(pdev, "eDMA BAR I/O remapping failed\n");
202		return err;
203	}
204
205	pci_set_master(pdev);
206
207	/* DMA configuration */
208	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
209	if (err) {
210		pci_err(pdev, "DMA mask 64 set failed\n");
211		return err;
212	}
213
214	/* Data structure allocation */
215	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
216	if (!chip)
217		return -ENOMEM;
218
219	/* IRQs allocation */
220	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
221					PCI_IRQ_MSI | PCI_IRQ_MSIX);
222	if (nr_irqs < 1) {
223		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
224			nr_irqs);
225		return -EPERM;
226	}
227
228	/* Data structure initialization */
229	chip->dev = dev;
230
231	chip->mf = vsec_data->mf;
232	chip->nr_irqs = nr_irqs;
233	chip->ops = &dw_edma_pcie_plat_ops;
234
235	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
236	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
237
238	chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
239	if (!chip->reg_base)
240		return -ENOMEM;
241
242	for (i = 0; i < chip->ll_wr_cnt; i++) {
243		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
244		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
245		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
246		struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
247
248		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
249		if (!ll_region->vaddr.io)
250			return -ENOMEM;
251
252		ll_region->vaddr.io += ll_block->off;
253		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
254		ll_region->paddr += ll_block->off;
255		ll_region->sz = ll_block->sz;
256
257		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
258		if (!dt_region->vaddr.io)
259			return -ENOMEM;
260
261		dt_region->vaddr.io += dt_block->off;
262		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
263		dt_region->paddr += dt_block->off;
264		dt_region->sz = dt_block->sz;
265	}
266
267	for (i = 0; i < chip->ll_rd_cnt; i++) {
268		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
269		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
270		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
271		struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
272
273		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
274		if (!ll_region->vaddr.io)
275			return -ENOMEM;
276
277		ll_region->vaddr.io += ll_block->off;
278		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
279		ll_region->paddr += ll_block->off;
280		ll_region->sz = ll_block->sz;
281
282		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
283		if (!dt_region->vaddr.io)
284			return -ENOMEM;
285
286		dt_region->vaddr.io += dt_block->off;
287		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
288		dt_region->paddr += dt_block->off;
289		dt_region->sz = dt_block->sz;
290	}
291
292	/* Debug info */
293	if (chip->mf == EDMA_MF_EDMA_LEGACY)
294		pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
295	else if (chip->mf == EDMA_MF_EDMA_UNROLL)
296		pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
297	else if (chip->mf == EDMA_MF_HDMA_COMPAT)
298		pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
299	else if (chip->mf == EDMA_MF_HDMA_NATIVE)
300		pci_dbg(pdev, "Version:\tHDMA Native (0x%x)\n", chip->mf);
301	else
302		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
303
304	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
305		vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
306		chip->reg_base);
307
308
309	for (i = 0; i < chip->ll_wr_cnt; i++) {
310		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
311			i, vsec_data->ll_wr[i].bar,
312			vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
313			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
314
315		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
316			i, vsec_data->dt_wr[i].bar,
317			vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
318			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
319	}
320
321	for (i = 0; i < chip->ll_rd_cnt; i++) {
322		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
323			i, vsec_data->ll_rd[i].bar,
324			vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
325			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
326
327		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
328			i, vsec_data->dt_rd[i].bar,
329			vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
330			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
331	}
332
333	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
334
335	/* Validating if PCI interrupts were enabled */
336	if (!pci_dev_msi_enabled(pdev)) {
337		pci_err(pdev, "enable interrupt failed\n");
338		return -EPERM;
339	}
340
341	/* Starting eDMA driver */
342	err = dw_edma_probe(chip);
343	if (err) {
344		pci_err(pdev, "eDMA probe failed\n");
345		return err;
346	}
347
348	/* Saving data structure reference */
349	pci_set_drvdata(pdev, chip);
350
351	return 0;
352}
353
354static void dw_edma_pcie_remove(struct pci_dev *pdev)
355{
356	struct dw_edma_chip *chip = pci_get_drvdata(pdev);
357	int err;
358
359	/* Stopping eDMA driver */
360	err = dw_edma_remove(chip);
361	if (err)
362		pci_warn(pdev, "can't remove device properly: %d\n", err);
363
364	/* Freeing IRQs */
365	pci_free_irq_vectors(pdev);
366}
367
368static const struct pci_device_id dw_edma_pcie_id_table[] = {
369	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
370	{ }
371};
372MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
373
374static struct pci_driver dw_edma_pcie_driver = {
375	.name		= "dw-edma-pcie",
376	.id_table	= dw_edma_pcie_id_table,
377	.probe		= dw_edma_pcie_probe,
378	.remove		= dw_edma_pcie_remove,
379};
380
381module_pci_driver(dw_edma_pcie_driver);
382
383MODULE_LICENSE("GPL v2");
384MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");
385MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
~/ Read-only file preview.