summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-29 11:38:27 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-29 11:38:27 -0700
commitb00ed48bb0a7c295facf9036135a573a5cdbe7de (patch)
treea14d3702971e30dfec8392af4f7b9e97d2246f95 /drivers
parentc3a9a3c5f5590e85da15d6201e415ff636fe5670 (diff)
parentd1a28597808268b87f156138aad3104aa255e62b (diff)
downloadlinux-b00ed48bb0a7c295facf9036135a573a5cdbe7de.tar.gz
linux-b00ed48bb0a7c295facf9036135a573a5cdbe7de.tar.bz2
linux-b00ed48bb0a7c295facf9036135a573a5cdbe7de.zip
Merge tag 'dmaengine-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul: "Nothing special, this includes a couple of new device support and new driver support and bunch of driver updates. New support: - Tegra gpcdma driver support - Qualcomm SM8350, Sm8450 and SC7280 device support - Renesas RZN1 dma and platform support Updates: - stm32 device pause/resume support and updates - DMA memset ops Documentation and usage clarification - deprecate '#dma-channels' & '#dma-requests' bindings - driver updates for stm32, ptdma idsx etc" * tag 'dmaengine-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (87 commits) dmaengine: idxd: make idxd_wq_enable() return 0 if wq is already enabled dmaengine: sun6i: Add support for the D1 variant dmaengine: sun6i: Add support for 34-bit physical addresses dmaengine: sun6i: Do not use virt_to_phys dt-bindings: dma: sun50i-a64: Add compatible for D1 dmaengine: tegra: Remove unused switch case dmaengine: tegra: Fix uninitialized variable usage dmaengine: stm32-dma: add device_pause/device_resume support dmaengine: stm32-dma: rename pm ops before dma pause/resume introduction dmaengine: stm32-dma: pass DMA_SxSCR value to stm32_dma_handle_chan_done() dmaengine: stm32-dma: introduce stm32_dma_sg_inc to manage chan->next_sg dmaengine: stm32-dmamux: avoid reset of dmamux if used by coprocessor dmaengine: qcom: gpi: Add support for sc7280 dt-bindings: dma: pl330: Add power-domains dmaengine: stm32-mdma: use dev_dbg on non-busy channel spurious it dmaengine: stm32-mdma: fix chan initialization in stm32_mdma_irq_handler() dmaengine: stm32-mdma: remove GISR1 register dmaengine: ti: deprecate '#dma-channels' dmaengine: mmp: deprecate '#dma-channels' dmaengine: pxa: deprecate '#dma-channels' and '#dma-requests' ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c40
-rw-r--r--drivers/dma/Kconfig14
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/amba-pl08x.c11
-rw-r--r--drivers/dma/at_hdmac.c10
-rw-r--r--drivers/dma/at_xdmac.c9
-rw-r--r--drivers/dma/bestcomm/bestcomm.c2
-rw-r--r--drivers/dma/dma-jz4780.c9
-rw-r--r--drivers/dma/dmaengine.c7
-rw-r--r--drivers/dma/dmatest.c13
-rw-r--r--drivers/dma/dw/Kconfig9
-rw-r--r--drivers/dma/dw/Makefile2
-rw-r--r--drivers/dma/dw/platform.c1
-rw-r--r--drivers/dma/dw/rzn1-dmamux.c155
-rw-r--r--drivers/dma/ep93xx_dma.c2
-rw-r--r--drivers/dma/idxd/cdev.c18
-rw-r--r--drivers/dma/idxd/device.c151
-rw-r--r--drivers/dma/idxd/dma.c65
-rw-r--r--drivers/dma/idxd/idxd.h20
-rw-r--r--drivers/dma/idxd/init.c30
-rw-r--r--drivers/dma/idxd/registers.h1
-rw-r--r--drivers/dma/idxd/sysfs.c12
-rw-r--r--drivers/dma/mediatek/mtk-cqdma.c12
-rw-r--r--drivers/dma/mediatek/mtk-hsdma.c13
-rw-r--r--drivers/dma/mmp_pdma.c14
-rw-r--r--drivers/dma/mv_xor_v2.c4
-rw-r--r--drivers/dma/nbpfaxi.c14
-rw-r--r--drivers/dma/plx_dma.c4
-rw-r--r--drivers/dma/ptdma/ptdma-dev.c36
-rw-r--r--drivers/dma/ptdma/ptdma-dmaengine.c16
-rw-r--r--drivers/dma/ptdma/ptdma.h13
-rw-r--r--drivers/dma/pxa_dma.c13
-rw-r--r--drivers/dma/qcom/gpi.c21
-rw-r--r--drivers/dma/qcom/hidma.c13
-rw-r--r--drivers/dma/sf-pdma/sf-pdma.c24
-rw-r--r--drivers/dma/sf-pdma/sf-pdma.h8
-rw-r--r--drivers/dma/sh/Kconfig2
-rw-r--r--drivers/dma/sprd-dma.c6
-rw-r--r--drivers/dma/stm32-dma.c311
-rw-r--r--drivers/dma/stm32-dmamux.c2
-rw-r--r--drivers/dma/stm32-mdma.c53
-rw-r--r--drivers/dma/sun6i-dma.c92
-rw-r--r--drivers/dma/tegra186-gpc-dma.c1498
-rw-r--r--drivers/dma/ti/cppi41.c6
-rw-r--r--drivers/dma/ti/k3-psil-am62.c8
-rw-r--r--drivers/dma/xilinx/zynqmp_dma.c17
46 files changed, 2459 insertions, 323 deletions
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index 1826aa73b713..35ffc462af1a 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -16,13 +16,17 @@
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
+#include <linux/soc/renesas/r9a06g032-sysctrl.h>
#include <linux/spinlock.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
+#define R9A06G032_SYSCTRL_DMAMUX 0xA0
+
struct r9a06g032_gate {
u16 gate, reset, ready, midle,
scon, mirack, mistat;
@@ -315,6 +319,30 @@ struct r9a06g032_priv {
void __iomem *reg;
};
+static struct r9a06g032_priv *sysctrl_priv;
+
+/* Exported helper to access the DMAMUX register */
+int r9a06g032_sysctrl_set_dmamux(u32 mask, u32 val)
+{
+ unsigned long flags;
+ u32 dmamux;
+
+ if (!sysctrl_priv)
+ return -EPROBE_DEFER;
+
+ spin_lock_irqsave(&sysctrl_priv->lock, flags);
+
+ dmamux = readl(sysctrl_priv->reg + R9A06G032_SYSCTRL_DMAMUX);
+ dmamux &= ~mask;
+ dmamux |= val & mask;
+ writel(dmamux, sysctrl_priv->reg + R9A06G032_SYSCTRL_DMAMUX);
+
+ spin_unlock_irqrestore(&sysctrl_priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(r9a06g032_sysctrl_set_dmamux);
+
/* register/bit pairs are encoded as an uint16_t */
static void
clk_rdesc_set(struct r9a06g032_priv *clocks,
@@ -963,7 +991,17 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
if (error)
return error;
- return r9a06g032_add_clk_domain(dev);
+ error = r9a06g032_add_clk_domain(dev);
+ if (error)
+ return error;
+
+ sysctrl_priv = clocks;
+
+ error = of_platform_populate(np, NULL, NULL, dev);
+ if (error)
+ dev_err(dev, "Failed to populate children (%d)\n", error);
+
+ return 0;
}
static const struct of_device_id r9a06g032_match[] = {
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d5de3f77d3aa..487ed4ddc3be 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -163,7 +163,7 @@ config DMA_SUN4I
config DMA_SUN6I
tristate "Allwinner A31 SoCs DMA support"
- depends on MACH_SUN6I || MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ depends on ARCH_SUNXI || COMPILE_TEST
depends on RESET_CONTROLLER
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
@@ -629,6 +629,18 @@ config TXX9_DMAC
Support the TXx9 SoC internal DMA controller. This can be
integrated in chips such as the Toshiba TX4927/38/39.
+config TEGRA186_GPC_DMA
+ tristate "NVIDIA Tegra GPC DMA support"
+ depends on (ARCH_TEGRA || COMPILE_TEST) && ARCH_DMA_ADDR_T_64BIT
+ depends on IOMMU_API
+ select DMA_ENGINE
+ help
+ Support for the NVIDIA Tegra General Purpose Central DMA controller.
+ The DMA controller has multiple DMA channels which can be configured
+ for different peripherals like UART, SPI, etc which are on APB bus.
+ This DMA controller transfers data from memory to peripheral FIFO
+ or vice versa. It also supports memory to memory data transfer.
+
config TEGRA20_APB_DMA
tristate "NVIDIA Tegra20 APB DMA support"
depends on ARCH_TEGRA || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 616d926cf2a5..2f1b87ffd7ab 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_STM32_MDMA) += stm32-mdma.o
obj-$(CONFIG_SPRD_DMA) += sprd-dma.o
obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
+obj-$(CONFIG_TEGRA186_GPC_DMA) += tegra186-gpc-dma.o
obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index a24882ba3764..a4a794e62ac2 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1535,14 +1535,6 @@ static void pl08x_free_chan_resources(struct dma_chan *chan)
vchan_free_chan_resources(to_virt_chan(chan));
}
-static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
- struct dma_chan *chan, unsigned long flags)
-{
- struct dma_async_tx_descriptor *retval = NULL;
-
- return retval;
-}
-
/*
* Code accessing dma_async_is_complete() in a tight loop may give problems.
* If slaves are relying on interrupts to signal completion this function
@@ -2760,7 +2752,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->memcpy.dev = &adev->dev;
pl08x->memcpy.device_free_chan_resources = pl08x_free_chan_resources;
pl08x->memcpy.device_prep_dma_memcpy = pl08x_prep_dma_memcpy;
- pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
pl08x->memcpy.device_config = pl08x_config;
@@ -2787,8 +2778,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->slave.dev = &adev->dev;
pl08x->slave.device_free_chan_resources =
pl08x_free_chan_resources;
- pl08x->slave.device_prep_dma_interrupt =
- pl08x_prep_dma_interrupt;
pl08x->slave.device_tx_status = pl08x_dma_tx_status;
pl08x->slave.device_issue_pending = pl08x_issue_pending;
pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 30ae36124b1d..5a50423b7378 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -942,6 +942,7 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
struct at_desc *desc;
void __iomem *vaddr;
dma_addr_t paddr;
+ char fill_pattern;
dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
&dest, value, len, flags);
@@ -963,7 +964,14 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
__func__);
return NULL;
}
- *(u32*)vaddr = value;
+
+ /* Only the first byte of value is to be used according to dmaengine */
+ fill_pattern = (char)value;
+
+ *(u32*)vaddr = (fill_pattern << 24) |
+ (fill_pattern << 16) |
+ (fill_pattern << 8) |
+ fill_pattern;
desc = atc_create_memset_desc(chan, paddr, dest, len);
if (!desc) {
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index def564d1e8fa..3e9d726504e2 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1202,6 +1202,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
unsigned long flags;
size_t ublen;
u32 dwidth;
+ char pattern;
/*
* WARNING: The channel configuration is set here since there is no
* dmaengine_slave_config call in this case. Moreover we don't know the
@@ -1244,10 +1245,16 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth);
+ /* Only the first byte of value is to be used according to dmaengine */
+ pattern = (char)value;
+
ublen = len >> dwidth;
desc->lld.mbr_da = dst_addr;
- desc->lld.mbr_ds = value;
+ desc->lld.mbr_ds = (pattern << 24) |
+ (pattern << 16) |
+ (pattern << 8) |
+ pattern;
desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV3
| AT_XDMAC_MBR_UBC_NDEN
| AT_XDMAC_MBR_UBC_NSEN
diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c
index 8c42e5ca00a9..1822a7034630 100644
--- a/drivers/dma/bestcomm/bestcomm.c
+++ b/drivers/dma/bestcomm/bestcomm.c
@@ -17,7 +17,9 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index fc513eb2b289..e2ec540e6519 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -911,6 +912,14 @@ static int jz4780_dma_probe(struct platform_device *pdev)
dd = &jzdma->dma_device;
+ /*
+ * The real segment size limit is dependent on the size unit selected
+ * for the transfer. Because the size unit is selected automatically
+ * and may be as small as 1 byte, use a safe limit of 2^24-1 bytes to
+ * ensure the 24-bit transfer count in the descriptor cannot overflow.
+ */
+ dma_set_max_seg_size(dev, 0xffffff);
+
dma_cap_set(DMA_MEMCPY, dd->cap_mask);
dma_cap_set(DMA_SLAVE, dd->cap_mask);
dma_cap_set(DMA_CYCLIC, dd->cap_mask);
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 2cfa8458b51b..e80feeea0e01 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1053,9 +1053,7 @@ static int __dma_async_device_channel_register(struct dma_device *device,
* When the chan_id is a negative value, we are dynamically adding
* the channel. Otherwise we are static enumerating.
*/
- mutex_lock(&device->chan_mutex);
chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
- mutex_unlock(&device->chan_mutex);
if (chan->chan_id < 0) {
pr_err("%s: unable to alloc ida for chan: %d\n",
__func__, chan->chan_id);
@@ -1078,9 +1076,7 @@ static int __dma_async_device_channel_register(struct dma_device *device,
return 0;
err_out_ida:
- mutex_lock(&device->chan_mutex);
ida_free(&device->chan_ida, chan->chan_id);
- mutex_unlock(&device->chan_mutex);
err_free_dev:
kfree(chan->dev);
err_free_local:
@@ -1113,9 +1109,7 @@ static void __dma_async_device_channel_unregister(struct dma_device *device,
device->chancnt--;
chan->dev->chan = NULL;
mutex_unlock(&dma_list_mutex);
- mutex_lock(&device->chan_mutex);
ida_free(&device->chan_ida, chan->chan_id);
- mutex_unlock(&device->chan_mutex);
device_unregister(&chan->dev->device);
free_percpu(chan->local);
}
@@ -1250,7 +1244,6 @@ int dma_async_device_register(struct dma_device *device)
if (rc != 0)
return rc;
- mutex_init(&device->chan_mutex);
ida_init(&device->chan_ida);
/* represent channels in sysfs. Probably want devs too */
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index f696246f57fd..0a2168a4ccb0 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -675,10 +675,16 @@ static int dmatest_func(void *data)
/*
* src and dst buffers are freed by ourselves below
*/
- if (params->polled)
+ if (params->polled) {
flags = DMA_CTRL_ACK;
- else
- flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ } else {
+ if (dma_has_cap(DMA_INTERRUPT, dev->cap_mask)) {
+ flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ } else {
+ pr_err("Channel does not support interrupt!\n");
+ goto err_pq_array;
+ }
+ }
ktime = ktime_get();
while (!(kthread_should_stop() ||
@@ -906,6 +912,7 @@ error_unmap_continue:
runtime = ktime_to_us(ktime);
ret = 0;
+err_pq_array:
kfree(dma_pq);
err_srcs_array:
kfree(srcs);
diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig
index db25f9b7778c..a9828ddd6d06 100644
--- a/drivers/dma/dw/Kconfig
+++ b/drivers/dma/dw/Kconfig
@@ -16,6 +16,15 @@ config DW_DMAC
Support the Synopsys DesignWare AHB DMA controller. This
can be integrated in chips such as the Intel Cherrytrail.
+config RZN1_DMAMUX
+ tristate "Renesas RZ/N1 DMAMUX driver"
+ depends on DW_DMAC
+ depends on ARCH_RZN1 || COMPILE_TEST
+ help
+ Support the Renesas RZ/N1 DMAMUX which is located in front of
+ the Synopsys DesignWare AHB DMA controller located on Renesas
+ SoCs.
+
config DW_DMAC_PCI
tristate "Synopsys DesignWare AHB DMA PCI driver"
depends on PCI
diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile
index a6f358ad8591..e1796015f213 100644
--- a/drivers/dma/dw/Makefile
+++ b/drivers/dma/dw/Makefile
@@ -9,3 +9,5 @@ dw_dmac-$(CONFIG_OF) += of.o
obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o
dw_dmac_pci-y := pci.o
+
+obj-$(CONFIG_RZN1_DMAMUX) += rzn1-dmamux.o
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index 246118955877..47f2292dba98 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -137,6 +137,7 @@ static void dw_shutdown(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id dw_dma_of_id_table[] = {
{ .compatible = "snps,dma-spear1340", .data = &dw_dma_chip_pdata },
+ { .compatible = "renesas,rzn1-dma", .data = &dw_dma_chip_pdata },
{}
};
MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
diff --git a/drivers/dma/dw/rzn1-dmamux.c b/drivers/dma/dw/rzn1-dmamux.c
new file mode 100644
index 000000000000..11d254e450b0
--- /dev/null
+++ b/drivers/dma/dw/rzn1-dmamux.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Schneider-Electric
+ * Author: Miquel Raynal <miquel.raynal@bootlin.com
+ * Based on TI crossbar driver written by Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+#include <linux/bitops.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/slab.h>
+#include <linux/soc/renesas/r9a06g032-sysctrl.h>
+#include <linux/types.h>
+
+#define RNZ1_DMAMUX_NCELLS 6
+#define RZN1_DMAMUX_MAX_LINES 64
+#define RZN1_DMAMUX_LINES_PER_CTLR 16
+
+struct rzn1_dmamux_data {
+ struct dma_router dmarouter;
+ DECLARE_BITMAP(used_chans, 2 * RZN1_DMAMUX_LINES_PER_CTLR);
+};
+
+struct rzn1_dmamux_map {
+ unsigned int req_idx;
+};
+
+static void rzn1_dmamux_free(struct device *dev, void *route_data)
+{
+ struct rzn1_dmamux_data *dmamux = dev_get_drvdata(dev);
+ struct rzn1_dmamux_map *map = route_data;
+
+ dev_dbg(dev, "Unmapping DMAMUX request %u\n", map->req_idx);
+
+ clear_bit(map->req_idx, dmamux->used_chans);
+
+ kfree(map);
+}
+
+static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
+ struct rzn1_dmamux_data *dmamux = platform_get_drvdata(pdev);
+ struct rzn1_dmamux_map *map;
+ unsigned int dmac_idx, chan, val;
+ u32 mask;
+ int ret;
+
+ if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS)
+ return ERR_PTR(-EINVAL);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return ERR_PTR(-ENOMEM);
+
+ chan = dma_spec->args[0];
+ map->req_idx = dma_spec->args[4];
+ val = dma_spec->args[5];
+ dma_spec->args_count -= 2;
+
+ if (chan >= RZN1_DMAMUX_LINES_PER_CTLR) {
+ dev_err(&pdev->dev, "Invalid DMA request line: %u\n", chan);
+ ret = -EINVAL;
+ goto free_map;
+ }
+
+ if (map->req_idx >= RZN1_DMAMUX_MAX_LINES ||
+ (map->req_idx % RZN1_DMAMUX_LINES_PER_CTLR) != chan) {
+ dev_err(&pdev->dev, "Invalid MUX request line: %u\n", map->req_idx);
+ ret = -EINVAL;
+ goto free_map;
+ }
+
+ dmac_idx = map->req_idx >= RZN1_DMAMUX_LINES_PER_CTLR ? 1 : 0;
+ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", dmac_idx);
+ if (!dma_spec->np) {
+ dev_err(&pdev->dev, "Can't get DMA master\n");
+ ret = -EINVAL;
+ goto free_map;
+ }
+
+ dev_dbg(&pdev->dev, "Mapping DMAMUX request %u to DMAC%u request %u\n",
+ map->req_idx, dmac_idx, chan);
+
+ if (test_and_set_bit(map->req_idx, dmamux->used_chans)) {
+ ret = -EBUSY;
+ goto free_map;
+ }
+
+ mask = BIT(map->req_idx);
+ ret = r9a06g032_sysctrl_set_dmamux(mask, val ? mask : 0);
+ if (ret)
+ goto clear_bitmap;
+
+ return map;
+
+clear_bitmap:
+ clear_bit(map->req_idx, dmamux->used_chans);
+free_map:
+ kfree(map);
+
+ return ERR_PTR(ret);
+}
+
+static const struct of_device_id rzn1_dmac_match[] = {
+ { .compatible = "renesas,rzn1-dma" },
+ {}
+};
+
+static int rzn1_dmamux_probe(struct platform_device *pdev)
+{
+ struct device_node *mux_node = pdev->dev.of_node;
+ const struct of_device_id *match;
+ struct device_node *dmac_node;
+ struct rzn1_dmamux_data *dmamux;
+
+ dmamux = devm_kzalloc(&pdev->dev, sizeof(*dmamux), GFP_KERNEL);
+ if (!dmamux)
+ return -ENOMEM;
+
+ dmac_node = of_parse_phandle(mux_node, "dma-masters", 0);
+ if (!dmac_node)
+ return dev_err_probe(&pdev->dev, -ENODEV, "Can't get DMA master node\n");
+
+ match = of_match_node(rzn1_dmac_match, dmac_node);
+ of_node_put(dmac_node);
+ if (!match)
+ return dev_err_probe(&pdev->dev, -EINVAL, "DMA master is not supported\n");
+
+ dmamux->dmarouter.dev = &pdev->dev;
+ dmamux->dmarouter.route_free = rzn1_dmamux_free;
+
+ platform_set_drvdata(pdev, dmamux);
+
+ return of_dma_router_register(mux_node, rzn1_dmamux_route_allocate,
+ &dmamux->dmarouter);
+}
+
+static const struct of_device_id rzn1_dmamux_match[] = {
+ { .compatible = "renesas,rzn1-dmamux" },
+ {}
+};
+
+static struct platform_driver rzn1_dmamux_driver = {
+ .driver = {
+ .name = "renesas,rzn1-dmamux",
+ .of_match_table = rzn1_dmamux_match,
+ },
+ .probe = rzn1_dmamux_probe,
+};
+module_platform_driver(rzn1_dmamux_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
+MODULE_DESCRIPTION("Renesas RZ/N1 DMAMUX driver");
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 98f9ee70362e..971ff5f9ae84 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -132,7 +132,7 @@ struct ep93xx_dma_desc {
/**
* struct ep93xx_dma_chan - an EP93xx DMA M2P/M2M channel
* @chan: dmaengine API channel
- * @edma: pointer to to the engine device
+ * @edma: pointer to the engine device
* @regs: memory mapped registers
* @irq: interrupt number of the channel
* @clk: clock used by this channel
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index b9b2b4a4124e..c2808fd081d6 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -99,7 +99,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
ctx->wq = wq;
filp->private_data = ctx;
- if (device_pasid_enabled(idxd)) {
+ if (device_user_pasid_enabled(idxd)) {
sva = iommu_sva_bind_device(dev, current->mm, NULL);
if (IS_ERR(sva)) {
rc = PTR_ERR(sva);
@@ -152,7 +152,7 @@ static int idxd_cdev_release(struct inode *node, struct file *filep)
if (wq_shared(wq)) {
idxd_device_drain_pasid(idxd, ctx->pasid);
} else {
- if (device_pasid_enabled(idxd)) {
+ if (device_user_pasid_enabled(idxd)) {
/* The wq disable in the disable pasid function will drain the wq */
rc = idxd_wq_disable_pasid(wq);
if (rc < 0)
@@ -314,7 +314,7 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev)
mutex_lock(&wq->wq_lock);
wq->type = IDXD_WQT_USER;
- rc = __drv_enable_wq(wq);
+ rc = drv_enable_wq(wq);
if (rc < 0)
goto err;
@@ -329,7 +329,7 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev)
return 0;
err_cdev:
- __drv_disable_wq(wq);
+ drv_disable_wq(wq);
err:
wq->type = IDXD_WQT_NONE;
mutex_unlock(&wq->wq_lock);
@@ -342,7 +342,7 @@ static void idxd_user_drv_remove(struct idxd_dev *idxd_dev)
mutex_lock(&wq->wq_lock);
idxd_wq_del_cdev(wq);
- __drv_disable_wq(wq);
+ drv_disable_wq(wq);
wq->type = IDXD_WQT_NONE;
mutex_unlock(&wq->wq_lock);
}
@@ -369,10 +369,16 @@ int idxd_cdev_register(void)
rc = alloc_chrdev_region(&ictx[i].devt, 0, MINORMASK,
ictx[i].name);
if (rc)
- return rc;
+ goto err_free_chrdev_region;
}
return 0;
+
+err_free_chrdev_region:
+ for (i--; i >= 0; i--)
+ unregister_chrdev_region(ictx[i].devt, MINORMASK);
+
+ return rc;
}
void idxd_cdev_remove(void)
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index f652da6ab47d..ff0ea60051f0 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -184,7 +184,7 @@ int idxd_wq_enable(struct idxd_wq *wq)
if (wq->state == IDXD_WQ_ENABLED) {
dev_dbg(dev, "WQ %d already enabled\n", wq->id);
- return -ENXIO;
+ return 0;
}
idxd_cmd_exec(idxd, IDXD_CMD_ENABLE_WQ, wq->id, &status);
@@ -299,24 +299,46 @@ void idxd_wqs_unmap_portal(struct idxd_device *idxd)
}
}
-int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid)
+static void __idxd_wq_set_priv_locked(struct idxd_wq *wq