From e636c8d336489bf3eed5878299e6cc045bbad077 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:17:29 +0000
Subject: [PATCH] debug lk
---
kernel/drivers/dma/pl330.c | 203 +++++++++++++++++++++++++++++++++-----------------
1 files changed, 133 insertions(+), 70 deletions(-)
diff --git a/kernel/drivers/dma/pl330.c b/kernel/drivers/dma/pl330.c
index b1d6fae..0d14147 100644
--- a/kernel/drivers/dma/pl330.c
+++ b/kernel/drivers/dma/pl330.c
@@ -405,6 +405,12 @@
*/
BUSY,
/*
+ * Pause was called while descriptor was BUSY. Due to hardware
+ * limitations, only termination is possible for descriptors
+ * that have been paused.
+ */
+ PAUSED,
+ /*
* Sitting on the channel work_list but xfer done
* by PL330 core
*/
@@ -541,11 +547,9 @@
/* For cyclic capability */
bool cyclic;
size_t num_periods;
-#ifdef CONFIG_NO_GKI
- /* interlace size */
- unsigned int src_interlace_size;
- unsigned int dst_interlace_size;
-#endif
+
+ /* interleaved size */
+ struct data_chunk sgl;
};
struct _xfer_spec {
@@ -1073,7 +1077,7 @@
return true;
}
-static bool _start(struct pl330_thread *thrd)
+static bool pl330_start_thread(struct pl330_thread *thrd)
{
switch (_state(thrd)) {
case PL330_STATE_FAULT_COMPLETING:
@@ -1204,7 +1208,7 @@
const struct _xfer_spec *pxs, int cyc,
enum pl330_cond cond)
{
- int off = 0;
+ int off = 0, i = 0, burstn = 1;
/*
* do FLUSHP at beginning to clear any stale dma requests before the
@@ -1212,30 +1216,36 @@
*/
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+
+ if (pxs->desc->sgl.size) {
+ WARN_ON(BYTE_MOD_BURST_LEN(pxs->desc->sgl.size, pxs->ccr));
+ burstn = BYTE_TO_BURST(pxs->desc->sgl.size, pxs->ccr);
+ }
+
while (cyc--) {
- off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
- off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype,
- pxs->desc->peri);
- off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
- pxs->desc->peri);
-#ifdef CONFIG_NO_GKI
+ for (i = 0; i < burstn; i++) {
+ off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
+ off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype,
+ pxs->desc->peri);
+ off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
+ pxs->desc->peri);
+ }
+
switch (pxs->desc->rqtype) {
case DMA_DEV_TO_MEM:
-
- if (pxs->desc->dst_interlace_size)
+ if (pxs->desc->sgl.dst_icg)
off += _emit_ADDH(dry_run, &buf[off], DST,
- pxs->desc->dst_interlace_size);
+ pxs->desc->sgl.dst_icg);
break;
case DMA_MEM_TO_DEV:
- if (pxs->desc->src_interlace_size)
+ if (pxs->desc->sgl.src_icg)
off += _emit_ADDH(dry_run, &buf[off], SRC,
- pxs->desc->src_interlace_size);
+ pxs->desc->sgl.src_icg);
break;
default:
WARN_ON(1);
break;
}
-#endif
}
return off;
@@ -1450,9 +1460,7 @@
off += _emit_LPEND(dry_run, &buf[off], &lpend);
}
-#ifdef CONFIG_NO_GKI
- if (!pxs->desc->src_interlace_size &&
- !pxs->desc->dst_interlace_size) {
+ if (!pxs->desc->sgl.src_icg && !pxs->desc->sgl.dst_icg) {
num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
if (num_dregs) {
@@ -1460,14 +1468,6 @@
off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
}
}
-#else
- num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
-
- if (num_dregs) {
- off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
- off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
- }
-#endif
off += _emit_SEV(dry_run, &buf[off], ev);
@@ -1535,26 +1535,18 @@
BRST_SIZE(ccr);
int off = 0;
-#ifdef CONFIG_NO_GKI
- if (pxs->desc->rqtype == DMA_DEV_TO_MEM)
- bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) +
- pxs->desc->dst_interlace_size);
- else if (pxs->desc->rqtype == DMA_MEM_TO_DEV)
- bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) +
- pxs->desc->src_interlace_size);
-#endif
+ if (pxs->desc->sgl.size)
+ bursts = x->bytes / pxs->desc->sgl.size;
+
while (bursts) {
c = bursts;
off += _loop(pl330, dry_run, &buf[off], &c, pxs);
bursts -= c;
}
-#ifdef CONFIG_NO_GKI
- if (!pxs->desc->src_interlace_size &&
- !pxs->desc->dst_interlace_size)
+
+ if (!pxs->desc->sgl.src_icg && !pxs->desc->sgl.dst_icg)
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
-#else
- off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
-#endif
+
return off;
}
@@ -1585,14 +1577,9 @@
unsigned long bursts = BYTE_TO_BURST(x->bytes, ccr);
int off = 0;
-#ifdef CONFIG_NO_GKI
- if (pxs->desc->rqtype == DMA_DEV_TO_MEM)
- bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr)
- + pxs->desc->dst_interlace_size);
- else if (pxs->desc->rqtype == DMA_MEM_TO_DEV)
- bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr)
- + pxs->desc->src_interlace_size);
-#endif
+ if (pxs->desc->sgl.size)
+ bursts = x->bytes / pxs->desc->sgl.size;
+
/* Setup Loop(s) */
off += _loop_cyclic(pl330, dry_run, &buf[off], bursts, pxs, ev);
@@ -1907,7 +1894,7 @@
thrd->req[active].desc = NULL;
thrd->req_running = -1;
/* Get going again ASAP */
- _start(thrd);
+ pl330_start_thread(thrd);
}
/* For now, just make a list of callbacks to be done */
@@ -2248,7 +2235,7 @@
list_for_each_entry(desc, &pch->work_list, node) {
/* If already submitted */
- if (desc->status == BUSY)
+ if (desc->status == BUSY || desc->status == PAUSED)
continue;
ret = pl330_submit_req(pch->thread, desc);
@@ -2309,7 +2296,7 @@
} else {
/* Make sure the PL330 Channel thread is active */
spin_lock(&pch->thread->dmac->lock);
- _start(pch->thread);
+ pl330_start_thread(pch->thread);
spin_unlock(&pch->thread->dmac->lock);
}
@@ -2454,10 +2441,6 @@
pch->fifo_addr = slave_config->dst_addr;
if (slave_config->dst_addr_width)
pch->burst_sz = __ffs(slave_config->dst_addr_width);
-#ifdef CONFIG_NO_GKI
- if (slave_config->src_interlace_size)
- pch->slave_config.src_interlace_size = slave_config->src_interlace_size;
-#endif
pch->burst_len = fixup_burst_len(slave_config->dst_maxburst,
pch->dmac->quirks);
} else if (direction == DMA_DEV_TO_MEM) {
@@ -2465,10 +2448,6 @@
pch->fifo_addr = slave_config->src_addr;
if (slave_config->src_addr_width)
pch->burst_sz = __ffs(slave_config->src_addr_width);
-#ifdef CONFIG_NO_GKI
- if (slave_config->dst_interlace_size)
- pch->slave_config.dst_interlace_size = slave_config->dst_interlace_size;
-#endif
pch->burst_len = fixup_burst_len(slave_config->src_maxburst,
pch->dmac->quirks);
}
@@ -2541,6 +2520,7 @@
{
struct dma_pl330_chan *pch = to_pchan(chan);
struct pl330_dmac *pl330 = pch->dmac;
+ struct dma_pl330_desc *desc;
unsigned long flags;
pm_runtime_get_sync(pl330->ddma.dev);
@@ -2550,6 +2530,10 @@
_stop(pch->thread);
spin_unlock(&pl330->lock);
+ list_for_each_entry(desc, &pch->work_list, node) {
+ if (desc->status == BUSY)
+ desc->status = PAUSED;
+ }
spin_unlock_irqrestore(&pch->lock, flags);
pm_runtime_mark_last_busy(pl330->ddma.dev);
pm_runtime_put_autosuspend(pl330->ddma.dev);
@@ -2639,7 +2623,7 @@
else if (running && desc == running)
transferred =
pl330_get_current_xferred_count(pch, desc);
- else if (desc->status == BUSY)
+ else if (desc->status == BUSY || desc->status == PAUSED)
/*
* Busy but not running means either just enqueued,
* or finished and not yet marked done
@@ -2655,6 +2639,9 @@
switch (desc->status) {
case DONE:
ret = DMA_COMPLETE;
+ break;
+ case PAUSED:
+ ret = DMA_PAUSED;
break;
case PREP:
case BUSY:
@@ -2821,6 +2808,10 @@
desc->cyclic = false;
desc->num_periods = 1;
+ desc->sgl.size = 0;
+ desc->sgl.src_icg = 0;
+ desc->sgl.dst_icg = 0;
+
dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
return desc;
@@ -2936,10 +2927,82 @@
desc->cyclic = true;
desc->num_periods = len / period_len;
desc->txd.flags = flags;
+
+ return &desc->txd;
+}
+
+static struct dma_async_tx_descriptor *pl330_prep_interleaved_dma(
+ struct dma_chan *chan, struct dma_interleaved_template *xt,
+ unsigned long flags)
+{
+ struct dma_pl330_desc *desc = NULL;
+ struct dma_pl330_chan *pch = to_pchan(chan);
+ dma_addr_t dst = 0, src = 0;
+ size_t size, src_icg, dst_icg, period_bytes, buffer_bytes, full_buffer_bytes;
+ size_t nump = 0, numf = 0;
+
+ if (!xt->numf || !xt->sgl[0].size || xt->frame_size != 1)
+ return NULL;
+
#ifdef CONFIG_NO_GKI
- desc->src_interlace_size = pch->slave_config.src_interlace_size;
- desc->dst_interlace_size = pch->slave_config.dst_interlace_size;
+ nump = xt->nump;
#endif
+ numf = xt->numf;
+ size = xt->sgl[0].size;
+ period_bytes = size * nump;
+ buffer_bytes = size * numf;
+
+ if (flags & DMA_PREP_REPEAT && (!nump || (numf % nump)))
+ return NULL;
+
+ src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]);
+ dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]);
+
+ pl330_config_write(chan, &pch->slave_config, xt->dir);
+
+ if (!pl330_prep_slave_fifo(pch, xt->dir))
+ return NULL;
+
+ desc = pl330_get_desc(pch);
+ if (!desc) {
+ dev_err(chan->device->dev, "Failed to get desc\n");
+ return NULL;
+ }
+
+ if (xt->dir == DMA_MEM_TO_DEV) {
+ desc->rqcfg.src_inc = 1;
+ desc->rqcfg.dst_inc = 0;
+ src = xt->src_start;
+ dst = pch->fifo_dma;
+ full_buffer_bytes = (size + src_icg) * numf;
+ } else {
+ desc->rqcfg.src_inc = 0;
+ desc->rqcfg.dst_inc = 1;
+ src = pch->fifo_dma;
+ dst = xt->dst_start;
+ full_buffer_bytes = (size + dst_icg) * numf;
+ }
+
+ desc->rqtype = xt->dir;
+ desc->rqcfg.brst_size = pch->burst_sz;
+ desc->rqcfg.brst_len = pch->burst_len;
+ desc->bytes_requested = full_buffer_bytes;
+ desc->sgl.size = size;
+ desc->sgl.src_icg = src_icg;
+ desc->sgl.dst_icg = dst_icg;
+ desc->txd.flags = flags;
+
+ if (flags & DMA_PREP_REPEAT) {
+ desc->cyclic = true;
+ desc->num_periods = numf / nump;
+ fill_px(&desc->px, dst, src, period_bytes);
+ } else {
+ fill_px(&desc->px, dst, src, buffer_bytes);
+ }
+
+ dev_dbg(chan->device->dev, "size: %zu, src_icg: %zu, dst_icg: %zu, nump: %zu, numf: %zu\n",
+ size, src_icg, dst_icg, nump, numf);
+
return &desc->txd;
}
@@ -3072,10 +3135,6 @@
desc->rqcfg.brst_len = pch->burst_len;
desc->rqtype = direction;
desc->bytes_requested = sg_dma_len(sg);
-#ifdef CONFIG_NO_GKI
- desc->src_interlace_size = pch->slave_config.src_interlace_size;
- desc->dst_interlace_size = pch->slave_config.dst_interlace_size;
-#endif
}
/* Return the last desc in the chain */
@@ -3311,12 +3370,16 @@
dma_cap_set(DMA_SLAVE, pd->cap_mask);
dma_cap_set(DMA_CYCLIC, pd->cap_mask);
dma_cap_set(DMA_PRIVATE, pd->cap_mask);
+ dma_cap_set(DMA_INTERLEAVE, pd->cap_mask);
+ dma_cap_set(DMA_REPEAT, pd->cap_mask);
+ dma_cap_set(DMA_LOAD_EOT, pd->cap_mask);
}
pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
pd->device_free_chan_resources = pl330_free_chan_resources;
pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
+ pd->device_prep_interleaved_dma = pl330_prep_interleaved_dma;
pd->device_tx_status = pl330_tx_status;
pd->device_prep_slave_sg = pl330_prep_slave_sg;
pd->device_config = pl330_config;
--
Gitblit v1.6.2