mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'dmaengine-fix-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul:
"New support:
- Loongson LS2X APB DMA controller
- sf-pdma: mpfs-pdma support
- Qualcomm X1E80100 GPI dma controller support
Updates:
- Xilinx XDMA updates to support interleaved DMA transfers
- TI PSIL threads for AM62P and J722S and cfg register regions
description
- axi-dmac Improving the cyclic DMA transfers
- Tegra Support dma-channel-mask property
- Remaining platform remove callback returning void conversions
Driver fixes for:
- Xilinx xdma driver operator precedence and initialization fix
- Excess kernel-doc warning fix in imx-sdma xilinx xdma drivers
- format-overflow warning fix for rz-dmac, sh usb dmac drivers
- 'output may be truncated' fix for shdma, fsl-qdma and dw-edma
drivers"
* tag 'dmaengine-fix-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (58 commits)
dmaengine: dw-edma: increase size of 'name' in debugfs code
dmaengine: fsl-qdma: increase size of 'irq_name'
dmaengine: shdma: increase size of 'dev_id'
dmaengine: xilinx: xdma: Fix kernel-doc warnings
dmaengine: usb-dmac: Avoid format-overflow warning
dmaengine: sh: rz-dmac: Avoid format-overflow warning
dmaengine: imx-sdma: fix Excess kernel-doc warnings
dmaengine: xilinx: xdma: Fix initialization location of desc in xdma_channel_isr()
dmaengine: xilinx: xdma: Fix operator precedence in xdma_prep_interleaved_dma()
dmaengine: xilinx: xdma: statify xdma_prep_interleaved_dma
dmaengine: xilinx: xdma: Workaround truncation compilation error
dmaengine: pl330: issue_pending waits until WFP state
dmaengine: xilinx: xdma: Implement interleaved DMA transfers
dmaengine: xilinx: xdma: Prepare the introduction of interleaved DMA transfers
dmaengine: xilinx: xdma: Add transfer error reporting
dmaengine: xilinx: xdma: Add error checking in xdma_channel_isr()
dmaengine: xilinx: xdma: Rework xdma_terminate_all()
dmaengine: xilinx: xdma: Ease dma_pool alignment requirements
dmaengine: xilinx: xdma: Add necessary macro definitions
dmaengine: xilinx: xdma: Get rid of unused code
...
This commit is contained in:
@@ -19,19 +19,4 @@ properties:
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
dma: dma-controller@48000000 {
|
||||
compatible = "ti,omap-sdma";
|
||||
reg = <0x48000000 0x1000>;
|
||||
interrupts = <0 12 0x4>,
|
||||
<0 13 0x4>,
|
||||
<0 14 0x4>,
|
||||
<0 15 0x4>;
|
||||
#dma-cells = <1>;
|
||||
dma-channels = <32>;
|
||||
dma-requests = <127>;
|
||||
dma-channel-mask = <0xfffe>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -40,15 +40,4 @@ required:
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
sdma_xbar: dma-router@4a002b78 {
|
||||
compatible = "ti,dra7-dma-crossbar";
|
||||
reg = <0x4a002b78 0xfc>;
|
||||
#dma-cells = <1>;
|
||||
dma-requests = <205>;
|
||||
ti,dma-safe-map = <0>;
|
||||
dma-masters = <&sdma>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/loongson,ls2x-apbdma.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Loongson LS2X APB DMA controller
|
||||
|
||||
description:
|
||||
The Loongson LS2X APB DMA controller is used for transferring data
|
||||
between system memory and the peripherals on the APB bus.
|
||||
|
||||
maintainers:
|
||||
- Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: loongson,ls2k1000-apbdma
|
||||
- items:
|
||||
- const: loongson,ls2k0500-apbdma
|
||||
- const: loongson,ls2k1000-apbdma
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
'#dma-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- '#dma-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/loongson,ls2k-clk.h>
|
||||
|
||||
dma-controller@1fe00c00 {
|
||||
compatible = "loongson,ls2k1000-apbdma";
|
||||
reg = <0x1fe00c00 0x8>;
|
||||
interrupt-parent = <&liointc1>;
|
||||
interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk LOONGSON2_APB_CLK>;
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -53,6 +53,9 @@ properties:
|
||||
ADMA_CHn_CTRL register.
|
||||
const: 1
|
||||
|
||||
dma-channel-mask:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -32,6 +32,8 @@ properties:
|
||||
- qcom,sm8350-gpi-dma
|
||||
- qcom,sm8450-gpi-dma
|
||||
- qcom,sm8550-gpi-dma
|
||||
- qcom,sm8650-gpi-dma
|
||||
- qcom,x1e80100-gpi-dma
|
||||
- const: qcom,sm6350-gpi-dma
|
||||
- items:
|
||||
- enum:
|
||||
|
||||
@@ -16,7 +16,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-dmac # RZ/G2UL
|
||||
- renesas,r9a07g043-dmac # RZ/G2UL and RZ/Five
|
||||
- renesas,r9a07g044-dmac # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-dmac # RZ/V2L
|
||||
- const: renesas,rz-dmac
|
||||
|
||||
@@ -29,6 +29,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- microchip,mpfs-pdma
|
||||
- sifive,fu540-c000-pdma
|
||||
- const: sifive,pdma0
|
||||
description:
|
||||
|
||||
@@ -37,11 +37,11 @@ properties:
|
||||
|
||||
reg:
|
||||
minItems: 3
|
||||
maxItems: 5
|
||||
maxItems: 9
|
||||
|
||||
reg-names:
|
||||
minItems: 3
|
||||
maxItems: 5
|
||||
maxItems: 9
|
||||
|
||||
"#dma-cells":
|
||||
const: 3
|
||||
@@ -141,7 +141,10 @@ allOf:
|
||||
ti,sci-rm-range-tchan: false
|
||||
|
||||
reg:
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: BCDMA Control /Status Registers region
|
||||
- description: RX Channel Realtime Registers region
|
||||
- description: Ring Realtime Registers region
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
@@ -161,14 +164,29 @@ allOf:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: BCDMA Control /Status Registers region
|
||||
- description: Block Copy Channel Realtime Registers region
|
||||
- description: RX Channel Realtime Registers region
|
||||
- description: TX Channel Realtime Registers region
|
||||
- description: Ring Realtime Registers region
|
||||
- description: Ring Configuration Registers region
|
||||
- description: TX Channel Configuration Registers region
|
||||
- description: RX Channel Configuration Registers region
|
||||
- description: Block Copy Channel Configuration Registers region
|
||||
|
||||
reg-names:
|
||||
minItems: 5
|
||||
items:
|
||||
- const: gcfg
|
||||
- const: bchanrt
|
||||
- const: rchanrt
|
||||
- const: tchanrt
|
||||
- const: ringrt
|
||||
- const: ring
|
||||
- const: tchan
|
||||
- const: rchan
|
||||
- const: bchan
|
||||
|
||||
required:
|
||||
- ti,sci-rm-range-bchan
|
||||
@@ -184,7 +202,11 @@ allOf:
|
||||
ti,sci-rm-range-bchan: false
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: BCDMA Control /Status Registers region
|
||||
- description: RX Channel Realtime Registers region
|
||||
- description: TX Channel Realtime Registers region
|
||||
- description: Ring Realtime Registers region
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
@@ -220,8 +242,13 @@ examples:
|
||||
<0x0 0x4c000000 0x0 0x20000>,
|
||||
<0x0 0x4a820000 0x0 0x20000>,
|
||||
<0x0 0x4aa40000 0x0 0x20000>,
|
||||
<0x0 0x4bc00000 0x0 0x100000>;
|
||||
reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt";
|
||||
<0x0 0x4bc00000 0x0 0x100000>,
|
||||
<0x0 0x48600000 0x0 0x8000>,
|
||||
<0x0 0x484a4000 0x0 0x2000>,
|
||||
<0x0 0x484c2000 0x0 0x2000>,
|
||||
<0x0 0x48420000 0x0 0x2000>;
|
||||
reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt",
|
||||
"ring", "tchan", "rchan", "bchan";
|
||||
msi-parent = <&inta_main_dmss>;
|
||||
#dma-cells = <3>;
|
||||
|
||||
|
||||
@@ -45,14 +45,28 @@ properties:
|
||||
The second cell is the ASEL value for the channel
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
minItems: 4
|
||||
items:
|
||||
- description: Packet DMA Control /Status Registers region
|
||||
- description: RX Channel Realtime Registers region
|
||||
- description: TX Channel Realtime Registers region
|
||||
- description: Ring Realtime Registers region
|
||||
- description: Ring Configuration Registers region
|
||||
- description: TX Configuration Registers region
|
||||
- description: RX Configuration Registers region
|
||||
- description: RX Flow Configuration Registers region
|
||||
|
||||
reg-names:
|
||||
minItems: 4
|
||||
items:
|
||||
- const: gcfg
|
||||
- const: rchanrt
|
||||
- const: tchanrt
|
||||
- const: ringrt
|
||||
- const: ring
|
||||
- const: tchan
|
||||
- const: rchan
|
||||
- const: rflow
|
||||
|
||||
msi-parent: true
|
||||
|
||||
@@ -136,8 +150,14 @@ examples:
|
||||
reg = <0x0 0x485c0000 0x0 0x100>,
|
||||
<0x0 0x4a800000 0x0 0x20000>,
|
||||
<0x0 0x4aa00000 0x0 0x40000>,
|
||||
<0x0 0x4b800000 0x0 0x400000>;
|
||||
reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt";
|
||||
<0x0 0x4b800000 0x0 0x400000>,
|
||||
<0x0 0x485e0000 0x0 0x20000>,
|
||||
<0x0 0x484a0000 0x0 0x4000>,
|
||||
<0x0 0x484c0000 0x0 0x2000>,
|
||||
<0x0 0x48430000 0x0 0x4000>;
|
||||
reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt",
|
||||
"ring", "tchan", "rchan", "rflow";
|
||||
|
||||
msi-parent = <&inta_main_dmss>;
|
||||
#dma-cells = <2>;
|
||||
|
||||
|
||||
@@ -69,13 +69,24 @@ properties:
|
||||
- ti,j721e-navss-mcu-udmap
|
||||
|
||||
reg:
|
||||
maxItems: 3
|
||||
minItems: 3
|
||||
items:
|
||||
- description: UDMA-P Control /Status Registers region
|
||||
- description: RX Channel Realtime Registers region
|
||||
- description: TX Channel Realtime Registers region
|
||||
- description: TX Configuration Registers region
|
||||
- description: RX Configuration Registers region
|
||||
- description: RX Flow Configuration Registers region
|
||||
|
||||
reg-names:
|
||||
minItems: 3
|
||||
items:
|
||||
- const: gcfg
|
||||
- const: rchanrt
|
||||
- const: tchanrt
|
||||
- const: tchan
|
||||
- const: rchan
|
||||
- const: rflow
|
||||
|
||||
msi-parent: true
|
||||
|
||||
@@ -158,8 +169,11 @@ examples:
|
||||
compatible = "ti,am654-navss-main-udmap";
|
||||
reg = <0x0 0x31150000 0x0 0x100>,
|
||||
<0x0 0x34000000 0x0 0x100000>,
|
||||
<0x0 0x35000000 0x0 0x100000>;
|
||||
reg-names = "gcfg", "rchanrt", "tchanrt";
|
||||
<0x0 0x35000000 0x0 0x100000>,
|
||||
<0x0 0x30b00000 0x0 0x20000>,
|
||||
<0x0 0x30c00000 0x0 0x8000>,
|
||||
<0x0 0x30d00000 0x0 0x4000>;
|
||||
reg-names = "gcfg", "rchanrt", "tchanrt", "tchan", "rchan", "rflow";
|
||||
#dma-cells = <1>;
|
||||
|
||||
ti,ringacc = <&ringacc>;
|
||||
|
||||
@@ -12639,6 +12639,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml
|
||||
F: drivers/gpio/gpio-loongson-64bit.c
|
||||
|
||||
LOONGSON LS2X APB DMA DRIVER
|
||||
M: Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
L: dmaengine@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml
|
||||
F: drivers/dma/ls2x-apb-dma.c
|
||||
|
||||
LOONGSON LS2X I2C DRIVER
|
||||
M: Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
|
||||
@@ -378,6 +378,20 @@ config LPC18XX_DMAMUX
|
||||
Enable support for DMA on NXP LPC18xx/43xx platforms
|
||||
with PL080 and multiplexed DMA request lines.
|
||||
|
||||
config LS2X_APB_DMA
|
||||
tristate "Loongson LS2X APB DMA support"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
help
|
||||
Support for the Loongson LS2X APB DMA controller driver. The
|
||||
DMA controller is having single DMA channel which can be
|
||||
configured for different peripherals like audio, nand, sdio
|
||||
etc which is in APB bus.
|
||||
|
||||
This DMA controller transfers data from memory to peripheral fifo.
|
||||
It does not support memory to memory data transfer.
|
||||
|
||||
config MCF_EDMA
|
||||
tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs"
|
||||
depends on M5441x || COMPILE_TEST
|
||||
|
||||
@@ -48,6 +48,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/
|
||||
obj-y += idxd/
|
||||
obj-$(CONFIG_K3_DMA) += k3dma.o
|
||||
obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o
|
||||
obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o
|
||||
obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o
|
||||
obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o
|
||||
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
|
||||
#define REG_BUS_WIDTH(ch) (0x8040 + (ch) * 0x200)
|
||||
|
||||
#define BUS_WIDTH_WORD_SIZE GENMASK(3, 0)
|
||||
#define BUS_WIDTH_FRAME_SIZE GENMASK(7, 4)
|
||||
#define BUS_WIDTH_8BIT 0x00
|
||||
#define BUS_WIDTH_16BIT 0x01
|
||||
#define BUS_WIDTH_32BIT 0x02
|
||||
@@ -740,7 +742,8 @@ static int admac_device_config(struct dma_chan *chan,
|
||||
struct admac_data *ad = adchan->host;
|
||||
bool is_tx = admac_chan_direction(adchan->no) == DMA_MEM_TO_DEV;
|
||||
int wordsize = 0;
|
||||
u32 bus_width = 0;
|
||||
u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) &
|
||||
~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE);
|
||||
|
||||
switch (is_tx ? config->dst_addr_width : config->src_addr_width) {
|
||||
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||
|
||||
@@ -81,9 +81,13 @@
|
||||
#define AXI_DMAC_REG_CURRENT_DEST_ADDR 0x438
|
||||
#define AXI_DMAC_REG_PARTIAL_XFER_LEN 0x44c
|
||||
#define AXI_DMAC_REG_PARTIAL_XFER_ID 0x450
|
||||
#define AXI_DMAC_REG_CURRENT_SG_ID 0x454
|
||||
#define AXI_DMAC_REG_SG_ADDRESS 0x47c
|
||||
#define AXI_DMAC_REG_SG_ADDRESS_HIGH 0x4bc
|
||||
|
||||
#define AXI_DMAC_CTRL_ENABLE BIT(0)
|
||||
#define AXI_DMAC_CTRL_PAUSE BIT(1)
|
||||
#define AXI_DMAC_CTRL_ENABLE_SG BIT(2)
|
||||
|
||||
#define AXI_DMAC_IRQ_SOT BIT(0)
|
||||
#define AXI_DMAC_IRQ_EOT BIT(1)
|
||||
@@ -97,20 +101,35 @@
|
||||
/* The maximum ID allocated by the hardware is 31 */
|
||||
#define AXI_DMAC_SG_UNUSED 32U
|
||||
|
||||
/* Flags for axi_dmac_hw_desc.flags */
|
||||
#define AXI_DMAC_HW_FLAG_LAST BIT(0)
|
||||
#define AXI_DMAC_HW_FLAG_IRQ BIT(1)
|
||||
|
||||
struct axi_dmac_hw_desc {
|
||||
u32 flags;
|
||||
u32 id;
|
||||
u64 dest_addr;
|
||||
u64 src_addr;
|
||||
u64 next_sg_addr;
|
||||
u32 y_len;
|
||||
u32 x_len;
|
||||
u32 src_stride;
|
||||
u32 dst_stride;
|
||||
u64 __pad[2];
|
||||
};
|
||||
|
||||
struct axi_dmac_sg {
|
||||
dma_addr_t src_addr;
|
||||
dma_addr_t dest_addr;
|
||||
unsigned int x_len;
|
||||
unsigned int y_len;
|
||||
unsigned int dest_stride;
|
||||
unsigned int src_stride;
|
||||
unsigned int id;
|
||||
unsigned int partial_len;
|
||||
bool schedule_when_free;
|
||||
|
||||
struct axi_dmac_hw_desc *hw;
|
||||
dma_addr_t hw_phys;
|
||||
};
|
||||
|
||||
struct axi_dmac_desc {
|
||||
struct virt_dma_desc vdesc;
|
||||
struct axi_dmac_chan *chan;
|
||||
|
||||
bool cyclic;
|
||||
bool have_partial_xfer;
|
||||
|
||||
@@ -139,6 +158,7 @@ struct axi_dmac_chan {
|
||||
bool hw_partial_xfer;
|
||||
bool hw_cyclic;
|
||||
bool hw_2d;
|
||||
bool hw_sg;
|
||||
};
|
||||
|
||||
struct axi_dmac {
|
||||
@@ -213,9 +233,11 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
|
||||
unsigned int flags = 0;
|
||||
unsigned int val;
|
||||
|
||||
val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER);
|
||||
if (val) /* Queue is full, wait for the next SOT IRQ */
|
||||
return;
|
||||
if (!chan->hw_sg) {
|
||||
val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER);
|
||||
if (val) /* Queue is full, wait for the next SOT IRQ */
|
||||
return;
|
||||
}
|
||||
|
||||
desc = chan->next_desc;
|
||||
|
||||
@@ -229,14 +251,15 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
|
||||
sg = &desc->sg[desc->num_submitted];
|
||||
|
||||
/* Already queued in cyclic mode. Wait for it to finish */
|
||||
if (sg->id != AXI_DMAC_SG_UNUSED) {
|
||||
if (sg->hw->id != AXI_DMAC_SG_UNUSED) {
|
||||
sg->schedule_when_free = true;
|
||||
return;
|
||||
}
|
||||
|
||||
desc->num_submitted++;
|
||||
if (desc->num_submitted == desc->num_sgs ||
|
||||
desc->have_partial_xfer) {
|
||||
if (chan->hw_sg) {
|
||||
chan->next_desc = NULL;
|
||||
} else if (++desc->num_submitted == desc->num_sgs ||
|
||||
desc->have_partial_xfer) {
|
||||
if (desc->cyclic)
|
||||
desc->num_submitted = 0; /* Start again */
|
||||
else
|
||||
@@ -246,32 +269,42 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan)
|
||||
chan->next_desc = desc;
|
||||
}
|
||||
|
||||
sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID);
|
||||
sg->hw->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID);
|
||||
|
||||
if (axi_dmac_dest_is_mem(chan)) {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->dest_addr);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->dest_stride);
|
||||
}
|
||||
if (!chan->hw_sg) {
|
||||
if (axi_dmac_dest_is_mem(chan)) {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->hw->dest_addr);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->hw->dst_stride);
|
||||
}
|
||||
|
||||
if (axi_dmac_src_is_mem(chan)) {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->src_addr);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->src_stride);
|
||||
if (axi_dmac_src_is_mem(chan)) {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->hw->src_addr);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->hw->src_stride);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the hardware supports cyclic transfers and there is no callback to
|
||||
* call and only a single segment, enable hw cyclic mode to avoid
|
||||
* unnecessary interrupts.
|
||||
* call, enable hw cyclic mode to avoid unnecessary interrupts.
|
||||
*/
|
||||
if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback &&
|
||||
desc->num_sgs == 1)
|
||||
flags |= AXI_DMAC_FLAG_CYCLIC;
|
||||
if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) {
|
||||
if (chan->hw_sg)
|
||||
desc->sg[desc->num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_IRQ;
|
||||
else if (desc->num_sgs == 1)
|
||||
flags |= AXI_DMAC_FLAG_CYCLIC;
|
||||
}
|
||||
|
||||
if (chan->hw_partial_xfer)
|
||||
flags |= AXI_DMAC_FLAG_PARTIAL_REPORT;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->y_len - 1);
|
||||
if (chan->hw_sg) {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS, (u32)sg->hw_phys);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS_HIGH,
|
||||
(u64)sg->hw_phys >> 32);
|
||||
} else {
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->hw->x_len);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->hw->y_len);
|
||||
}
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, flags);
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 1);
|
||||
}
|
||||
@@ -286,9 +319,9 @@ static inline unsigned int axi_dmac_total_sg_bytes(struct axi_dmac_chan *chan,
|
||||
struct axi_dmac_sg *sg)
|
||||
{
|
||||
if (chan->hw_2d)
|
||||
return sg->x_len * sg->y_len;
|
||||
return (sg->hw->x_len + 1) * (sg->hw->y_len + 1);
|
||||
else
|
||||
return sg->x_len;
|
||||
return (sg->hw->x_len + 1);
|
||||
}
|
||||
|
||||
static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan)
|
||||
@@ -307,9 +340,9 @@ static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan)
|
||||
list_for_each_entry(desc, &chan->active_descs, vdesc.node) {
|
||||
for (i = 0; i < desc->num_sgs; i++) {
|
||||
sg = &desc->sg[i];
|
||||
if (sg->id == AXI_DMAC_SG_UNUSED)
|
||||
if (sg->hw->id == AXI_DMAC_SG_UNUSED)
|
||||
continue;
|
||||
if (sg->id == id) {
|
||||
if (sg->hw->id == id) {
|
||||
desc->have_partial_xfer = true;
|
||||
sg->partial_len = len;
|
||||
found_sg = true;
|
||||
@@ -348,6 +381,9 @@ static void axi_dmac_compute_residue(struct axi_dmac_chan *chan,
|
||||
rslt->result = DMA_TRANS_NOERROR;
|
||||
rslt->residue = 0;
|
||||
|
||||
if (chan->hw_sg)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We get here if the last completed segment is partial, which
|
||||
* means we can compute the residue from that segment onwards
|
||||
@@ -374,36 +410,47 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan,
|
||||
(completed_transfers & AXI_DMAC_FLAG_PARTIAL_XFER_DONE))
|
||||
axi_dmac_dequeue_partial_xfers(chan);
|
||||
|
||||
do {
|
||||
sg = &active->sg[active->num_completed];
|
||||
if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */
|
||||
break;
|
||||
if (!(BIT(sg->id) & completed_transfers))
|
||||
break;
|
||||
active->num_completed++;
|
||||
sg->id = AXI_DMAC_SG_UNUSED;
|
||||
if (sg->schedule_when_free) {
|
||||
sg->schedule_when_free = false;
|
||||
start_next = true;
|
||||
}
|
||||
|
||||
if (sg->partial_len)
|
||||
axi_dmac_compute_residue(chan, active);
|
||||
|
||||
if (active->cyclic)
|
||||
if (chan->hw_sg) {
|
||||
if (active->cyclic) {
|
||||
vchan_cyclic_callback(&active->vdesc);
|
||||
|
||||
if (active->num_completed == active->num_sgs ||
|
||||
sg->partial_len) {
|
||||
if (active->cyclic) {
|
||||
active->num_completed = 0; /* wrap around */
|
||||
} else {
|
||||
list_del(&active->vdesc.node);
|
||||
vchan_cookie_complete(&active->vdesc);
|
||||
active = axi_dmac_active_desc(chan);
|
||||
}
|
||||
} else {
|
||||
list_del(&active->vdesc.node);
|
||||
vchan_cookie_complete(&active->vdesc);
|
||||
active = axi_dmac_active_desc(chan);
|
||||
start_next = !!active;
|
||||
}
|
||||
} while (active);
|
||||
} else {
|
||||
do {
|
||||
sg = &active->sg[active->num_completed];
|
||||
if (sg->hw->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */
|
||||
break;
|
||||
if (!(BIT(sg->hw->id) & completed_transfers))
|
||||
break;
|
||||
active->num_completed++;
|
||||
sg->hw->id = AXI_DMAC_SG_UNUSED;
|
||||
if (sg->schedule_when_free) {
|
||||
sg->schedule_when_free = false;
|
||||
start_next = true;
|
||||
}
|
||||
|
||||
if (sg->partial_len)
|
||||
axi_dmac_compute_residue(chan, active);
|
||||
|
||||
if (active->cyclic)
|
||||
vchan_cyclic_callback(&active->vdesc);
|
||||
|
||||
if (active->num_completed == active->num_sgs ||
|
||||
sg->partial_len) {
|
||||
if (active->cyclic) {
|
||||
active->num_completed = 0; /* wrap around */
|
||||
} else {
|
||||
list_del(&active->vdesc.node);
|
||||
vchan_cookie_complete(&active->vdesc);
|
||||
active = axi_dmac_active_desc(chan);
|
||||
}
|
||||
}
|
||||
} while (active);
|
||||
}
|
||||
|
||||
return start_next;
|
||||
}
|
||||
@@ -467,8 +514,12 @@ static void axi_dmac_issue_pending(struct dma_chan *c)
|
||||
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
|
||||
struct axi_dmac *dmac = chan_to_axi_dmac(chan);
|
||||
unsigned long flags;
|
||||
u32 ctrl = AXI_DMAC_CTRL_ENABLE;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
|
||||
if (chan->hw_sg)
|
||||
ctrl |= AXI_DMAC_CTRL_ENABLE_SG;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, ctrl);
|
||||
|
||||
spin_lock_irqsave(&chan->vchan.lock, flags);
|
||||
if (vchan_issue_pending(&chan->vchan))
|
||||
@@ -476,22 +527,58 @@ static void axi_dmac_issue_pending(struct dma_chan *c)
|
||||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
}
|
||||
|
||||
static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs)
|
||||
static struct axi_dmac_desc *
|
||||
axi_dmac_alloc_desc(struct axi_dmac_chan *chan, unsigned int num_sgs)
|
||||
{
|
||||
struct axi_dmac *dmac = chan_to_axi_dmac(chan);
|
||||
struct device *dev = dmac->dma_dev.dev;
|
||||
struct axi_dmac_hw_desc *hws;
|
||||
struct axi_dmac_desc *desc;
|
||||
dma_addr_t hw_phys;
|
||||
unsigned int i;
|
||||
|
||||
desc = kzalloc(struct_size(desc, sg, num_sgs), GFP_NOWAIT);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
desc->num_sgs = num_sgs;
|
||||
desc->chan = chan;
|
||||
|
||||
for (i = 0; i < num_sgs; i++)
|
||||
desc->sg[i].id = AXI_DMAC_SG_UNUSED;
|
||||
hws = dma_alloc_coherent(dev, PAGE_ALIGN(num_sgs * sizeof(*hws)),
|
||||
&hw_phys, GFP_ATOMIC);
|
||||
if (!hws) {
|
||||
kfree(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sgs; i++) {
|
||||
desc->sg[i].hw = &hws[i];
|
||||
desc->sg[i].hw_phys = hw_phys + i * sizeof(*hws);
|
||||
|
||||
hws[i].id = AXI_DMAC_SG_UNUSED;
|
||||
hws[i].flags = 0;
|
||||
|
||||
/* Link hardware descriptors */
|
||||
hws[i].next_sg_addr = hw_phys + (i + 1) * sizeof(*hws);
|
||||
}
|
||||
|
||||
/* The last hardware descriptor will trigger an interrupt */
|
||||
desc->sg[num_sgs - 1].hw->flags = AXI_DMAC_HW_FLAG_LAST | AXI_DMAC_HW_FLAG_IRQ;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void axi_dmac_free_desc(struct axi_dmac_desc *desc)
|
||||
{
|
||||
struct axi_dmac *dmac = chan_to_axi_dmac(desc->chan);
|
||||
struct device *dev = dmac->dma_dev.dev;
|
||||
struct axi_dmac_hw_desc *hw = desc->sg[0].hw;
|
||||
dma_addr_t hw_phys = desc->sg[0].hw_phys;
|
||||
|
||||
dma_free_coherent(dev, PAGE_ALIGN(desc->num_sgs * sizeof(*hw)),
|
||||
hw, hw_phys);
|
||||
kfree(desc);
|
||||
}
|
||||
|
||||
static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
|
||||
enum dma_transfer_direction direction, dma_addr_t addr,
|
||||
unsigned int num_periods, unsigned int period_len,
|
||||
@@ -508,26 +595,24 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
|
||||
segment_size = ((segment_size - 1) | chan->length_align_mask) + 1;
|
||||
|
||||
for (i = 0; i < num_periods; i++) {
|
||||
len = period_len;
|
||||
|
||||
while (len > segment_size) {
|
||||
for (len = period_len; len > segment_size; sg++) {
|
||||
if (direction == DMA_DEV_TO_MEM)
|
||||
sg->dest_addr = addr;
|
||||
sg->hw->dest_addr = addr;
|
||||
else
|
||||
sg->src_addr = addr;
|
||||
sg->x_len = segment_size;
|
||||
sg->y_len = 1;
|
||||
sg++;
|
||||
sg->hw->src_addr = addr;
|
||||
sg->hw->x_len = segment_size - 1;
|
||||
sg->hw->y_len = 0;
|
||||
sg->hw->flags = 0;
|
||||
addr += segment_size;
|
||||
len -= segment_size;
|
||||
}
|
||||
|
||||
if (direction == DMA_DEV_TO_MEM)
|
||||
sg->dest_addr = addr;
|
||||
sg->hw->dest_addr = addr;
|
||||
else
|
||||
sg->src_addr = addr;
|
||||
sg->x_len = len;
|
||||
sg->y_len = 1;
|
||||
sg->hw->src_addr = addr;
|
||||
sg->hw->x_len = len - 1;
|
||||
sg->hw->y_len = 0;
|
||||
sg++;
|
||||
addr += len;
|
||||
}
|
||||
@@ -554,7 +639,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
|
||||
for_each_sg(sgl, sg, sg_len, i)
|
||||
num_sgs += DIV_ROUND_UP(sg_dma_len(sg), chan->max_length);
|
||||
|
||||
desc = axi_dmac_alloc_desc(num_sgs);
|
||||
desc = axi_dmac_alloc_desc(chan, num_sgs);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
@@ -563,7 +648,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) ||
|
||||
!axi_dmac_check_len(chan, sg_dma_len(sg))) {
|
||||
kfree(desc);
|
||||
axi_dmac_free_desc(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -583,7 +668,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
|
||||
{
|
||||
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
|
||||
struct axi_dmac_desc *desc;
|
||||
unsigned int num_periods, num_segments;
|
||||
unsigned int num_periods, num_segments, num_sgs;
|
||||
|
||||
if (direction != chan->direction)
|
||||
return NULL;
|
||||
@@ -597,11 +682,16 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
|
||||
|
||||
num_periods = buf_len / period_len;
|
||||
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
|
||||
num_sgs = num_periods * num_segments;
|
||||
|
||||
desc = axi_dmac_alloc_desc(num_periods * num_segments);
|
||||
desc = axi_dmac_alloc_desc(chan, num_sgs);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
/* Chain the last descriptor to the first, and remove its "last" flag */
|
||||
desc->sg[num_sgs - 1].hw->next_sg_addr = desc->sg[0].hw_phys;
|
||||
desc->sg[num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_LAST;
|
||||
|
||||
axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods,
|
||||
period_len, desc->sg);
|
||||
|
||||
@@ -653,26 +743,26 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
desc = axi_dmac_alloc_desc(1);
|
||||
desc = axi_dmac_alloc_desc(chan, 1);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
if (axi_dmac_src_is_mem(chan)) {
|
||||
desc->sg[0].src_addr = xt->src_start;
|
||||
desc->sg[0].src_stride = xt->sgl[0].size + src_icg;
|
||||
desc->sg[0].hw->src_addr = xt->src_start;
|
||||
desc->sg[0].hw->src_stride = xt->sgl[0].size + src_icg;
|
||||
}
|
||||
|
||||
if (axi_dmac_dest_is_mem(chan)) {
|
||||
desc->sg[0].dest_addr = xt->dst_start;
|
||||
desc->sg[0].dest_stride = xt->sgl[0].size + dst_icg;
|
||||
desc->sg[0].hw->dest_addr = xt->dst_start;
|
||||
desc->sg[0].hw->dst_stride = xt->sgl[0].size + dst_icg;
|
||||
}
|
||||
|
||||
if (chan->hw_2d) {
|
||||
desc->sg[0].x_len = xt->sgl[0].size;
|
||||
desc->sg[0].y_len = xt->numf;
|
||||
desc->sg[0].hw->x_len = xt->sgl[0].size - 1;
|
||||
desc->sg[0].hw->y_len = xt->numf - 1;
|
||||
} else {
|
||||
desc->sg[0].x_len = xt->sgl[0].size * xt->numf;
|
||||
desc->sg[0].y_len = 1;
|
||||
desc->sg[0].hw->x_len = xt->sgl[0].size * xt->numf - 1;
|
||||
desc->sg[0].hw->y_len = 0;
|
||||
}
|
||||
|
||||
if (flags & DMA_CYCLIC)
|
||||
@@ -688,7 +778,7 @@ static void axi_dmac_free_chan_resources(struct dma_chan *c)
|
||||
|
||||
static void axi_dmac_desc_free(struct virt_dma_desc *vdesc)
|
||||
{
|
||||
kfree(container_of(vdesc, struct axi_dmac_desc, vdesc));
|
||||
axi_dmac_free_desc(to_axi_dmac_desc(vdesc));
|
||||
}
|
||||
|
||||
static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg)
|
||||
@@ -714,6 +804,9 @@ static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg)
|
||||
case AXI_DMAC_REG_CURRENT_DEST_ADDR:
|
||||
case AXI_DMAC_REG_PARTIAL_XFER_LEN:
|
||||
case AXI_DMAC_REG_PARTIAL_XFER_ID:
|
||||
case AXI_DMAC_REG_CURRENT_SG_ID:
|
||||
case AXI_DMAC_REG_SG_ADDRESS:
|
||||
case AXI_DMAC_REG_SG_ADDRESS_HIGH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -866,6 +959,10 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
|
||||
if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
|
||||
chan->hw_cyclic = true;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS, 0xffffffff);
|
||||
if (axi_dmac_read(dmac, AXI_DMAC_REG_SG_ADDRESS))
|
||||
chan->hw_sg = true;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 1);
|
||||
if (axi_dmac_read(dmac, AXI_DMAC_REG_Y_LENGTH) == 1)
|
||||
chan->hw_2d = true;
|
||||
@@ -911,6 +1008,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
struct axi_dmac *dmac;
|
||||
struct regmap *regmap;
|
||||
unsigned int version;
|
||||
u32 irq_mask = 0;
|
||||
int ret;
|
||||
|
||||
dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
|
||||
@@ -966,6 +1064,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
dma_dev->dst_addr_widths = BIT(dmac->chan.dest_width);
|
||||
dma_dev->directions = BIT(dmac->chan.direction);
|
||||
dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
|
||||
dma_dev->max_sg_burst = 31; /* 31 SGs maximum in one burst */
|
||||
INIT_LIST_HEAD(&dma_dev->channels);
|
||||
|
||||
dmac->chan.vchan.desc_free = axi_dmac_desc_free;
|
||||
@@ -977,7 +1076,10 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
|
||||
dma_dev->copy_align = (dmac->chan.address_align_mask + 1);
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
|
||||
if (dmac->chan.hw_sg)
|
||||
irq_mask |= AXI_DMAC_IRQ_SOT;
|
||||
|
||||
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, irq_mask);
|
||||
|
||||
if (of_dma_is_coherent(pdev->dev.of_node)) {
|
||||
ret = axi_dmac_read(dmac, AXI_DMAC_REG_COHERENCY_DESC);
|
||||
|
||||
@@ -1103,6 +1103,9 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_register);
|
||||
static void __dma_async_device_channel_unregister(struct dma_device *device,
|
||||
struct dma_chan *chan)
|
||||
{
|
||||
if (chan->local == NULL)
|
||||
return;
|
||||
|
||||
WARN_ONCE(!device->device_release && chan->client_count,
|
||||
"%s called while %d clients hold a reference\n",
|
||||
__func__, chan->client_count);
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
static bool nobounce;
|
||||
module_param(nobounce, bool, 0644);
|
||||
MODULE_PARM_DESC(nobounce, "Prevent using swiotlb buffer (default: use swiotlb buffer)");
|
||||
|
||||
static unsigned int test_buf_size = 16384;
|
||||
module_param(test_buf_size, uint, 0644);
|
||||
MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
|
||||
@@ -90,6 +94,7 @@ MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts");
|
||||
|
||||
/**
|
||||
* struct dmatest_params - test parameters.
|
||||
* @nobounce: prevent using swiotlb buffer
|
||||
* @buf_size: size of the memcpy test buffer
|
||||
* @channel: bus ID of the channel to test
|
||||
* @device: bus ID of the DMA Engine to test
|
||||
@@ -106,6 +111,7 @@ MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts");
|
||||
* @polled: use polling for completion instead of interrupts
|
||||
*/
|
||||
struct dmatest_params {
|
||||
bool nobounce;
|
||||
unsigned int buf_size;
|
||||
char channel[20];
|
||||
char device[32];
|
||||
@@ -215,6 +221,7 @@ struct dmatest_done {
|
||||
struct dmatest_data {
|
||||
u8 **raw;
|
||||
u8 **aligned;
|
||||
gfp_t gfp_flags;
|
||||
unsigned int cnt;
|
||||
unsigned int off;
|
||||
};
|
||||
@@ -533,7 +540,7 @@ static int dmatest_alloc_test_data(struct dmatest_data *d,
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < d->cnt; i++) {
|
||||
d->raw[i] = kmalloc(buf_size + align, GFP_KERNEL);
|
||||
d->raw[i] = kmalloc(buf_size + align, d->gfp_flags);
|
||||
if (!d->raw[i])
|
||||
goto err;
|
||||
|
||||
@@ -655,6 +662,13 @@ static int dmatest_func(void *data)
|
||||
goto err_free_coefs;
|
||||
}
|
||||
|
||||
src->gfp_flags = GFP_KERNEL;
|
||||
dst->gfp_flags = GFP_KERNEL;
|
||||
if (params->nobounce) {
|
||||
src->gfp_flags = GFP_DMA;
|
||||
dst->gfp_flags = GFP_DMA;
|
||||
}
|
||||
|
||||
if (dmatest_alloc_test_data(src, buf_size, align) < 0)
|
||||
goto err_free_coefs;
|
||||
|
||||
@@ -1093,6 +1107,7 @@ static void add_threaded_test(struct dmatest_info *info)
|
||||
struct dmatest_params *params = &info->params;
|
||||
|
||||
/* Copy test parameters */
|
||||
params->nobounce = nobounce;
|
||||
params->buf_size = test_buf_size;
|
||||
strscpy(params->channel, strim(test_channel), sizeof(params->channel));
|
||||
strscpy(params->device, strim(test_device), sizeof(params->device));
|
||||
|
||||
@@ -176,7 +176,7 @@ dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
|
||||
};
|
||||
struct dentry *regs_dent, *ch_dent;
|
||||
int nr_entries, i;
|
||||
char name[16];
|
||||
char name[32];
|
||||
|
||||
regs_dent = debugfs_create_dir(WRITE_STR, dent);
|
||||
|
||||
@@ -239,7 +239,7 @@ static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw,
|
||||
};
|
||||
struct dentry *regs_dent, *ch_dent;
|
||||
int nr_entries, i;
|
||||
char name[16];
|
||||
char name[32];
|
||||
|
||||
regs_dent = debugfs_create_dir(READ_STR, dent);
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ static void dw_hdma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir,
|
||||
static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
|
||||
{
|
||||
struct dentry *regs_dent, *ch_dent;
|
||||
char name[16];
|
||||
char name[32];
|
||||
int i;
|
||||
|
||||
regs_dent = debugfs_create_dir(WRITE_STR, dent);
|
||||
@@ -133,7 +133,7 @@ static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
|
||||
static void dw_hdma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dent)
|
||||
{
|
||||
struct dentry *regs_dent, *ch_dent;
|
||||
char name[16];
|
||||
char name[32];
|
||||
int i;
|
||||
|
||||
regs_dent = debugfs_create_dir(READ_STR, dent);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* Vybrid and Layerscape SoCs.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/dma/fsl-edma.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -21,10 +22,6 @@
|
||||
|
||||
#include "fsl-edma-common.h"
|
||||
|
||||
#define ARGS_RX BIT(0)
|
||||
#define ARGS_REMOTE BIT(1)
|
||||
#define ARGS_MULTI_FIFO BIT(2)
|
||||
|
||||
static void fsl_edma_synchronize(struct dma_chan *chan)
|
||||
{
|
||||
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
|
||||
@@ -153,9 +150,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
|
||||
i = fsl_chan - fsl_edma->chans;
|
||||
|
||||
fsl_chan->priority = dma_spec->args[1];
|
||||
fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
|
||||
fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
|
||||
fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO;
|
||||
fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
|
||||
fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
|
||||
fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
|
||||
|
||||
if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
|
||||
continue;
|
||||
|
||||
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
|
||||
continue;
|
||||
|
||||
if (!b_chmux && i == dma_spec->args[0]) {
|
||||
chan = dma_get_slave_channel(chan);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user