]> git.itanic.dy.fi Git - linux-stable/commitdiff
dmaengine: dw-edma: Add mem-mapped LL-entries support
authorSerge Semin <Sergey.Semin@baikalelectronics.ru>
Fri, 13 Jan 2023 17:14:05 +0000 (20:14 +0300)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 22 Feb 2023 19:45:53 +0000 (13:45 -0600)
Currently the DW eDMA driver only supports the linked lists memory
allocated locally with respect to the remote eDMA engine setup. It means
the linked lists will be accessible by the CPU via the MMIO space only. If
eDMA is embedded into the DW PCIe Root Ports or local Endpoints (which
support will be added in subsequent commits) the linked lists are supposed
to be allocated in the CPU memory. In that case the LL-entries can be
directly accessed, while the former case implies using the MMIO accessors
for that.

In order to have both cases supported by the driver, the dw_edma_region
descriptor should be fixed to contain the MMIO-backed and just memory-based
virtual addresses. The linked lists initialization procedure will use one
of them depending on the eDMA device nature. If the eDMA engine is embedded
into the local DW PCIe Root Port/Endpoint controllers, the list entries
will be directly accessed by referencing the corresponding structure
fields.  Otherwise the MMIO accessors usage will be preserved.

Link: https://lore.kernel.org/r/20230113171409.30470-24-Sergey.Semin@baikalelectronics.ru
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/dw-edma/dw-edma-pcie.c
drivers/dma/dw-edma/dw-edma-v0-core.c
include/linux/dma/edma.h

index 3f9dadc73854c529a2645af505c321b730ea6eba..2b40f2b44f5e19b801b99401ddf2700553a241de 100644 (file)
@@ -240,20 +240,20 @@ 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->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->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;
@@ -265,20 +265,20 @@ 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->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->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;
@@ -303,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);
index 6bcc575122586f5194688e5d7013cab7ef7f5f41..72e79a0c0a4ebc55ac1222722f4067e72cc4c5cb 100644 (file)
@@ -159,9 +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)
-
 static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
                             u64 value, void __iomem *addr)
 {
@@ -218,9 +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)
-
 /* eDMA management callbacks */
 void dw_edma_v0_core_off(struct dw_edma *dw)
 {
@@ -292,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;
 
@@ -314,27 +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 */
-               SET_LL_64(&lli[i].sar.reg, child->sar);
-               /* DAR */
-               SET_LL_64(&lli[i].dar.reg, child->dar);
-
-               i++;
+
+               dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
+                                        child->sar, child->dar);
        }
 
-       llp = (void __iomem *)&lli[i];
        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 */
-       SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
+       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)
index 96bfd0173f3a2f8a0ef488005ac418679e12752a..3b80040b95cc63761171b5f712f774e9d8446537 100644 (file)
@@ -19,7 +19,10 @@ struct dw_edma;
 
 struct dw_edma_region {
        u64             paddr;
-       void __iomem    *vaddr;
+       union {
+               void            *mem;
+               void __iomem    *io;
+       } vaddr;
        size_t          sz;
 };