dmaengine: dw-edma: Improve the linked list and data blocks definition

In the previous implementation, the driver assumed that there existed
only two memory spaces that would equally distribute the amount of
read/write channels.

This might not be the case on some other implementations, therefore this
patch change this requirement so that each write/read channel has
its own linked list and data space well defined, which allows
different sizes and locations.

Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Link: https://lore.kernel.org/r/2e316cb983f8a1e09ce929029f87619dc92a52de.1613674948.git.gustavo.pimentel@synopsys.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Gustavo Pimentel 2021-02-18 20:04:03 +01:00 committed by Vinod Koul
parent f3167dc163
commit 31fb8c1ff9
3 changed files with 160 additions and 85 deletions

View file

@ -81,8 +81,13 @@ static struct dw_edma_chunk *dw_edma_alloc_chunk(struct dw_edma_desc *desc)
* - Even chunks originate CB equal to 1
*/
chunk->cb = !(desc->chunks_alloc % 2);
chunk->ll_region.paddr = dw->ll_region.paddr + chan->ll_off;
chunk->ll_region.vaddr = dw->ll_region.vaddr + chan->ll_off;
if (chan->dir == EDMA_DIR_WRITE) {
chunk->ll_region.paddr = dw->ll_region_wr[chan->id].paddr;
chunk->ll_region.vaddr = dw->ll_region_wr[chan->id].vaddr;
} else {
chunk->ll_region.paddr = dw->ll_region_rd[chan->id].paddr;
chunk->ll_region.vaddr = dw->ll_region_rd[chan->id].vaddr;
}
if (desc->chunk) {
/* Create and add new element into the linked list */
@ -691,24 +696,13 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
struct device *dev = chip->dev;
struct dw_edma *dw = chip->dw;
struct dw_edma_chan *chan;
size_t ll_chunk, dt_chunk;
struct dw_edma_irq *irq;
struct dma_device *dma;
u32 i, j, cnt, ch_cnt;
u32 alloc, off_alloc;
u32 i, j, cnt;
int err = 0;
u32 pos;
ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
ll_chunk = dw->ll_region.sz;
dt_chunk = dw->dt_region.sz;
/* Calculate linked list chunk for each channel */
ll_chunk /= roundup_pow_of_two(ch_cnt);
/* Calculate linked list chunk for each channel */
dt_chunk /= roundup_pow_of_two(ch_cnt);
if (write) {
i = 0;
cnt = dw->wr_ch_cnt;
@ -740,14 +734,14 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
chan->request = EDMA_REQ_NONE;
chan->status = EDMA_ST_IDLE;
chan->ll_off = (ll_chunk * i);
chan->ll_max = (ll_chunk / EDMA_LL_SZ) - 1;
if (write)
chan->ll_max = (dw->ll_region_wr[j].sz / EDMA_LL_SZ);
else
chan->ll_max = (dw->ll_region_rd[j].sz / EDMA_LL_SZ);
chan->ll_max -= 1;
chan->dt_off = (dt_chunk * i);
dev_vdbg(dev, "L. List:\tChannel %s[%u] off=0x%.8lx, max_cnt=%u\n",
write ? "write" : "read", j,
chan->ll_off, chan->ll_max);
dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
write ? "write" : "read", j, chan->ll_max);
if (dw->nr_irqs == 1)
pos = 0;
@ -772,12 +766,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
chan->vc.desc_free = vchan_free_desc;
vchan_init(&chan->vc, dma);
dt_region->paddr = dw->dt_region.paddr + chan->dt_off;
dt_region->vaddr = dw->dt_region.vaddr + chan->dt_off;
dt_region->sz = dt_chunk;
dev_vdbg(dev, "Data:\tChannel %s[%u] off=0x%.8lx\n",
write ? "write" : "read", j, chan->dt_off);
if (write) {
dt_region->paddr = dw->dt_region_wr[j].paddr;
dt_region->vaddr = dw->dt_region_wr[j].vaddr;
dt_region->sz = dw->dt_region_wr[j].sz;
} else {
dt_region->paddr = dw->dt_region_rd[j].paddr;
dt_region->vaddr = dw->dt_region_rd[j].vaddr;
dt_region->sz = dw->dt_region_rd[j].sz;
}
dw_edma_v0_core_device_config(chan);
}

View file

@ -91,11 +91,8 @@ struct dw_edma_chan {
int id;
enum dw_edma_dir dir;
off_t ll_off;
u32 ll_max;
off_t dt_off;
struct msi_msg msi;
enum dw_edma_request request;
@ -126,8 +123,10 @@ struct dw_edma {
u16 rd_ch_cnt;
struct dw_edma_region rg_region; /* Registers */
struct dw_edma_region ll_region; /* Linked list */
struct dw_edma_region dt_region; /* Data */
struct dw_edma_region ll_region_wr[EDMA_MAX_WR_CH];
struct dw_edma_region ll_region_rd[EDMA_MAX_RD_CH];
struct dw_edma_region dt_region_wr[EDMA_MAX_WR_CH];
struct dw_edma_region dt_region_rd[EDMA_MAX_RD_CH];
struct dw_edma_irq *irq;
int nr_irqs;

View file

@ -23,19 +23,28 @@
#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0)
#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16)
#define DW_BLOCK(a, b, c) \
{ \
.bar = a, \
.off = b, \
.sz = c, \
},
struct dw_edma_block {
enum pci_barno bar;
off_t off;
size_t sz;
};
struct dw_edma_pcie_data {
/* eDMA registers location */
enum pci_barno rg_bar;
off_t rg_off;
size_t rg_sz;
struct dw_edma_block rg;
/* eDMA memory linked list location */
enum pci_barno ll_bar;
off_t ll_off;
size_t ll_sz;
struct dw_edma_block ll_wr[EDMA_MAX_WR_CH];
struct dw_edma_block ll_rd[EDMA_MAX_RD_CH];
/* eDMA memory data location */
enum pci_barno dt_bar;
off_t dt_off;
size_t dt_sz;
struct dw_edma_block dt_wr[EDMA_MAX_WR_CH];
struct dw_edma_block dt_rd[EDMA_MAX_RD_CH];
/* Other */
enum dw_edma_map_format mf;
u8 irqs;
@ -45,22 +54,40 @@ struct dw_edma_pcie_data {
static const struct dw_edma_pcie_data snps_edda_data = {
/* eDMA registers location */
.rg_bar = BAR_0,
.rg_off = 0x00001000, /* 4 Kbytes */
.rg_sz = 0x00002000, /* 8 Kbytes */
.rg.bar = BAR_0,
.rg.off = 0x00001000, /* 4 Kbytes */
.rg.sz = 0x00002000, /* 8 Kbytes */
/* eDMA memory linked list location */
.ll_bar = BAR_2,
.ll_off = 0x00000000, /* 0 Kbytes */
.ll_sz = 0x00800000, /* 8 Mbytes */
.ll_wr = {
/* Channel 0 - BAR 2, offset 0 Mbytes, size 2 Mbytes */
DW_BLOCK(BAR_2, 0x00000000, 0x00200000)
/* Channel 1 - BAR 2, offset 2 Mbytes, size 2 Mbytes */
DW_BLOCK(BAR_2, 0x00200000, 0x00200000)
},
.ll_rd = {
/* Channel 0 - BAR 2, offset 4 Mbytes, size 2 Mbytes */
DW_BLOCK(BAR_2, 0x00400000, 0x00200000)
/* Channel 1 - BAR 2, offset 6 Mbytes, size 2 Mbytes */
DW_BLOCK(BAR_2, 0x00600000, 0x00200000)
},
/* eDMA memory data location */
.dt_bar = BAR_2,
.dt_off = 0x00800000, /* 8 Mbytes */
.dt_sz = 0x03800000, /* 56 Mbytes */
.dt_wr = {
/* Channel 0 - BAR 2, offset 8 Mbytes, size 14 Mbytes */
DW_BLOCK(BAR_2, 0x00800000, 0x00e00000)
/* Channel 1 - BAR 2, offset 22 Mbytes, size 14 Mbytes */
DW_BLOCK(BAR_2, 0x01600000, 0x00e00000)
},
.dt_rd = {
/* Channel 0 - BAR 2, offset 36 Mbytes, size 14 Mbytes */
DW_BLOCK(BAR_2, 0x02400000, 0x00e00000)
/* Channel 1 - BAR 2, offset 50 Mbytes, size 14 Mbytes */
DW_BLOCK(BAR_2, 0x03200000, 0x00e00000)
},
/* Other */
.mf = EDMA_MF_EDMA_UNROLL,
.irqs = 1,
.wr_ch_cnt = 0,
.rd_ch_cnt = 0,
.wr_ch_cnt = 2,
.rd_ch_cnt = 2,
};
static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
@ -98,18 +125,20 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
return;
pdata->mf = map;
pdata->rg_bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val);
pdata->rg.bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val);
pci_read_config_dword(pdev, vsec + 0xc, &val);
pdata->wr_ch_cnt = FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val);
pdata->rd_ch_cnt = FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val);
pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,
FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val));
pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt,
FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val));
pci_read_config_dword(pdev, vsec + 0x14, &val);
off = val;
pci_read_config_dword(pdev, vsec + 0x10, &val);
off <<= 32;
off |= val;
pdata->rg_off = off;
pdata->rg.off = off;
}
static int dw_edma_pcie_probe(struct pci_dev *pdev,
@ -121,6 +150,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
struct dw_edma_chip *chip;
struct dw_edma *dw;
int err, nr_irqs;
int i, mask;
/* Enable PCI device */
err = pcim_enable_device(pdev);
@ -138,10 +168,16 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
dw_edma_pcie_get_vsec_dma_data(pdev, &vsec_data);
/* Mapping PCI BAR regions */
err = pcim_iomap_regions(pdev, BIT(vsec_data.rg_bar) |
BIT(vsec_data.ll_bar) |
BIT(vsec_data.dt_bar),
pci_name(pdev));
mask = BIT(vsec_data.rg.bar);
for (i = 0; i < vsec_data.wr_ch_cnt; i++) {
mask |= BIT(vsec_data.ll_wr[i].bar);
mask |= BIT(vsec_data.dt_wr[i].bar);
}
for (i = 0; i < vsec_data.rd_ch_cnt; i++) {
mask |= BIT(vsec_data.ll_rd[i].bar);
mask |= BIT(vsec_data.dt_rd[i].bar);
}
err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
if (err) {
pci_err(pdev, "eDMA BAR I/O remapping failed\n");
return err;
@ -197,30 +233,56 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
chip->id = pdev->devfn;
chip->irq = pdev->irq;
dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg_bar];
dw->rg_region.vaddr += vsec_data.rg_off;
dw->rg_region.paddr = pdev->resource[vsec_data.rg_bar].start;
dw->rg_region.paddr += vsec_data.rg_off;
dw->rg_region.sz = vsec_data.rg_sz;
dw->ll_region.vaddr = pcim_iomap_table(pdev)[vsec_data.ll_bar];
dw->ll_region.vaddr += vsec_data.ll_off;
dw->ll_region.paddr = pdev->resource[vsec_data.ll_bar].start;
dw->ll_region.paddr += vsec_data.ll_off;
dw->ll_region.sz = vsec_data.ll_sz;
dw->dt_region.vaddr = pcim_iomap_table(pdev)[vsec_data.dt_bar];
dw->dt_region.vaddr += vsec_data.dt_off;
dw->dt_region.paddr = pdev->resource[vsec_data.dt_bar].start;
dw->dt_region.paddr += vsec_data.dt_off;
dw->dt_region.sz = vsec_data.dt_sz;
dw->mf = vsec_data.mf;
dw->nr_irqs = nr_irqs;
dw->ops = &dw_edma_pcie_core_ops;
dw->wr_ch_cnt = vsec_data.wr_ch_cnt;
dw->rd_ch_cnt = vsec_data.rd_ch_cnt;
dw->rg_region.vaddr = pcim_iomap_table(pdev)[vsec_data.rg.bar];
dw->rg_region.vaddr += vsec_data.rg.off;
dw->rg_region.paddr = pdev->resource[vsec_data.rg.bar].start;
dw->rg_region.paddr += vsec_data.rg.off;
dw->rg_region.sz = vsec_data.rg.sz;
for (i = 0; i < dw->wr_ch_cnt; i++) {
struct dw_edma_region *ll_region = &dw->ll_region_wr[i];
struct dw_edma_region *dt_region = &dw->dt_region_wr[i];
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];
ll_region->vaddr += ll_block->off;
ll_region->paddr = pdev->resource[ll_block->bar].start;
ll_region->paddr += ll_block->off;
ll_region->sz = ll_block->sz;
dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
dt_region->vaddr += dt_block->off;
dt_region->paddr = pdev->resource[dt_block->bar].start;
dt_region->paddr += dt_block->off;
dt_region->sz = dt_block->sz;
}
for (i = 0; i < dw->rd_ch_cnt; i++) {
struct dw_edma_region *ll_region = &dw->ll_region_rd[i];
struct dw_edma_region *dt_region = &dw->dt_region_rd[i];
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];
ll_region->vaddr += ll_block->off;
ll_region->paddr = pdev->resource[ll_block->bar].start;
ll_region->paddr += ll_block->off;
ll_region->sz = ll_block->sz;
dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
dt_region->vaddr += dt_block->off;
dt_region->paddr = pdev->resource[dt_block->bar].start;
dt_region->paddr += dt_block->off;
dt_region->sz = dt_block->sz;
}
/* Debug info */
if (dw->mf == EDMA_MF_EDMA_LEGACY)
pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", dw->mf);
@ -232,16 +294,33 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", dw->mf);
pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
vsec_data.rg_bar, vsec_data.rg_off, vsec_data.rg_sz,
vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
dw->rg_region.vaddr, &dw->rg_region.paddr);
pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
vsec_data.ll_bar, vsec_data.ll_off, vsec_data.ll_sz,
dw->ll_region.vaddr, &dw->ll_region.paddr);
pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
vsec_data.dt_bar, vsec_data.dt_off, vsec_data.dt_sz,
dw->dt_region.vaddr, &dw->dt_region.paddr);
for (i = 0; i < dw->wr_ch_cnt; i++) {
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, dw->ll_region_wr[i].sz,
dw->ll_region_wr[i].vaddr, &dw->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, dw->dt_region_wr[i].sz,
dw->dt_region_wr[i].vaddr, &dw->dt_region_wr[i].paddr);
}
for (i = 0; i < dw->rd_ch_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, dw->ll_region_rd[i].sz,
dw->ll_region_rd[i].vaddr, &dw->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, dw->dt_region_rd[i].sz,
dw->dt_region_rd[i].vaddr, &dw->dt_region_rd[i].paddr);
}
pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);