From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/dma/pl330.c | 276 ++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 190 insertions(+), 86 deletions(-)
diff --git a/kernel/drivers/dma/pl330.c b/kernel/drivers/dma/pl330.c
index 21cfb81..9159280 100644
--- a/kernel/drivers/dma/pl330.c
+++ b/kernel/drivers/dma/pl330.c
@@ -1,16 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
+#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/init.h>
@@ -28,6 +25,7 @@
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/bug.h>
+#include <linux/reset.h>
#include "dmaengine.h"
#define PL330_MAX_CHAN 8
@@ -37,16 +35,6 @@
#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0)
#define PL330_QUIRK_PERIPH_BURST BIT(1)
-
-#ifdef CONFIG_CPU_RV1126
-#undef writel
-#define writel(v, c) \
- do { \
- readl_relaxed(c); \
- __iowmb(); \
- writel_relaxed(v, c); \
- } while (0)
-#endif
enum pl330_cachectrl {
CCTRL0, /* Noncacheable and nonbufferable */
@@ -268,7 +256,7 @@
static unsigned cmd_line;
#define PL330_DBGCMD_DUMP(off, x...) do { \
printk("%x:", cmd_line); \
- printk(x); \
+ printk(KERN_CONT x); \
cmd_line += off; \
} while (0)
#define PL330_DBGMC_START(addr) (cmd_line = addr)
@@ -298,7 +286,7 @@
u32 irq_ns;
};
-/**
+/*
* Request Configuration.
* The PL330 core does not modify this and uses the last
* working configuration if the request doesn't provide any.
@@ -460,8 +448,7 @@
/* DMA-mapped view of the FIFO; may differ if an IOMMU is present */
dma_addr_t fifo_dma;
enum dma_data_direction dir;
- unsigned int src_interlace_size;
- unsigned int dst_interlace_size;
+ struct dma_slave_config slave_config;
/* for runtime pm tracking */
bool active;
@@ -470,9 +457,6 @@
struct pl330_dmac {
/* DMA-Engine Device */
struct dma_device ddma;
-
- /* Holds info about sg limitations */
- struct device_dma_parameters dma_parms;
/* Pool of descriptors available for the DMAC's channels */
struct list_head desc_pool;
@@ -509,6 +493,9 @@
unsigned int num_peripherals;
struct dma_pl330_chan *peripherals; /* keep at end */
int quirks;
+
+ struct reset_control *rstc;
+ struct reset_control *rstc_ocp;
};
static struct pl330_of_quirks {
@@ -554,15 +541,21 @@
/* 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
};
struct _xfer_spec {
u32 ccr;
struct dma_pl330_desc *desc;
};
+
+static int pl330_config_write(struct dma_chan *chan,
+ struct dma_slave_config *slave_config,
+ enum dma_transfer_direction direction);
static inline bool _queue_full(struct pl330_thread *thrd)
{
@@ -1088,16 +1081,16 @@
if (_state(thrd) == PL330_STATE_KILLING)
UNTIL(thrd, PL330_STATE_STOPPED)
- /* fall through */
+ fallthrough;
case PL330_STATE_FAULTING:
_stop(thrd);
- /* fall through */
+ fallthrough;
case PL330_STATE_KILLING:
case PL330_STATE_COMPLETING:
UNTIL(thrd, PL330_STATE_STOPPED)
- /* fall through */
+ fallthrough;
case PL330_STATE_STOPPED:
return _trigger(thrd);
@@ -1148,7 +1141,6 @@
switch (direction) {
case DMA_MEM_TO_MEM:
- /* fall through */
case DMA_MEM_TO_DEV:
off += _emit_LD(dry_run, &buf[off], cond);
break;
@@ -1182,7 +1174,6 @@
switch (direction) {
case DMA_MEM_TO_MEM:
- /* fall through */
case DMA_DEV_TO_MEM:
off += _emit_ST(dry_run, &buf[off], cond);
break;
@@ -1227,8 +1218,10 @@
pxs->desc->peri);
off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
pxs->desc->peri);
+#ifdef CONFIG_NO_GKI
switch (pxs->desc->rqtype) {
case DMA_DEV_TO_MEM:
+
if (pxs->desc->dst_interlace_size)
off += _emit_ADDH(dry_run, &buf[off], DST,
pxs->desc->dst_interlace_size);
@@ -1242,6 +1235,7 @@
WARN_ON(1);
break;
}
+#endif
}
return off;
@@ -1258,7 +1252,6 @@
switch (pxs->desc->rqtype) {
case DMA_MEM_TO_DEV:
- /* fall through */
case DMA_DEV_TO_MEM:
off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, cyc,
cond);
@@ -1293,7 +1286,7 @@
switch (pxs->desc->rqtype) {
case DMA_MEM_TO_DEV:
- /* fall through */
+ fallthrough;
case DMA_DEV_TO_MEM:
/*
* dregs_len = (total bytes - BURST_TO_BYTE(bursts, ccr)) /
@@ -1457,6 +1450,7 @@
off += _emit_LPEND(dry_run, &buf[off], &lpend);
}
+#ifdef CONFIG_NO_GKI
if (!pxs->desc->src_interlace_size &&
!pxs->desc->dst_interlace_size) {
num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
@@ -1466,6 +1460,14 @@
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);
@@ -1533,21 +1535,26 @@
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
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)
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
-
+#else
+ off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
+#endif
return off;
}
@@ -1578,12 +1585,14 @@
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
/* Setup Loop(s) */
off += _loop_cyclic(pl330, dry_run, &buf[off], bursts, pxs, ev);
@@ -1767,9 +1776,9 @@
tasklet_schedule(&pch->task);
}
-static void pl330_dotask(unsigned long data)
+static void pl330_dotask(struct tasklet_struct *t)
{
- struct pl330_dmac *pl330 = (struct pl330_dmac *) data;
+ struct pl330_dmac *pl330 = from_tasklet(pl330, t, tasks);
unsigned long flags;
int i;
@@ -2126,9 +2135,10 @@
if (ret) {
dev_err(pl330->ddma.dev, "%s:%d Can't to create channels for DMAC!\n",
__func__, __LINE__);
- dma_free_coherent(pl330->ddma.dev,
+ dma_free_attrs(pl330->ddma.dev,
chans * pl330->mcbufsz,
- pl330->mcode_cpu, pl330->mcode_bus);
+ pl330->mcode_cpu, pl330->mcode_bus,
+ DMA_ATTR_PRIVILEGED);
return ret;
}
@@ -2174,7 +2184,7 @@
return ret;
}
- tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330);
+ tasklet_setup(&pl330->tasks, pl330_dotask);
pl330->state = INIT;
@@ -2207,9 +2217,9 @@
/* Free DMAC resources */
dmac_free_threads(pl330);
- dma_free_coherent(pl330->ddma.dev,
+ dma_free_attrs(pl330->ddma.dev,
pl330->pcfg.num_chan * pl330->mcbufsz, pl330->mcode_cpu,
- pl330->mcode_bus);
+ pl330->mcode_bus, DMA_ATTR_PRIVILEGED);
}
/* forward declaration */
@@ -2257,9 +2267,9 @@
}
}
-static void pl330_tasklet(unsigned long data)
+static void pl330_tasklet(struct tasklet_struct *t)
{
- struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+ struct dma_pl330_chan *pch = from_tasklet(pch, t, task);
struct dma_pl330_desc *desc, *_dt;
unsigned long flags;
bool power_down = false;
@@ -2367,7 +2377,7 @@
return -ENOMEM;
}
- tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
+ tasklet_setup(&pch->task, pl330_tasklet);
spin_unlock_irqrestore(&pl330->lock, flags);
@@ -2432,31 +2442,46 @@
return max_burst_len;
}
+static int pl330_config_write(struct dma_chan *chan,
+ struct dma_slave_config *slave_config,
+ enum dma_transfer_direction direction)
+{
+ struct dma_pl330_chan *pch = to_pchan(chan);
+
+ pl330_unprep_slave_fifo(pch);
+ if (direction == DMA_MEM_TO_DEV) {
+ if (slave_config->dst_addr)
+ 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) {
+ if (slave_config->src_addr)
+ 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);
+ }
+
+ return 0;
+}
+
static int pl330_config(struct dma_chan *chan,
struct dma_slave_config *slave_config)
{
struct dma_pl330_chan *pch = to_pchan(chan);
- pl330_unprep_slave_fifo(pch);
- if (slave_config->direction == DMA_MEM_TO_DEV) {
- if (slave_config->dst_addr)
- pch->fifo_addr = slave_config->dst_addr;
- if (slave_config->dst_addr_width)
- pch->burst_sz = __ffs(slave_config->dst_addr_width);
- if (slave_config->src_interlace_size)
- pch->src_interlace_size = slave_config->src_interlace_size;
- pch->burst_len = fixup_burst_len(slave_config->dst_maxburst,
- pch->dmac->quirks);
- } else if (slave_config->direction == DMA_DEV_TO_MEM) {
- if (slave_config->src_addr)
- pch->fifo_addr = slave_config->src_addr;
- if (slave_config->src_addr_width)
- pch->burst_sz = __ffs(slave_config->src_addr_width);
- if (slave_config->dst_interlace_size)
- pch->dst_interlace_size = slave_config->dst_interlace_size;
- pch->burst_len = fixup_burst_len(slave_config->src_maxburst,
- pch->dmac->quirks);
- }
+ memcpy(&pch->slave_config, slave_config, sizeof(*slave_config));
return 0;
}
@@ -2467,7 +2492,6 @@
struct dma_pl330_desc *desc;
unsigned long flags;
struct pl330_dmac *pl330 = pch->dmac;
- LIST_HEAD(list);
bool power_down = false;
pm_runtime_get_sync(pl330->ddma.dev);
@@ -2672,7 +2696,7 @@
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
spin_unlock_irqrestore(&pch->lock, flags);
- pl330_tasklet((unsigned long)pch);
+ pl330_tasklet(&pch->task);
}
/*
@@ -2776,7 +2800,7 @@
/* If the DMAC pool is empty, alloc new */
if (!desc) {
- DEFINE_SPINLOCK(lock);
+ static DEFINE_SPINLOCK(lock);
LIST_HEAD(pool);
if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
@@ -2862,8 +2886,8 @@
{
struct dma_pl330_desc *desc = NULL;
struct dma_pl330_chan *pch = to_pchan(chan);
- dma_addr_t dst;
- dma_addr_t src;
+ dma_addr_t dst = 0;
+ dma_addr_t src = 0;
if (len % period_len != 0)
return NULL;
@@ -2873,6 +2897,8 @@
__func__, __LINE__);
return NULL;
}
+
+ pl330_config_write(chan, &pch->slave_config, direction);
if (!pl330_prep_slave_fifo(pch, direction))
return NULL;
@@ -2910,10 +2936,10 @@
desc->cyclic = true;
desc->num_periods = len / period_len;
desc->txd.flags = flags;
-
- desc->src_interlace_size = pch->src_interlace_size;
- desc->dst_interlace_size = pch->dst_interlace_size;
-
+#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 &desc->txd;
}
@@ -3004,6 +3030,8 @@
if (unlikely(!pch || !sgl || !sg_len))
return NULL;
+ pl330_config_write(chan, &pch->slave_config, direction);
+
if (!pl330_prep_slave_fifo(pch, direction))
return NULL;
@@ -3044,8 +3072,10 @@
desc->rqcfg.brst_len = pch->burst_len;
desc->rqtype = direction;
desc->bytes_requested = sg_dma_len(sg);
- desc->src_interlace_size = pch->src_interlace_size;
- desc->dst_interlace_size = pch->dst_interlace_size;
+#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 */
@@ -3068,6 +3098,55 @@
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+#ifdef CONFIG_DEBUG_FS
+static int pl330_debugfs_show(struct seq_file *s, void *data)
+{
+ struct pl330_dmac *pl330 = s->private;
+ int chans, pchs, ch, pr;
+
+ chans = pl330->pcfg.num_chan;
+ pchs = pl330->num_peripherals;
+
+ seq_puts(s, "PL330 physical channels:\n");
+ seq_puts(s, "THREAD:\t\tCHANNEL:\n");
+ seq_puts(s, "--------\t-----\n");
+ for (ch = 0; ch < chans; ch++) {
+ struct pl330_thread *thrd = &pl330->channels[ch];
+ int found = -1;
+
+ for (pr = 0; pr < pchs; pr++) {
+ struct dma_pl330_chan *pch = &pl330->peripherals[pr];
+
+ if (!pch->thread || thrd->id != pch->thread->id)
+ continue;
+
+ found = pr;
+ }
+
+ seq_printf(s, "%d\t\t", thrd->id);
+ if (found == -1)
+ seq_puts(s, "--\n");
+ else
+ seq_printf(s, "%d\n", found);
+ }
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(pl330_debugfs);
+
+static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
+{
+ debugfs_create_file(dev_name(pl330->ddma.dev),
+ S_IFREG | 0444, NULL, pl330,
+ &pl330_debugfs_fops);
+}
+#else
+static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
+{
+}
+#endif
+
/*
* Runtime PM callbacks are provided by amba/bus.c driver.
*
@@ -3078,12 +3157,7 @@
{
struct amba_device *pcdev = to_amba_device(dev);
- pm_runtime_disable(dev);
-
- if (!pm_runtime_status_suspended(dev)) {
- /* amba did not disable the clock */
- amba_pclk_disable(pcdev);
- }
+ pm_runtime_force_suspend(dev);
amba_pclk_unprepare(pcdev);
return 0;
@@ -3098,15 +3172,14 @@
if (ret)
return ret;
- if (!pm_runtime_status_suspended(dev))
- ret = amba_pclk_enable(pcdev);
-
- pm_runtime_enable(dev);
+ pm_runtime_force_resume(dev);
return ret;
}
-static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
+static const struct dev_pm_ops pl330_pm = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pl330_suspend, pl330_resume)
+};
static int
pl330_probe(struct amba_device *adev, const struct amba_id *id)
@@ -3145,6 +3218,29 @@
return PTR_ERR(pl330->base);
amba_set_drvdata(adev, pl330);
+
+ pl330->rstc = devm_reset_control_get_optional(&adev->dev, "dma");
+ if (IS_ERR(pl330->rstc)) {
+ return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc), "Failed to get reset!\n");
+ } else {
+ ret = reset_control_deassert(pl330->rstc);
+ if (ret) {
+ dev_err(&adev->dev, "Couldn't deassert the device from reset!\n");
+ return ret;
+ }
+ }
+
+ pl330->rstc_ocp = devm_reset_control_get_optional(&adev->dev, "dma-ocp");
+ if (IS_ERR(pl330->rstc_ocp)) {
+ return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc_ocp),
+ "Failed to get OCP reset!\n");
+ } else {
+ ret = reset_control_deassert(pl330->rstc_ocp);
+ if (ret) {
+ dev_err(&adev->dev, "Couldn't deassert the device from OCP reset!\n");
+ return ret;
+ }
+ }
for (i = 0; i < AMBA_NR_IRQS; i++) {
irq = adev->irq[i];
@@ -3242,8 +3338,6 @@
}
}
- adev->dev.dma_parms = &pl330->dma_parms;
-
/*
* This is the limit for transfers with a buswidth of 1, larger
* buswidths will have larger limits.
@@ -3253,6 +3347,7 @@
dev_err(&adev->dev, "unable to set the seg size\n");
+ init_pl330_debugfs(pl330);
dev_info(&adev->dev,
"Loaded driver for PL330 DMAC-%x\n", adev->periphid);
dev_info(&adev->dev,
@@ -3284,10 +3379,15 @@
probe_err2:
pl330_del(pl330);
+ if (pl330->rstc_ocp)
+ reset_control_assert(pl330->rstc_ocp);
+
+ if (pl330->rstc)
+ reset_control_assert(pl330->rstc);
return ret;
}
-static int pl330_remove(struct amba_device *adev)
+static void pl330_remove(struct amba_device *adev)
{
struct pl330_dmac *pl330 = amba_get_drvdata(adev);
struct dma_pl330_chan *pch, *_p;
@@ -3322,7 +3422,11 @@
pl330_del(pl330);
- return 0;
+ if (pl330->rstc_ocp)
+ reset_control_assert(pl330->rstc_ocp);
+
+ if (pl330->rstc)
+ reset_control_assert(pl330->rstc);
}
static const struct amba_id pl330_ids[] = {
--
Gitblit v1.6.2