mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
dmaengine updates for v7.4
Core:
- Better document descriptor flags and clarify ordering rules around
cookie completion
- New APIs to start hiding dmaengine guts so that we can start making
them internal
New Support:
- Nord and Maili GPI DMAengine support
- DW axi dma updates and support for UltraRISC DP1000 controller
- Apple M3 generation ADMACs support
- Amlogic A9 SoC DMA controller driver
- Sun6i refactoring and support for Allwinner A733 DMA controller
Updates:
- Freescale device_prep_peripheral_dma_vec support and dynamic
scatter/gather chaining
- TI crossbar and cppi DT schema conversion
- zynqmp driver updates for error patch handling
- Link list handling improvements for DW edma driver
- ST dma40 improvements and corner case handling
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmriBLYACgkQfBQHDyUj
g0edThAApa2lWUowEsgkLYAEX+ufHWqlBlNtXTpBwSL6XKJ3yPupvaq1aR3lquud
NZ8TS5VnVpnYWtcog04f/murYh9NEX/YHJm9n/FrS+y0caq/P6xpCi4Uozb8hSCS
JlLW8nQFYTBugx/YJ7EZ0YsWB4QPY6q6KOkOQnJYLvpuTliTxu71lPSe4izk4tMD
zz7t2vUXpKz2L+oD0LpJ37gqYMxz6wSeRFbBP+YiEc/x0GLVK2xkdoKvagHSC0tb
QVc8pztUviwBWlqmWIeoHUikoboKKift61TLBHU5cMNEv3+M8I3hORHsWSlhQWBo
d3pJbCdLPjt8CAX2jeWpI97hKjSxrhtpox8p7hzCZX9FLvr0SPwaYsapHPJzjfLc
09BQOgRi6KGuWt/4GWpBLZtFSR8y6wOOqrdVNRT0QS1sqqiBd7LWYPFboWo+WZFx
Rc2DPhmWnmZyRO391xUNXjxBDxdERKUHi57VCX1R5946NH8Ve+ga1y9hR2hQMKu+
TqrwVUc+JgHqze4C4JjLEkgAgVfX8A1vRdTRA9Xa3f2kvuSmdB6gq/v2057hJz3H
uH6pMDhX0PH8QxB0Tx/YTWeJOWztvmqBl3XeuqmVSUzLHZiXgUEKHbROYIyIvu1k
5/uZtlDcV4Tl51r2Adl6aPqZlvsljHtcS9pJeP4aHs5rFA00xY0=
=2PH5
-----END PGP SIGNATURE-----
Merge tag 'dmaengine-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul:
"This consists of start of work for hiding dmaengine internals and
adding new APIs for dmaengine calls. Also couple of drivers and device
and lot of updates esp AI-assisted improvements to drivers.
Core:
- Better document descriptor flags and clarify ordering rules around
cookie completion
- New APIs to start hiding dmaengine guts so that we can start making
them internal
New Support:
- Nord and Maili GPI DMAengine support
- DW axi dma updates and support for UltraRISC DP1000 controller
- Apple M3 generation ADMACs support
- Amlogic A9 SoC DMA controller driver
- Sun6i refactoring and support for Allwinner A733 DMA controller
Updates:
- Freescale device_prep_peripheral_dma_vec support and dynamic
scatter/gather chaining
- TI crossbar and cppi DT schema conversion
- zynqmp driver updates for error patch handling
- Link list handling improvements for DW edma driver
- ST dma40 improvements and corner case handling"
* tag 'dmaengine-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (149 commits)
dmaengine: amlogic: Fix regmap error check issue
dmaengine: ste_dma40: Preserve the LCPA I/O address space
docs: dmaengine: clarify ordering rules around cookie completion
dmaengine: move driver-private helpers out of include/linux/dmaengine.h
dmaengine: add dmaengine_desc_set_callback() helper
dmaengine: add dmaengine_get_provider_device() API
dmaengine: add dmaengine_get_max_xor() helper
dmaengine: add dmaengine_get_cap_mask() and dmaengine_has_cap() helpers
dmaengine: add dmaengine_get_copy_align() and related alignment getter helpers
dmaengine: add dmaengine_is_*_aligned() helpers for DMA consumers
dmaengine: add dmaengine_prep_dma_(pq|pq_val|interrupt|xor)() API
dmaengine: sh: rcar-dmac: Add support for R-Car Gen5 SoCs
dt-bindings: renesas,rcar-dmac: Add support for R-Car X5H SoC
dmaengine: sh: rcar-dmac: SMMU doesn't need IPMMU workaround
dmaengine: sh: rcar-dmac: fix style in struct initialization
dmaengine: qcom: bam_dma: free interrupt before the clock in error path
dmaengine: ppc4xx: fix typo "contoller" in comment
dmaengine: ste_dma40: Search all blocks for fixed logical channels
dt-bindings: dma: dma40: Restore disabled-channels
dmaengine: ste_dma40: Validate memcpy configuration
...
This commit is contained in:
commit
ae3690eb2a
|
|
@ -25,6 +25,7 @@ properties:
|
|||
- allwinner,sun50i-a64-dma
|
||||
- allwinner,sun50i-a100-dma
|
||||
- allwinner,sun50i-h6-dma
|
||||
- allwinner,sun60i-a733-dma
|
||||
- items:
|
||||
- const: allwinner,sun8i-r40-dma
|
||||
- const: allwinner,sun50i-a64-dma
|
||||
|
|
@ -70,6 +71,7 @@ if:
|
|||
- allwinner,sun20i-d1-dma
|
||||
- allwinner,sun50i-a100-dma
|
||||
- allwinner,sun50i-h6-dma
|
||||
- allwinner,sun60i-a733-dma
|
||||
|
||||
then:
|
||||
properties:
|
||||
|
|
|
|||
68
Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
Normal file
68
Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/amlogic,a9-dma.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic general DMA controller
|
||||
|
||||
description:
|
||||
This is a general-purpose peripheral DMA controller. It currently supports
|
||||
major peripherals including I2C, I3C, PIO, and CAN-BUS. Transmit and receive
|
||||
for the same peripheral use two separate channels, controlled by different
|
||||
register sets. I2C and I3C transfer data in 1-byte units, while PIO and
|
||||
CAN-BUS transfer data in 4-byte units. From the controller’s perspective,
|
||||
there is no significant difference.
|
||||
|
||||
maintainers:
|
||||
- Xianwei Zhao <xianwei.zhao@amlogic.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: amlogic,a9-dma
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: sys
|
||||
|
||||
'#dma-cells':
|
||||
const: 2
|
||||
description:
|
||||
The first cell is the DMA channel type(AMLOGIC_A9_DMA_TX or AMLOGIC_A9_DMA_RX).
|
||||
The second cell is the DMA channel index.
|
||||
|
||||
dma-channels:
|
||||
maximum: 64
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- '#dma-cells'
|
||||
- dma-channels
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
dma-controller@fe400000 {
|
||||
compatible = "amlogic,a9-dma";
|
||||
reg = <0xfe400000 0x4000>;
|
||||
interrupts = <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc 45>;
|
||||
#dma-cells = <2>;
|
||||
dma-channels = <28>;
|
||||
};
|
||||
|
|
@ -10,7 +10,7 @@ description: |
|
|||
Apple's Audio DMA Controller (ADMAC) is used to fetch and store audio samples
|
||||
on SoCs from the "Apple Silicon" family.
|
||||
|
||||
The controller has been seen with up to 24 channels. Even-numbered channels
|
||||
The controller has been seen with up to 32 channels. Even-numbered channels
|
||||
are TX-only, odd-numbered are RX-only. Individual channels are coupled to
|
||||
fixed device endpoints.
|
||||
|
||||
|
|
@ -33,6 +33,12 @@ properties:
|
|||
- apple,t8103-admac
|
||||
- apple,t8112-admac
|
||||
- const: apple,admac
|
||||
- items:
|
||||
- enum:
|
||||
- apple,t6030-admac
|
||||
- apple,t6031-admac
|
||||
- const: apple,t8122-admac
|
||||
- const: apple,t8122-admac
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -43,7 +49,7 @@ properties:
|
|||
Clients specify a single cell with channel number.
|
||||
|
||||
dma-channels:
|
||||
maximum: 24
|
||||
maximum: 32
|
||||
|
||||
interrupts:
|
||||
minItems: 4
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/hisilicon,k3-dma-1.0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Hisilicon K3 DMA controller
|
||||
|
||||
maintainers:
|
||||
- Wei Xu <xuwei5@hisilicon.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- hisilicon,k3-dma-1.0
|
||||
- hisilicon,hisi-pcm-asp-dma-1.0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
'#dma-cells':
|
||||
const: 1
|
||||
|
||||
dma-channels:
|
||||
description: Number of physical DMA channels supported.
|
||||
maximum: 32
|
||||
|
||||
dma-requests:
|
||||
description: Number of virtual DMA request lines supported.
|
||||
maximum: 32
|
||||
|
||||
dma-channel-mask:
|
||||
description: Bitmask of usable DMA channels.
|
||||
|
||||
dma-no-cci:
|
||||
type: boolean
|
||||
description: DMA is not coherent with the CCI.
|
||||
|
||||
dma-type:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: SoC-specific DMA type name.
|
||||
enum:
|
||||
- hi3660_dma
|
||||
- hi6220_dma
|
||||
|
||||
interrupt-names:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- '#dma-cells'
|
||||
- dma-channels
|
||||
- dma-requests
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: hisilicon,k3-dma-1.0
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dma-controller@fcd02000 {
|
||||
compatible = "hisilicon,k3-dma-1.0";
|
||||
reg = <0xfcd02000 0x1000>;
|
||||
#dma-cells = <1>;
|
||||
dma-channels = <16>;
|
||||
dma-requests = <27>;
|
||||
interrupts = <0 12 4>;
|
||||
clocks = <&pclk>;
|
||||
};
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
* Hisilicon K3 DMA controller
|
||||
|
||||
See dma.txt first
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of
|
||||
- "hisilicon,k3-dma-1.0"
|
||||
- "hisilicon,hisi-pcm-asp-dma-1.0"
|
||||
- reg: Should contain DMA registers location and length.
|
||||
- interrupts: Should contain one interrupt shared by all channel
|
||||
- #dma-cells: see dma.txt, should be 1, para number
|
||||
- dma-channels: physical channels supported
|
||||
- dma-requests: virtual channels supported, each virtual channel
|
||||
have specific request line
|
||||
- clocks: clock required
|
||||
|
||||
Example:
|
||||
|
||||
Controller:
|
||||
dma0: dma@fcd02000 {
|
||||
compatible = "hisilicon,k3-dma-1.0";
|
||||
reg = <0xfcd02000 0x1000>;
|
||||
#dma-cells = <1>;
|
||||
dma-channels = <16>;
|
||||
dma-requests = <27>;
|
||||
interrupts = <0 12 4>;
|
||||
clocks = <&pclk>;
|
||||
};
|
||||
|
||||
Client:
|
||||
Use specific request line passing from dmax
|
||||
For example, i2c0 read channel request line is 18, while write channel use 19
|
||||
|
||||
i2c0: i2c@fcb08000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
dmas = <&dma0 18 /* read channel */
|
||||
&dma0 19>; /* write channel */
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
i2c1: i2c@fcb09000 {
|
||||
compatible = "snps,designware-i2c";
|
||||
dmas = <&dma0 20 /* read channel */
|
||||
&dma0 21>; /* write channel */
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2712-uart-dma
|
||||
- mediatek,mt6572-uart-dma
|
||||
- mediatek,mt6795-uart-dma
|
||||
- mediatek,mt8173-uart-dma
|
||||
- mediatek,mt8183-uart-dma
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ properties:
|
|||
- qcom,glymur-gpi-dma
|
||||
- qcom,hawi-gpi-dma
|
||||
- qcom,kaanapali-gpi-dma
|
||||
- qcom,maili-gpi-dma
|
||||
- qcom,milos-gpi-dma
|
||||
- qcom,nord-gpi-dma
|
||||
- qcom,qcm2290-gpi-dma
|
||||
- qcom,qcs8300-gpi-dma
|
||||
- qcom,qdu1000-gpi-dma
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ properties:
|
|||
- renesas,dmac-r8a779h0 # R-Car V4M
|
||||
- const: renesas,rcar-gen4-dmac # R-Car Gen4
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,dmac-r8a78000 # R-Car X5H
|
||||
- const: renesas,rcar-gen5-dmac # R-Car Gen5
|
||||
|
||||
reg: true
|
||||
|
||||
interrupts:
|
||||
|
|
@ -123,6 +128,7 @@ if:
|
|||
contains:
|
||||
enum:
|
||||
- renesas,rcar-gen4-dmac
|
||||
- renesas,rcar-gen5-dmac
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,27 @@ description:
|
|||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ultrarisc,dp1000-axi-dma
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
interrupts:
|
||||
minItems: 8
|
||||
dma-channels:
|
||||
const: 8
|
||||
snps,dma-masters:
|
||||
const: 1
|
||||
snps,data-width:
|
||||
const: 4
|
||||
snps,priority:
|
||||
minItems: 8
|
||||
snps,block-size:
|
||||
minItems: 8
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -27,6 +48,7 @@ properties:
|
|||
- enum:
|
||||
- altr,agilex5-axi-dma
|
||||
- sophgo,cv1800b-axi-dma
|
||||
- ultrarisc,dp1000-axi-dma
|
||||
- const: snps,axi-dma-1.01a
|
||||
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -140,8 +140,22 @@ properties:
|
|||
- description: LCPA (Logical Channel Parameter Address) memory.
|
||||
- description: LCLA (Logical Channel Link base Address) memory.
|
||||
|
||||
disabled-channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
maxItems: 31
|
||||
uniqueItems: true
|
||||
items:
|
||||
maximum: 31
|
||||
description: Physical channels that cannot be used by the DMA engine.
|
||||
|
||||
memcpy-channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
maxItems: 8
|
||||
uniqueItems: true
|
||||
items:
|
||||
maximum: 63
|
||||
description: Array of u32 elements indicating which channels on the DMA
|
||||
engine are eligible for memcpy transfers
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/ti,dra7-dma-crossbar.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DMA Crossbar (DMA request router)
|
||||
|
||||
maintainers:
|
||||
- Vignesh Raghavendra <vigneshr@ti.com>
|
||||
- Bhargav Joshi <j.bhargav.u@gmail.com>
|
||||
|
||||
description:
|
||||
When requesting channel via ti,dra7-dma-crossbar, the DMA client must request
|
||||
the DMA event number as crossbar ID (input to the DMA crossbar). For
|
||||
ti,am335x-edma-crossbar the meaning of parameters of dmas for clients dmas =
|
||||
<&edma_xbar 12 0 1>; where <12> is the DMA request number, <0> is the TC the
|
||||
event should be assigned and <1> is the mux selection for in the crossbar.
|
||||
When mux 0 is used the DMA channel can be requested directly from edma node.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,dra7-dma-crossbar
|
||||
- ti,am335x-edma-crossbar
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#dma-cells":
|
||||
minimum: 1
|
||||
maximum: 3
|
||||
|
||||
dma-requests:
|
||||
minimum: 1
|
||||
maximum: 256
|
||||
|
||||
dma-masters:
|
||||
maxItems: 1
|
||||
|
||||
ti,dma-safe-map:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Safe routing value for unused request lines
|
||||
|
||||
ti,reserved-dma-request-ranges:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
description:
|
||||
DMA request ranges which should not be used when mapping xbar input to
|
||||
DMA request, they are either allocated to be used by for example the DSP
|
||||
or they are used as memcpy channels in eDMA.
|
||||
items:
|
||||
items:
|
||||
- description: starting DMA request line number
|
||||
- description: number of consecutive lines to reserve
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#dma-cells"
|
||||
- dma-requests
|
||||
- dma-masters
|
||||
|
||||
allOf:
|
||||
- $ref: dma-router.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,am335x-edma-crossbar
|
||||
then:
|
||||
properties:
|
||||
"#dma-cells":
|
||||
const: 3
|
||||
|
||||
else:
|
||||
properties:
|
||||
"#dma-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dma-router@4a002b78 {
|
||||
compatible = "ti,dra7-dma-crossbar";
|
||||
reg = <0x4a002b78 0xfc>;
|
||||
#dma-cells = <1>;
|
||||
dma-requests = <205>;
|
||||
ti,dma-safe-map = <0>;
|
||||
/* Protect the sDMA request ranges: 10-14 and 100-126 */
|
||||
ti,reserved-dma-request-ranges = <10 5>, <100 27>;
|
||||
dma-masters = <&sdma>;
|
||||
};
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
Texas Instruments DMA Crossbar (DMA request router)
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar
|
||||
"ti,am335x-edma-crossbar" for AM335x and AM437x
|
||||
- reg: Memory map for accessing module
|
||||
- #dma-cells: Should be set to match with the DMA controller's dma-cells
|
||||
for ti,dra7-dma-crossbar and <3> for ti,am335x-edma-crossbar.
|
||||
- dma-requests: Number of DMA requests the crossbar can receive
|
||||
- dma-masters: phandle pointing to the DMA controller
|
||||
|
||||
The DMA controller node need to have the following poroperties:
|
||||
- dma-requests: Number of DMA requests the controller can handle
|
||||
|
||||
Optional properties:
|
||||
- ti,dma-safe-map: Safe routing value for unused request lines
|
||||
- ti,reserved-dma-request-ranges: DMA request ranges which should not be used
|
||||
when mapping xbar input to DMA request, they are either
|
||||
allocated to be used by for example the DSP or they are used as
|
||||
memcpy channels in eDMA.
|
||||
|
||||
Notes:
|
||||
When requesting channel via ti,dra7-dma-crossbar, the DMA client must request
|
||||
the DMA event number as crossbar ID (input to the DMA crossbar).
|
||||
|
||||
For ti,am335x-edma-crossbar: the meaning of parameters of dmas for clients:
|
||||
dmas = <&edma_xbar 12 0 1>; where <12> is the DMA request number, <0> is the TC
|
||||
the event should be assigned and <1> is the mux selection for in the crossbar.
|
||||
When mux 0 is used the DMA channel can be requested directly from edma node.
|
||||
|
||||
Example:
|
||||
|
||||
/* DMA controller */
|
||||
sdma: dma-controller@4a056000 {
|
||||
compatible = "ti,omap4430-sdma";
|
||||
reg = <0x4a056000 0x1000>;
|
||||
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#dma-cells = <1>;
|
||||
dma-channels = <32>;
|
||||
dma-requests = <127>;
|
||||
};
|
||||
|
||||
/* DMA crossbar */
|
||||
sdma_xbar: dma-router@4a002b78 {
|
||||
compatible = "ti,dra7-dma-crossbar";
|
||||
reg = <0x4a002b78 0xfc>;
|
||||
#dma-cells = <1>;
|
||||
dma-requests = <205>;
|
||||
ti,dma-safe-map = <0>;
|
||||
/* Protect the sDMA request ranges: 10-14 and 100-126 */
|
||||
ti,reserved-dma-request-ranges = <10 5>, <100 27>;
|
||||
dma-masters = <&sdma>;
|
||||
};
|
||||
|
||||
/* DMA client */
|
||||
uart1: serial@4806a000 {
|
||||
compatible = "ti,omap4-uart";
|
||||
reg = <0x4806a000 0x100>;
|
||||
interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ti,hwmods = "uart1";
|
||||
clock-frequency = <48000000>;
|
||||
/* Requesting crossbar input 49 and 50 */
|
||||
dmas = <&sdma_xbar 49>, <&sdma_xbar 50>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
|
@ -321,7 +321,7 @@ to use.
|
|||
- DESC_METADATA_CLIENT
|
||||
|
||||
The metadata buffer is allocated/provided by the client driver and it is
|
||||
attached (via the dmaengine_desc_attach_metadata() helper to the descriptor.
|
||||
attached (via the dmaengine_desc_attach_metadata() helper) to the descriptor.
|
||||
|
||||
From the DMA driver the following is expected for this mode:
|
||||
|
||||
|
|
@ -413,9 +413,11 @@ supported.
|
|||
|
||||
- You'll also need to set following fields in this structure:
|
||||
|
||||
- flags:
|
||||
TODO: Can it be modified by the driver itself, or
|
||||
should it be always the flags passed in the arguments
|
||||
- flags: this field belongs to the client. The driver stores the
|
||||
flags passed in the arguments and must not modify them. It reads
|
||||
the DMA_PREP_* bits while preparing the descriptor, and must only
|
||||
test DMA_CTRL_ACK and DMA_CTRL_REUSE, which the client may change
|
||||
after the descriptor has been prepared.
|
||||
|
||||
- tx_submit: A pointer to a function you have to implement,
|
||||
that is supposed to push the current transaction descriptor to a
|
||||
|
|
@ -555,6 +557,11 @@ dma_cookie_t
|
|||
- Not really relevant any more since the introduction of ``virt-dma``
|
||||
that abstracts it away.
|
||||
|
||||
- dmaengine drivers need to ensure buffers are flushed before invoking
|
||||
vchan_cookie_complete() or dma_cookie_complete(). This would imply a call
|
||||
to unmapping buffers or any such architecture calls to ensure caller seeing
|
||||
buffers are flushed is done before invoking these calls.
|
||||
|
||||
dma_vec
|
||||
|
||||
- A small structure that contains a DMA address and length.
|
||||
|
|
|
|||
|
|
@ -1391,6 +1391,13 @@ F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
|
|||
F: drivers/perf/amlogic/
|
||||
F: include/soc/amlogic/
|
||||
|
||||
AMLOGIC DMA DRIVER
|
||||
M: Xianwei Zhao <xianwei.zhao@amlogic.com>
|
||||
L: linux-amlogic@lists.infradead.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/dma/amlogic,a9-dma.yaml
|
||||
F: drivers/dma/amlogic-dma.c
|
||||
|
||||
AMLOGIC ISP DRIVER
|
||||
M: Keke Li <keke.li@amlogic.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
@ -27622,7 +27629,7 @@ TEXAS INSTRUMENTS DMA DRIVERS
|
|||
M: Vignesh Raghavendra <vigneshr@ti.com>
|
||||
L: dmaengine@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
|
||||
F: Documentation/devicetree/bindings/dma/ti,dra7-dma-crossbar.yaml
|
||||
F: Documentation/devicetree/bindings/dma/ti-edma.txt
|
||||
F: Documentation/devicetree/bindings/dma/ti/
|
||||
F: drivers/dma/ti/
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ config AMCC_PPC440SPE_ADMA
|
|||
help
|
||||
Enable support for the AMCC PPC440SPe RAID engines.
|
||||
|
||||
config AMLOGIC_DMA
|
||||
tristate "Amlogic general DMA support"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Enable support for the Amlogic general DMA engines. THis DMA
|
||||
controller is used some Amlogic SoCs, such as A9.
|
||||
|
||||
config APPLE_ADMAC
|
||||
tristate "Apple ADMAC support"
|
||||
depends on ARCH_APPLE || COMPILE_TEST
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o
|
|||
obj-$(CONFIG_ALTERA_MSGDMA) += altera-msgdma.o
|
||||
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
|
||||
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
|
||||
obj-$(CONFIG_AMLOGIC_DMA) += amlogic-dma.o
|
||||
obj-$(CONFIG_APPLE_ADMAC) += apple-admac.o
|
||||
obj-$(CONFIG_ARM_DMA350) += arm-dma350.o
|
||||
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
|
||||
|
|
|
|||
|
|
@ -847,11 +847,6 @@ static int msgdma_probe(struct platform_device *pdev)
|
|||
if (mdev->irq < 0)
|
||||
return -ENXIO;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, mdev->irq, msgdma_irq_handler,
|
||||
0, dev_name(&pdev->dev), mdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tasklet_setup(&mdev->irq_tasklet, msgdma_tasklet);
|
||||
|
||||
dma_cookie_init(&mdev->dmachan);
|
||||
|
|
@ -863,6 +858,11 @@ static int msgdma_probe(struct platform_device *pdev)
|
|||
INIT_LIST_HEAD(&mdev->done_list);
|
||||
INIT_LIST_HEAD(&mdev->free_list);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, mdev->irq, msgdma_irq_handler,
|
||||
0, dev_name(&pdev->dev), mdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dma_dev = &mdev->dmadev;
|
||||
|
||||
/* Set DMA capabilities */
|
||||
|
|
|
|||
|
|
@ -2500,8 +2500,8 @@ DEFINE_SHOW_ATTRIBUTE(pl08x_debugfs);
|
|||
static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
|
||||
{
|
||||
/* Expose a simple debugfs interface to view all clocks */
|
||||
debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
|
||||
NULL, pl08x, &pl08x_debugfs_fops);
|
||||
debugfs_create_file("stats", 0444, pl08x->memcpy.dbg_dev_root,
|
||||
pl08x, &pl08x_debugfs_fops);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
737
drivers/dma/amlogic-dma.c
Normal file
737
drivers/dma/amlogic-dma.c
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
|
||||
/*
|
||||
* Copyright (C) 2026 Amlogic, Inc. All rights reserved
|
||||
* Author: Xianwei Zhao <xianwei.zhao@amlogic.com>
|
||||
*/
|
||||
|
||||
#include <dt-bindings/dma/amlogic,a9-dma.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "virt-dma.h"
|
||||
|
||||
#define RCH_REG_BASE 0x0
|
||||
#define WCH_REG_BASE 0x2000
|
||||
/*
|
||||
* Each rch (read from memory) REG offset Rch_offset 0x0 each channel total 0x40
|
||||
* rch addr = DMA_base + Rch_offset+ chan_id * 0x40 + reg_offset
|
||||
*/
|
||||
#define RCH_READY 0x0
|
||||
#define RCH_STATUS 0x4
|
||||
#define RCH_CFG 0x8
|
||||
#define CFG_CLEAR BIT(25)
|
||||
#define CFG_PAUSE BIT(26)
|
||||
#define CFG_ENABLE BIT(27)
|
||||
#define CFG_DONE BIT(28)
|
||||
#define RCH_ADDR 0xc
|
||||
#define RCH_LEN 0x10
|
||||
#define RCH_RD_LEN 0x14
|
||||
#define RCH_PRT 0x18
|
||||
#define RCH_SYCN_STAT 0x1c
|
||||
#define RCH_ADDR_LOW 0x20
|
||||
#define RCH_ADDR_HIGH 0x24
|
||||
/* if work on 64, it work with RCH_PRT */
|
||||
#define RCH_PTR_HIGH 0x28
|
||||
|
||||
/*
|
||||
* Each wch (write to memory) REG offset Wch_offset 0x2000 each channel total 0x40
|
||||
* wch addr = DMA_base + Wch_offset+ chan_id * 0x40 + reg_offset
|
||||
*/
|
||||
#define WCH_READY 0x0
|
||||
#define WCH_TOTAL_LEN 0x4
|
||||
#define WCH_CFG 0x8
|
||||
#define WCH_ADDR 0xc
|
||||
#define WCH_LEN 0x10
|
||||
#define WCH_RD_LEN 0x14
|
||||
#define WCH_PRT 0x18
|
||||
#define WCH_CMD_CNT 0x1c
|
||||
#define WCH_ADDR_LOW 0x20
|
||||
#define WCH_ADDR_HIGH 0x24
|
||||
/* if work on 64, it work with RCH_PRT */
|
||||
#define WCH_PTR_HIGH 0x28
|
||||
|
||||
/* DMA controller reg */
|
||||
#define RCH_INT_MASK 0x1000
|
||||
#define WCH_INT_MASK 0x1004
|
||||
#define CLEAR_W_BATCH 0x1014
|
||||
#define CLEAR_RCH 0x1024
|
||||
#define CLEAR_WCH 0x1028
|
||||
#define RCH_ACTIVE 0x1038
|
||||
#define WCH_ACTIVE 0x103c
|
||||
#define RCH_DONE 0x104c
|
||||
#define WCH_DONE 0x1050
|
||||
#define RCH_ERR 0x1060
|
||||
#define RCH_LEN_ERR 0x1064
|
||||
#define WCH_ERR 0x1068
|
||||
#define DMA_BATCH_END 0x1078
|
||||
#define WCH_EOC_DONE 0x1088
|
||||
#define WDMA_RESP_ERR 0x1098
|
||||
#define UPT_PKT_SYNC 0x10a8
|
||||
#define RCHN_CFG 0x10ac
|
||||
#define WCHN_CFG 0x10b0
|
||||
#define MEM_PD_CFG 0x10b4
|
||||
#define MEM_BUS_CFG 0x10b8
|
||||
#define DMA_GMV_CFG 0x10bc
|
||||
#define DMA_GMR_CFG 0x10c0
|
||||
|
||||
#define MAX_CHAN_ID 32
|
||||
#define SG_MAX_LEN GENMASK(26, 2)
|
||||
#define INT_MASK 0xffffffff
|
||||
|
||||
struct aml_dma_sg_link {
|
||||
#define LINK_LEN GENMASK(26, 0)
|
||||
#define LINK_IRQ BIT(27)
|
||||
#define LINK_EOC BIT(28)
|
||||
#define LINK_LOOP BIT(29)
|
||||
#define LINK_ERR BIT(30)
|
||||
#define LINK_OWNER BIT(31)
|
||||
__le32 ctl;
|
||||
__le32 addr_low;
|
||||
__le32 addr_high;
|
||||
__le32 revered;
|
||||
} __packed;
|
||||
|
||||
/* 1 page for link 256*16 */
|
||||
#define DMA_MAX_LINK 256
|
||||
/* sizeof(struct aml_dma_sg_link) */
|
||||
#define DMA_LINK_SIZE 16
|
||||
#define DMA_LINK_MAX_SIZE (DMA_LINK_SIZE * DMA_MAX_LINK)
|
||||
|
||||
struct aml_dma_desc {
|
||||
struct virt_dma_desc vd;
|
||||
struct aml_dma_sg_link *sg_link;
|
||||
struct dma_device *dma_device;
|
||||
dma_addr_t sg_link_phys;
|
||||
size_t sg_link_size;
|
||||
u32 data_len;
|
||||
struct work_struct free_work;
|
||||
};
|
||||
|
||||
struct aml_dma_chan {
|
||||
struct virt_dma_chan vchan;
|
||||
struct aml_dma_dev *aml_dma;
|
||||
struct aml_dma_desc *cur_desc;
|
||||
enum dma_status pre_status;
|
||||
enum dma_status status;
|
||||
enum dma_transfer_direction direction;
|
||||
int chan_id;
|
||||
/* reg_base (direction + chan_id) */
|
||||
int reg_offs;
|
||||
/* When there are multiple consecutive transmission errors, this channel halt */
|
||||
int err_num;
|
||||
};
|
||||
|
||||
struct aml_dma_dev {
|
||||
struct dma_device dma_device;
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
struct platform_device *pdev;
|
||||
struct aml_dma_chan *aml_rch[MAX_CHAN_ID];
|
||||
struct aml_dma_chan *aml_wch[MAX_CHAN_ID];
|
||||
struct workqueue_struct *free_wq;
|
||||
unsigned int chan_nr;
|
||||
unsigned int chan_used;
|
||||
struct aml_dma_chan aml_chans[]__counted_by(chan_nr);
|
||||
};
|
||||
|
||||
static inline struct aml_dma_chan *to_aml_dma_chan(struct dma_chan *chan)
|
||||
{
|
||||
return container_of(chan, struct aml_dma_chan, vchan.chan);
|
||||
}
|
||||
|
||||
static inline struct aml_dma_desc *to_aml_dma_desc(struct virt_dma_desc *vd)
|
||||
{
|
||||
return container_of(vd, struct aml_dma_desc, vd);
|
||||
}
|
||||
|
||||
static void aml_dma_free_desc_work(struct work_struct *work)
|
||||
{
|
||||
struct aml_dma_desc *aml_desc =
|
||||
container_of(work, struct aml_dma_desc, free_work);
|
||||
|
||||
dma_free_coherent(aml_desc->dma_device->dev,
|
||||
aml_desc->sg_link_size,
|
||||
aml_desc->sg_link,
|
||||
aml_desc->sg_link_phys);
|
||||
kfree(aml_desc);
|
||||
}
|
||||
|
||||
static void aml_dma_free_desc(struct virt_dma_desc *vd)
|
||||
{
|
||||
struct aml_dma_desc *aml_desc = to_aml_dma_desc(vd);
|
||||
struct aml_dma_dev *aml_dev = container_of(aml_desc->dma_device,
|
||||
struct aml_dma_dev, dma_device);
|
||||
|
||||
queue_work(aml_dev->free_wq, &aml_desc->free_work);
|
||||
}
|
||||
|
||||
static int aml_dma_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
|
||||
/* offset is the same RCH_CFG and WCH_CFG */
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
|
||||
aml_chan->status = DMA_COMPLETE;
|
||||
aml_chan->cur_desc = NULL;
|
||||
aml_chan->err_num = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aml_dma_free_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
struct virt_dma_desc *cur_vd = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
if (aml_chan->cur_desc)
|
||||
cur_vd = &aml_chan->cur_desc->vd;
|
||||
aml_chan->cur_desc = NULL;
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
if (cur_vd)
|
||||
aml_dma_free_desc(cur_vd);
|
||||
|
||||
vchan_free_chan_resources(&aml_chan->vchan);
|
||||
}
|
||||
|
||||
/* DMA transfer state update how many data reside it */
|
||||
static enum dma_status aml_dma_tx_status(struct dma_chan *chan,
|
||||
dma_cookie_t cookie,
|
||||
struct dma_tx_state *txstate)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
struct aml_dma_desc *aml_desc = NULL;
|
||||
struct virt_dma_desc *vd;
|
||||
u32 residue = 0, done = 0;
|
||||
unsigned long flags;
|
||||
enum dma_status ret;
|
||||
|
||||
ret = dma_cookie_status(chan, cookie, txstate);
|
||||
if (ret == DMA_COMPLETE)
|
||||
return ret;
|
||||
|
||||
if (aml_chan->status == DMA_PAUSED)
|
||||
ret = DMA_PAUSED;
|
||||
if (!txstate)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
vd = vchan_find_desc(&aml_chan->vchan, cookie);
|
||||
if (vd) {
|
||||
aml_desc = to_aml_dma_desc(vd);
|
||||
residue = aml_desc->data_len;
|
||||
} else if (aml_chan->cur_desc && aml_chan->cur_desc->vd.tx.cookie == cookie) {
|
||||
aml_desc = aml_chan->cur_desc;
|
||||
regmap_read(aml_dma->regmap, aml_chan->reg_offs + RCH_RD_LEN, &done);
|
||||
residue = aml_desc->data_len - done;
|
||||
} else {
|
||||
dev_err(aml_dma->dma_device.dev, "cookie error\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
dma_set_residue(txstate, residue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *aml_dma_prep_slave_sg
|
||||
(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||
unsigned long flags, void *context)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
struct aml_dma_desc *aml_desc = NULL;
|
||||
struct aml_dma_sg_link *sg_link = NULL;
|
||||
struct scatterlist *sg = NULL;
|
||||
u64 paddr;
|
||||
u32 link_count, avail;
|
||||
u32 i;
|
||||
|
||||
if (aml_chan->direction != direction) {
|
||||
dev_err(aml_dma->dma_device.dev, "direction not support\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
link_count = sg_nents_for_dma(sgl, sg_len, SG_MAX_LEN);
|
||||
if (link_count == 0)
|
||||
return NULL;
|
||||
|
||||
aml_desc = kzalloc_obj(*aml_desc, GFP_NOWAIT);
|
||||
if (!aml_desc)
|
||||
return NULL;
|
||||
|
||||
INIT_WORK(&aml_desc->free_work, aml_dma_free_desc_work);
|
||||
aml_desc->sg_link_size = link_count * sizeof(*sg_link);
|
||||
aml_desc->sg_link = dma_alloc_coherent(aml_dma->dma_device.dev, aml_desc->sg_link_size,
|
||||
&aml_desc->sg_link_phys, GFP_NOWAIT);
|
||||
if (!aml_desc->sg_link) {
|
||||
kfree(aml_desc);
|
||||
return NULL;
|
||||
}
|
||||
aml_desc->dma_device = &aml_dma->dma_device;
|
||||
|
||||
sg_link = aml_desc->sg_link;
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
avail = sg_dma_len(sg);
|
||||
if (avail == 0)
|
||||
continue;
|
||||
paddr = sg->dma_address;
|
||||
while (avail > SG_MAX_LEN) {
|
||||
/* set dma address and len to sglink*/
|
||||
sg_link->addr_low = cpu_to_le32(lower_32_bits(paddr));
|
||||
sg_link->addr_high = cpu_to_le32(upper_32_bits(paddr));
|
||||
sg_link->ctl = cpu_to_le32(FIELD_PREP(LINK_LEN, SG_MAX_LEN));
|
||||
paddr = paddr + SG_MAX_LEN;
|
||||
avail = avail - SG_MAX_LEN;
|
||||
sg_link++;
|
||||
}
|
||||
/* set dma address and len to sglink*/
|
||||
sg_link->addr_low = cpu_to_le32(lower_32_bits(paddr));
|
||||
sg_link->addr_high = cpu_to_le32(upper_32_bits(paddr));
|
||||
sg_link->ctl = cpu_to_le32(FIELD_PREP(LINK_LEN, avail));
|
||||
|
||||
aml_desc->data_len += sg_dma_len(sg);
|
||||
sg_link++;
|
||||
}
|
||||
|
||||
/* the last sg set eoc flag */
|
||||
sg_link--;
|
||||
sg_link->ctl |= LINK_EOC;
|
||||
|
||||
return vchan_tx_prep(&aml_chan->vchan, &aml_desc->vd, flags);
|
||||
}
|
||||
|
||||
static int aml_dma_chan_pause(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
aml_chan->pre_status = aml_chan->status;
|
||||
aml_chan->status = DMA_PAUSED;
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_dma_chan_resume(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
aml_chan->status = aml_chan->pre_status;
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_dma_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
int chan_id = aml_chan->chan_id;
|
||||
struct virt_dma_desc *cur_vd;
|
||||
unsigned long flags;
|
||||
LIST_HEAD(head);
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
|
||||
if (aml_chan->direction == DMA_MEM_TO_DEV)
|
||||
regmap_set_bits(aml_dma->regmap, RCH_INT_MASK, BIT(chan_id));
|
||||
else if (aml_chan->direction == DMA_DEV_TO_MEM)
|
||||
regmap_set_bits(aml_dma->regmap, WCH_INT_MASK, BIT(chan_id));
|
||||
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
|
||||
vchan_get_all_descriptors(&aml_chan->vchan, &head);
|
||||
cur_vd = &aml_chan->cur_desc->vd;
|
||||
aml_chan->cur_desc = NULL;
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
if (cur_vd)
|
||||
aml_dma_free_desc(cur_vd);
|
||||
|
||||
vchan_dma_desc_free_list(&aml_chan->vchan, &head);
|
||||
|
||||
aml_chan->status = DMA_COMPLETE;
|
||||
aml_chan->err_num = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aml_dma_start(struct aml_dma_chan *aml_chan)
|
||||
{
|
||||
struct virt_dma_desc *vd = vchan_next_desc(&aml_chan->vchan);
|
||||
struct aml_dma_dev *aml_dma = aml_chan->aml_dma;
|
||||
struct aml_dma_desc *aml_desc = NULL;
|
||||
int chan_id = aml_chan->chan_id;
|
||||
|
||||
if (aml_chan->status == DMA_ERROR) {
|
||||
if (aml_chan->err_num > 5) {
|
||||
dev_err(aml_dma->dma_device.dev, "hw error\n");
|
||||
return;
|
||||
}
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_set_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
aml_chan->err_num++;
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_PAUSE);
|
||||
regmap_clear_bits(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, CFG_CLEAR);
|
||||
aml_chan->status = DMA_COMPLETE;
|
||||
} else {
|
||||
aml_chan->err_num = 0;
|
||||
}
|
||||
|
||||
if (!vd)
|
||||
return;
|
||||
|
||||
if (aml_chan->status != DMA_COMPLETE)
|
||||
return;
|
||||
|
||||
list_del(&vd->node);
|
||||
aml_desc = to_aml_dma_desc(vd);
|
||||
aml_chan->cur_desc = aml_desc;
|
||||
|
||||
if (aml_chan->direction == DMA_MEM_TO_DEV) {
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_ADDR,
|
||||
lower_32_bits(aml_desc->sg_link_phys));
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_ADDR_HIGH,
|
||||
upper_32_bits(aml_desc->sg_link_phys));
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_LEN, aml_desc->data_len);
|
||||
regmap_clear_bits(aml_dma->regmap, RCH_INT_MASK, BIT(chan_id));
|
||||
/* for rch (tx) need set cfg 0 to trigger start */
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + RCH_CFG, 0);
|
||||
} else if (aml_chan->direction == DMA_DEV_TO_MEM) {
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + WCH_ADDR,
|
||||
lower_32_bits(aml_desc->sg_link_phys));
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + WCH_ADDR_HIGH,
|
||||
upper_32_bits(aml_desc->sg_link_phys));
|
||||
regmap_write(aml_dma->regmap, aml_chan->reg_offs + WCH_LEN, aml_desc->data_len);
|
||||
regmap_clear_bits(aml_dma->regmap, WCH_INT_MASK, BIT(chan_id));
|
||||
}
|
||||
}
|
||||
|
||||
static void aml_dma_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
struct aml_dma_chan *aml_chan = to_aml_dma_chan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&aml_chan->vchan.lock, flags);
|
||||
if (vchan_issue_pending(&aml_chan->vchan) && !aml_chan->cur_desc)
|
||||
aml_dma_start(aml_chan);
|
||||
spin_unlock_irqrestore(&aml_chan->vchan.lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t aml_dma_interrupt_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct aml_dma_dev *aml_dma = dev_id;
|
||||
struct aml_dma_chan *aml_chan;
|
||||
struct aml_dma_desc *aml_desc;
|
||||
u32 done, eoc_done, err, err_l, end;
|
||||
u32 cpl_data;
|
||||
int i = 0;
|
||||
|
||||
/* deal with rch normal complete and error */
|
||||
regmap_read(aml_dma->regmap, RCH_DONE, &done);
|
||||
regmap_read(aml_dma->regmap, RCH_ERR, &err);
|
||||
regmap_read(aml_dma->regmap, RCH_LEN_ERR, &err_l);
|
||||
err = err | err_l;
|
||||
|
||||
done = done | err;
|
||||
|
||||
while (done) {
|
||||
i = ffs(done) - 1;
|
||||
regmap_write(aml_dma->regmap, CLEAR_RCH, BIT(i));
|
||||
done &= ~BIT(i);
|
||||
aml_chan = aml_dma->aml_rch[i];
|
||||
if (!aml_chan) {
|
||||
dev_err(aml_dma->dma_device.dev, "idx %d rch not initialized\n", i);
|
||||
continue;
|
||||
}
|
||||
spin_lock(&aml_chan->vchan.lock);
|
||||
aml_chan->status = (err & BIT(i)) ? DMA_ERROR : DMA_COMPLETE;
|
||||
aml_desc = aml_chan->cur_desc;
|
||||
if (!aml_desc) {
|
||||
spin_unlock(&aml_chan->vchan.lock);
|
||||
continue;
|
||||
}
|
||||
if (aml_chan->status == DMA_ERROR) {
|
||||
aml_desc->vd.tx_result.result = DMA_TRANS_READ_FAILED;
|
||||
regmap_read(aml_dma->regmap, aml_chan->reg_offs + RCH_RD_LEN, &cpl_data);
|
||||
aml_desc->vd.tx_result.residue = aml_desc->data_len - cpl_data;
|
||||
}
|
||||
vchan_cookie_complete(&aml_desc->vd);
|
||||
aml_chan->cur_desc = NULL;
|
||||
aml_dma_start(aml_chan);
|
||||
spin_unlock(&aml_chan->vchan.lock);
|
||||
}
|
||||
|
||||
/* deal with wch normal complete and error */
|
||||
regmap_read(aml_dma->regmap, DMA_BATCH_END, &end);
|
||||
if (end)
|
||||
regmap_write(aml_dma->regmap, CLEAR_W_BATCH, end);
|
||||
|
||||
regmap_read(aml_dma->regmap, WCH_DONE, &done);
|
||||
regmap_read(aml_dma->regmap, WCH_EOC_DONE, &eoc_done);
|
||||
done = done | eoc_done;
|
||||
|
||||
regmap_read(aml_dma->regmap, WCH_ERR, &err);
|
||||
regmap_read(aml_dma->regmap, WDMA_RESP_ERR, &err_l);
|
||||
err = err | err_l;
|
||||
|
||||
done = done | err;
|
||||
i = 0;
|
||||
while (done) {
|
||||
i = ffs(done) - 1;
|
||||
done &= ~BIT(i);
|
||||
regmap_write(aml_dma->regmap, CLEAR_WCH, BIT(i));
|
||||
aml_chan = aml_dma->aml_wch[i];
|
||||
if (!aml_chan) {
|
||||
dev_err(aml_dma->dma_device.dev, "idx %d wch not initialized\n", i);
|
||||
continue;
|
||||
}
|
||||
spin_lock(&aml_chan->vchan.lock);
|
||||
aml_chan->status = (err & BIT(i)) ? DMA_ERROR : DMA_COMPLETE;
|
||||
aml_desc = aml_chan->cur_desc;
|
||||
if (!aml_desc) {
|
||||
spin_unlock(&aml_chan->vchan.lock);
|
||||
continue;
|
||||
}
|
||||
if (aml_chan->status == DMA_ERROR) {
|
||||
aml_desc->vd.tx_result.result = DMA_TRANS_WRITE_FAILED;
|
||||
regmap_read(aml_dma->regmap, aml_chan->reg_offs + RCH_RD_LEN, &cpl_data);
|
||||
aml_desc->vd.tx_result.residue = aml_desc->data_len - cpl_data;
|
||||
}
|
||||
vchan_cookie_complete(&aml_desc->vd);
|
||||
aml_chan->cur_desc = NULL;
|
||||
aml_dma_start(aml_chan);
|
||||
spin_unlock(&aml_chan->vchan.lock);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct dma_chan *aml_of_dma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma)
|
||||
{
|
||||
struct aml_dma_dev *aml_dma = (struct aml_dma_dev *)ofdma->of_dma_data;
|
||||
struct aml_dma_chan *aml_chan = NULL;
|
||||
u32 type;
|
||||
u32 phy_chan_id;
|
||||
|
||||
if (dma_spec->args_count != 2)
|
||||
return NULL;
|
||||
|
||||
type = dma_spec->args[0];
|
||||
phy_chan_id = dma_spec->args[1];
|
||||
|
||||
if (phy_chan_id >= MAX_CHAN_ID)
|
||||
return NULL;
|
||||
|
||||
if (type == AMLOGIC_A9_DMA_TX) {
|
||||
aml_chan = aml_dma->aml_rch[phy_chan_id];
|
||||
if (!aml_chan) {
|
||||
if (aml_dma->chan_used >= aml_dma->chan_nr) {
|
||||
dev_err(aml_dma->dma_device.dev, "some dma clients err used\n");
|
||||
return NULL;
|
||||
}
|
||||
aml_chan = &aml_dma->aml_chans[aml_dma->chan_used];
|
||||
aml_dma->chan_used++;
|
||||
aml_chan->direction = DMA_MEM_TO_DEV;
|
||||
aml_chan->chan_id = phy_chan_id;
|
||||
aml_chan->reg_offs = RCH_REG_BASE + 0x40 * aml_chan->chan_id;
|
||||
aml_dma->aml_rch[phy_chan_id] = aml_chan;
|
||||
}
|
||||
} else if (type == AMLOGIC_A9_DMA_RX) {
|
||||
aml_chan = aml_dma->aml_wch[phy_chan_id];
|
||||
if (!aml_chan) {
|
||||
if (aml_dma->chan_used >= aml_dma->chan_nr) {
|
||||
dev_err(aml_dma->dma_device.dev, "some dma clients err used\n");
|
||||
return NULL;
|
||||
}
|
||||
aml_chan = &aml_dma->aml_chans[aml_dma->chan_used];
|
||||
aml_dma->chan_used++;
|
||||
aml_chan->direction = DMA_DEV_TO_MEM;
|
||||
aml_chan->chan_id = phy_chan_id;
|
||||
aml_chan->reg_offs = WCH_REG_BASE + 0x40 * aml_chan->chan_id;
|
||||
aml_dma->aml_wch[phy_chan_id] = aml_chan;
|
||||
}
|
||||
} else {
|
||||
dev_err(aml_dma->dma_device.dev, "type %d not supported\n", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dma_get_slave_channel(&aml_chan->vchan.chan);
|
||||
}
|
||||
|
||||
static int aml_dma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct dma_device *dma_dev;
|
||||
struct aml_dma_dev *aml_dma;
|
||||
int ret, i, len;
|
||||
u32 chan_nr;
|
||||
|
||||
const struct regmap_config aml_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = 0x3000,
|
||||
};
|
||||
|
||||
ret = of_property_read_u32(np, "dma-channels", &chan_nr);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to read dma-channels\n");
|
||||
if (chan_nr > (MAX_CHAN_ID * 2))
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "dma-channels unusual\n");
|
||||
|
||||
len = sizeof(struct aml_dma_dev) + sizeof(struct aml_dma_chan) * chan_nr;
|
||||
aml_dma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
|
||||
if (!aml_dma)
|
||||
return -ENOMEM;
|
||||
|
||||
aml_dma->free_wq = alloc_ordered_workqueue("aml_dma_free", 0);
|
||||
if (!aml_dma->free_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
aml_dma->chan_nr = chan_nr;
|
||||
|
||||
aml_dma->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(aml_dma->base))
|
||||
return PTR_ERR(aml_dma->base);
|
||||
|
||||
aml_dma->regmap = devm_regmap_init_mmio(&pdev->dev, aml_dma->base,
|
||||
&aml_regmap_config);
|
||||
if (IS_ERR(aml_dma->regmap))
|
||||
return PTR_ERR(aml_dma->regmap);
|
||||
|
||||
aml_dma->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(aml_dma->clk))
|
||||
return PTR_ERR(aml_dma->clk);
|
||||
|
||||
aml_dma->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
aml_dma->pdev = pdev;
|
||||
aml_dma->dma_device.dev = &pdev->dev;
|
||||
|
||||
dma_dev = &aml_dma->dma_device;
|
||||
INIT_LIST_HEAD(&dma_dev->channels);
|
||||
|
||||
/* Initialize channel parameters */
|
||||
for (i = 0; i < chan_nr; i++) {
|
||||
struct aml_dma_chan *aml_chan = &aml_dma->aml_chans[i];
|
||||
|
||||
aml_chan->aml_dma = aml_dma;
|
||||
aml_chan->vchan.desc_free = aml_dma_free_desc;
|
||||
vchan_init(&aml_chan->vchan, &aml_dma->dma_device);
|
||||
}
|
||||
aml_dma->chan_used = 0;
|
||||
|
||||
dma_set_max_seg_size(dma_dev->dev, SG_MAX_LEN);
|
||||
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
|
||||
dma_dev->device_alloc_chan_resources = aml_dma_alloc_chan_resources;
|
||||
dma_dev->device_free_chan_resources = aml_dma_free_chan_resources;
|
||||
dma_dev->device_tx_status = aml_dma_tx_status;
|
||||
dma_dev->device_prep_slave_sg = aml_dma_prep_slave_sg;
|
||||
dma_dev->device_pause = aml_dma_chan_pause;
|
||||
dma_dev->device_resume = aml_dma_chan_resume;
|
||||
dma_dev->device_terminate_all = aml_dma_terminate_all;
|
||||
dma_dev->device_issue_pending = aml_dma_issue_pending;
|
||||
/* PIO 4 bytes and I2C 1 byte */
|
||||
dma_dev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
|
||||
dma_dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
|
||||
|
||||
regmap_write(aml_dma->regmap, RCH_INT_MASK, INT_MASK);
|
||||
regmap_write(aml_dma->regmap, WCH_INT_MASK, INT_MASK);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, aml_dma->irq, aml_dma_interrupt_handler,
|
||||
0, dev_name(&pdev->dev), aml_dma);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to register irq\n");
|
||||
|
||||
ret = dmaenginem_async_device_register(dma_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to register dmaenginem\n");
|
||||
|
||||
ret = of_dma_controller_register(np, aml_of_dma_xlate, aml_dma);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to register xlate\n");
|
||||
|
||||
platform_set_drvdata(pdev, aml_dma);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aml_dma_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_dma_dev *aml_dma = platform_get_drvdata(pdev);
|
||||
struct aml_dma_chan *aml_chan = NULL;
|
||||
int i;
|
||||
|
||||
of_dma_controller_free((&pdev->dev)->of_node);
|
||||
|
||||
regmap_write(aml_dma->regmap, RCH_INT_MASK, INT_MASK);
|
||||
regmap_write(aml_dma->regmap, WCH_INT_MASK, INT_MASK);
|
||||
|
||||
for (i = 0; i < MAX_CHAN_ID; i++) {
|
||||
aml_chan = aml_dma->aml_rch[i];
|
||||
if (aml_chan)
|
||||
tasklet_kill(&aml_chan->vchan.task);
|
||||
aml_chan = aml_dma->aml_wch[i];
|
||||
if (aml_chan)
|
||||
tasklet_kill(&aml_chan->vchan.task);
|
||||
}
|
||||
destroy_workqueue(aml_dma->free_wq);
|
||||
}
|
||||
|
||||
static const struct of_device_id aml_dma_ids[] = {
|
||||
{ .compatible = "amlogic,a9-dma", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aml_dma_ids);
|
||||
|
||||
static struct platform_driver aml_dma_driver = {
|
||||
.probe = aml_dma_probe,
|
||||
.remove = aml_dma_remove,
|
||||
.driver = {
|
||||
.name = "aml-dma",
|
||||
.of_match_table = aml_dma_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(aml_dma_driver);
|
||||
|
||||
MODULE_DESCRIPTION("GENERAL DMA driver for Amlogic");
|
||||
MODULE_AUTHOR("Xianwei Zhao <xianwei.zhao@amlogic.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -39,10 +39,14 @@
|
|||
|
||||
#define FLAG_DESC_NOTIFY BIT(16)
|
||||
|
||||
#define T8122_UNK_28_VAL 0x200000
|
||||
|
||||
#define REG_TX_START 0x0000
|
||||
#define REG_TX_STOP 0x0004
|
||||
#define REG_RX_START 0x0008
|
||||
#define REG_RX_STOP 0x000c
|
||||
#define REG_UNK_28 0x0028
|
||||
#define REG_UNK_2C 0x002c
|
||||
#define REG_IMPRINT 0x0090
|
||||
#define REG_TX_SRAM_SIZE 0x0094
|
||||
#define REG_RX_SRAM_SIZE 0x0098
|
||||
|
|
@ -85,6 +89,10 @@
|
|||
struct admac_data;
|
||||
struct admac_tx;
|
||||
|
||||
struct admac_hw {
|
||||
bool set_unk28;
|
||||
};
|
||||
|
||||
struct admac_chan {
|
||||
unsigned int no;
|
||||
struct admac_data *host;
|
||||
|
|
@ -127,6 +135,7 @@ struct admac_data {
|
|||
struct mutex cache_alloc_lock;
|
||||
struct admac_sram txcache, rxcache;
|
||||
|
||||
const struct admac_hw *hw;
|
||||
int irq;
|
||||
int irq_index;
|
||||
int nchannels;
|
||||
|
|
@ -747,6 +756,11 @@ static int admac_device_config(struct dma_chan *chan,
|
|||
u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) &
|
||||
~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE);
|
||||
|
||||
if (ad->hw->set_unk28) {
|
||||
writel_relaxed(T8122_UNK_28_VAL, ad->base + REG_UNK_28);
|
||||
writel_relaxed(T8122_UNK_28_VAL, ad->base + REG_UNK_2C);
|
||||
}
|
||||
|
||||
switch (is_tx ? config->dst_addr_width : config->src_addr_width) {
|
||||
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||
wordsize = 1;
|
||||
|
|
@ -800,11 +814,18 @@ static int admac_device_config(struct dma_chan *chan,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct admac_hw admac_base_hw = {};
|
||||
|
||||
static const struct admac_hw admac_t8122_hw = {
|
||||
.set_unk28 = true,
|
||||
};
|
||||
|
||||
static int admac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct admac_data *ad;
|
||||
struct dma_device *dma;
|
||||
const struct admac_hw *hw;
|
||||
int nchannels;
|
||||
int err, irq, i;
|
||||
|
||||
|
|
@ -822,6 +843,8 @@ static int admac_probe(struct platform_device *pdev)
|
|||
ad->dev = &pdev->dev;
|
||||
ad->nchannels = nchannels;
|
||||
mutex_init(&ad->cache_alloc_lock);
|
||||
hw = of_device_get_match_data(&pdev->dev);
|
||||
ad->hw = hw ? hw : &admac_base_hw;
|
||||
|
||||
/*
|
||||
* The controller has 4 IRQ outputs. Try them all until
|
||||
|
|
@ -936,6 +959,7 @@ static void admac_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id admac_of_match[] = {
|
||||
{ .compatible = "apple,t8122-admac", .data = &admac_t8122_hw },
|
||||
{ .compatible = "apple,t8103-admac", },
|
||||
{ .compatible = "apple,admac", },
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ static int d350_alloc_chan_resources(struct dma_chan *chan)
|
|||
{
|
||||
struct d350_chan *dch = to_d350_chan(chan);
|
||||
int ret = request_irq(dch->irq, d350_irq, IRQF_SHARED,
|
||||
dev_name(&dch->vc.chan.dev->device), dch);
|
||||
vchan_chan_name(&dch->vc), dch);
|
||||
if (!ret)
|
||||
writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN);
|
||||
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ struct at_desc {
|
|||
/* Memset temporary buffer */
|
||||
bool memset_buffer;
|
||||
dma_addr_t memset_paddr;
|
||||
int *memset_vaddr;
|
||||
u32 *memset_vaddr;
|
||||
struct atdma_sg sg[] __counted_by(sglen);
|
||||
};
|
||||
|
||||
|
|
@ -381,23 +381,18 @@ static inline struct at_dma *to_at_dma(struct dma_device *ddev)
|
|||
|
||||
/*-- Helper functions ------------------------------------------------*/
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
#if defined(VERBOSE_DEBUG)
|
||||
static void vdbg_dump_regs(struct at_dma_chan *atchan)
|
||||
{
|
||||
struct at_dma *atdma = to_at_dma(atchan->vc.chan.device);
|
||||
|
||||
dev_err(chan2dev(&atchan->vc.chan),
|
||||
dev_err(vchan_chan_dev(&atchan->vc),
|
||||
" channel %d : imr = 0x%x, chsr = 0x%x\n",
|
||||
atchan->vc.chan.chan_id,
|
||||
dma_readl(atdma, EBCIMR),
|
||||
dma_readl(atdma, CHSR));
|
||||
|
||||
dev_err(chan2dev(&atchan->vc.chan),
|
||||
dev_err(vchan_chan_dev(&atchan->vc),
|
||||
" channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
|
||||
channel_readl(atchan, SADDR),
|
||||
channel_readl(atchan, DADDR),
|
||||
|
|
@ -412,7 +407,7 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
|
|||
|
||||
static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
|
||||
{
|
||||
dev_crit(chan2dev(&atchan->vc.chan),
|
||||
dev_crit(vchan_chan_dev(&atchan->vc),
|
||||
"desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n",
|
||||
&lli->saddr, &lli->daddr,
|
||||
lli->ctrla, lli->ctrlb, &lli->dscr);
|
||||
|
|
@ -790,8 +785,8 @@ static void atc_handle_error(struct at_dma_chan *atchan, unsigned int i)
|
|||
* controller flagged an error instead of scribbling over
|
||||
* random memory locations.
|
||||
*/
|
||||
dev_crit(chan2dev(&atchan->vc.chan), "Bad descriptor submitted for DMA!\n");
|
||||
dev_crit(chan2dev(&atchan->vc.chan), "cookie: %d\n",
|
||||
dev_crit(vchan_chan_dev(&atchan->vc), "Bad descriptor submitted for DMA!\n");
|
||||
dev_crit(vchan_chan_dev(&atchan->vc), "cookie: %d\n",
|
||||
desc->vd.tx.cookie);
|
||||
for (i = 0; i < desc->sglen; i++)
|
||||
atc_dump_lli(atchan, desc->sg[i].lli);
|
||||
|
|
@ -886,7 +881,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
|
|||
|
||||
first = xt->sgl;
|
||||
|
||||
dev_info(chan2dev(chan),
|
||||
dev_info(dmaengine_chan_dev(chan),
|
||||
"%s: src=%pad, dest=%pad, numf=%zu, frame_size=%zu, flags=0x%lx\n",
|
||||
__func__, &xt->src_start, &xt->dst_start, xt->numf,
|
||||
xt->frame_size, flags);
|
||||
|
|
@ -903,7 +898,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
|
|||
if ((chunk->size != xt->sgl->size) ||
|
||||
(dmaengine_get_dst_icg(xt, chunk) != dmaengine_get_dst_icg(xt, first)) ||
|
||||
(dmaengine_get_src_icg(xt, chunk) != dmaengine_get_src_icg(xt, first))) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"%s: the controller can transfer only identical chunks\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
|
|
@ -916,7 +911,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
|
|||
|
||||
xfer_count = len >> dwidth;
|
||||
if (xfer_count > ATC_BTSIZE_MAX) {
|
||||
dev_err(chan2dev(chan), "%s: buffer is too big\n", __func__);
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: buffer is too big\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -983,11 +978,11 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
u32 ctrla;
|
||||
u32 ctrlb;
|
||||
|
||||
dev_dbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
|
||||
&dest, &src, len, flags);
|
||||
|
||||
if (unlikely(!len)) {
|
||||
dev_err(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "prep_dma_memcpy: length is zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1062,7 +1057,7 @@ static int atdma_create_memset_lli(struct dma_chan *chan,
|
|||
|
||||
xfer_count = len >> 2;
|
||||
if (xfer_count > ATC_BTSIZE_MAX) {
|
||||
dev_err(chan2dev(chan), "%s: buffer is too big\n", __func__);
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: buffer is too big\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1097,28 +1092,28 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
|
|||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
struct at_dma *atdma = to_at_dma(chan->device);
|
||||
struct at_desc *desc;
|
||||
void __iomem *vaddr;
|
||||
u32 *vaddr;
|
||||
dma_addr_t paddr;
|
||||
char fill_pattern;
|
||||
int ret;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
|
||||
&dest, value, len, flags);
|
||||
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: length is zero!\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
|
||||
dev_dbg(chan2dev(chan), "%s: buffer is not aligned\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: buffer is not aligned\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vaddr = dma_pool_alloc(atdma->memset_pool, GFP_NOWAIT, &paddr);
|
||||
if (!vaddr) {
|
||||
dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: couldn't allocate buffer\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1126,10 +1121,10 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int 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;
|
||||
*vaddr = (fill_pattern << 24) |
|
||||
(fill_pattern << 16) |
|
||||
(fill_pattern << 8) |
|
||||
fill_pattern;
|
||||
|
||||
desc = kzalloc_flex(*desc, sg, 1, GFP_ATOMIC);
|
||||
if (!desc)
|
||||
|
|
@ -1168,28 +1163,28 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
|
|||
struct at_dma *atdma = to_at_dma(chan->device);
|
||||
struct at_desc *desc;
|
||||
struct scatterlist *sg;
|
||||
void __iomem *vaddr;
|
||||
u32 *vaddr;
|
||||
dma_addr_t paddr;
|
||||
size_t total_len = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%x f0x%lx\n", __func__,
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s: v0x%x l0x%x f0x%lx\n", __func__,
|
||||
value, sg_len, flags);
|
||||
|
||||
if (unlikely(!sgl || !sg_len)) {
|
||||
dev_dbg(chan2dev(chan), "%s: scatterlist is empty!\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: scatterlist is empty!\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vaddr = dma_pool_alloc(atdma->memset_pool, GFP_NOWAIT, &paddr);
|
||||
if (!vaddr) {
|
||||
dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: couldn't allocate buffer\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
*(u32*)vaddr = value;
|
||||
*vaddr = value;
|
||||
|
||||
desc = kzalloc_flex(*desc, sg, sg_len, GFP_ATOMIC);
|
||||
if (!desc)
|
||||
|
|
@ -1200,11 +1195,11 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
|
|||
dma_addr_t dest = sg_dma_address(sg);
|
||||
size_t len = sg_dma_len(sg);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s: d%pad, l0x%zx\n",
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s: d%pad, l0x%zx\n",
|
||||
__func__, &dest, len);
|
||||
|
||||
if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
|
||||
dev_err(chan2dev(chan), "%s: buffer is not aligned\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: buffer is not aligned\n",
|
||||
__func__);
|
||||
goto err_free_desc;
|
||||
}
|
||||
|
|
@ -1264,13 +1259,13 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
struct scatterlist *sg;
|
||||
size_t total_len = 0;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n",
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "prep_slave_sg (%d): %s f0x%lx\n",
|
||||
sg_len,
|
||||
direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
|
||||
flags);
|
||||
|
||||
if (unlikely(!atslave || !sg_len)) {
|
||||
dev_dbg(chan2dev(chan), "prep_slave_sg: sg length is zero!\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "prep_slave_sg: sg length is zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1310,7 +1305,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
mem = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"prep_slave_sg: sg(%d) data length is zero\n", i);
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -1359,7 +1354,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
mem = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"prep_slave_sg: sg(%d) data length is zero\n", i);
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -1392,7 +1387,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
|
||||
|
||||
err_desc_get:
|
||||
dev_err(chan2dev(chan), "not enough descriptors available\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "not enough descriptors available\n");
|
||||
err:
|
||||
atdma_desc_free(&desc->vd);
|
||||
return NULL;
|
||||
|
|
@ -1503,19 +1498,19 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
|
|||
unsigned int periods = buf_len / period_len;
|
||||
unsigned int i;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%zu/%zu)\n",
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%zu/%zu)\n",
|
||||
direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
|
||||
&buf_addr,
|
||||
periods, buf_len, period_len);
|
||||
|
||||
if (unlikely(!atslave || !buf_len || !period_len)) {
|
||||
dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "prep_dma_cyclic: length is zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
was_cyclic = test_and_set_bit(ATC_IS_CYCLIC, &atchan->status);
|
||||
if (was_cyclic) {
|
||||
dev_dbg(chan2dev(chan), "prep_dma_cyclic: channel in use!\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "prep_dma_cyclic: channel in use!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1561,7 +1556,7 @@ static int atc_config(struct dma_chan *chan,
|
|||
{
|
||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
/* Check if it is chan is configured for slave transfers */
|
||||
if (!chan->private)
|
||||
|
|
@ -1582,7 +1577,7 @@ static int atc_pause(struct dma_chan *chan)
|
|||
int chan_id = atchan->vc.chan.chan_id;
|
||||
unsigned long flags;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&atchan->vc.lock, flags);
|
||||
|
||||
|
|
@ -1601,7 +1596,7 @@ static int atc_resume(struct dma_chan *chan)
|
|||
int chan_id = atchan->vc.chan.chan_id;
|
||||
unsigned long flags;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
if (!atc_chan_is_paused(atchan))
|
||||
return 0;
|
||||
|
|
@ -1625,7 +1620,7 @@ static int atc_terminate_all(struct dma_chan *chan)
|
|||
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
/*
|
||||
* This is only called when something went wrong elsewhere, so
|
||||
|
|
@ -1691,13 +1686,13 @@ atc_tx_status(struct dma_chan *chan,
|
|||
spin_unlock_irqrestore(&atchan->vc.lock, flags);
|
||||
|
||||
if (unlikely(ret < 0)) {
|
||||
dev_vdbg(chan2dev(chan), "get residual bytes error\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "get residual bytes error\n");
|
||||
return DMA_ERROR;
|
||||
} else {
|
||||
dma_set_residue(txstate, residue);
|
||||
}
|
||||
|
||||
dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %u\n",
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "tx_status %d: cookie = %d residue = %u\n",
|
||||
dma_status, cookie, residue);
|
||||
|
||||
return dma_status;
|
||||
|
|
@ -1729,11 +1724,11 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct at_dma_slave *atslave;
|
||||
u32 cfg;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "alloc_chan_resources\n");
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
if (atc_chan_is_enabled(atchan)) {
|
||||
dev_dbg(chan2dev(chan), "DMA channel not idle ?\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "DMA channel not idle ?\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -1782,7 +1777,7 @@ static void atc_free_chan_resources(struct dma_chan *chan)
|
|||
chan->private = NULL;
|
||||
}
|
||||
|
||||
dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "free_chan_resources: done\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
@ -1940,6 +1935,20 @@ static void at_dma_off(struct at_dma *atdma)
|
|||
cpu_relax();
|
||||
}
|
||||
|
||||
static void at_dma_cleanup_channels(struct at_dma *atdma)
|
||||
{
|
||||
struct dma_chan *chan, *_chan;
|
||||
int i = 0;
|
||||
|
||||
list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
|
||||
device_node) {
|
||||
/* Disable interrupts */
|
||||
atc_disable_chan_irq(atdma, i++);
|
||||
tasklet_kill(&to_at_dma_chan(chan)->vc.task);
|
||||
list_del(&chan->device_node);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init at_dma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at_dma *atdma;
|
||||
|
|
@ -1980,20 +1989,16 @@ static int __init at_dma_probe(struct platform_device *pdev)
|
|||
atdma->dma_device.cap_mask = plat_dat->cap_mask;
|
||||
atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
|
||||
|
||||
atdma->clk = devm_clk_get(&pdev->dev, "dma_clk");
|
||||
atdma->clk = devm_clk_get_enabled(&pdev->dev, "dma_clk");
|
||||
if (IS_ERR(atdma->clk))
|
||||
return PTR_ERR(atdma->clk);
|
||||
|
||||
err = clk_prepare_enable(atdma->clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* force dma off, just in case */
|
||||
at_dma_off(atdma);
|
||||
|
||||
err = request_irq(irq, at_dma_interrupt, 0, "at_hdmac", atdma);
|
||||
if (err)
|
||||
goto err_irq;
|
||||
return err;
|
||||
|
||||
platform_set_drvdata(pdev, atdma);
|
||||
|
||||
|
|
@ -2105,38 +2110,30 @@ static int __init at_dma_probe(struct platform_device *pdev)
|
|||
err_of_dma_controller_register:
|
||||
dma_async_device_unregister(&atdma->dma_device);
|
||||
err_dma_async_device_register:
|
||||
disable_irq(platform_get_irq(pdev, 0));
|
||||
at_dma_cleanup_channels(atdma);
|
||||
dma_pool_destroy(atdma->memset_pool);
|
||||
err_memset_pool_create:
|
||||
dma_pool_destroy(atdma->lli_pool);
|
||||
err_desc_pool_create:
|
||||
free_irq(platform_get_irq(pdev, 0), atdma);
|
||||
err_irq:
|
||||
clk_disable_unprepare(atdma->clk);
|
||||
free_irq(irq, atdma);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void at_dma_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct at_dma *atdma = platform_get_drvdata(pdev);
|
||||
struct dma_chan *chan, *_chan;
|
||||
|
||||
at_dma_off(atdma);
|
||||
if (pdev->dev.of_node)
|
||||
of_dma_controller_free(pdev->dev.of_node);
|
||||
dma_async_device_unregister(&atdma->dma_device);
|
||||
|
||||
dma_pool_destroy(atdma->memset_pool);
|
||||
dma_pool_destroy(atdma->lli_pool);
|
||||
free_irq(platform_get_irq(pdev, 0), atdma);
|
||||
|
||||
list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
|
||||
device_node) {
|
||||
/* Disable interrupts */
|
||||
atc_disable_chan_irq(atdma, chan->chan_id);
|
||||
list_del(&chan->device_node);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(atdma->clk);
|
||||
at_dma_cleanup_channels(atdma);
|
||||
dma_pool_destroy(atdma->memset_pool);
|
||||
dma_pool_destroy(atdma->lli_pool);
|
||||
}
|
||||
|
||||
static void at_dma_shutdown(struct platform_device *pdev)
|
||||
|
|
@ -2169,7 +2166,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan)
|
|||
/* Channel should be paused by user
|
||||
* do it anyway even if it is not done already */
|
||||
if (!atc_chan_is_paused(atchan)) {
|
||||
dev_warn(chan2dev(chan),
|
||||
dev_warn(dmaengine_chan_dev(chan),
|
||||
"cyclic channel not paused, should be done by channel user\n");
|
||||
atc_pause(chan);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,11 +324,6 @@ static inline struct at_xdmac_chan *to_at_xdmac_chan(struct dma_chan *dchan)
|
|||
return container_of(dchan, struct at_xdmac_chan, chan);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline struct at_xdmac *to_at_xdmac(struct dma_device *ddev)
|
||||
{
|
||||
return container_of(ddev, struct at_xdmac, dma);
|
||||
|
|
@ -459,7 +454,7 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
|
|||
if (ret < 0)
|
||||
return;
|
||||
|
||||
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, first);
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan), "%s: desc 0x%p\n", __func__, first);
|
||||
|
||||
/* Set transfer as active to not try to start it again. */
|
||||
first->active_xfer = true;
|
||||
|
|
@ -496,7 +491,7 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
|
|||
| AT_XDMAC_CNDC_NDE;
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, reg);
|
||||
|
||||
dev_vdbg(chan2dev(&atchan->chan),
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan),
|
||||
"%s: CC=0x%08x CNDA=0x%08x, CNDC=0x%08x, CSA=0x%08x, CDA=0x%08x, CUBC=0x%08x\n",
|
||||
__func__, at_xdmac_chan_read(atchan, AT_XDMAC_CC),
|
||||
at_xdmac_chan_read(atchan, AT_XDMAC_CNDA),
|
||||
|
|
@ -524,12 +519,12 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
|
|||
at_xdmac_chan_write(atchan, AT_XDMAC_CIE,
|
||||
reg | AT_XDMAC_CIE_LIE);
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GIE, atchan->mask);
|
||||
dev_vdbg(chan2dev(&atchan->chan),
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan),
|
||||
"%s: enable channel (0x%08x)\n", __func__, atchan->mask);
|
||||
wmb();
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
|
||||
|
||||
dev_vdbg(chan2dev(&atchan->chan),
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan),
|
||||
"%s: CC=0x%08x CNDA=0x%08x, CNDC=0x%08x, CSA=0x%08x, CDA=0x%08x, CUBC=0x%08x\n",
|
||||
__func__, at_xdmac_chan_read(atchan, AT_XDMAC_CC),
|
||||
at_xdmac_chan_read(atchan, AT_XDMAC_CNDA),
|
||||
|
|
@ -552,7 +547,7 @@ static dma_cookie_t at_xdmac_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
list_add_tail(&desc->xfer_node, &atchan->xfers_list);
|
||||
spin_unlock_irqrestore(&atchan->lock, irqflags);
|
||||
|
||||
dev_vdbg(chan2dev(tx->chan), "%s: atchan 0x%p, add desc 0x%p to xfers_list\n",
|
||||
dev_vdbg(dmaengine_chan_dev(tx->chan), "%s: atchan 0x%p, add desc 0x%p to xfers_list\n",
|
||||
__func__, atchan, desc);
|
||||
|
||||
return cookie;
|
||||
|
|
@ -612,7 +607,7 @@ static void at_xdmac_queue_desc(struct dma_chan *chan,
|
|||
prev->lld.mbr_nda = desc->tx_dma_desc.phys;
|
||||
prev->lld.mbr_ubc |= AT_XDMAC_MBR_UBC_NDE;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: chain lld: prev=0x%p, mbr_nda=%pad\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: chain lld: prev=0x%p, mbr_nda=%pad\n",
|
||||
__func__, prev, &prev->lld.mbr_nda);
|
||||
}
|
||||
|
||||
|
|
@ -624,7 +619,7 @@ static inline void at_xdmac_increment_block_count(struct dma_chan *chan,
|
|||
|
||||
desc->lld.mbr_bc++;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: incrementing the block count of the desc 0x%p\n",
|
||||
__func__, desc);
|
||||
}
|
||||
|
|
@ -680,13 +675,13 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
|
|||
|
||||
csize = ffs(atchan->sconfig.src_maxburst) - 1;
|
||||
if (csize < 0) {
|
||||
dev_err(chan2dev(chan), "invalid src maxburst value\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid src maxburst value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
|
||||
dwidth = ffs(atchan->sconfig.src_addr_width) - 1;
|
||||
if (dwidth < 0) {
|
||||
dev_err(chan2dev(chan), "invalid src addr width value\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid src addr width value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
|
||||
|
|
@ -705,19 +700,19 @@ static int at_xdmac_compute_chan_conf(struct dma_chan *chan,
|
|||
|
||||
csize = ffs(atchan->sconfig.dst_maxburst) - 1;
|
||||
if (csize < 0) {
|
||||
dev_err(chan2dev(chan), "invalid src maxburst value\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid src maxburst value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
atchan->cfg |= AT_XDMAC_CC_CSIZE(csize);
|
||||
dwidth = ffs(atchan->sconfig.dst_addr_width) - 1;
|
||||
if (dwidth < 0) {
|
||||
dev_err(chan2dev(chan), "invalid dst addr width value\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid dst addr width value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth);
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -746,7 +741,7 @@ static int at_xdmac_set_slave_config(struct dma_chan *chan,
|
|||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
|
||||
if (at_xdmac_check_slave_config(sconfig)) {
|
||||
dev_err(chan2dev(chan), "invalid slave configuration\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid slave configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -772,11 +767,11 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
return NULL;
|
||||
|
||||
if (!is_slave_direction(direction)) {
|
||||
dev_err(chan2dev(chan), "invalid DMA direction\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid DMA direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: sg_len=%d, dir=%s, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: sg_len=%d, dir=%s, flags=0x%lx\n",
|
||||
__func__, sg_len,
|
||||
direction == DMA_MEM_TO_DEV ? "to device" : "from device",
|
||||
flags);
|
||||
|
|
@ -795,15 +790,15 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
len = sg_dma_len(sg);
|
||||
mem = sg_dma_address(sg);
|
||||
if (unlikely(!len)) {
|
||||
dev_err(chan2dev(chan), "sg data length is zero\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "sg data length is zero\n");
|
||||
goto spin_unlock;
|
||||
}
|
||||
dev_dbg(chan2dev(chan), "%s: * sg%d len=%u, mem=0x%08x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: * sg%d len=%u, mem=0x%08x\n",
|
||||
__func__, i, len, mem);
|
||||
|
||||
desc = at_xdmac_get_desc(atchan);
|
||||
if (!desc) {
|
||||
dev_err(chan2dev(chan), "can't get descriptor\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "can't get descriptor\n");
|
||||
if (first)
|
||||
list_splice_tail_init(&first->descs_list,
|
||||
&atchan->free_descs_list);
|
||||
|
|
@ -828,7 +823,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
| (len >> fixed_dwidth); /* microblock length */
|
||||
desc->lld.mbr_cfg = (atchan->cfg & ~AT_XDMAC_CC_DWIDTH_MASK) |
|
||||
AT_XDMAC_CC_DWIDTH(fixed_dwidth);
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
|
||||
|
||||
|
|
@ -840,7 +835,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
if (!first)
|
||||
first = desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, desc, first);
|
||||
list_add_tail(&desc->desc_node, &first->descs_list);
|
||||
xfer_size += len;
|
||||
|
|
@ -869,17 +864,17 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
|
|||
int i;
|
||||
unsigned long irqflags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: buf_addr=%pad, buf_len=%zd, period_len=%zd, dir=%s, flags=0x%lx\n",
|
||||
__func__, &buf_addr, buf_len, period_len,
|
||||
direction == DMA_MEM_TO_DEV ? "mem2per" : "per2mem", flags);
|
||||
|
||||
if (!is_slave_direction(direction)) {
|
||||
dev_err(chan2dev(chan), "invalid DMA direction\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "invalid DMA direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status)) {
|
||||
dev_err(chan2dev(chan), "channel currently used\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "channel currently used\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -892,7 +887,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
|
|||
spin_lock_irqsave(&atchan->lock, irqflags);
|
||||
desc = at_xdmac_get_desc(atchan);
|
||||
if (!desc) {
|
||||
dev_err(chan2dev(chan), "can't get descriptor\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "can't get descriptor\n");
|
||||
if (first)
|
||||
list_splice_tail_init(&first->descs_list,
|
||||
&atchan->free_descs_list);
|
||||
|
|
@ -900,7 +895,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
|
|||
return NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&atchan->lock, irqflags);
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: desc=0x%p, tx_dma_desc.phys=%pad\n",
|
||||
__func__, desc, &desc->tx_dma_desc.phys);
|
||||
|
||||
|
|
@ -917,7 +912,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
|
|||
| AT_XDMAC_MBR_UBC_NSEN
|
||||
| period_len >> at_xdmac_get_dwidth(desc->lld.mbr_cfg);
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
|
||||
|
||||
|
|
@ -929,7 +924,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
|
|||
if (!first)
|
||||
first = desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, desc, first);
|
||||
list_add_tail(&desc->desc_node, &first->descs_list);
|
||||
}
|
||||
|
|
@ -956,16 +951,16 @@ static inline u32 at_xdmac_align_width(struct dma_chan *chan, dma_addr_t addr)
|
|||
*/
|
||||
if (!(addr & 7)) {
|
||||
width = AT_XDMAC_CC_DWIDTH_DWORD;
|
||||
dev_dbg(chan2dev(chan), "%s: dwidth: double word\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dwidth: double word\n", __func__);
|
||||
} else if (!(addr & 3)) {
|
||||
width = AT_XDMAC_CC_DWIDTH_WORD;
|
||||
dev_dbg(chan2dev(chan), "%s: dwidth: word\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dwidth: word\n", __func__);
|
||||
} else if (!(addr & 1)) {
|
||||
width = AT_XDMAC_CC_DWIDTH_HALFWORD;
|
||||
dev_dbg(chan2dev(chan), "%s: dwidth: half word\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dwidth: half word\n", __func__);
|
||||
} else {
|
||||
width = AT_XDMAC_CC_DWIDTH_BYTE;
|
||||
dev_dbg(chan2dev(chan), "%s: dwidth: byte\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dwidth: byte\n", __func__);
|
||||
}
|
||||
|
||||
return width;
|
||||
|
|
@ -1005,7 +1000,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
|
|||
|
||||
dwidth = at_xdmac_align_width(chan, src | dst | chunk->size);
|
||||
if (chunk->size >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) {
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: chunk too big (%zu, max size %lu)...\n",
|
||||
__func__, chunk->size,
|
||||
AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth);
|
||||
|
|
@ -1013,7 +1008,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
|
|||
}
|
||||
|
||||
if (prev)
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"Adding items at the end of desc 0x%p\n", prev);
|
||||
|
||||
if (xt->src_inc) {
|
||||
|
|
@ -1034,7 +1029,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
|
|||
desc = at_xdmac_get_desc(atchan);
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
if (!desc) {
|
||||
dev_err(chan2dev(chan), "can't get descriptor\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "can't get descriptor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1053,7 +1048,7 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
|
|||
| ublen;
|
||||
desc->lld.mbr_cfg = chan_cc;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da,
|
||||
desc->lld.mbr_ubc, desc->lld.mbr_cfg);
|
||||
|
|
@ -1087,7 +1082,7 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
|
|||
if ((xt->numf > 1) && (xt->frame_size > 1))
|
||||
return NULL;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, numf=%zu, frame_size=%zu, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: src=%pad, dest=%pad, numf=%zu, frame_size=%zu, flags=0x%lx\n",
|
||||
__func__, &xt->src_start, &xt->dst_start, xt->numf,
|
||||
xt->frame_size, flags);
|
||||
|
||||
|
|
@ -1106,7 +1101,7 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
|
|||
for (i = 0; i < xt->numf - 1; i++)
|
||||
at_xdmac_increment_block_count(chan, first);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, first, first);
|
||||
list_add_tail(&first->desc_node, &first->descs_list);
|
||||
} else {
|
||||
|
|
@ -1122,7 +1117,7 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
|
|||
src_skip = chunk->size + src_icg;
|
||||
dst_skip = chunk->size + dst_icg;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: chunk size=%zu, src icg=%zu, dst icg=%zu\n",
|
||||
__func__, chunk->size, src_icg, dst_icg);
|
||||
|
||||
|
|
@ -1140,7 +1135,7 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
|
|||
if (!first)
|
||||
first = desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, desc, first);
|
||||
list_add_tail(&desc->desc_node, &first->descs_list);
|
||||
|
||||
|
|
@ -1193,7 +1188,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
| AT_XDMAC_CC_TYPE_MEM_TRAN;
|
||||
unsigned long irqflags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, len=%zd, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: src=%pad, dest=%pad, len=%zd, flags=0x%lx\n",
|
||||
__func__, &src, &dest, len, flags);
|
||||
|
||||
if (unlikely(!len))
|
||||
|
|
@ -1205,13 +1200,13 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
while (remaining_size) {
|
||||
struct at_xdmac_desc *desc = NULL;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: remaining_size=%zu\n", __func__, remaining_size);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: remaining_size=%zu\n", __func__, remaining_size);
|
||||
|
||||
spin_lock_irqsave(&atchan->lock, irqflags);
|
||||
desc = at_xdmac_get_desc(atchan);
|
||||
spin_unlock_irqrestore(&atchan->lock, irqflags);
|
||||
if (!desc) {
|
||||
dev_err(chan2dev(chan), "can't get descriptor\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "can't get descriptor\n");
|
||||
if (first)
|
||||
list_splice_tail_init(&first->descs_list,
|
||||
&atchan->free_descs_list);
|
||||
|
|
@ -1227,7 +1222,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
else
|
||||
xfer_size = remaining_size;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: xfer_size=%zu\n", __func__, xfer_size);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: xfer_size=%zu\n", __func__, xfer_size);
|
||||
|
||||
/* Check remaining length and change data width if needed. */
|
||||
dwidth = at_xdmac_align_width(chan,
|
||||
|
|
@ -1246,7 +1241,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
| ublen;
|
||||
desc->lld.mbr_cfg = chan_cc;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc, desc->lld.mbr_cfg);
|
||||
|
||||
|
|
@ -1258,7 +1253,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
if (!first)
|
||||
first = desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, desc, first);
|
||||
list_add_tail(&desc->desc_node, &first->descs_list);
|
||||
}
|
||||
|
|
@ -1306,7 +1301,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
|
|||
dwidth = at_xdmac_align_width(chan, dst_addr);
|
||||
|
||||
if (len >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"%s: Transfer too large, aborting...\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
|
|
@ -1316,7 +1311,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
|
|||
desc = at_xdmac_get_desc(atchan);
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
if (!desc) {
|
||||
dev_err(chan2dev(chan), "can't get descriptor\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "can't get descriptor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1338,7 +1333,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
|
|||
| ublen;
|
||||
desc->lld.mbr_cfg = chan_cc;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: lld: mbr_da=%pad, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
|
||||
desc->lld.mbr_cfg);
|
||||
|
|
@ -1353,7 +1348,7 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
|
|||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
struct at_xdmac_desc *desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%zu, pattern=0x%x, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dest=%pad, len=%zu, pattern=0x%x, flags=0x%lx\n",
|
||||
__func__, &dest, len, value, flags);
|
||||
|
||||
if (unlikely(!len))
|
||||
|
|
@ -1386,12 +1381,12 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
if (!sgl)
|
||||
return NULL;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: sg_len=%d, value=0x%x, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: sg_len=%d, value=0x%x, flags=0x%lx\n",
|
||||
__func__, sg_len, value, flags);
|
||||
|
||||
/* Prepare descriptors. */
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
|
||||
__func__, &sg_dma_address(sg), sg_dma_len(sg),
|
||||
value, flags);
|
||||
desc = at_xdmac_memset_create_desc(chan, atchan,
|
||||
|
|
@ -1433,7 +1428,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
if (ppdesc && pdesc) {
|
||||
if ((stride == pstride) &&
|
||||
(sg_dma_len(ppsg) == sg_dma_len(psg))) {
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: desc 0x%p can be merged with desc 0x%p\n",
|
||||
__func__, pdesc, ppdesc);
|
||||
|
||||
|
|
@ -1481,7 +1476,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
*/
|
||||
list_add_tail(&desc->desc_node,
|
||||
&first->descs_list);
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: add desc 0x%p to descs_list 0x%p\n",
|
||||
__func__, desc, first);
|
||||
}
|
||||
|
|
@ -1496,7 +1491,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
*/
|
||||
if ((i == (sg_len - 1)) &&
|
||||
sg_dma_len(psg) == sg_dma_len(sg)) {
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: desc 0x%p can be merged with desc 0x%p\n",
|
||||
__func__, desc, pdesc);
|
||||
|
||||
|
|
@ -1667,7 +1662,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
|||
|
||||
dma_set_residue(txstate, residue);
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s: desc=0x%p, tx_dma_desc.phys=%pad, tx_status=%d, cookie=%d, residue=%d\n",
|
||||
__func__, desc, &desc->tx_dma_desc.phys, ret, cookie, residue);
|
||||
|
||||
|
|
@ -1690,7 +1685,7 @@ static void at_xdmac_advance_work(struct at_xdmac_chan *atchan)
|
|||
|
||||
desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc,
|
||||
xfer_node);
|
||||
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
|
||||
if (!desc->active_xfer)
|
||||
at_xdmac_start_xfer(atchan, desc);
|
||||
}
|
||||
|
|
@ -1701,7 +1696,7 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
|
|||
struct dma_async_tx_descriptor *txd;
|
||||
|
||||
spin_lock_irq(&atchan->lock);
|
||||
dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&atchan->chan), "%s: status=0x%08x\n",
|
||||
__func__, atchan->irq_status);
|
||||
if (list_empty(&atchan->xfers_list)) {
|
||||
spin_unlock_irq(&atchan->lock);
|
||||
|
|
@ -1733,11 +1728,11 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
|
|||
* descriptors queued (if any).
|
||||
*/
|
||||
if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
|
||||
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
|
||||
dev_err(dmaengine_chan_dev(&atchan->chan), "read bus error!!!");
|
||||
if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
|
||||
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
|
||||
dev_err(dmaengine_chan_dev(&atchan->chan), "write bus error!!!");
|
||||
if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
|
||||
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
|
||||
dev_err(dmaengine_chan_dev(&atchan->chan), "request overflow error!!!");
|
||||
|
||||
/* Channel must be disabled first as it's not done automatically */
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
|
||||
|
|
@ -1749,7 +1744,7 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
|
|||
xfer_node);
|
||||
|
||||
/* Print bad descriptor's details if needed */
|
||||
dev_dbg(chan2dev(&atchan->chan),
|
||||
dev_dbg(dmaengine_chan_dev(&atchan->chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
|
||||
__func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da,
|
||||
bad_desc->lld.mbr_ubc);
|
||||
|
|
@ -1775,7 +1770,7 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
|
|||
|
||||
spin_lock_irq(&atchan->lock);
|
||||
|
||||
dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&atchan->chan), "%s: status=0x%08x\n",
|
||||
__func__, atchan->irq_status);
|
||||
|
||||
if (!(atchan->irq_status & AT_XDMAC_CIS_LIS) &&
|
||||
|
|
@ -1789,9 +1784,9 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
|
|||
|
||||
desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc,
|
||||
xfer_node);
|
||||
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
|
||||
if (!desc->active_xfer) {
|
||||
dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting");
|
||||
dev_err(dmaengine_chan_dev(&atchan->chan), "Xfer not active: exiting");
|
||||
spin_unlock_irq(&atchan->lock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1852,7 +1847,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
|
|||
dev_vdbg(atxdmac->dma.dev,
|
||||
"%s: chan%d: imr=0x%x, status=0x%x\n",
|
||||
__func__, i, chan_imr, chan_status);
|
||||
dev_vdbg(chan2dev(&atchan->chan),
|
||||
dev_vdbg(dmaengine_chan_dev(&atchan->chan),
|
||||
"%s: CC=0x%08x CNDA=0x%08x, CNDC=0x%08x, CSA=0x%08x, CDA=0x%08x, CUBC=0x%08x\n",
|
||||
__func__,
|
||||
at_xdmac_chan_read(atchan, AT_XDMAC_CC),
|
||||
|
|
@ -1879,7 +1874,7 @@ static void at_xdmac_issue_pending(struct dma_chan *chan)
|
|||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(&atchan->chan), "%s\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(&atchan->chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
at_xdmac_advance_work(atchan);
|
||||
|
|
@ -1895,7 +1890,7 @@ static int at_xdmac_device_config(struct dma_chan *chan,
|
|||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
ret = at_xdmac_set_slave_config(chan, config);
|
||||
|
|
@ -1931,7 +1926,7 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
if (test_and_set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status))
|
||||
return 0;
|
||||
|
|
@ -1971,7 +1966,7 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
ret = pm_runtime_resume_and_get(atxdmac->dev);
|
||||
if (ret < 0)
|
||||
|
|
@ -2004,7 +1999,7 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
ret = pm_runtime_resume_and_get(atxdmac->dev);
|
||||
if (ret < 0)
|
||||
|
|
@ -2045,13 +2040,13 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
int i;
|
||||
|
||||
if (at_xdmac_chan_is_enabled(atchan)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"can't allocate channel resources (channel enabled)\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!list_empty(&atchan->free_descs_list)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"can't allocate channel resources (channel not free from a previous use)\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -2060,11 +2055,11 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
desc = at_xdmac_alloc_desc(chan, GFP_KERNEL);
|
||||
if (!desc) {
|
||||
if (i == 0) {
|
||||
dev_warn(chan2dev(chan),
|
||||
dev_warn(dmaengine_chan_dev(chan),
|
||||
"can't allocate any descriptors\n");
|
||||
return -EIO;
|
||||
}
|
||||
dev_warn(chan2dev(chan),
|
||||
dev_warn(dmaengine_chan_dev(chan),
|
||||
"only %d descriptors have been allocated\n", i);
|
||||
break;
|
||||
}
|
||||
|
|
@ -2073,7 +2068,7 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
|
||||
dma_cookie_init(chan);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: allocated %d descriptors\n", __func__, i);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
@ -2085,7 +2080,7 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan)
|
|||
struct at_xdmac_desc *desc, *_desc;
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &atchan->free_descs_list, desc_node) {
|
||||
dev_dbg(chan2dev(chan), "%s: freeing descriptor %p\n", __func__, desc);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: freeing descriptor %p\n", __func__, desc);
|
||||
list_del(&desc->desc_node);
|
||||
dma_pool_free(atxdmac->at_xdmac_desc_pool, desc, desc->tx_dma_desc.phys);
|
||||
}
|
||||
|
|
@ -2148,7 +2143,7 @@ static int __maybe_unused atmel_xdmac_suspend(struct device *dev)
|
|||
atchan->save_cc = at_xdmac_chan_read(atchan, AT_XDMAC_CC);
|
||||
if (at_xdmac_chan_is_cyclic(atchan)) {
|
||||
if (!at_xdmac_chan_is_paused(atchan)) {
|
||||
dev_warn(chan2dev(chan), "%s: channel %d not paused\n",
|
||||
dev_warn(dmaengine_chan_dev(chan), "%s: channel %d not paused\n",
|
||||
__func__, chan->chan_id);
|
||||
at_xdmac_device_pause_internal(atchan);
|
||||
at_xdmac_runtime_suspend_descriptors(atchan);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
config PPC_BESTCOMM
|
||||
tristate "Bestcomm DMA engine support"
|
||||
depends on PPC_MPC52xx
|
||||
depends on PPC_MPC52xx || (PPC && COMPILE_TEST)
|
||||
default n
|
||||
select PPC_LIB_RHEAP
|
||||
help
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ bcom_ata_init(int queue_len, int maxbufsize)
|
|||
{
|
||||
struct bcom_task *tsk;
|
||||
struct bcom_ata_var *var;
|
||||
struct bcom_ata_inc *inc;
|
||||
|
||||
/* Prefetch breaks ATA DMA. Turn it off for ATA DMA */
|
||||
bcom_disable_prefetch();
|
||||
|
|
@ -69,7 +68,6 @@ bcom_ata_init(int queue_len, int maxbufsize)
|
|||
bcom_ata_reset_bd(tsk);
|
||||
|
||||
var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum);
|
||||
inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
|
||||
|
||||
if (bcom_load_image(tsk->tasknum, bcom_ata_task)) {
|
||||
bcom_task_free(tsk);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/io.h>
|
||||
|
|
@ -365,13 +364,19 @@ bcom_engine_cleanup(void)
|
|||
static int mpc52xx_bcom_probe(struct platform_device *op)
|
||||
{
|
||||
struct device_node *ofn_sram;
|
||||
struct resource res_bcom;
|
||||
struct resource *res_bcom;
|
||||
void __iomem *regs;
|
||||
|
||||
int rv;
|
||||
|
||||
/* Inform user we're ok so far */
|
||||
printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
|
||||
|
||||
/* Get, reserve & map io */
|
||||
regs = devm_platform_get_and_ioremap_resource(op, 0, &res_bcom);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
/* Get the bestcomm node */
|
||||
of_node_get(op->dev.of_node);
|
||||
|
||||
|
|
@ -402,35 +407,13 @@ static int mpc52xx_bcom_probe(struct platform_device *op)
|
|||
/* Save the node */
|
||||
bcom_eng->ofnode = op->dev.of_node;
|
||||
|
||||
/* Get, reserve & map io */
|
||||
if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
|
||||
printk(KERN_ERR DRIVER_NAME ": "
|
||||
"Can't get resource\n");
|
||||
rv = -EINVAL;
|
||||
goto error_sramclean;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res_bcom.start, resource_size(&res_bcom),
|
||||
DRIVER_NAME)) {
|
||||
printk(KERN_ERR DRIVER_NAME ": "
|
||||
"Can't request registers region\n");
|
||||
rv = -EBUSY;
|
||||
goto error_sramclean;
|
||||
}
|
||||
|
||||
bcom_eng->regs_base = res_bcom.start;
|
||||
bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
|
||||
if (!bcom_eng->regs) {
|
||||
printk(KERN_ERR DRIVER_NAME ": "
|
||||
"Can't map registers\n");
|
||||
rv = -ENOMEM;
|
||||
goto error_release;
|
||||
}
|
||||
bcom_eng->regs = regs;
|
||||
bcom_eng->regs_base = res_bcom->start;
|
||||
|
||||
/* Now, do the real init */
|
||||
rv = bcom_engine_init();
|
||||
if (rv)
|
||||
goto error_unmap;
|
||||
goto error_sramclean;
|
||||
|
||||
/* Done ! */
|
||||
printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
|
||||
|
|
@ -439,12 +422,9 @@ static int mpc52xx_bcom_probe(struct platform_device *op)
|
|||
return 0;
|
||||
|
||||
/* Error path */
|
||||
error_unmap:
|
||||
iounmap(bcom_eng->regs);
|
||||
error_release:
|
||||
release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
|
||||
error_sramclean:
|
||||
kfree(bcom_eng);
|
||||
bcom_eng = NULL;
|
||||
bcom_sram_cleanup();
|
||||
error_ofput:
|
||||
of_node_put(op->dev.of_node);
|
||||
|
|
@ -463,10 +443,6 @@ static void mpc52xx_bcom_remove(struct platform_device *op)
|
|||
/* Cleanup SRAM */
|
||||
bcom_sram_cleanup();
|
||||
|
||||
/* Release regs */
|
||||
iounmap(bcom_eng->regs);
|
||||
release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
|
||||
|
||||
/* Release the node */
|
||||
of_node_put(bcom_eng->ofnode);
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ struct bcom_gen_bd_priv {
|
|||
/* Task support code */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct bcom_task *
|
||||
static struct bcom_task *
|
||||
bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
|
||||
int initiator, int ipr, int maxbufsize)
|
||||
{
|
||||
|
|
@ -108,7 +108,6 @@ bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
|
|||
|
||||
return tsk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
|
||||
|
||||
int
|
||||
bcom_gen_bd_rx_reset(struct bcom_task *tsk)
|
||||
|
|
@ -166,7 +165,7 @@ bcom_gen_bd_rx_release(struct bcom_task *tsk)
|
|||
EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
|
||||
|
||||
|
||||
extern struct bcom_task *
|
||||
static struct bcom_task *
|
||||
bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
|
||||
int initiator, int ipr)
|
||||
{
|
||||
|
|
@ -192,7 +191,6 @@ bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
|
|||
|
||||
return tsk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
|
||||
|
||||
int
|
||||
bcom_gen_bd_tx_reset(struct bcom_task *tsk)
|
||||
|
|
@ -254,17 +252,23 @@ EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
|
|||
*/
|
||||
|
||||
/**
|
||||
* bcom_psc_parameters - Bestcomm initialization value table for PSC devices
|
||||
* struct bcom_psc_params - Bestcomm initialization value table for PSC devices
|
||||
* @rx_initiator: RX initiator ID
|
||||
* @rx_ipr: RX interrupt priority register value
|
||||
* @tx_initiator: TX initiator ID
|
||||
* @tx_ipr: TX interrupt priority register value
|
||||
*
|
||||
* This structure is only used internally. It is a lookup table for PSC
|
||||
* specific parameters to bestcomm tasks.
|
||||
*/
|
||||
static struct bcom_psc_params {
|
||||
struct bcom_psc_params {
|
||||
int rx_initiator;
|
||||
int rx_ipr;
|
||||
int tx_initiator;
|
||||
int tx_ipr;
|
||||
} bcom_psc_params[] = {
|
||||
};
|
||||
|
||||
static const struct bcom_psc_params bcom_psc_params[] = {
|
||||
[0] = {
|
||||
.rx_initiator = BCOM_INITIATOR_PSC1_RX,
|
||||
.rx_ipr = BCOM_IPR_PSC1_RX,
|
||||
|
|
@ -315,7 +319,7 @@ static struct bcom_psc_params {
|
|||
struct bcom_task * bcom_psc_gen_bd_rx_init(unsigned psc_num, int queue_len,
|
||||
phys_addr_t fifo, int maxbufsize)
|
||||
{
|
||||
if (psc_num >= MPC52xx_PSC_MAXNUM)
|
||||
if (psc_num >= ARRAY_SIZE(bcom_psc_params))
|
||||
return NULL;
|
||||
|
||||
return bcom_gen_bd_rx_init(queue_len, fifo,
|
||||
|
|
@ -336,6 +340,9 @@ EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_rx_init);
|
|||
struct bcom_task *
|
||||
bcom_psc_gen_bd_tx_init(unsigned psc_num, int queue_len, phys_addr_t fifo)
|
||||
{
|
||||
if (psc_num >= ARRAY_SIZE(bcom_psc_params))
|
||||
return NULL;
|
||||
|
||||
struct psc;
|
||||
return bcom_gen_bd_tx_init(queue_len, fifo,
|
||||
bcom_psc_params[psc_num].tx_initiator,
|
||||
|
|
|
|||
|
|
@ -687,12 +687,12 @@ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
|
|||
jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
|
||||
|
||||
if (dcs & JZ_DMA_DCS_AR) {
|
||||
dev_warn(&jzchan->vchan.chan.dev->device,
|
||||
dev_warn(vchan_chan_dev(&jzchan->vchan),
|
||||
"address error (DCS=0x%x)\n", dcs);
|
||||
}
|
||||
|
||||
if (dcs & JZ_DMA_DCS_HLT) {
|
||||
dev_warn(&jzchan->vchan.chan.dev->device,
|
||||
dev_warn(vchan_chan_dev(&jzchan->vchan),
|
||||
"channel halt (DCS=0x%x)\n", dcs);
|
||||
}
|
||||
|
||||
|
|
@ -721,7 +721,7 @@ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
dev_err(&jzchan->vchan.chan.dev->device,
|
||||
dev_err(vchan_chan_dev(&jzchan->vchan),
|
||||
"channel IRQ with no active transfer\n");
|
||||
}
|
||||
|
||||
|
|
@ -760,12 +760,12 @@ static int jz4780_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
{
|
||||
struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
|
||||
|
||||
jzchan->desc_pool = dma_pool_create(dev_name(&chan->dev->device),
|
||||
jzchan->desc_pool = dma_pool_create(dma_chan_name(chan),
|
||||
chan->device->dev,
|
||||
JZ_DMA_DESC_BLOCK_SIZE,
|
||||
PAGE_SIZE, 0);
|
||||
if (!jzchan->desc_pool) {
|
||||
dev_err(&chan->dev->device,
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"failed to allocate descriptor pool\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -879,10 +879,10 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
|
|||
return chan;
|
||||
chan->slave = dev;
|
||||
|
||||
if (sysfs_create_link(&chan->dev->device.kobj, &dev->kobj,
|
||||
if (sysfs_create_link(&dmaengine_chan_dev(chan)->kobj, &dev->kobj,
|
||||
DMA_SLAVE_NAME))
|
||||
dev_warn(dev, "Cannot create DMA %s symlink\n", DMA_SLAVE_NAME);
|
||||
if (sysfs_create_link(&dev->kobj, &chan->dev->device.kobj, chan->name))
|
||||
if (sysfs_create_link(&dev->kobj, &dmaengine_chan_dev(chan)->kobj, chan->name))
|
||||
dev_warn(dev, "Cannot create DMA %s symlink\n", chan->name);
|
||||
|
||||
return chan;
|
||||
|
|
@ -928,7 +928,7 @@ void dma_release_channel(struct dma_chan *chan)
|
|||
dma_chan_put(chan);
|
||||
|
||||
if (chan->slave) {
|
||||
sysfs_remove_link(&chan->dev->device.kobj, DMA_SLAVE_NAME);
|
||||
sysfs_remove_link(&dmaengine_chan_dev(chan)->kobj, DMA_SLAVE_NAME);
|
||||
sysfs_remove_link(&chan->slave->kobj, chan->name);
|
||||
kfree(chan->name);
|
||||
chan->name = NULL;
|
||||
|
|
@ -1089,22 +1089,25 @@ static int __dma_async_device_channel_register(struct dma_device *device,
|
|||
struct dma_chan *chan,
|
||||
const char *name)
|
||||
{
|
||||
unsigned int id;
|
||||
int rc;
|
||||
|
||||
chan->local = alloc_percpu(typeof(*chan->local));
|
||||
if (!chan->local)
|
||||
return -ENOMEM;
|
||||
chan->dev = kzalloc_obj(*chan->dev);
|
||||
if (!chan->dev) {
|
||||
chan->chan_dev = kzalloc_obj(*chan->chan_dev);
|
||||
if (!chan->chan_dev) {
|
||||
rc = -ENOMEM;
|
||||
goto err_free_local;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the chan_id is a negative value, we are dynamically adding
|
||||
* the channel. Otherwise we are static enumerating.
|
||||
*/
|
||||
chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
|
||||
if (chan->chan_id & DMA_CHAN_ID_STATIC) {
|
||||
id = chan->chan_id & ~DMA_CHAN_ID_STATIC;
|
||||
chan->chan_id = ida_alloc_range(&device->chan_ida, id, id,
|
||||
GFP_KERNEL);
|
||||
} else {
|
||||
chan->chan_id = ida_alloc(&device->chan_ida, GFP_KERNEL);
|
||||
}
|
||||
if (chan->chan_id < 0) {
|
||||
pr_err("%s: unable to alloc ida for chan: %d\n",
|
||||
__func__, chan->chan_id);
|
||||
|
|
@ -1112,17 +1115,17 @@ static int __dma_async_device_channel_register(struct dma_device *device,
|
|||
goto err_free_dev;
|
||||
}
|
||||
|
||||
chan->dev->device.class = &dma_devclass;
|
||||
chan->dev->device.parent = device->dev;
|
||||
chan->dev->chan = chan;
|
||||
chan->dev->dev_id = device->dev_id;
|
||||
dmaengine_chan_dev(chan)->class = &dma_devclass;
|
||||
dmaengine_chan_dev(chan)->parent = device->dev;
|
||||
chan->chan_dev->chan = chan;
|
||||
chan->chan_dev->dev_id = device->dev_id;
|
||||
spin_lock_init(&chan->lock);
|
||||
|
||||
if (!name)
|
||||
dev_set_name(&chan->dev->device, "dma%dchan%d", device->dev_id, chan->chan_id);
|
||||
dev_set_name(dmaengine_chan_dev(chan), "dma%dchan%d", device->dev_id, chan->chan_id);
|
||||
else
|
||||
dev_set_name(&chan->dev->device, "%s", name);
|
||||
rc = device_register(&chan->dev->device);
|
||||
dev_set_name(dmaengine_chan_dev(chan), "%s", name);
|
||||
rc = device_register(dmaengine_chan_dev(chan));
|
||||
if (rc)
|
||||
goto err_out_ida;
|
||||
chan->client_count = 0;
|
||||
|
|
@ -1133,7 +1136,7 @@ static int __dma_async_device_channel_register(struct dma_device *device,
|
|||
err_out_ida:
|
||||
ida_free(&device->chan_ida, chan->chan_id);
|
||||
err_free_dev:
|
||||
kfree(chan->dev);
|
||||
kfree(chan->chan_dev);
|
||||
err_free_local:
|
||||
free_percpu(chan->local);
|
||||
chan->local = NULL;
|
||||
|
|
@ -1166,10 +1169,10 @@ static void __dma_async_device_channel_unregister(struct dma_device *device,
|
|||
__func__, chan->client_count);
|
||||
mutex_lock(&dma_list_mutex);
|
||||
device->chancnt--;
|
||||
chan->dev->chan = NULL;
|
||||
chan->chan_dev->chan = NULL;
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
ida_free(&device->chan_ida, chan->chan_id);
|
||||
device_unregister(&chan->dev->device);
|
||||
device_unregister(dmaengine_chan_dev(chan));
|
||||
free_percpu(chan->local);
|
||||
}
|
||||
|
||||
|
|
@ -1301,9 +1304,9 @@ int dma_async_device_register(struct dma_device *device)
|
|||
if (chan->local == NULL)
|
||||
continue;
|
||||
mutex_lock(&dma_list_mutex);
|
||||
chan->dev->chan = NULL;
|
||||
chan->chan_dev->chan = NULL;
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
device_unregister(&chan->dev->device);
|
||||
device_unregister(dmaengine_chan_dev(chan));
|
||||
free_percpu(chan->local);
|
||||
}
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,38 @@ dmaengine_desc_callback_valid(struct dmaengine_desc_callback *cb)
|
|||
struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
|
||||
struct dma_chan *dma_get_any_slave_channel(struct dma_device *device);
|
||||
|
||||
static inline char *
|
||||
dmaengine_get_direction_text(enum dma_transfer_direction dir)
|
||||
{
|
||||
switch (dir) {
|
||||
case DMA_DEV_TO_MEM:
|
||||
return "DEV_TO_MEM";
|
||||
case DMA_MEM_TO_DEV:
|
||||
return "MEM_TO_DEV";
|
||||
case DMA_MEM_TO_MEM:
|
||||
return "MEM_TO_MEM";
|
||||
case DMA_DEV_TO_DEV:
|
||||
return "DEV_TO_DEV";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_slave_direction(enum dma_transfer_direction direction)
|
||||
{
|
||||
return (direction == DMA_MEM_TO_DEV) || (direction == DMA_DEV_TO_MEM) ||
|
||||
(direction == DMA_DEV_TO_DEV);
|
||||
}
|
||||
|
||||
int dma_async_device_register(struct dma_device *device);
|
||||
int dmaenginem_async_device_register(struct dma_device *device);
|
||||
void dma_async_device_unregister(struct dma_device *device);
|
||||
int dma_async_device_channel_register(struct dma_device *device,
|
||||
struct dma_chan *chan,
|
||||
const char *name);
|
||||
void dma_async_device_channel_unregister(struct dma_device *device,
|
||||
struct dma_chan *chan);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -101,23 +102,25 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan,
|
|||
{
|
||||
u32 cfg_lo, cfg_hi;
|
||||
|
||||
cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
|
||||
config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
|
||||
if (chan->chip->dw->hdata->reg_map_8_channels &&
|
||||
!chan->chip->dw->hdata->use_cfg2) {
|
||||
cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
|
||||
config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
|
||||
config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
|
||||
config->src_per << CH_CFG_H_SRC_PER_POS |
|
||||
config->dst_per << CH_CFG_H_DST_PER_POS |
|
||||
config->prior << CH_CFG_H_PRIORITY_POS;
|
||||
cfg_lo = FIELD_PREP(CH_CFG_L_DST_MULTBLK_TYPE, config->dst_multblk_type) |
|
||||
FIELD_PREP(CH_CFG_L_SRC_MULTBLK_TYPE, config->src_multblk_type);
|
||||
cfg_hi = FIELD_PREP(CH_CFG_H_TT_FC, config->tt_fc) |
|
||||
FIELD_PREP(CH_CFG_H_HS_SEL_SRC, config->hs_sel_src) |
|
||||
FIELD_PREP(CH_CFG_H_HS_SEL_DST, config->hs_sel_dst) |
|
||||
FIELD_PREP(CH_CFG_H_SRC_PER, config->src_per) |
|
||||
FIELD_PREP(CH_CFG_H_DST_PER, config->dst_per) |
|
||||
FIELD_PREP(CH_CFG_H_PRIORITY, config->prior);
|
||||
} else {
|
||||
cfg_lo |= config->src_per << CH_CFG2_L_SRC_PER_POS |
|
||||
config->dst_per << CH_CFG2_L_DST_PER_POS;
|
||||
cfg_hi = config->tt_fc << CH_CFG2_H_TT_FC_POS |
|
||||
config->hs_sel_src << CH_CFG2_H_HS_SEL_SRC_POS |
|
||||
config->hs_sel_dst << CH_CFG2_H_HS_SEL_DST_POS |
|
||||
config->prior << CH_CFG2_H_PRIORITY_POS;
|
||||
cfg_lo = FIELD_PREP(CH_CFG_L_DST_MULTBLK_TYPE, config->dst_multblk_type) |
|
||||
FIELD_PREP(CH_CFG_L_SRC_MULTBLK_TYPE, config->src_multblk_type) |
|
||||
FIELD_PREP(CH_CFG2_L_SRC_PER, config->src_per) |
|
||||
FIELD_PREP(CH_CFG2_L_DST_PER, config->dst_per);
|
||||
cfg_hi = FIELD_PREP(CH_CFG2_H_TT_FC, config->tt_fc) |
|
||||
FIELD_PREP(CH_CFG2_H_HS_SEL_SRC, config->hs_sel_src) |
|
||||
FIELD_PREP(CH_CFG2_H_HS_SEL_DST, config->hs_sel_dst) |
|
||||
FIELD_PREP(CH_CFG2_H_PRIORITY, config->prior);
|
||||
}
|
||||
axi_chan_iowrite32(chan, CH_CFG_L, cfg_lo);
|
||||
axi_chan_iowrite32(chan, CH_CFG_H, cfg_hi);
|
||||
|
|
@ -316,7 +319,7 @@ static struct axi_dma_lli *axi_desc_get(struct axi_dma_chan *chan,
|
|||
|
||||
lli = dma_pool_zalloc(chan->desc_pool, GFP_NOWAIT, &phys);
|
||||
if (unlikely(!lli)) {
|
||||
dev_err(chan2dev(chan), "%s: not enough descriptors available\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "%s: not enough descriptors available\n",
|
||||
axi_chan_name(chan));
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -342,7 +345,7 @@ static void axi_desc_put(struct axi_dma_desc *desc)
|
|||
kfree(desc->hw_desc);
|
||||
kfree(desc);
|
||||
atomic_sub(descs_put, &chan->descs_allocated);
|
||||
dev_vdbg(chan2dev(chan), "%s: %d descs put, %d still allocated\n",
|
||||
dev_vdbg(vchan_chan_dev(&chan->vc), "%s: %d descs put, %d still allocated\n",
|
||||
axi_chan_name(chan), descs_put,
|
||||
atomic_read(&chan->descs_allocated));
|
||||
}
|
||||
|
|
@ -431,7 +434,7 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
|
|||
u8 lms = 0; /* Select AXI0 master for LLI fetching */
|
||||
|
||||
if (unlikely(axi_chan_is_hw_enable(chan))) {
|
||||
dev_err(chan2dev(chan), "%s is non-idle!\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "%s is non-idle!\n",
|
||||
axi_chan_name(chan));
|
||||
|
||||
return;
|
||||
|
|
@ -490,7 +493,7 @@ static void axi_chan_start_first_queued(struct axi_dma_chan *chan)
|
|||
return;
|
||||
|
||||
desc = vd_to_axi_desc(vd);
|
||||
dev_vdbg(chan2dev(chan), "%s: started %u\n", axi_chan_name(chan),
|
||||
dev_vdbg(vchan_chan_dev(&chan->vc), "%s: started %u\n", axi_chan_name(chan),
|
||||
vd->tx.cookie);
|
||||
axi_chan_block_xfer_start(chan, desc);
|
||||
}
|
||||
|
|
@ -524,23 +527,22 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
|
|||
|
||||
/* ASSERT: channel is idle */
|
||||
if (axi_chan_is_hw_enable(chan)) {
|
||||
dev_err(chan2dev(chan), "%s is non-idle!\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "%s is non-idle!\n",
|
||||
axi_chan_name(chan));
|
||||
pm_runtime_put(chan->chip->dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* LLI address must be aligned to a 64-byte boundary */
|
||||
chan->desc_pool = dma_pool_create(dev_name(chan2dev(chan)),
|
||||
chan->chip->dev,
|
||||
chan->desc_pool = dma_pool_create(dma_chan_name(dchan), chan->chip->dev,
|
||||
sizeof(struct axi_dma_lli),
|
||||
64, 0);
|
||||
if (!chan->desc_pool) {
|
||||
dev_err(chan2dev(chan), "No memory for descriptors\n");
|
||||
dev_err(vchan_chan_dev(&chan->vc), "No memory for descriptors\n");
|
||||
pm_runtime_put(chan->chip->dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev_vdbg(dchan2dev(dchan), "%s: allocating\n", axi_chan_name(chan));
|
||||
dev_vdbg(dmaengine_chan_dev(dchan), "%s: allocating\n", axi_chan_name(chan));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -551,7 +553,7 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan)
|
|||
|
||||
/* ASSERT: channel is idle */
|
||||
if (axi_chan_is_hw_enable(chan))
|
||||
dev_err(dchan2dev(dchan), "%s is non-idle!\n",
|
||||
dev_err(dmaengine_chan_dev(dchan), "%s is non-idle!\n",
|
||||
axi_chan_name(chan));
|
||||
|
||||
axi_chan_disable(chan);
|
||||
|
|
@ -561,7 +563,7 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan)
|
|||
|
||||
dma_pool_destroy(chan->desc_pool);
|
||||
chan->desc_pool = NULL;
|
||||
dev_vdbg(dchan2dev(dchan),
|
||||
dev_vdbg(dmaengine_chan_dev(dchan),
|
||||
"%s: free resources, descriptor still allocated: %u\n",
|
||||
axi_chan_name(chan), atomic_read(&chan->descs_allocated));
|
||||
|
||||
|
|
@ -677,19 +679,19 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|||
case DMA_MEM_TO_DEV:
|
||||
reg_width = __ffs(chan->config.dst_addr_width);
|
||||
device_addr = chan->config.dst_addr;
|
||||
ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
|
||||
mem_width << CH_CTL_L_SRC_WIDTH_POS |
|
||||
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
|
||||
ctllo = FIELD_PREP(CH_CTL_L_DST_WIDTH, reg_width) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_WIDTH, mem_width) |
|
||||
FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_NOINC) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_INC);
|
||||
block_ts = len >> mem_width;
|
||||
break;
|
||||
case DMA_DEV_TO_MEM:
|
||||
reg_width = __ffs(chan->config.src_addr_width);
|
||||
device_addr = chan->config.src_addr;
|
||||
ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
|
||||
mem_width << CH_CTL_L_DST_WIDTH_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
|
||||
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
|
||||
ctllo = FIELD_PREP(CH_CTL_L_SRC_WIDTH, reg_width) |
|
||||
FIELD_PREP(CH_CTL_L_DST_WIDTH, mem_width) |
|
||||
FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_INC) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_NOINC);
|
||||
block_ts = len >> reg_width;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -706,10 +708,10 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|||
ctlhi = CH_CTL_H_LLI_VALID;
|
||||
|
||||
if (chan->chip->dw->hdata->restrict_axi_burst_len) {
|
||||
burst_len = chan->chip->dw->hdata->axi_rw_burst_len;
|
||||
burst_len = chan->chip->dw->hdata->axi_rw_burst_len - 1;
|
||||
ctlhi |= CH_CTL_H_ARLEN_EN | CH_CTL_H_AWLEN_EN |
|
||||
burst_len << CH_CTL_H_ARLEN_POS |
|
||||
burst_len << CH_CTL_H_AWLEN_POS;
|
||||
FIELD_PREP(CH_CTL_H_ARLEN, burst_len) |
|
||||
FIELD_PREP(CH_CTL_H_AWLEN, burst_len);
|
||||
}
|
||||
|
||||
hw_desc->lli->ctl_hi = cpu_to_le32(ctlhi);
|
||||
|
|
@ -724,8 +726,8 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|||
|
||||
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
|
||||
|
||||
ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
||||
DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
|
||||
ctllo |= FIELD_PREP(CH_CTL_L_DST_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4);
|
||||
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
|
||||
|
||||
set_desc_src_master(hw_desc);
|
||||
|
|
@ -930,7 +932,7 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
|
|||
u64 llp = 0;
|
||||
u8 lms = 0; /* Select AXI0 master for LLI fetching */
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: memcpy: src: %pad dst: %pad length: %zd flags: %#lx",
|
||||
dev_dbg(vchan_chan_dev(&chan->vc), "%s: memcpy: src: %pad dst: %pad length: %zd flags: %#lx",
|
||||
axi_chan_name(chan), &src_adr, &dst_adr, len, flags);
|
||||
|
||||
max_block_ts = chan->chip->dw->hdata->block_size[chan->id];
|
||||
|
|
@ -975,21 +977,21 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
|
|||
|
||||
reg = CH_CTL_H_LLI_VALID;
|
||||
if (chan->chip->dw->hdata->restrict_axi_burst_len) {
|
||||
u32 burst_len = chan->chip->dw->hdata->axi_rw_burst_len;
|
||||
u32 burst_len = chan->chip->dw->hdata->axi_rw_burst_len - 1;
|
||||
|
||||
reg |= (CH_CTL_H_ARLEN_EN |
|
||||
burst_len << CH_CTL_H_ARLEN_POS |
|
||||
CH_CTL_H_AWLEN_EN |
|
||||
burst_len << CH_CTL_H_AWLEN_POS);
|
||||
reg |= CH_CTL_H_ARLEN_EN |
|
||||
FIELD_PREP(CH_CTL_H_ARLEN, burst_len) |
|
||||
CH_CTL_H_AWLEN_EN |
|
||||
FIELD_PREP(CH_CTL_H_AWLEN, burst_len);
|
||||
}
|
||||
hw_desc->lli->ctl_hi = cpu_to_le32(reg);
|
||||
|
||||
reg = (DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
||||
DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
|
||||
xfer_width << CH_CTL_L_DST_WIDTH_POS |
|
||||
xfer_width << CH_CTL_L_SRC_WIDTH_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
|
||||
reg = FIELD_PREP(CH_CTL_L_DST_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_MSIZE, DWAXIDMAC_BURST_TRANS_LEN_4) |
|
||||
FIELD_PREP(CH_CTL_L_DST_WIDTH, xfer_width) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_WIDTH, xfer_width) |
|
||||
FIELD_PREP(CH_CTL_L_DST_INC, DWAXIDMAC_CH_CTL_L_INC) |
|
||||
FIELD_PREP(CH_CTL_L_SRC_INC, DWAXIDMAC_CH_CTL_L_INC);
|
||||
hw_desc->lli->ctl_lo = cpu_to_le32(reg);
|
||||
|
||||
set_desc_src_master(hw_desc);
|
||||
|
|
@ -1035,11 +1037,11 @@ static void axi_chan_dump_lli(struct axi_dma_chan *chan,
|
|||
struct axi_dma_hw_desc *desc)
|
||||
{
|
||||
if (!desc->lli) {
|
||||
dev_err(dchan2dev(&chan->vc.chan), "NULL LLI\n");
|
||||
dev_err(vchan_chan_dev(&chan->vc), "NULL LLI\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev_err(dchan2dev(&chan->vc.chan),
|
||||
dev_err(vchan_chan_dev(&chan->vc),
|
||||
"SAR: 0x%llx DAR: 0x%llx LLP: 0x%llx BTS 0x%x CTL: 0x%x:%08x",
|
||||
le64_to_cpu(desc->lli->sar),
|
||||
le64_to_cpu(desc->lli->dar),
|
||||
|
|
@ -1052,10 +1054,7 @@ static void axi_chan_dump_lli(struct axi_dma_chan *chan,
|
|||
static void axi_chan_list_dump_lli(struct axi_dma_chan *chan,
|
||||
struct axi_dma_desc *desc_head)
|
||||
{
|
||||
int count = atomic_read(&chan->descs_allocated);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (unsigned int i = 0; i < desc_head->nr_hw_descs; i++)
|
||||
axi_chan_dump_lli(chan, &desc_head->hw_desc[i]);
|
||||
}
|
||||
|
||||
|
|
@ -1071,7 +1070,7 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
|
|||
/* The bad descriptor currently is in the head of vc list */
|
||||
vd = vchan_next_desc(&chan->vc);
|
||||
if (!vd) {
|
||||
dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "BUG: %s, IRQ with no descriptors\n",
|
||||
axi_chan_name(chan));
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1079,7 +1078,7 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
|
|||
list_del(&vd->node);
|
||||
|
||||
/* WARN about bad descriptor */
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vc),
|
||||
"Bad descriptor submitted for %s, cookie: %d, irq: 0x%08x\n",
|
||||
axi_chan_name(chan), vd->tx.cookie, status);
|
||||
axi_chan_list_dump_lli(chan, vd_to_axi_desc(vd));
|
||||
|
|
@ -1105,7 +1104,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
|
|||
|
||||
spin_lock_irqsave(&chan->vc.lock, flags);
|
||||
if (unlikely(axi_chan_is_hw_enable(chan))) {
|
||||
dev_err(chan2dev(chan), "BUG: %s caught DWAXIDMAC_IRQ_DMA_TRF, but channel not idle!\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "BUG: %s caught DWAXIDMAC_IRQ_DMA_TRF, but channel not idle!\n",
|
||||
axi_chan_name(chan));
|
||||
axi_chan_disable(chan);
|
||||
}
|
||||
|
|
@ -1113,7 +1112,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
|
|||
/* The completed descriptor currently is in the head of vc list */
|
||||
vd = vchan_next_desc(&chan->vc);
|
||||
if (!vd) {
|
||||
dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
|
||||
dev_err(vchan_chan_dev(&chan->vc), "BUG: %s, IRQ with no descriptors\n",
|
||||
axi_chan_name(chan));
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1193,7 +1192,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
|
|||
ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val,
|
||||
!(val & chan_active), 1000, 50000);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_warn(dchan2dev(dchan),
|
||||
dev_warn(dmaengine_chan_dev(dchan),
|
||||
"%s failed to stop\n", axi_chan_name(chan));
|
||||
|
||||
if (chan->direction != DMA_MEM_TO_MEM)
|
||||
|
|
@ -1210,7 +1209,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
|
|||
|
||||
vchan_dma_desc_free_list(&chan->vc, &head);
|
||||
|
||||
dev_vdbg(dchan2dev(dchan), "terminated: %s\n", axi_chan_name(chan));
|
||||
dev_vdbg(dmaengine_chan_dev(dchan), "terminated: %s\n", axi_chan_name(chan));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1320,8 +1319,7 @@ static int axi_dma_suspend(struct axi_dma_chip *chip)
|
|||
axi_dma_irq_disable(chip);
|
||||
axi_dma_disable(chip);
|
||||
|
||||
clk_disable_unprepare(chip->core_clk);
|
||||
clk_disable_unprepare(chip->cfgr_clk);
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(chip->clks), chip->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1330,11 +1328,7 @@ static int axi_dma_resume(struct axi_dma_chip *chip)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(chip->cfgr_clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(chip->core_clk);
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(chip->clks), chip->clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1524,13 +1518,11 @@ static int dw_probe(struct platform_device *pdev)
|
|||
|
||||
chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2);
|
||||
|
||||
chip->core_clk = devm_clk_get(chip->dev, "core-clk");
|
||||
if (IS_ERR(chip->core_clk))
|
||||
return PTR_ERR(chip->core_clk);
|
||||
|
||||
chip->cfgr_clk = devm_clk_get(chip->dev, "cfgr-clk");
|
||||
if (IS_ERR(chip->cfgr_clk))
|
||||
return PTR_ERR(chip->cfgr_clk);
|
||||
chip->clks[0].id = "core-clk";
|
||||
chip->clks[1].id = "cfgr-clk";
|
||||
ret = devm_clk_bulk_get(chip->dev, ARRAY_SIZE(chip->clks), chip->clks);
|
||||
if (ret)
|
||||
return dev_err_probe(chip->dev, ret, "failed to get clocks\n");
|
||||
|
||||
ret = parse_device_properties(chip);
|
||||
if (ret)
|
||||
|
|
@ -1640,10 +1632,13 @@ static void dw_remove(struct platform_device *pdev)
|
|||
struct dw_axi_dma *dw = chip->dw;
|
||||
struct axi_dma_chan *chan, *_chan;
|
||||
u32 i;
|
||||
int ret;
|
||||
|
||||
/* Enable clk before accessing to registers */
|
||||
clk_prepare_enable(chip->cfgr_clk);
|
||||
clk_prepare_enable(chip->core_clk);
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(chip->clks), chip->clks);
|
||||
if (ret)
|
||||
dev_warn(chip->dev, "failed to enable clocks before remove: %d\n",
|
||||
ret);
|
||||
axi_dma_irq_disable(chip);
|
||||
for (i = 0; i < dw->hdata->nr_channels; i++) {
|
||||
axi_chan_disable(&chip->dw->chan[i]);
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ struct axi_dma_chip {
|
|||
int irq[DMAC_MAX_CHANNELS];
|
||||
void __iomem *regs;
|
||||
void __iomem *apb_regs;
|
||||
struct clk *core_clk;
|
||||
struct clk *cfgr_clk;
|
||||
struct clk_bulk_data clks[2];
|
||||
struct dw_axi_dma *dw;
|
||||
};
|
||||
|
||||
|
|
@ -119,16 +118,6 @@ struct axi_dma_chan_config {
|
|||
u8 hs_sel_src;
|
||||
};
|
||||
|
||||
static inline struct device *dchan2dev(struct dma_chan *dchan)
|
||||
{
|
||||
return &dchan->dev->device;
|
||||
}
|
||||
|
||||
static inline struct device *chan2dev(struct axi_dma_chan *chan)
|
||||
{
|
||||
return &chan->vc.chan.dev->device;
|
||||
}
|
||||
|
||||
static inline struct axi_dma_desc *vd_to_axi_desc(struct virt_dma_desc *vd)
|
||||
{
|
||||
return container_of(vd, struct axi_dma_desc, vd);
|
||||
|
|
@ -234,9 +223,9 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
|
|||
|
||||
/* CH_CTL_H */
|
||||
#define CH_CTL_H_ARLEN_EN BIT(6)
|
||||
#define CH_CTL_H_ARLEN_POS 7
|
||||
#define CH_CTL_H_ARLEN GENMASK(14, 7)
|
||||
#define CH_CTL_H_AWLEN_EN BIT(15)
|
||||
#define CH_CTL_H_AWLEN_POS 16
|
||||
#define CH_CTL_H_AWLEN GENMASK(23, 16)
|
||||
|
||||
enum {
|
||||
DWAXIDMAC_ARWLEN_1 = 0,
|
||||
|
|
@ -258,8 +247,8 @@ enum {
|
|||
/* CH_CTL_L */
|
||||
#define CH_CTL_L_LAST_WRITE_EN BIT(30)
|
||||
|
||||
#define CH_CTL_L_DST_MSIZE_POS 18
|
||||
#define CH_CTL_L_SRC_MSIZE_POS 14
|
||||
#define CH_CTL_L_DST_MSIZE GENMASK(21, 18)
|
||||
#define CH_CTL_L_SRC_MSIZE GENMASK(17, 14)
|
||||
|
||||
enum {
|
||||
DWAXIDMAC_BURST_TRANS_LEN_1 = 0,
|
||||
|
|
@ -274,11 +263,11 @@ enum {
|
|||
DWAXIDMAC_BURST_TRANS_LEN_1024
|
||||
};
|
||||
|
||||
#define CH_CTL_L_DST_WIDTH_POS 11
|
||||
#define CH_CTL_L_SRC_WIDTH_POS 8
|
||||
#define CH_CTL_L_DST_WIDTH GENMASK(13, 11)
|
||||
#define CH_CTL_L_SRC_WIDTH GENMASK(10, 8)
|
||||
|
||||
#define CH_CTL_L_DST_INC_POS 6
|
||||
#define CH_CTL_L_SRC_INC_POS 4
|
||||
#define CH_CTL_L_DST_INC BIT(6)
|
||||
#define CH_CTL_L_SRC_INC BIT(4)
|
||||
enum {
|
||||
DWAXIDMAC_CH_CTL_L_INC = 0,
|
||||
DWAXIDMAC_CH_CTL_L_NOINC
|
||||
|
|
@ -288,17 +277,17 @@ enum {
|
|||
#define CH_CTL_L_SRC_MAST BIT(0)
|
||||
|
||||
/* CH_CFG_H */
|
||||
#define CH_CFG_H_PRIORITY_POS 17
|
||||
#define CH_CFG_H_DST_PER_POS 12
|
||||
#define CH_CFG_H_SRC_PER_POS 7
|
||||
#define CH_CFG_H_HS_SEL_DST_POS 4
|
||||
#define CH_CFG_H_HS_SEL_SRC_POS 3
|
||||
#define CH_CFG_H_PRIORITY GENMASK(19, 17)
|
||||
#define CH_CFG_H_DST_PER GENMASK(15, 12)
|
||||
#define CH_CFG_H_SRC_PER GENMASK(10, 7)
|
||||
#define CH_CFG_H_HS_SEL_DST BIT(4)
|
||||
#define CH_CFG_H_HS_SEL_SRC BIT(3)
|
||||
enum {
|
||||
DWAXIDMAC_HS_SEL_HW = 0,
|
||||
DWAXIDMAC_HS_SEL_SW
|
||||
};
|
||||
|
||||
#define CH_CFG_H_TT_FC_POS 0
|
||||
#define CH_CFG_H_TT_FC GENMASK(2, 0)
|
||||
enum {
|
||||
DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC = 0,
|
||||
DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC,
|
||||
|
|
@ -311,8 +300,8 @@ enum {
|
|||
};
|
||||
|
||||
/* CH_CFG_L */
|
||||
#define CH_CFG_L_DST_MULTBLK_TYPE_POS 2
|
||||
#define CH_CFG_L_SRC_MULTBLK_TYPE_POS 0
|
||||
#define CH_CFG_L_DST_MULTBLK_TYPE GENMASK(3, 2)
|
||||
#define CH_CFG_L_SRC_MULTBLK_TYPE GENMASK(1, 0)
|
||||
enum {
|
||||
DWAXIDMAC_MBLK_TYPE_CONTIGUOUS = 0,
|
||||
DWAXIDMAC_MBLK_TYPE_RELOAD,
|
||||
|
|
@ -321,13 +310,13 @@ enum {
|
|||
};
|
||||
|
||||
/* CH_CFG2 */
|
||||
#define CH_CFG2_L_SRC_PER_POS 4
|
||||
#define CH_CFG2_L_DST_PER_POS 11
|
||||
#define CH_CFG2_L_SRC_PER GENMASK(9, 4)
|
||||
#define CH_CFG2_L_DST_PER GENMASK(16, 11)
|
||||
|
||||
#define CH_CFG2_H_TT_FC_POS 0
|
||||
#define CH_CFG2_H_HS_SEL_SRC_POS 3
|
||||
#define CH_CFG2_H_HS_SEL_DST_POS 4
|
||||
#define CH_CFG2_H_PRIORITY_POS 20
|
||||
#define CH_CFG2_H_TT_FC GENMASK(2, 0)
|
||||
#define CH_CFG2_H_HS_SEL_SRC BIT(3)
|
||||
#define CH_CFG2_H_HS_SEL_DST BIT(4)
|
||||
#define CH_CFG2_H_PRIORITY GENMASK(19, 15)
|
||||
|
||||
/**
|
||||
* DW AXI DMA channel interrupts
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/dma/edma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
|
@ -30,9 +32,9 @@ struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
|
|||
return container_of(vd, struct dw_edma_desc, vd);
|
||||
}
|
||||
|
||||
enum dw_edma_irq_event {
|
||||
DW_EDMA_IRQ_DONE = BIT(0),
|
||||
DW_EDMA_IRQ_ABORT = BIT(1),
|
||||
enum dw_edma_deferred_event {
|
||||
DW_EDMA_DEFERRED_DONE = BIT(0),
|
||||
DW_EDMA_DEFERRED_ABORT = BIT(1),
|
||||
};
|
||||
|
||||
static inline
|
||||
|
|
@ -51,13 +53,19 @@ dw_edma_alloc_desc(struct dw_edma_chan *chan, size_t nburst)
|
|||
{
|
||||
struct dw_edma_desc *desc;
|
||||
|
||||
/*
|
||||
* For now, a descriptor that does not fit would stall the channel
|
||||
* forever: reject it up front.
|
||||
*/
|
||||
if (!chan->non_ll && nburst > chan->ll_max - 1)
|
||||
return NULL;
|
||||
|
||||
desc = kzalloc_flex(*desc, burst, nburst, GFP_NOWAIT);
|
||||
if (unlikely(!desc))
|
||||
return NULL;
|
||||
|
||||
desc->chan = chan;
|
||||
desc->nburst = nburst;
|
||||
desc->cb = true;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
|
@ -67,38 +75,122 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)
|
|||
kfree(vd2dw_edma_desc(vdesc));
|
||||
}
|
||||
|
||||
static void dw_edma_core_start(struct dw_edma_desc *desc, bool first)
|
||||
/* Must be called with vc.lock held. */
|
||||
static void
|
||||
dw_edma_set_request(struct dw_edma_chan *chan, enum dw_edma_request request)
|
||||
{
|
||||
chan->request = request;
|
||||
}
|
||||
|
||||
static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,
|
||||
enum dmaengine_tx_result result)
|
||||
{
|
||||
u32 residue = 0;
|
||||
struct dw_edma_desc *desc;
|
||||
struct dmaengine_result *res;
|
||||
|
||||
if (!vd->tx.callback_result)
|
||||
return;
|
||||
|
||||
desc = vd2dw_edma_desc(vd);
|
||||
if (desc) {
|
||||
residue = desc->alloc_sz;
|
||||
|
||||
if (result == DMA_TRANS_NOERROR)
|
||||
residue -= desc->burst[desc->start_burst - 1].xfer_sz;
|
||||
else if (desc->done_burst)
|
||||
residue -= desc->burst[desc->done_burst - 1].xfer_sz;
|
||||
}
|
||||
|
||||
res = &vd->tx_result;
|
||||
res->result = result;
|
||||
res->residue = residue;
|
||||
}
|
||||
|
||||
static void dw_edma_core_reset_ll(struct dw_edma_chan *chan)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
chan->ll_head = 0;
|
||||
chan->ll_done = 0;
|
||||
/* Drop stale CB bits before reusing the circular LL ring. */
|
||||
for (i = 0; i < chan->ll_max; i++)
|
||||
dw_edma_core_ll_clear(chan, i);
|
||||
chan->cb = true;
|
||||
|
||||
dw_edma_core_ll_link(chan, chan->ll_max, chan->cb,
|
||||
chan->ll_region.paddr);
|
||||
|
||||
dw_edma_core_ch_enable(chan);
|
||||
chan->ll_valid = true;
|
||||
}
|
||||
|
||||
static u32 dw_edma_core_get_ll_dist(struct dw_edma_chan *chan, u32 from, u32 to)
|
||||
{
|
||||
return (to + chan->ll_max - from) % chan->ll_max;
|
||||
}
|
||||
|
||||
static u32 dw_edma_core_get_used_num(struct dw_edma_chan *chan)
|
||||
{
|
||||
return dw_edma_core_get_ll_dist(chan, chan->ll_done, chan->ll_head);
|
||||
}
|
||||
|
||||
static u32 dw_edma_core_get_free_num(struct dw_edma_chan *chan)
|
||||
{
|
||||
/* Keep one data entry free so equal indices mean an empty ring. */
|
||||
return chan->ll_max - 1 - dw_edma_core_get_used_num(chan);
|
||||
}
|
||||
|
||||
static bool dw_edma_ll_pending(struct dw_edma_chan *chan)
|
||||
{
|
||||
return chan->ll_head != chan->ll_done;
|
||||
}
|
||||
|
||||
static void dw_edma_core_ll_start(struct dw_edma_desc *desc)
|
||||
{
|
||||
struct dw_edma_chan *chan = desc->chan;
|
||||
size_t i;
|
||||
u32 free;
|
||||
|
||||
free = dw_edma_core_get_free_num(chan);
|
||||
for (i = desc->start_burst; i < desc->nburst && free; i++, free--) {
|
||||
/*
|
||||
* Refresh the link element before filling the last data slot so
|
||||
* the next lap has the updated CB value.
|
||||
*/
|
||||
if (chan->ll_head == chan->ll_max - 1)
|
||||
dw_edma_core_ll_link(chan, chan->ll_max, chan->cb,
|
||||
chan->ll_region.paddr);
|
||||
|
||||
dw_edma_core_ll_data(chan, &desc->burst[i],
|
||||
chan->ll_head, chan->cb,
|
||||
i == desc->nburst - 1 || free == 1);
|
||||
|
||||
chan->ll_head++;
|
||||
|
||||
if (chan->ll_head == chan->ll_max) {
|
||||
chan->cb = !chan->cb;
|
||||
chan->ll_head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
desc->done_burst = desc->start_burst;
|
||||
desc->start_burst = i;
|
||||
}
|
||||
|
||||
static void dw_edma_core_start(struct dw_edma_desc *desc)
|
||||
{
|
||||
struct dw_edma_chan *chan = desc->chan;
|
||||
size_t i = 0;
|
||||
|
||||
if (chan->non_ll) {
|
||||
chan->dw->core->non_ll_start(chan, &desc->burst[desc->start_burst]);
|
||||
chan->dw->core->non_ll_start(chan,
|
||||
&desc->burst[desc->start_burst]);
|
||||
desc->done_burst = desc->start_burst;
|
||||
desc->start_burst += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i + desc->start_burst < desc->nburst; i++) {
|
||||
u32 idx = i + desc->start_burst;
|
||||
|
||||
if (i == chan->ll_max)
|
||||
break;
|
||||
|
||||
dw_edma_core_ll_data(chan, &desc->burst[idx],
|
||||
i, desc->cb,
|
||||
idx == desc->nburst - 1 || i == chan->ll_max - 1);
|
||||
}
|
||||
|
||||
desc->done_burst = desc->start_burst;
|
||||
desc->start_burst += i;
|
||||
|
||||
dw_edma_core_ll_link(chan, i, desc->cb, chan->ll_region.paddr);
|
||||
|
||||
if (first)
|
||||
dw_edma_core_ch_enable(chan);
|
||||
|
||||
dw_edma_core_ch_doorbell(chan);
|
||||
dw_edma_core_ll_start(desc);
|
||||
}
|
||||
|
||||
static int dw_edma_start_transfer(struct dw_edma_chan *chan)
|
||||
|
|
@ -114,9 +206,10 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
|
|||
if (!desc)
|
||||
return 0;
|
||||
|
||||
dw_edma_core_start(desc, !desc->start_burst);
|
||||
if (!chan->non_ll && !chan->ll_valid)
|
||||
dw_edma_core_reset_ll(chan);
|
||||
|
||||
desc->cb = !desc->cb;
|
||||
dw_edma_core_start(desc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -150,6 +243,46 @@ static void dw_edma_terminate_all_descs(struct dw_edma_chan *chan)
|
|||
dw_edma_terminate_vdesc_list(&chan->vc.desc_submitted);
|
||||
}
|
||||
|
||||
/* Must be called with vc.lock held after the channel has stopped. */
|
||||
static void dw_edma_finish_termination(struct dw_edma_chan *chan)
|
||||
{
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
|
||||
/* Preserve a clean ring; resync only if entries remain published. */
|
||||
if (!chan->non_ll && dw_edma_ll_pending(chan))
|
||||
dw_edma_core_reset_ll(chan);
|
||||
|
||||
dw_edma_set_request(chan, EDMA_REQ_NONE);
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
}
|
||||
|
||||
static void dw_edma_core_ll_sync(struct dw_edma_chan *chan)
|
||||
{
|
||||
/*
|
||||
* Remote controller registers and LL memory may be reached through
|
||||
* different paths. Complete posted LL writes before the doorbell.
|
||||
*/
|
||||
if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
|
||||
readl(chan->ll_region.vaddr.io);
|
||||
}
|
||||
|
||||
/* Must be called with vc.lock held for an LL channel. */
|
||||
static void dw_edma_core_ch_doorbell(struct dw_edma_chan *chan)
|
||||
{
|
||||
dw_edma_core_ll_sync(chan);
|
||||
dw_edma_core_do_ch_doorbell(chan);
|
||||
}
|
||||
|
||||
/* Must be called with vc.lock held. */
|
||||
static void dw_edma_core_ch_maybe_doorbell(struct dw_edma_chan *chan)
|
||||
{
|
||||
if (chan->non_ll || chan->request != EDMA_REQ_NONE ||
|
||||
chan->status != EDMA_ST_BUSY || !dw_edma_ll_pending(chan))
|
||||
return;
|
||||
|
||||
dw_edma_core_ch_doorbell(chan);
|
||||
}
|
||||
|
||||
static void dw_edma_device_caps(struct dma_chan *dchan,
|
||||
struct dma_slave_caps *caps)
|
||||
{
|
||||
|
|
@ -177,48 +310,76 @@ dw_edma_get_default_irq_mode(struct dw_edma_chan *chan)
|
|||
DW_EDMA_CH_IRQ_REMOTE;
|
||||
}
|
||||
|
||||
static int dw_edma_device_config_irq_mode(struct dw_edma_chan *chan,
|
||||
enum dw_edma_ch_irq_mode mode)
|
||||
{
|
||||
if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) ||
|
||||
(mode != DW_EDMA_CH_IRQ_LOCAL && mode != DW_EDMA_CH_IRQ_REMOTE))
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock_irqsave)(&chan->vc.lock);
|
||||
|
||||
if (chan->status != EDMA_ST_IDLE || chan->request != EDMA_REQ_NONE)
|
||||
return -EBUSY;
|
||||
|
||||
/* IRQ routing cannot change after the initial configuration. */
|
||||
if (chan->irq_mode == mode)
|
||||
return 0;
|
||||
|
||||
if (chan->configured)
|
||||
return -EBUSY;
|
||||
|
||||
chan->irq_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_edma_device_config(struct dma_chan *dchan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
const struct dw_edma_chan_config *dw_config = config->peripheral_config;
|
||||
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
|
||||
bool cfg_non_ll;
|
||||
int non_ll = 0;
|
||||
bool non_ll = false;
|
||||
u32 flags = 0;
|
||||
int ret;
|
||||
|
||||
chan->non_ll = false;
|
||||
if (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE) {
|
||||
if (config->peripheral_config &&
|
||||
config->peripheral_size != sizeof(int)) {
|
||||
dev_err(dchan->device->dev,
|
||||
"config param peripheral size mismatch\n");
|
||||
if (dw_config) {
|
||||
if (config->peripheral_size != sizeof(*dw_config) ||
|
||||
dw_config->flags & ~(DW_EDMA_CH_CONFIG_NON_LL |
|
||||
DW_EDMA_CH_CONFIG_IRQ_MODE))
|
||||
return -EINVAL;
|
||||
flags = dw_config->flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* When there is no valid LLP base address available then the
|
||||
* default DMA ops will use the non-LL mode.
|
||||
*
|
||||
* When LL mode is the default, clients can request non-LL mode
|
||||
* through DW_EDMA_CH_CONFIG_NON_LL.
|
||||
*/
|
||||
non_ll = chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE &&
|
||||
chan->dw->chip->cfg_non_ll;
|
||||
|
||||
if (flags & DW_EDMA_CH_CONFIG_NON_LL) {
|
||||
if (chan->dw->chip->mf != EDMA_MF_HDMA_NATIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (chan->dw->chip->cfg_non_ll && !dw_config->non_ll) {
|
||||
dev_err(dchan->device->dev, "invalid configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* When there is no valid LLP base address available then the
|
||||
* default DMA ops will use the non-LL mode.
|
||||
*
|
||||
* Cases where LL mode is enabled and client wants to use the
|
||||
* non-LL mode then also client can do so via providing the
|
||||
* peripheral_config param.
|
||||
*/
|
||||
cfg_non_ll = chan->dw->chip->cfg_non_ll;
|
||||
if (config->peripheral_config) {
|
||||
non_ll = *(int *)config->peripheral_config;
|
||||
|
||||
if (cfg_non_ll && !non_ll) {
|
||||
dev_err(dchan->device->dev, "invalid configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg_non_ll || non_ll)
|
||||
chan->non_ll = true;
|
||||
} else if (config->peripheral_config) {
|
||||
dev_err(dchan->device->dev,
|
||||
"peripheral config param applicable only for HDMA\n");
|
||||
return -EINVAL;
|
||||
non_ll = dw_config->non_ll;
|
||||
}
|
||||
|
||||
if (flags & DW_EDMA_CH_CONFIG_IRQ_MODE) {
|
||||
ret = dw_edma_device_config_irq_mode(chan, dw_config->irq_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
chan->non_ll = non_ll;
|
||||
memcpy(&chan->config, config, sizeof(*config));
|
||||
chan->configured = true;
|
||||
|
||||
|
|
@ -253,7 +414,7 @@ static int dw_edma_device_pause(struct dma_chan *dchan)
|
|||
else if (chan->request != EDMA_REQ_NONE)
|
||||
err = -EPERM;
|
||||
else
|
||||
chan->request = EDMA_REQ_PAUSE;
|
||||
dw_edma_set_request(chan, EDMA_REQ_PAUSE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -275,6 +436,7 @@ static int dw_edma_device_resume(struct dma_chan *dchan)
|
|||
chan->status = EDMA_ST_BUSY;
|
||||
if (!dw_edma_start_transfer(chan))
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
dw_edma_core_ch_maybe_doorbell(chan);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
@ -290,24 +452,22 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan)
|
|||
if (!chan->configured) {
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
} else if (chan->status == EDMA_ST_PAUSE) {
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
dw_edma_finish_termination(chan);
|
||||
} else if (chan->status == EDMA_ST_IDLE) {
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
dw_edma_finish_termination(chan);
|
||||
} else if (dw_edma_core_ch_status(chan) == DMA_COMPLETE) {
|
||||
/*
|
||||
* The channel is in a false BUSY state, probably didn't
|
||||
* receive or lost an interrupt
|
||||
*/
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
dw_edma_finish_termination(chan);
|
||||
} else if (chan->request > EDMA_REQ_PAUSE) {
|
||||
err = -EPERM;
|
||||
} else {
|
||||
chan->request = EDMA_REQ_STOP;
|
||||
dw_edma_set_request(chan, EDMA_REQ_STOP);
|
||||
}
|
||||
if (chan->status == EDMA_ST_IDLE)
|
||||
chan->request = EDMA_REQ_NONE;
|
||||
dw_edma_set_request(chan, EDMA_REQ_NONE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -323,6 +483,7 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)
|
|||
chan->status == EDMA_ST_IDLE) {
|
||||
chan->status = EDMA_ST_BUSY;
|
||||
dw_edma_start_transfer(chan);
|
||||
dw_edma_core_ch_maybe_doorbell(chan);
|
||||
}
|
||||
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
}
|
||||
|
|
@ -588,77 +749,62 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan,
|
|||
return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL));
|
||||
}
|
||||
|
||||
static void dw_hdma_set_callback_result(struct virt_dma_desc *vd,
|
||||
enum dmaengine_tx_result result)
|
||||
/* Must be called with vc.lock held. */
|
||||
static void dw_edma_done_interrupt_locked(struct dw_edma_chan *chan)
|
||||
{
|
||||
u32 residue = 0;
|
||||
struct dw_edma_desc *desc;
|
||||
struct dmaengine_result *res;
|
||||
struct virt_dma_desc *vd;
|
||||
|
||||
if (!vd->tx.callback_result)
|
||||
lockdep_assert_held(&chan->vc.lock);
|
||||
|
||||
if (chan->status == EDMA_ST_PAUSE)
|
||||
return;
|
||||
|
||||
desc = vd2dw_edma_desc(vd);
|
||||
if (desc) {
|
||||
residue = desc->alloc_sz;
|
||||
switch (chan->request) {
|
||||
case EDMA_REQ_NONE:
|
||||
case EDMA_REQ_PAUSE:
|
||||
vd = vchan_next_desc(&chan->vc);
|
||||
if (!vd)
|
||||
break;
|
||||
|
||||
if (result == DMA_TRANS_NOERROR)
|
||||
residue -= desc->burst[desc->start_burst - 1].xfer_sz;
|
||||
else if (desc->done_burst)
|
||||
residue -= desc->burst[desc->done_burst - 1].xfer_sz;
|
||||
desc = vd2dw_edma_desc(vd);
|
||||
if (desc->start_burst >= desc->nburst) {
|
||||
dw_hdma_set_callback_result(vd, DMA_TRANS_NOERROR);
|
||||
list_del(&vd->node);
|
||||
vchan_cookie_complete(vd);
|
||||
if (!chan->non_ll)
|
||||
chan->ll_done = chan->ll_head;
|
||||
}
|
||||
|
||||
if (chan->request == EDMA_REQ_PAUSE) {
|
||||
dw_edma_set_request(chan, EDMA_REQ_NONE);
|
||||
chan->status = EDMA_ST_PAUSE;
|
||||
break;
|
||||
}
|
||||
|
||||
chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
|
||||
break;
|
||||
|
||||
case EDMA_REQ_STOP:
|
||||
vd = vchan_next_desc(&chan->vc);
|
||||
if (!vd)
|
||||
break;
|
||||
|
||||
dw_edma_finish_termination(chan);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
res = &vd->tx_result;
|
||||
res->result = result;
|
||||
res->residue = residue;
|
||||
dw_edma_core_ch_maybe_doorbell(chan);
|
||||
}
|
||||
|
||||
static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
|
||||
{
|
||||
struct dw_edma_desc *desc;
|
||||
struct virt_dma_desc *vd;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chan->vc.lock, flags);
|
||||
if (chan->status == EDMA_ST_PAUSE) {
|
||||
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
vd = vchan_next_desc(&chan->vc);
|
||||
if (vd) {
|
||||
switch (chan->request) {
|
||||
case EDMA_REQ_NONE:
|
||||
case EDMA_REQ_PAUSE:
|
||||
desc = vd2dw_edma_desc(vd);
|
||||
if (desc->start_burst >= desc->nburst) {
|
||||
dw_hdma_set_callback_result(vd,
|
||||
DMA_TRANS_NOERROR);
|
||||
list_del(&vd->node);
|
||||
vchan_cookie_complete(vd);
|
||||
}
|
||||
|
||||
if (chan->request == EDMA_REQ_PAUSE) {
|
||||
chan->request = EDMA_REQ_NONE;
|
||||
chan->status = EDMA_ST_PAUSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Continue transferring if there are remaining chunks or issued requests.
|
||||
*/
|
||||
chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
|
||||
break;
|
||||
|
||||
case EDMA_REQ_STOP:
|
||||
dw_edma_terminate_all_descs(chan);
|
||||
chan->request = EDMA_REQ_NONE;
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
dw_edma_done_interrupt_locked(chan);
|
||||
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -676,7 +822,9 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
|
|||
list_del(&vd->node);
|
||||
vchan_cookie_complete(vd);
|
||||
}
|
||||
chan->request = EDMA_REQ_NONE;
|
||||
if (!chan->non_ll)
|
||||
dw_edma_core_reset_ll(chan);
|
||||
dw_edma_set_request(chan, EDMA_REQ_NONE);
|
||||
chan->status = EDMA_ST_IDLE;
|
||||
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
}
|
||||
|
|
@ -690,28 +838,32 @@ static void dw_edma_irq_work(struct work_struct *work)
|
|||
do {
|
||||
events = atomic_xchg(&chan->irq_pending, 0);
|
||||
|
||||
if (events & DW_EDMA_IRQ_DONE)
|
||||
if (events & DW_EDMA_DEFERRED_DONE)
|
||||
dw_edma_done_interrupt(chan);
|
||||
if (events & DW_EDMA_IRQ_ABORT)
|
||||
if (events & DW_EDMA_DEFERRED_ABORT)
|
||||
dw_edma_abort_interrupt(chan);
|
||||
} while (atomic_read(&chan->irq_pending));
|
||||
}
|
||||
|
||||
static void dw_edma_queue_irq_work(struct dw_edma_chan *chan,
|
||||
enum dw_edma_irq_event event)
|
||||
unsigned int events)
|
||||
{
|
||||
atomic_or(event, &chan->irq_pending);
|
||||
atomic_or(events, &chan->irq_pending);
|
||||
queue_work(chan->dw->wq, &chan->irq_work);
|
||||
}
|
||||
|
||||
static void dw_edma_done_interrupt_deferred(struct dw_edma_chan *chan)
|
||||
static void dw_edma_record_irq(struct dw_edma_chan *chan, unsigned int events)
|
||||
{
|
||||
dw_edma_queue_irq_work(chan, DW_EDMA_IRQ_DONE);
|
||||
}
|
||||
unsigned int pending = 0;
|
||||
|
||||
static void dw_edma_abort_interrupt_deferred(struct dw_edma_chan *chan)
|
||||
{
|
||||
dw_edma_queue_irq_work(chan, DW_EDMA_IRQ_ABORT);
|
||||
if (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_PROGRESS |
|
||||
DW_EDMA_IRQ_STOP))
|
||||
pending |= DW_EDMA_DEFERRED_DONE;
|
||||
if (events & DW_EDMA_IRQ_ABORT)
|
||||
pending |= DW_EDMA_DEFERRED_ABORT;
|
||||
|
||||
if (pending)
|
||||
dw_edma_queue_irq_work(chan, pending);
|
||||
}
|
||||
|
||||
static void dw_edma_emul_irq_ack(struct irq_data *d)
|
||||
|
|
@ -812,8 +964,7 @@ static inline irqreturn_t dw_edma_interrupt_write_inner(int irq, void *data)
|
|||
struct dw_edma_irq *dw_irq = data;
|
||||
|
||||
return dw_edma_core_handle_int(dw_irq, EDMA_DIR_WRITE,
|
||||
dw_edma_done_interrupt_deferred,
|
||||
dw_edma_abort_interrupt_deferred);
|
||||
dw_edma_record_irq);
|
||||
}
|
||||
|
||||
static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data)
|
||||
|
|
@ -821,8 +972,7 @@ static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data)
|
|||
struct dw_edma_irq *dw_irq = data;
|
||||
|
||||
return dw_edma_core_handle_int(dw_irq, EDMA_DIR_READ,
|
||||
dw_edma_done_interrupt_deferred,
|
||||
dw_edma_abort_interrupt_deferred);
|
||||
dw_edma_record_irq);
|
||||
}
|
||||
|
||||
static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
|
||||
|
|
@ -863,6 +1013,9 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
|
|||
if (chan->status != EDMA_ST_IDLE)
|
||||
return -EBUSY;
|
||||
|
||||
/* The hardware context may have been invalidated while unowned. */
|
||||
chan->ll_valid = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -890,11 +1043,53 @@ static void dw_edma_wait_termination(struct dma_chan *dchan)
|
|||
"timeout waiting for channel termination\n");
|
||||
}
|
||||
|
||||
static void dw_edma_synchronize_chan_irq(struct dw_edma_chan *chan)
|
||||
{
|
||||
struct dw_edma *dw = chan->dw;
|
||||
unsigned long *mask;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* A shared handler may retain this channel's status across quiesce.
|
||||
* With nr_irqs == 1, it scans both directions even if routing and
|
||||
* delegation are direction-wide. Drain it before allowing a routing change.
|
||||
*/
|
||||
for (i = 0; i < dw->nr_irqs; i++) {
|
||||
mask = chan->dir == EDMA_DIR_WRITE ? dw->irq[i].wr_mask :
|
||||
dw->irq[i].rd_mask;
|
||||
if (!test_bit(chan->id, mask))
|
||||
continue;
|
||||
|
||||
synchronize_irq(dw->chip->ops->irq_vector(dw->chip->dev, i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_edma_device_synchronize(struct dma_chan *dchan)
|
||||
{
|
||||
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
|
||||
bool remote;
|
||||
|
||||
/*
|
||||
* irq_mode is fixed after initial configuration. The free path
|
||||
* restores it only after synchronization.
|
||||
*/
|
||||
remote = chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL &&
|
||||
chan->irq_mode == DW_EDMA_CH_IRQ_REMOTE;
|
||||
|
||||
/*
|
||||
* Peer-driven transfers bypass local descriptor tracking, so quiesce
|
||||
* the hardware explicitly.
|
||||
*/
|
||||
if (remote && dw_edma_core_ch_quiesce(chan))
|
||||
dev_warn(chan->dw->chip->dev,
|
||||
"failed to quiesce remote-routed %s channel %u\n",
|
||||
chan->dir == EDMA_DIR_WRITE ? "write" : "read",
|
||||
chan->id);
|
||||
|
||||
dw_edma_wait_termination(dchan);
|
||||
if (remote)
|
||||
dw_edma_synchronize_chan_irq(chan);
|
||||
cancel_work_sync(&chan->irq_work);
|
||||
atomic_set(&chan->irq_pending, 0);
|
||||
vchan_synchronize(&chan->vc);
|
||||
|
|
@ -907,8 +1102,10 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
|
|||
dw_edma_device_terminate_all(dchan);
|
||||
dw_edma_device_synchronize(dchan);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &chan->vc.lock)
|
||||
scoped_guard(spinlock_irqsave, &chan->vc.lock) {
|
||||
chan->configured = false;
|
||||
chan->irq_mode = dw_edma_get_default_irq_mode(chan);
|
||||
}
|
||||
|
||||
vchan_free_chan_resources(&chan->vc);
|
||||
}
|
||||
|
|
@ -954,6 +1151,13 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
|
|||
else
|
||||
chan->ll_region = chip->ll_region_rd[chan->id];
|
||||
|
||||
if (!chip->cfg_non_ll && chan->ll_region.sz < 3 * EDMA_LL_SZ) {
|
||||
dev_err(dev,
|
||||
"channel %s[%u]: LL region has fewer than 2 data entries\n",
|
||||
str_write_read(chan->dir == EDMA_DIR_WRITE),
|
||||
chan->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
chan->ll_max = chan->ll_region.sz / EDMA_LL_SZ - 1;
|
||||
|
||||
dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
|
||||
|
|
@ -988,6 +1192,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
|
|||
&dw->chip->dt_region_rd[chan->id];
|
||||
|
||||
vchan_init(&chan->vc, dma);
|
||||
dmaengine_set_static_chan_id(&chan->vc.chan, i);
|
||||
|
||||
dw_edma_core_ch_config(chan);
|
||||
}
|
||||
|
|
@ -1033,12 +1238,23 @@ static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
|
|||
}
|
||||
}
|
||||
|
||||
static void dw_edma_compose_msi(int irq, struct msi_msg *msi)
|
||||
{
|
||||
struct msi_desc *desc = irq_get_msi_desc(irq);
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
get_cached_msi_msg(irq, msi);
|
||||
if (dev_is_pci(desc->dev) && !desc->pci.msi_attrib.is_msix)
|
||||
msi->data += irq - desc->irq;
|
||||
}
|
||||
|
||||
static int dw_edma_irq_request(struct dw_edma *dw,
|
||||
u32 *wr_alloc, u32 *rd_alloc)
|
||||
{
|
||||
struct dw_edma_chip *chip = dw->chip;
|
||||
struct device *dev = dw->chip->dev;
|
||||
struct msi_desc *msi_desc;
|
||||
int i, err = 0;
|
||||
u32 ch_cnt;
|
||||
int irq;
|
||||
|
|
@ -1063,8 +1279,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (irq_get_msi_desc(irq))
|
||||
get_cached_msi_msg(irq, &dw->irq[0].msi);
|
||||
dw_edma_compose_msi(irq, &dw->irq[0].msi);
|
||||
|
||||
dw->nr_irqs = 1;
|
||||
} else {
|
||||
|
|
@ -1087,12 +1302,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
|
|||
&dw->irq[i]);
|
||||
if (err)
|
||||
goto err_irq_free;
|
||||
msi_desc = irq_get_msi_desc(irq);
|
||||
if (msi_desc) {
|
||||
get_cached_msi_msg(irq, &dw->irq[i].msi);
|
||||
if (!msi_desc->pci.msi_attrib.is_msix)
|
||||
dw->irq[i].msi.data = dw->irq[0].msi.data + i;
|
||||
}
|
||||
dw_edma_compose_msi(irq, &dw->irq[i].msi);
|
||||
}
|
||||
|
||||
dw->nr_irqs = i;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,13 @@ enum dw_edma_xfer_type {
|
|||
EDMA_XFER_INTERLEAVED
|
||||
};
|
||||
|
||||
enum dw_edma_irq_event {
|
||||
DW_EDMA_IRQ_DONE = BIT(0),
|
||||
DW_EDMA_IRQ_PROGRESS = BIT(1),
|
||||
DW_EDMA_IRQ_STOP = BIT(2),
|
||||
DW_EDMA_IRQ_ABORT = BIT(3),
|
||||
};
|
||||
|
||||
struct dw_edma_chan;
|
||||
struct dw_edma_chunk;
|
||||
|
||||
|
|
@ -60,7 +67,6 @@ struct dw_edma_desc {
|
|||
|
||||
size_t done_burst;
|
||||
size_t start_burst;
|
||||
u8 cb;
|
||||
size_t nburst;
|
||||
struct dw_edma_burst burst[] __counted_by(nburst);
|
||||
};
|
||||
|
|
@ -72,8 +78,32 @@ struct dw_edma_chan {
|
|||
enum dw_edma_dir dir;
|
||||
u8 func_no;
|
||||
|
||||
u32 ll_max;
|
||||
/*
|
||||
* New LL entries are appended at ll_head. Entries between ll_done
|
||||
* and ll_head, modulo the LL ring, are owned by DMA; the rest are
|
||||
* owned by software.
|
||||
*
|
||||
* software-owned DMA-owned software-owned
|
||||
* +---------------+-------------------+---------------+
|
||||
* ^ ^ ^
|
||||
* 0 ll_done ll_head
|
||||
*
|
||||
* The link entry points back to the region start. ll_head == ll_done
|
||||
* means all entries are software-owned and previous DMA work is
|
||||
* done.
|
||||
*
|
||||
* Software always keeps at least one free entry, so the ring is
|
||||
* never completely DMA-owned. That keeps a hardware-reported physical
|
||||
* LL index unique within the current ll_done..ll_head producer window.
|
||||
*/
|
||||
u32 ll_head;
|
||||
u32 ll_done;
|
||||
|
||||
u32 ll_max; /* Data entries */
|
||||
struct dw_edma_region ll_region; /* Linked list */
|
||||
bool ll_valid; /* LL context programmed */
|
||||
|
||||
bool cb;
|
||||
|
||||
struct msi_msg msi;
|
||||
|
||||
|
|
@ -124,7 +154,8 @@ struct dw_edma {
|
|||
const struct dw_edma_core_ops *core;
|
||||
};
|
||||
|
||||
typedef void (*dw_edma_handler_t)(struct dw_edma_chan *);
|
||||
typedef void (*dw_edma_handler_t)(struct dw_edma_chan *chan,
|
||||
unsigned int events);
|
||||
|
||||
struct dw_edma_core_ops {
|
||||
void (*off)(struct dw_edma *dw);
|
||||
|
|
@ -133,11 +164,14 @@ struct dw_edma_core_ops {
|
|||
u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir);
|
||||
enum dma_status (*ch_status)(struct dw_edma_chan *chan);
|
||||
irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
||||
dw_edma_handler_t done, dw_edma_handler_t abort);
|
||||
dw_edma_handler_t handler);
|
||||
void (*non_ll_start)(struct dw_edma_chan *chan, struct dw_edma_burst *child);
|
||||
void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst,
|
||||
u32 idx, bool cb, bool irq);
|
||||
void (*ll_link)(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr);
|
||||
void (*ll_clear)(struct dw_edma_chan *chan, u32 idx);
|
||||
int (*ll_cur_idx)(struct dw_edma_chan *chan);
|
||||
void (*ll_irq_clear)(struct dw_edma_chan *chan);
|
||||
void (*ch_doorbell)(struct dw_edma_chan *chan);
|
||||
void (*ch_enable)(struct dw_edma_chan *chan);
|
||||
void (*ch_config)(struct dw_edma_chan *chan);
|
||||
|
|
@ -181,6 +215,15 @@ struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan)
|
|||
return vc2dw_edma_chan(to_virt_chan(dchan));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current LL entry index. A negative value means that the channel
|
||||
* context is not initialized or was lost after a link reset.
|
||||
*/
|
||||
static inline int dw_edma_core_ll_cur_idx(struct dw_edma_chan *chan)
|
||||
{
|
||||
return chan->dw->core->ll_cur_idx(chan);
|
||||
}
|
||||
|
||||
static inline u64 dw_edma_core_get_ll_paddr(struct dw_edma_chan *chan)
|
||||
{
|
||||
if (chan->dir == EDMA_DIR_WRITE)
|
||||
|
|
@ -221,9 +264,9 @@ enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan)
|
|||
|
||||
static inline irqreturn_t
|
||||
dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
||||
dw_edma_handler_t done, dw_edma_handler_t abort)
|
||||
dw_edma_handler_t handler)
|
||||
{
|
||||
return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort);
|
||||
return dw_irq->dw->core->handle_int(dw_irq, dir, handler);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
|
@ -245,7 +288,17 @@ dw_edma_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
|
|||
chan->dw->core->ll_link(chan, idx, cb, addr);
|
||||
}
|
||||
|
||||
static inline void dw_edma_core_ch_doorbell(struct dw_edma_chan *chan)
|
||||
static inline void dw_edma_core_ll_clear(struct dw_edma_chan *chan, u32 idx)
|
||||
{
|
||||
chan->dw->core->ll_clear(chan, idx);
|
||||
}
|
||||
|
||||
static inline void dw_edma_core_ll_irq_clear(struct dw_edma_chan *chan)
|
||||
{
|
||||
chan->dw->core->ll_irq_clear(chan);
|
||||
}
|
||||
|
||||
static inline void dw_edma_core_do_ch_doorbell(struct dw_edma_chan *chan)
|
||||
{
|
||||
chan->dw->core->ch_doorbell(chan);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8)
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0)
|
||||
/* AMD CPM6 (Xilinx) supported cap */
|
||||
#define DW_PCIE_XILINX_CPM6_VSEC_CH_SEP GENMASK(18, 16)
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0)
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16)
|
||||
|
||||
|
|
@ -76,6 +78,7 @@ struct dw_edma_pcie_data {
|
|||
u16 rd_ch_cnt;
|
||||
u64 devmem_phys_off;
|
||||
bool cfg_non_ll;
|
||||
u32 ch_space_sz;
|
||||
};
|
||||
|
||||
struct dw_edma_pcie_match_data {
|
||||
|
|
@ -130,6 +133,7 @@ static const struct dw_edma_pcie_data snps_edda_data = {
|
|||
.irqs = 1,
|
||||
.wr_ch_cnt = 2,
|
||||
.rd_ch_cnt = 2,
|
||||
.ch_space_sz = 256,
|
||||
};
|
||||
|
||||
static const struct dw_edma_pcie_data xilinx_mdb_data = {
|
||||
|
|
@ -143,6 +147,7 @@ static const struct dw_edma_pcie_data xilinx_mdb_data = {
|
|||
.irqs = 1,
|
||||
.wr_ch_cnt = 8,
|
||||
.rd_ch_cnt = 8,
|
||||
.ch_space_sz = 256,
|
||||
};
|
||||
|
||||
static const struct dw_edma_pcie_data xilinx_cpm6_dma_data = {
|
||||
|
|
@ -156,6 +161,7 @@ static const struct dw_edma_pcie_data xilinx_cpm6_dma_data = {
|
|||
.irqs = 1,
|
||||
.wr_ch_cnt = 8,
|
||||
.rd_ch_cnt = 8,
|
||||
.ch_space_sz = 512,
|
||||
};
|
||||
|
||||
static void dw_edma_set_chan_region_offset(struct dw_edma_pcie_data *pdata,
|
||||
|
|
@ -208,6 +214,13 @@ static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
|
|||
return pci_irq_vector(to_pci_dev(dev), nr);
|
||||
}
|
||||
|
||||
static u32 dw_edma_get_ch_space_sz(u32 val)
|
||||
{
|
||||
if (val > 0 && val <= 7)
|
||||
return 256 << val;
|
||||
return 256;
|
||||
}
|
||||
|
||||
static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
|
@ -298,6 +311,10 @@ static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev,
|
|||
pdata->mf = map;
|
||||
pdata->rg.bar = FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR, val);
|
||||
|
||||
if (pdev->device == PCI_DEVICE_ID_XILINX_B00F)
|
||||
pdata->ch_space_sz = dw_edma_get_ch_space_sz
|
||||
(FIELD_GET(DW_PCIE_XILINX_CPM6_VSEC_CH_SEP, val));
|
||||
|
||||
pci_read_config_dword(pdev, vsec + 0xc, &val);
|
||||
pdata->wr_ch_cnt = min(pdata->wr_ch_cnt,
|
||||
FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH, val));
|
||||
|
|
@ -477,6 +494,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
|
|||
chip->nr_irqs = nr_irqs;
|
||||
chip->ops = match->plat_ops;
|
||||
chip->cfg_non_ll = dma_data->cfg_non_ll;
|
||||
chip->ch_space_sz = dma_data->ch_space_sz;
|
||||
|
||||
chip->ll_wr_cnt = dma_data->wr_ch_cnt;
|
||||
chip->ll_rd_cnt = dma_data->rd_ch_cnt;
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ static void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan)
|
|||
|
||||
static irqreturn_t
|
||||
dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
||||
dw_edma_handler_t done, dw_edma_handler_t abort)
|
||||
dw_edma_handler_t handler)
|
||||
{
|
||||
struct dw_edma *dw = dw_irq->dw;
|
||||
unsigned long total, pos, val;
|
||||
|
|
@ -375,7 +375,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
|||
continue;
|
||||
|
||||
dw_edma_v0_core_clear_done_int(chan);
|
||||
done(chan);
|
||||
handler(chan, DW_EDMA_IRQ_DONE);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -389,7 +389,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
|||
continue;
|
||||
|
||||
dw_edma_v0_core_clear_abort_int(chan);
|
||||
abort(chan);
|
||||
handler(chan, DW_EDMA_IRQ_ABORT);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -480,20 +480,6 @@ static void dw_edma_v0_core_ch_enable(struct dw_edma_chan *chan)
|
|||
upper_32_bits(chan->ll_region.paddr));
|
||||
}
|
||||
|
||||
static void dw_edma_v0_sync_ll_data(struct dw_edma_chan *chan)
|
||||
{
|
||||
/*
|
||||
* In case of remote eDMA engine setup, the DW PCIe RP/EP internal
|
||||
* configuration registers and application memory are normally accessed
|
||||
* over different buses. Ensure LL-data reaches the memory before the
|
||||
* doorbell register is toggled by issuing the dummy-read from the remote
|
||||
* LL memory in a hope that the MRd TLP will return only after the
|
||||
* last MWr TLP is completed
|
||||
*/
|
||||
if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
|
||||
readl(chan->ll_region.vaddr.io);
|
||||
}
|
||||
|
||||
static void dw_edma_v0_core_ch_config(struct dw_edma_chan *chan)
|
||||
{
|
||||
struct dw_edma *dw = chan->dw;
|
||||
|
|
@ -605,17 +591,49 @@ dw_edma_v0_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
|
|||
dw_edma_v0_write_ll_link(chan, idx, control, addr);
|
||||
}
|
||||
|
||||
static void dw_edma_v0_core_ll_clear(struct dw_edma_chan *chan, u32 idx)
|
||||
{
|
||||
ptrdiff_t ofs = idx * sizeof(struct dw_edma_v0_lli);
|
||||
|
||||
if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
|
||||
struct dw_edma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
|
||||
|
||||
lli->control = 0;
|
||||
} else {
|
||||
struct dw_edma_v0_lli __iomem *lli = chan->ll_region.vaddr.io + ofs;
|
||||
|
||||
writel(0, &lli->control);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_edma_v0_core_ch_doorbell(struct dw_edma_chan *chan)
|
||||
{
|
||||
struct dw_edma *dw = chan->dw;
|
||||
|
||||
dw_edma_v0_sync_ll_data(chan);
|
||||
|
||||
/* Doorbell */
|
||||
SET_RW_32(dw, chan->dir, doorbell,
|
||||
FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id));
|
||||
}
|
||||
|
||||
static int dw_edma_v0_core_ll_cur_idx(struct dw_edma_chan *chan)
|
||||
{
|
||||
u32 base, val;
|
||||
|
||||
val = GET_CH_32(chan->dw, chan->dir, chan->id, llp.lsb);
|
||||
base = lower_32_bits(dw_edma_core_get_ll_paddr(chan));
|
||||
|
||||
/*
|
||||
* LL regions stay within one 4 GiB address window. Reject an all-ones
|
||||
* MMIO value. If the low word is zero, use the high word to distinguish
|
||||
* a nonzero boundary address from an unprogrammed all-zero context.
|
||||
*/
|
||||
if (val == U32_MAX ||
|
||||
(!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb)))
|
||||
return -EINVAL;
|
||||
|
||||
return (val - base) / EDMA_LL_SZ;
|
||||
}
|
||||
|
||||
/* eDMA debugfs callbacks */
|
||||
static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
|
||||
{
|
||||
|
|
@ -650,6 +668,9 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
|
|||
.handle_int = dw_edma_v0_core_handle_int,
|
||||
.ll_data = dw_edma_v0_core_ll_data,
|
||||
.ll_link = dw_edma_v0_core_ll_link,
|
||||
.ll_clear = dw_edma_v0_core_ll_clear,
|
||||
.ll_cur_idx = dw_edma_v0_core_ll_cur_idx,
|
||||
.ll_irq_clear = dw_edma_v0_core_clear_done_int,
|
||||
.ch_doorbell = dw_edma_v0_core_ch_doorbell,
|
||||
.ch_enable = dw_edma_v0_core_ch_enable,
|
||||
.ch_config = dw_edma_v0_core_ch_config,
|
||||
|
|
|
|||
|
|
@ -23,18 +23,23 @@ enum dw_hdma_control {
|
|||
DW_HDMA_V0_LLE = BIT(9),
|
||||
};
|
||||
|
||||
static inline struct dw_hdma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
|
||||
{
|
||||
return dw->chip->reg_base;
|
||||
}
|
||||
|
||||
static inline struct dw_hdma_v0_ch_regs __iomem *
|
||||
__dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch)
|
||||
{
|
||||
if (dir == EDMA_DIR_WRITE)
|
||||
return &(__dw_regs(dw)->ch[ch].wr);
|
||||
else
|
||||
return &(__dw_regs(dw)->ch[ch].rd);
|
||||
u32 ch_base;
|
||||
|
||||
/*
|
||||
* For Write, the channel register index starts at
|
||||
* wr_base(ch_idx) = (2 * ch_idx) * ch_space_sz
|
||||
*
|
||||
* For Read channel,
|
||||
* rd_base(ch_idx) = (2 * ch_idx + 1) * ch_space_sz
|
||||
*/
|
||||
ch_base = 2 * ch;
|
||||
if (dir == EDMA_DIR_READ)
|
||||
ch_base += 1;
|
||||
|
||||
return dw->chip->reg_base + (ch_base * dw->chip->ch_space_sz);
|
||||
}
|
||||
|
||||
#define SET_CH_32(dw, dir, ch, name, value) \
|
||||
|
|
@ -174,7 +179,7 @@ static u32 dw_hdma_v0_core_status_int(struct dw_edma_chan *chan)
|
|||
|
||||
static irqreturn_t
|
||||
dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
||||
dw_edma_handler_t done, dw_edma_handler_t abort)
|
||||
dw_edma_handler_t handler)
|
||||
{
|
||||
struct dw_edma *dw = dw_irq->dw;
|
||||
unsigned long total, pos, val;
|
||||
|
|
@ -200,14 +205,14 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
|
|||
val = dw_hdma_v0_core_status_int(chan);
|
||||
if (FIELD_GET(HDMA_V0_STOP_INT_MASK, val)) {
|
||||
dw_hdma_v0_core_clear_done_int(chan);
|
||||
done(chan);
|
||||
handler(chan, DW_EDMA_IRQ_STOP);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (FIELD_GET(HDMA_V0_ABORT_INT_MASK, val)) {
|
||||
dw_hdma_v0_core_clear_abort_int(chan);
|
||||
abort(chan);
|
||||
handler(chan, DW_EDMA_IRQ_ABORT);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -282,20 +287,6 @@ static void dw_hdma_v0_core_ch_enable(struct dw_edma_chan *chan)
|
|||
HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
|
||||
}
|
||||
|
||||
static void dw_hdma_v0_sync_ll_data(struct dw_edma_chan *chan)
|
||||
{
|
||||
/*
|
||||
* In case of remote HDMA engine setup, the DW PCIe RP/EP internal
|
||||
* configuration registers and application memory are normally accessed
|
||||
* over different buses. Ensure LL-data reaches the memory before the
|
||||
* doorbell register is toggled by issuing the dummy-read from the remote
|
||||
* LL memory in a hope that the MRd TLP will return only after the
|
||||
* last MWr TLP is completed
|
||||
*/
|
||||
if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
|
||||
readl(chan->ll_region.vaddr.io);
|
||||
}
|
||||
|
||||
static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chan *chan,
|
||||
struct dw_edma_burst *child)
|
||||
{
|
||||
|
|
@ -374,16 +365,48 @@ dw_hdma_v0_core_ll_link(struct dw_edma_chan *chan, u32 idx, bool cb, u64 addr)
|
|||
dw_hdma_v0_write_ll_link(chan, idx, control, addr);
|
||||
}
|
||||
|
||||
static void dw_hdma_v0_core_ll_clear(struct dw_edma_chan *chan, u32 idx)
|
||||
{
|
||||
ptrdiff_t ofs = idx * sizeof(struct dw_hdma_v0_lli);
|
||||
|
||||
if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
|
||||
struct dw_hdma_v0_lli *lli = chan->ll_region.vaddr.mem + ofs;
|
||||
|
||||
lli->control = 0;
|
||||
} else {
|
||||
struct dw_hdma_v0_lli __iomem *lli = chan->ll_region.vaddr.io + ofs;
|
||||
|
||||
writel(0, &lli->control);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_hdma_v0_core_ch_doorbell(struct dw_edma_chan *chan)
|
||||
{
|
||||
struct dw_edma *dw = chan->dw;
|
||||
|
||||
dw_hdma_v0_sync_ll_data(chan);
|
||||
|
||||
/* Doorbell */
|
||||
SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START);
|
||||
}
|
||||
|
||||
static int dw_hdma_v0_core_ll_cur_idx(struct dw_edma_chan *chan)
|
||||
{
|
||||
u32 base, val;
|
||||
|
||||
val = GET_CH_32(chan->dw, chan->dir, chan->id, llp.lsb);
|
||||
base = lower_32_bits(dw_edma_core_get_ll_paddr(chan));
|
||||
|
||||
/*
|
||||
* LL regions stay within one 4 GiB address window. Reject an all-ones
|
||||
* MMIO value. If the low word is zero, use the high word to distinguish
|
||||
* a nonzero boundary address from an unprogrammed all-zero context.
|
||||
*/
|
||||
if (val == U32_MAX ||
|
||||
(!val && !GET_CH_32(chan->dw, chan->dir, chan->id, llp.msb)))
|
||||
return -EINVAL;
|
||||
|
||||
return (val - base) / EDMA_LL_SZ;
|
||||
}
|
||||
|
||||
/* HDMA debugfs callbacks */
|
||||
static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw)
|
||||
{
|
||||
|
|
@ -406,6 +429,9 @@ static const struct dw_edma_core_ops dw_hdma_v0_core = {
|
|||
.non_ll_start = dw_hdma_v0_core_non_ll_start,
|
||||
.ll_data = dw_hdma_v0_core_ll_data,
|
||||
.ll_link = dw_hdma_v0_core_ll_link,
|
||||
.ll_clear = dw_hdma_v0_core_ll_clear,
|
||||
.ll_cur_idx = dw_hdma_v0_core_ll_cur_idx,
|
||||
.ll_irq_clear = dw_hdma_v0_core_clear_done_int,
|
||||
.ch_doorbell = dw_hdma_v0_core_ch_doorbell,
|
||||
.ch_enable = dw_hdma_v0_core_ch_enable,
|
||||
.ch_config = dw_hdma_v0_core_ch_config,
|
||||
|
|
|
|||
|
|
@ -13,22 +13,17 @@
|
|||
#include "dw-hdma-v0-regs.h"
|
||||
#include "dw-edma-core.h"
|
||||
|
||||
#define REGS_ADDR(dw, name) \
|
||||
({ \
|
||||
struct dw_hdma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \
|
||||
\
|
||||
(void __iomem *)&__regs->name; \
|
||||
})
|
||||
|
||||
#define REGS_CH_ADDR(dw, name, _dir, _ch) \
|
||||
({ \
|
||||
struct dw_hdma_v0_ch_regs __iomem *__ch_regs; \
|
||||
struct dw_hdma_v0_ch_regs __iomem *__ch_regs; \
|
||||
off_t __off = (dw)->chip->ch_space_sz; \
|
||||
\
|
||||
if (_dir == EDMA_DIR_READ) \
|
||||
__ch_regs = REGS_ADDR(dw, ch[_ch].rd); \
|
||||
if ((_dir) == EDMA_DIR_READ) \
|
||||
__off *= (2 * (_ch) + 1); \
|
||||
else \
|
||||
__ch_regs = REGS_ADDR(dw, ch[_ch].wr); \
|
||||
__off *= (2 * (_ch)); \
|
||||
\
|
||||
__ch_regs = ((dw)->chip->reg_base + __off); \
|
||||
(void __iomem *)&__ch_regs->name; \
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -85,16 +85,6 @@ struct dw_hdma_v0_ch_regs {
|
|||
};
|
||||
} msi_abort;
|
||||
u32 msi_msgdata; /* 0x00a8 */
|
||||
u32 padding_2[21]; /* 0x00ac..0x00fc */
|
||||
} __packed;
|
||||
|
||||
struct dw_hdma_v0_ch {
|
||||
struct dw_hdma_v0_ch_regs wr; /* 0x0000 */
|
||||
struct dw_hdma_v0_ch_regs rd; /* 0x0100 */
|
||||
} __packed;
|
||||
|
||||
struct dw_hdma_v0_regs {
|
||||
struct dw_hdma_v0_ch ch[HDMA_V0_MAX_NR_CH]; /* 0x0000..0x0fa8 */
|
||||
} __packed;
|
||||
|
||||
struct dw_hdma_v0_lli {
|
||||
|
|
|
|||
|
|
@ -41,11 +41,6 @@
|
|||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
|
||||
{
|
||||
return to_dw_desc(dwc->active_list.next);
|
||||
|
|
@ -69,7 +64,7 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
|
||||
list_add_tail(&desc->desc_node, &dwc->queue);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n",
|
||||
dev_vdbg(dmaengine_chan_dev(tx->chan), "%s: queued %u\n",
|
||||
__func__, desc->txd.cookie);
|
||||
|
||||
return cookie;
|
||||
|
|
@ -127,7 +122,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
|
|||
|
||||
static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
|
||||
{
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dwc->chan),
|
||||
" SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
|
||||
channel_readl(dwc, SAR),
|
||||
channel_readl(dwc, DAR),
|
||||
|
|
@ -177,7 +172,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
|
|||
|
||||
/* ASSERT: channel is idle */
|
||||
if (dma_readl(dw, CH_EN) & dwc->mask) {
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dwc->chan),
|
||||
"%s: BUG: Attempted to start non-idle channel\n",
|
||||
__func__);
|
||||
dwc_dump_chan_regs(dwc);
|
||||
|
|
@ -190,7 +185,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
|
|||
was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
|
||||
&dwc->flags);
|
||||
if (was_soft_llp) {
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dwc->chan),
|
||||
"BUG: Attempted to start new LLP transfer inside ongoing one\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -223,7 +218,7 @@ static void dwc_dostart_first_queued(struct dw_dma_chan *dwc)
|
|||
|
||||
list_move(dwc->queue.next, &dwc->active_list);
|
||||
desc = dwc_first_active(dwc);
|
||||
dev_vdbg(chan2dev(&dwc->chan), "%s: started %u\n", __func__, desc->txd.cookie);
|
||||
dev_vdbg(dmaengine_chan_dev(&dwc->chan), "%s: started %u\n", __func__, desc->txd.cookie);
|
||||
dwc_dostart(dwc, desc);
|
||||
}
|
||||
|
||||
|
|
@ -238,7 +233,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
|
|||
unsigned long flags;
|
||||
struct dmaengine_desc_callback cb;
|
||||
|
||||
dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
|
||||
dev_vdbg(dmaengine_chan_dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dma_cookie_complete(txd);
|
||||
|
|
@ -265,7 +260,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
|||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (dma_readl(dw, CH_EN) & dwc->mask) {
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dwc->chan),
|
||||
"BUG: XFER bit set, but channel not idle!\n");
|
||||
|
||||
/* Try to continue after resetting the channel... */
|
||||
|
|
@ -353,12 +348,12 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
|||
}
|
||||
|
||||
if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
|
||||
dev_vdbg(chan2dev(&dwc->chan), "%s: soft LLP mode\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(&dwc->chan), "%s: soft LLP mode\n", __func__);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
|
||||
dev_vdbg(dmaengine_chan_dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
|
||||
/* Initial residue value */
|
||||
|
|
@ -398,7 +393,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
|||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
}
|
||||
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dwc->chan),
|
||||
"BUG: All descriptors done, but channel not idle!\n");
|
||||
|
||||
/* Try to continue after resetting the channel... */
|
||||
|
|
@ -410,7 +405,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
|||
|
||||
static inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_desc *desc)
|
||||
{
|
||||
dev_crit(chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
|
||||
dev_crit(dmaengine_chan_dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
|
||||
lli_read(desc, sar),
|
||||
lli_read(desc, dar),
|
||||
lli_read(desc, llp),
|
||||
|
|
@ -449,7 +444,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
|||
* controller flagged an error instead of scribbling over
|
||||
* random memory locations.
|
||||
*/
|
||||
dev_WARN(chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"
|
||||
dev_WARN(dmaengine_chan_dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"
|
||||
" cookie: %d\n", bad_desc->txd.cookie);
|
||||
dwc_dump_lli(dwc, bad_desc);
|
||||
list_for_each_entry(child, &bad_desc->tx_list, desc_node)
|
||||
|
|
@ -552,12 +547,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
u32 ctllo, ctlhi;
|
||||
u8 lms = DWC_LLP_LMS(m_master);
|
||||
|
||||
dev_vdbg(chan2dev(chan),
|
||||
dev_vdbg(dmaengine_chan_dev(chan),
|
||||
"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
|
||||
&dest, &src, len, flags);
|
||||
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: length is zero!\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +625,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
struct scatterlist *sg;
|
||||
size_t total_len = 0;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
if (unlikely(!is_slave_direction(direction) || !sg_len))
|
||||
return NULL;
|
||||
|
|
@ -754,7 +749,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
return &first->txd;
|
||||
|
||||
err_desc_get:
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"not enough descriptors available. Direction %d\n", direction);
|
||||
dwc_desc_put(dwc, first);
|
||||
return NULL;
|
||||
|
|
@ -1063,11 +1058,11 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
|
||||
struct dw_dma *dw = to_dw_dma(chan->device);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s\n", __func__);
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
if (dma_readl(dw, CH_EN) & dwc->mask) {
|
||||
dev_dbg(chan2dev(chan), "DMA channel not idle?\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "DMA channel not idle?\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -1083,7 +1078,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
|
|||
* We need controller-specific data to set up slave transfers.
|
||||
*/
|
||||
if (chan->private && !dw_dma_filter(chan, chan->private)) {
|
||||
dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
|
||||
dev_warn(dmaengine_chan_dev(chan), "Wrong controller-specific data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1101,7 +1096,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
|
|||
struct dw_dma *dw = to_dw_dma(chan->device);
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: descs allocated=%u\n", __func__,
|
||||
dwc->descs_allocated);
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
|
|
@ -1126,7 +1121,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
|
|||
if (!dw->in_use)
|
||||
do_dw_dma_off(dw);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "%s: done\n", __func__);
|
||||
}
|
||||
|
||||
static void dwc_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../dmaengine.h"
|
||||
#include "internal.h"
|
||||
|
||||
static void dw_dma_initialize_chan(struct dw_dma_chan *dwc)
|
||||
|
|
|
|||
|
|
@ -141,14 +141,14 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id dw_dma_acpi_id_table[] = {
|
||||
{ "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
{ "80862286", (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
{ "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
{ .id = "INTL9C60", .driver_data = (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
{ .id = "80862286", .driver_data = (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
{ .id = "808622C0", .driver_data = (kernel_ulong_t)&dw_dma_chip_pdata },
|
||||
|
||||
/* Elkhart Lake iDMA 32-bit (PSE DMA) */
|
||||
{ "80864BB4", (kernel_ulong_t)&xbar_chip_pdata },
|
||||
{ "80864BB5", (kernel_ulong_t)&xbar_chip_pdata },
|
||||
{ "80864BB6", (kernel_ulong_t)&xbar_chip_pdata },
|
||||
{ .id = "80864BB4", .driver_data = (kernel_ulong_t)&xbar_chip_pdata },
|
||||
{ .id = "80864BB5", .driver_data = (kernel_ulong_t)&xbar_chip_pdata },
|
||||
{ .id = "80864BB6", .driver_data = (kernel_ulong_t)&xbar_chip_pdata },
|
||||
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -250,11 +250,6 @@ struct ep93xx_edma_data {
|
|||
size_t num_channels;
|
||||
};
|
||||
|
||||
static inline struct device *chan2dev(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
return &edmac->chan.dev->device;
|
||||
}
|
||||
|
||||
static struct ep93xx_dma_chan *to_ep93xx_dma_chan(struct dma_chan *chan)
|
||||
{
|
||||
return container_of(chan, struct ep93xx_dma_chan, chan);
|
||||
|
|
@ -415,7 +410,7 @@ static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
|
|||
m2p_set_control(edmac, 0);
|
||||
|
||||
while (m2p_channel_state(edmac) != M2P_STATE_IDLE)
|
||||
dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "M2P: Not yet IDLE\n");
|
||||
}
|
||||
|
||||
static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
|
||||
|
|
@ -425,7 +420,7 @@ static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
|
|||
|
||||
desc = ep93xx_dma_get_active(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "M2P: empty descriptor list\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "M2P: empty descriptor list\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -479,7 +474,7 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac)
|
|||
* Revisit this when there is a mechanism to report back the
|
||||
* errors.
|
||||
*/
|
||||
dev_err(chan2dev(edmac),
|
||||
dev_err(dmaengine_chan_dev(&edmac->chan),
|
||||
"DMA transfer failed! Details:\n"
|
||||
"\tcookie : %d\n"
|
||||
"\tsrc_addr : 0x%08x\n"
|
||||
|
|
@ -586,7 +581,7 @@ static void m2m_fill_desc(struct ep93xx_dma_chan *edmac)
|
|||
|
||||
desc = ep93xx_dma_get_active(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "M2M: empty descriptor list\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "M2M: empty descriptor list\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +844,7 @@ static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
|
|||
|
||||
desc = ep93xx_dma_get_active(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac),
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan),
|
||||
"got interrupt while active list is empty\n");
|
||||
spin_unlock(&edmac->lock);
|
||||
return IRQ_NONE;
|
||||
|
|
@ -867,7 +862,7 @@ static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_warn(chan2dev(edmac), "unknown interrupt!\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "unknown interrupt!\n");
|
||||
ret = IRQ_NONE;
|
||||
break;
|
||||
}
|
||||
|
|
@ -967,7 +962,7 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
|
||||
desc = kzalloc_obj(*desc);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "not enough descriptors\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "not enough descriptors\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1044,7 +1039,7 @@ ep93xx_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
|
|||
for (offset = 0; offset < len; offset += bytes) {
|
||||
desc = ep93xx_dma_desc_get(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "couldn't get descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -1091,13 +1086,13 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
int i;
|
||||
|
||||
if (!edmac->edma->m2m && dir != ep93xx_dma_chan_direction(chan)) {
|
||||
dev_warn(chan2dev(edmac),
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan),
|
||||
"channel was configured with different direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags)) {
|
||||
dev_warn(chan2dev(edmac),
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan),
|
||||
"channel is already used for cyclic transfers\n");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1109,14 +1104,14 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
size_t len = sg_dma_len(sg);
|
||||
|
||||
if (len > DMA_MAX_CHAN_BYTES) {
|
||||
dev_warn(chan2dev(edmac), "too big transfer size %zu\n",
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "too big transfer size %zu\n",
|
||||
len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
desc = ep93xx_dma_desc_get(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "couldn't get descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -1172,19 +1167,19 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
|
|||
size_t offset = 0;
|
||||
|
||||
if (!edmac->edma->m2m && dir != ep93xx_dma_chan_direction(chan)) {
|
||||
dev_warn(chan2dev(edmac),
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan),
|
||||
"channel was configured with different direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags)) {
|
||||
dev_warn(chan2dev(edmac),
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan),
|
||||
"channel is already used for cyclic transfers\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (period_len > DMA_MAX_CHAN_BYTES) {
|
||||
dev_warn(chan2dev(edmac), "too big period length %zu\n",
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "too big period length %zu\n",
|
||||
period_len);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1196,7 +1191,7 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
|
|||
for (offset = 0; offset < buf_len; offset += period_len) {
|
||||
desc = ep93xx_dma_desc_get(edmac);
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
|
||||
dev_warn(dmaengine_chan_dev(&edmac->chan), "couldn't get descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
|
||||
// Copyright (c) 2017 Sysam, Angelo Dureghello <angelo@sysam.it>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dmapool.h>
|
||||
|
|
@ -55,10 +56,36 @@ void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
|
|||
}
|
||||
|
||||
if (!fsl_chan->edesc->iscyclic) {
|
||||
list_del(&fsl_chan->edesc->vdesc.node);
|
||||
vchan_cookie_complete(&fsl_chan->edesc->vdesc);
|
||||
u16 csr = edma_read_tcdreg(fsl_chan, csr);
|
||||
u8 link_sg_id = FIELD_GET(EDMA_TCD_CSR_LINKCH, csr);
|
||||
struct virt_dma_desc *vdesc, *tmp;
|
||||
|
||||
/* Channel is DONE when a TCD with D_REQ set completes */
|
||||
if (!(fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG) ||
|
||||
(edma_readl_chreg(fsl_chan, ch_csr) & EDMA_V3_CH_CSR_DONE)) {
|
||||
fsl_chan->status = DMA_COMPLETE;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_issued, node) {
|
||||
struct fsl_edma_desc *fsl_desc = to_fsl_edma_desc(vdesc);
|
||||
bool id_match = (link_sg_id == fsl_desc->link_sg_id);
|
||||
|
||||
/*
|
||||
* If the transfer is still running,
|
||||
* don't mark as complete the current descriptor
|
||||
*/
|
||||
if (id_match && fsl_chan->status != DMA_COMPLETE)
|
||||
break;
|
||||
|
||||
list_del(&vdesc->node);
|
||||
vchan_cookie_complete(vdesc);
|
||||
|
||||
if (id_match)
|
||||
break;
|
||||
}
|
||||
|
||||
fsl_chan->edesc = NULL;
|
||||
fsl_chan->status = DMA_COMPLETE;
|
||||
|
||||
} else {
|
||||
vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
|
||||
}
|
||||
|
|
@ -673,6 +700,122 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
|
|||
return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
|
||||
}
|
||||
|
||||
struct dma_async_tx_descriptor *
|
||||
fsl_edma_prep_peripheral_dma_vec(struct dma_chan *chan, const struct dma_vec *vecs,
|
||||
size_t nb, enum dma_transfer_direction direction,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
|
||||
dma_addr_t src_addr, dst_addr, last_sg;
|
||||
struct fsl_edma_desc *fsl_desc;
|
||||
u16 soff, doff, iter;
|
||||
u32 nbytes;
|
||||
int i;
|
||||
|
||||
if (!is_slave_direction(direction))
|
||||
return NULL;
|
||||
|
||||
if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
|
||||
return NULL;
|
||||
|
||||
fsl_desc = fsl_edma_alloc_desc(fsl_chan, nb);
|
||||
if (!fsl_desc)
|
||||
return NULL;
|
||||
fsl_desc->iscyclic = flags & DMA_PREP_REPEAT;
|
||||
fsl_desc->dirn = direction;
|
||||
|
||||
if (direction == DMA_MEM_TO_DEV) {
|
||||
if (!fsl_chan->cfg.src_addr_width)
|
||||
fsl_chan->cfg.src_addr_width = fsl_chan->cfg.dst_addr_width;
|
||||
fsl_chan->attr =
|
||||
fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
|
||||
fsl_chan->cfg.dst_addr_width);
|
||||
nbytes = fsl_chan->cfg.dst_addr_width * fsl_chan->cfg.dst_maxburst;
|
||||
} else {
|
||||
if (!fsl_chan->cfg.dst_addr_width)
|
||||
fsl_chan->cfg.dst_addr_width = fsl_chan->cfg.src_addr_width;
|
||||
fsl_chan->attr =
|
||||
fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width,
|
||||
fsl_chan->cfg.dst_addr_width);
|
||||
nbytes = fsl_chan->cfg.src_addr_width * fsl_chan->cfg.src_maxburst;
|
||||
}
|
||||
|
||||
for (i = 0; i < nb; i++) {
|
||||
if (direction == DMA_MEM_TO_DEV) {
|
||||
src_addr = vecs[i].addr;
|
||||
dst_addr = fsl_chan->dma_dev_addr;
|
||||
soff = fsl_chan->cfg.dst_addr_width;
|
||||
doff = 0;
|
||||
} else if (direction == DMA_DEV_TO_MEM) {
|
||||
src_addr = fsl_chan->dma_dev_addr;
|
||||
dst_addr = vecs[i].addr;
|
||||
soff = 0;
|
||||
doff = fsl_chan->cfg.src_addr_width;
|
||||
} else {
|
||||
/* DMA_DEV_TO_DEV */
|
||||
src_addr = fsl_chan->cfg.src_addr;
|
||||
dst_addr = fsl_chan->cfg.dst_addr;
|
||||
soff = 0;
|
||||
doff = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose the suitable burst length if dma_vec length is not
|
||||
* multiple of burst length so that the whole transfer length is
|
||||
* multiple of minor loop(burst length).
|
||||
*/
|
||||
if (nbytes && vecs[i].len % nbytes) {
|
||||
u32 width = (direction == DMA_DEV_TO_MEM) ? doff : soff;
|
||||
u32 burst = (direction == DMA_DEV_TO_MEM) ?
|
||||
fsl_chan->cfg.src_maxburst :
|
||||
fsl_chan->cfg.dst_maxburst;
|
||||
int j;
|
||||
|
||||
for (j = burst; j > 1; j--) {
|
||||
if (!(vecs[i].len % (j * width))) {
|
||||
nbytes = j * width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Set burst size as 1 if there's no suitable one */
|
||||
if (j == 1)
|
||||
nbytes = width;
|
||||
}
|
||||
|
||||
if (!nbytes || vecs[i].len / nbytes > FIELD_MAX(EDMA_TCD_ITER_MASK))
|
||||
goto err_free_desc;
|
||||
|
||||
iter = vecs[i].len / nbytes;
|
||||
if (i < nb - 1) {
|
||||
last_sg = fsl_desc->tcd[(i + 1)].ptcd;
|
||||
fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
|
||||
dst_addr, fsl_chan->attr, soff,
|
||||
nbytes, 0, iter, iter, doff, last_sg,
|
||||
false, false, true);
|
||||
} else {
|
||||
if (fsl_desc->iscyclic) {
|
||||
last_sg = fsl_desc->tcd[0].ptcd;
|
||||
fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
|
||||
dst_addr, fsl_chan->attr, soff,
|
||||
nbytes, 0, iter, iter, doff, last_sg,
|
||||
true, false, true);
|
||||
} else {
|
||||
last_sg = 0;
|
||||
fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
|
||||
dst_addr, fsl_chan->attr, soff,
|
||||
nbytes, 0, iter, iter, doff, last_sg,
|
||||
true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
|
||||
|
||||
err_free_desc:
|
||||
fsl_edma_free_desc(&fsl_desc->vdesc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
|
||||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||
|
|
@ -815,14 +958,99 @@ void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
|
|||
if (!vdesc)
|
||||
return;
|
||||
fsl_chan->edesc = to_fsl_edma_desc(vdesc);
|
||||
fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
|
||||
fsl_edma_enable_request(fsl_chan);
|
||||
fsl_chan->status = DMA_IN_PROGRESS;
|
||||
|
||||
if (fsl_chan->status != DMA_IN_PROGRESS) {
|
||||
fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
|
||||
fsl_edma_enable_request(fsl_chan);
|
||||
fsl_chan->status = DMA_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_edma_link_sg(struct fsl_edma_chan *fsl_chan, struct fsl_edma_desc *fsl_desc)
|
||||
{
|
||||
u32 flags = fsl_edma_drvflags(fsl_chan);
|
||||
struct fsl_edma_hw_tcd *last_tcd;
|
||||
struct fsl_edma_desc *prev_desc;
|
||||
struct virt_dma_desc *vdesc;
|
||||
u16 last_csr;
|
||||
|
||||
lockdep_assert_held(&fsl_chan->vchan.lock);
|
||||
|
||||
if (!(flags & FSL_EDMA_DRV_CSR_LINKCH) || fsl_desc->iscyclic)
|
||||
return;
|
||||
|
||||
vdesc = list_last_entry_or_null(&fsl_chan->vchan.desc_issued,
|
||||
struct virt_dma_desc, node);
|
||||
if (!vdesc)
|
||||
return;
|
||||
|
||||
prev_desc = to_fsl_edma_desc(vdesc);
|
||||
if (prev_desc->iscyclic)
|
||||
return;
|
||||
|
||||
last_tcd = prev_desc->tcd[prev_desc->n_tcds - 1].vtcd;
|
||||
last_csr = fsl_edma_get_tcd_to_cpu(fsl_chan, last_tcd, csr);
|
||||
|
||||
for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
|
||||
struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
|
||||
|
||||
if (fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr) & EDMA_TCD_CSR_E_LINK)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(last_csr & EDMA_TCD_CSR_D_REQ) ||
|
||||
last_csr & EDMA_TCD_CSR_E_LINK)
|
||||
return;
|
||||
|
||||
/* Set a non-zero linked SG identifier to all TCD of the new descriptor */
|
||||
fsl_chan->link_sg_id++;
|
||||
if (fsl_chan->link_sg_id > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
|
||||
fsl_chan->link_sg_id = 1;
|
||||
|
||||
fsl_desc->link_sg_id = fsl_chan->link_sg_id;
|
||||
|
||||
for (unsigned int i = 0; i < fsl_desc->n_tcds; i++) {
|
||||
struct fsl_edma_hw_tcd *tcd = fsl_desc->tcd[i].vtcd;
|
||||
u16 csr = fsl_edma_get_tcd_to_cpu(fsl_chan, tcd, csr);
|
||||
|
||||
csr |= FIELD_PREP(EDMA_TCD_CSR_LINKCH, fsl_chan->link_sg_id);
|
||||
fsl_edma_set_tcd_to_le(fsl_chan, tcd, csr, csr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set DLAST_SGA before enabling E_SG in CSR: if the DMA engine
|
||||
* only picks up the former, it updates DADDR at end of transfer,
|
||||
* which is not reused.
|
||||
*/
|
||||
fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, fsl_desc->tcd[0].ptcd, dlast_sga);
|
||||
|
||||
dma_wmb();
|
||||
|
||||
last_csr &= ~EDMA_TCD_CSR_D_REQ;
|
||||
last_csr |= EDMA_TCD_CSR_E_SG;
|
||||
fsl_edma_set_tcd_to_le(fsl_chan, last_tcd, last_csr, csr);
|
||||
|
||||
/*
|
||||
* Update the registers if the engine already loaded the TCD,
|
||||
* unless doing so requires clearing the DONE bit, as that could
|
||||
* lead to lost completion.
|
||||
*/
|
||||
if (prev_desc == fsl_chan->edesc &&
|
||||
prev_desc->n_tcds == 1 &&
|
||||
!(flags & FSL_EDMA_DRV_CLEAR_DONE_E_SG)) {
|
||||
edma_cp_tcd_to_reg(fsl_chan, last_tcd, dlast_sga);
|
||||
edma_cp_tcd_to_reg(fsl_chan, last_tcd, csr);
|
||||
}
|
||||
|
||||
trace_edma_link_sg(fsl_chan, last_tcd);
|
||||
}
|
||||
|
||||
void fsl_edma_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
|
||||
struct virt_dma_desc *vdesc, *tmp;
|
||||
size_t issued_count = 0;
|
||||
struct list_head *pos;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
|
||||
|
|
@ -833,6 +1061,21 @@ void fsl_edma_issue_pending(struct dma_chan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Count the issued desc up to the maximum number of linked SG id */
|
||||
list_for_each(pos, &fsl_chan->vchan.desc_issued) {
|
||||
if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Link the SG descriptors with the available identifiers */
|
||||
list_for_each_entry_safe(vdesc, tmp, &fsl_chan->vchan.desc_submitted, node) {
|
||||
if (++issued_count > FIELD_MAX(EDMA_TCD_CSR_LINKCH))
|
||||
break;
|
||||
fsl_edma_link_sg(fsl_chan, to_fsl_edma_desc(vdesc));
|
||||
list_move_tail(&vdesc->node, &fsl_chan->vchan.desc_issued);
|
||||
}
|
||||
|
||||
/* Issue the rest of the descriptors unlinked */
|
||||
if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
|
||||
fsl_edma_xfer_desc(fsl_chan);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#define EDMA_TCD_CSR_E_LINK BIT(5)
|
||||
#define EDMA_TCD_CSR_ACTIVE BIT(6)
|
||||
#define EDMA_TCD_CSR_DONE BIT(7)
|
||||
#define EDMA_TCD_CSR_LINKCH GENMASK(12, 8)
|
||||
|
||||
#define EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(x) ((x) & GENMASK(9, 0))
|
||||
#define EDMA_V3_TCD_NBYTES_MLOFF(x) (x << 10)
|
||||
|
|
@ -169,6 +170,7 @@ struct fsl_edma_chan {
|
|||
struct dma_slave_config cfg;
|
||||
u32 attr;
|
||||
bool is_sw;
|
||||
u8 link_sg_id;
|
||||
struct dma_pool *tcd_pool;
|
||||
dma_addr_t dma_dev_addr;
|
||||
u32 dma_dev_size;
|
||||
|
|
@ -199,6 +201,7 @@ struct fsl_edma_desc {
|
|||
struct virt_dma_desc vdesc;
|
||||
struct fsl_edma_chan *echan;
|
||||
bool iscyclic;
|
||||
u8 link_sg_id;
|
||||
enum dma_transfer_direction dirn;
|
||||
unsigned int n_tcds;
|
||||
struct fsl_edma_sw_tcd tcd[];
|
||||
|
|
@ -225,6 +228,8 @@ struct fsl_edma_desc {
|
|||
#define FSL_EDMA_DRV_TCD64 BIT(15)
|
||||
/* All channel ERR IRQ share one IRQ line */
|
||||
#define FSL_EDMA_DRV_ERRIRQ_SHARE BIT(16)
|
||||
/* Major link channel in CSR used for linking SG descriptors */
|
||||
#define FSL_EDMA_DRV_CSR_LINKCH BIT(17)
|
||||
|
||||
|
||||
#define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
|
||||
|
|
@ -232,13 +237,15 @@ struct fsl_edma_desc {
|
|||
FSL_EDMA_DRV_DEV_TO_DEV | \
|
||||
FSL_EDMA_DRV_ALIGN_64BYTE | \
|
||||
FSL_EDMA_DRV_CLEAR_DONE_E_SG | \
|
||||
FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
|
||||
FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
|
||||
FSL_EDMA_DRV_CSR_LINKCH)
|
||||
|
||||
#define FSL_EDMA_DRV_EDMA4 (FSL_EDMA_DRV_SPLIT_REG | \
|
||||
FSL_EDMA_DRV_BUS_8BYTE | \
|
||||
FSL_EDMA_DRV_DEV_TO_DEV | \
|
||||
FSL_EDMA_DRV_ALIGN_64BYTE | \
|
||||
FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
|
||||
FSL_EDMA_DRV_CLEAR_DONE_E_LINK | \
|
||||
FSL_EDMA_DRV_CSR_LINKCH)
|
||||
|
||||
struct fsl_edma_drvdata {
|
||||
u32 dmamuxs; /* only used before v3 */
|
||||
|
|
@ -496,6 +503,10 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
|
|||
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
|
||||
size_t period_len, enum dma_transfer_direction direction,
|
||||
unsigned long flags);
|
||||
struct dma_async_tx_descriptor *fsl_edma_prep_peripheral_dma_vec(
|
||||
struct dma_chan *chan, const struct dma_vec *vecs,
|
||||
size_t nb, enum dma_transfer_direction direction,
|
||||
unsigned long flags);
|
||||
struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
|
||||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||
|
|
|
|||
|
|
@ -326,13 +326,16 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
|
|||
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
|
||||
continue;
|
||||
|
||||
chan = dma_get_slave_channel(chan);
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
fsl_chan->srcid = dma_spec->args[0];
|
||||
fsl_chan->priority = dma_spec->args[1];
|
||||
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;
|
||||
|
||||
chan = dma_get_slave_channel(chan);
|
||||
chan->device->privatecnt++;
|
||||
return chan;
|
||||
}
|
||||
|
|
@ -843,6 +846,8 @@ static int fsl_edma_probe(struct platform_device *pdev)
|
|||
fsl_edma->dma_dev.device_free_chan_resources
|
||||
= fsl_edma_free_chan_resources;
|
||||
fsl_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
|
||||
fsl_edma->dma_dev.device_prep_peripheral_dma_vec
|
||||
= fsl_edma_prep_peripheral_dma_vec;
|
||||
fsl_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
|
||||
fsl_edma->dma_dev.device_prep_dma_cyclic = fsl_edma_prep_dma_cyclic;
|
||||
fsl_edma->dma_dev.device_prep_dma_memcpy = fsl_edma_prep_memcpy;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,11 @@ DEFINE_EVENT(edma_log_tcd, edma_fill_tcd,
|
|||
TP_ARGS(chan, tcd)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(edma_log_tcd, edma_link_sg,
|
||||
TP_PROTO(struct fsl_edma_chan *chan, void *tcd),
|
||||
TP_ARGS(chan, tcd)
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
/* this part must be outside header guard */
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ static void fsl_re_dequeue(struct tasklet_struct *t)
|
|||
struct fsl_re_hw_desc *hwdesc;
|
||||
unsigned long flags;
|
||||
unsigned int count, oub_count;
|
||||
LIST_HEAD(completed);
|
||||
int found;
|
||||
|
||||
fsl_re_cleanup_descs(re_chan);
|
||||
|
|
@ -182,8 +183,7 @@ static void fsl_re_dequeue(struct tasklet_struct *t)
|
|||
}
|
||||
|
||||
if (found) {
|
||||
fsl_re_desc_done(desc);
|
||||
list_move_tail(&desc->node, &re_chan->ack_q);
|
||||
list_move_tail(&desc->node, &completed);
|
||||
} else {
|
||||
dev_err(re_chan->dev,
|
||||
"found hwdesc not in sw queue, discard it\n");
|
||||
|
|
@ -196,6 +196,17 @@ static void fsl_re_dequeue(struct tasklet_struct *t)
|
|||
FSL_RE_RMVD_JOB(1));
|
||||
}
|
||||
spin_unlock_irqrestore(&re_chan->desc_lock, flags);
|
||||
|
||||
/* Invoke the client callbacks outside the channel lock. The callback
|
||||
* may submit new work which re-acquires desc_lock, so holding it here
|
||||
* would deadlock.
|
||||
*/
|
||||
list_for_each_entry_safe(desc, _desc, &completed, node) {
|
||||
fsl_re_desc_done(desc);
|
||||
spin_lock_irqsave(&re_chan->desc_lock, flags);
|
||||
list_move_tail(&desc->node, &re_chan->ack_q);
|
||||
spin_unlock_irqrestore(&re_chan->desc_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Per Job Ring interrupt handler */
|
||||
|
|
@ -295,8 +306,8 @@ static struct fsl_re_desc *fsl_re_chan_alloc_desc(struct fsl_re_chan *re_chan,
|
|||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
cf = dma_pool_alloc(re_chan->re_dev->cf_desc_pool, GFP_NOWAIT,
|
||||
&paddr);
|
||||
cf = dma_pool_zalloc(re_chan->re_dev->cf_desc_pool, GFP_NOWAIT,
|
||||
&paddr);
|
||||
if (!cf) {
|
||||
kfree(desc);
|
||||
return NULL;
|
||||
|
|
@ -350,7 +361,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_genq(
|
|||
cdb |= FSL_RE_INTR_ON_ERROR << FSL_RE_CDB_ERROR_SHIFT;
|
||||
cdb |= FSL_RE_DATA_DEP << FSL_RE_CDB_DEPEND_SHIFT;
|
||||
xor = desc->cdb_addr;
|
||||
xor->cdb32 = cdb;
|
||||
xor->cdb32 = cpu_to_be32(cdb);
|
||||
|
||||
if (scf) {
|
||||
/* compute q = src0*coef0^src1*coef1^..., * is GF(8) mult */
|
||||
|
|
@ -470,7 +481,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_pq(
|
|||
cdb |= FSL_RE_DATA_DEP << FSL_RE_CDB_DEPEND_SHIFT;
|
||||
|
||||
pq = desc->cdb_addr;
|
||||
pq->cdb32 = cdb;
|
||||
pq->cdb32 = cpu_to_be32(cdb);
|
||||
|
||||
p = pq->gfm_q1;
|
||||
/* Init gfm_q1[] */
|
||||
|
|
@ -553,7 +564,7 @@ static struct dma_async_tx_descriptor *fsl_re_prep_dma_memcpy(
|
|||
cdb |= FSL_RE_DATA_DEP << FSL_RE_CDB_DEPEND_SHIFT;
|
||||
|
||||
move = desc->cdb_addr;
|
||||
move->cdb32 = cdb;
|
||||
move->cdb32 = cpu_to_be32(cdb);
|
||||
|
||||
/* Filling frame 0 of CFD with move CDB */
|
||||
cf = desc->cf_addr;
|
||||
|
|
@ -584,8 +595,8 @@ static int fsl_re_alloc_chan_resources(struct dma_chan *chan)
|
|||
if (!desc)
|
||||
break;
|
||||
|
||||
cf = dma_pool_alloc(re_chan->re_dev->cf_desc_pool, GFP_KERNEL,
|
||||
&paddr);
|
||||
cf = dma_pool_zalloc(re_chan->re_dev->cf_desc_pool, GFP_KERNEL,
|
||||
&paddr);
|
||||
if (!cf) {
|
||||
kfree(desc);
|
||||
break;
|
||||
|
|
@ -603,18 +614,15 @@ static int fsl_re_alloc_chan_resources(struct dma_chan *chan)
|
|||
static void fsl_re_free_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct fsl_re_chan *re_chan;
|
||||
struct fsl_re_desc *desc;
|
||||
struct fsl_re_desc *desc, *_desc;
|
||||
|
||||
re_chan = container_of(chan, struct fsl_re_chan, chan);
|
||||
while (re_chan->alloc_count--) {
|
||||
desc = list_first_entry(&re_chan->free_q,
|
||||
struct fsl_re_desc,
|
||||
node);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &re_chan->free_q, node) {
|
||||
list_del(&desc->node);
|
||||
dma_pool_free(re_chan->re_dev->cf_desc_pool, desc->cf_addr,
|
||||
desc->cf_paddr);
|
||||
kfree(desc);
|
||||
re_chan->alloc_count--;
|
||||
}
|
||||
|
||||
if (!list_empty(&re_chan->free_q))
|
||||
|
|
|
|||
|
|
@ -681,7 +681,7 @@ static void fsldma_cleanup_descriptors(struct fsldma_chan *chan)
|
|||
|
||||
/**
|
||||
* fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
|
||||
* @chan : Freescale DMA channel
|
||||
* @dchan : Freescale DMA channel
|
||||
*
|
||||
* This function will create a dma pool for descriptor allocation.
|
||||
*
|
||||
|
|
@ -738,7 +738,7 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
|
|||
|
||||
/**
|
||||
* fsl_dma_free_chan_resources - Free all resources of the channel.
|
||||
* @chan : Freescale DMA channel
|
||||
* @dchan : Freescale DMA channel
|
||||
*/
|
||||
static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
|
||||
{
|
||||
|
|
@ -873,7 +873,7 @@ static int fsl_dma_device_config(struct dma_chan *dchan,
|
|||
|
||||
/**
|
||||
* fsl_dma_memcpy_issue_pending - Issue the DMA start command
|
||||
* @chan : Freescale DMA channel
|
||||
* @dchan : Freescale DMA channel
|
||||
*/
|
||||
static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
|
||||
{
|
||||
|
|
@ -886,7 +886,9 @@ static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
|
|||
|
||||
/**
|
||||
* fsl_tx_status - Determine the DMA status
|
||||
* @chan : Freescale DMA channel
|
||||
* @dchan : Freescale DMA channel
|
||||
* @cookie : DMA transaction identifier
|
||||
* @txstate : DMA transaction state
|
||||
*/
|
||||
static enum dma_status fsl_tx_status(struct dma_chan *dchan,
|
||||
dma_cookie_t cookie,
|
||||
|
|
@ -1205,6 +1207,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
|
|||
|
||||
static void fsl_dma_chan_remove(struct fsldma_chan *chan)
|
||||
{
|
||||
tasklet_kill(&chan->tasklet);
|
||||
irq_dispose_mapping(chan->irq);
|
||||
list_del(&chan->common.device_node);
|
||||
iounmap(chan->regs);
|
||||
|
|
@ -1216,8 +1219,13 @@ static int fsldma_of_probe(struct platform_device *op)
|
|||
struct fsldma_device *fdev;
|
||||
struct device_node *child;
|
||||
unsigned int i;
|
||||
int irq;
|
||||
int err;
|
||||
|
||||
irq = platform_get_irq_optional(op, 0);
|
||||
if (irq == -EPROBE_DEFER)
|
||||
return irq;
|
||||
|
||||
fdev = kzalloc_obj(*fdev);
|
||||
if (!fdev) {
|
||||
err = -ENOMEM;
|
||||
|
|
@ -1238,7 +1246,9 @@ static int fsldma_of_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
/* map the channel IRQ if it exists, but don't hookup the handler yet */
|
||||
fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
|
||||
fdev->irq = irq;
|
||||
if (fdev->irq < 0)
|
||||
fdev->irq = 0;
|
||||
|
||||
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
|
||||
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
|
||||
|
|
@ -1300,7 +1310,6 @@ static int fsldma_of_probe(struct platform_device *op)
|
|||
if (fdev->chan[i])
|
||||
fsl_dma_chan_remove(fdev->chan[i]);
|
||||
}
|
||||
irq_dispose_mapping(fdev->irq);
|
||||
iounmap(fdev->regs);
|
||||
out_free:
|
||||
kfree(fdev);
|
||||
|
|
@ -1322,7 +1331,6 @@ static void fsldma_of_remove(struct platform_device *op)
|
|||
if (fdev->chan[i])
|
||||
fsl_dma_chan_remove(fdev->chan[i]);
|
||||
}
|
||||
irq_dispose_mapping(fdev->irq);
|
||||
|
||||
iounmap(fdev->regs);
|
||||
kfree(fdev);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,6 @@
|
|||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void idma64_off(struct idma64 *idma64)
|
||||
|
|
@ -507,11 +502,10 @@ static int idma64_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct idma64_chan *idma64c = to_idma64_chan(chan);
|
||||
|
||||
/* Create a pool of consistent memory blocks for hardware descriptors */
|
||||
idma64c->pool = dma_pool_create(dev_name(chan2dev(chan)),
|
||||
chan->device->dev,
|
||||
idma64c->pool = dma_pool_create(dma_chan_name(chan), chan->device->dev,
|
||||
sizeof(struct idma64_lli), 8, 0);
|
||||
if (!idma64c->pool) {
|
||||
dev_err(chan2dev(chan), "No memory for descriptors\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "No memory for descriptors\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ static int mdc_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct mdc_chan *mchan = to_mdc_chan(chan);
|
||||
struct device *dev = mdma2dev(mchan->mdma);
|
||||
|
||||
return pm_runtime_get_sync(dev);
|
||||
return pm_runtime_resume_and_get(dev);
|
||||
}
|
||||
|
||||
static void mdc_free_chan_resources(struct dma_chan *chan)
|
||||
|
|
|
|||
|
|
@ -1170,15 +1170,6 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
|
|||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
}
|
||||
|
||||
err = dma_async_device_register(&ioat_dma->dma_dev);
|
||||
if (err)
|
||||
goto err_disable_interrupts;
|
||||
|
||||
ioat_kobject_add(ioat_dma, &ioat_ktype);
|
||||
|
||||
if (dca)
|
||||
ioat_dma->dca = ioat_dca_init(pdev, ioat_dma->reg_base);
|
||||
|
||||
/* disable relaxed ordering */
|
||||
err = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &val16);
|
||||
if (err) {
|
||||
|
|
@ -1194,6 +1185,15 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
|
|||
goto err_disable_interrupts;
|
||||
}
|
||||
|
||||
err = dma_async_device_register(&ioat_dma->dma_dev);
|
||||
if (err)
|
||||
goto err_disable_interrupts;
|
||||
|
||||
ioat_kobject_add(ioat_dma, &ioat_ktype);
|
||||
|
||||
if (dca)
|
||||
ioat_dma->dca = ioat_dca_init(pdev, ioat_dma->reg_base);
|
||||
|
||||
if (ioat_dma->cap & IOAT_CAP_DPS)
|
||||
writeb(ioat_pending_level + 1,
|
||||
ioat_dma->reg_base + IOAT_PREFETCH_LIMIT_OFFSET);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ static ssize_t cap_show(struct dma_chan *c, char *page)
|
|||
{
|
||||
struct dma_device *dma = c->device;
|
||||
|
||||
return sprintf(page, "copy%s%s%s%s%s\n",
|
||||
dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "",
|
||||
dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "",
|
||||
dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "",
|
||||
dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "",
|
||||
dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : "");
|
||||
return sysfs_emit(page, "copy%s%s%s%s%s\n",
|
||||
dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "",
|
||||
dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "",
|
||||
dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "",
|
||||
dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "",
|
||||
dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : "");
|
||||
|
||||
}
|
||||
static const struct ioat_sysfs_entry ioat_cap_attr = __ATTR_RO(cap);
|
||||
|
|
@ -39,8 +39,8 @@ static ssize_t version_show(struct dma_chan *c, char *page)
|
|||
struct dma_device *dma = c->device;
|
||||
struct ioatdma_device *ioat_dma = to_ioatdma_device(dma);
|
||||
|
||||
return sprintf(page, "%d.%d\n",
|
||||
ioat_dma->version >> 4, ioat_dma->version & 0xf);
|
||||
return sysfs_emit(page, "%d.%d\n",
|
||||
ioat_dma->version >> 4, ioat_dma->version & 0xf);
|
||||
}
|
||||
static const struct ioat_sysfs_entry ioat_version_attr = __ATTR_RO(version);
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ static ssize_t ring_size_show(struct dma_chan *c, char *page)
|
|||
{
|
||||
struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
|
||||
|
||||
return sprintf(page, "%d\n", (1 << ioat_chan->alloc_order) & ~1);
|
||||
return sysfs_emit(page, "%d\n", (1 << ioat_chan->alloc_order) & ~1);
|
||||
}
|
||||
static const struct ioat_sysfs_entry ring_size_attr = __ATTR_RO(ring_size);
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ static ssize_t ring_active_show(struct dma_chan *c, char *page)
|
|||
struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
|
||||
|
||||
/* ...taken outside the lock, no need to be precise */
|
||||
return sprintf(page, "%d\n", ioat_ring_active(ioat_chan));
|
||||
return sysfs_emit(page, "%d\n", ioat_ring_active(ioat_chan));
|
||||
}
|
||||
static const struct ioat_sysfs_entry ring_active_attr = __ATTR_RO(ring_active);
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ static ssize_t intr_coalesce_show(struct dma_chan *c, char *page)
|
|||
{
|
||||
struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
|
||||
|
||||
return sprintf(page, "%d\n", ioat_chan->intr_coalesce);
|
||||
return sysfs_emit(page, "%d\n", ioat_chan->intr_coalesce);
|
||||
}
|
||||
|
||||
static ssize_t intr_coalesce_store(struct dma_chan *c, const char *page,
|
||||
|
|
|
|||
|
|
@ -89,11 +89,6 @@ static irqreturn_t ls1x_dma_irq_handler(int irq, void *data);
|
|||
#define to_ls1x_dma_desc(d) \
|
||||
container_of(d, struct ls1x_dma_desc, vd)
|
||||
|
||||
static inline struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline int ls1x_dma_query(struct ls1x_dma_chan *chan,
|
||||
dma_addr_t *lli_phys)
|
||||
{
|
||||
|
|
@ -107,7 +102,7 @@ static inline int ls1x_dma_query(struct ls1x_dma_chan *chan,
|
|||
ret = readl_poll_timeout_atomic(chan->reg_base + LS1X_DMA_CTRL, val,
|
||||
!(val & LS1X_DMA_ASK_VALID), 0, 3000);
|
||||
if (ret)
|
||||
dev_err(chan2dev(dchan), "failed to query DMA\n");
|
||||
dev_err(dmaengine_chan_dev(dchan), "failed to query DMA\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -116,7 +111,7 @@ static inline int ls1x_dma_start(struct ls1x_dma_chan *chan,
|
|||
dma_addr_t *lli_phys)
|
||||
{
|
||||
struct dma_chan *dchan = &chan->vc.chan;
|
||||
struct device *dev = chan2dev(dchan);
|
||||
struct device *dev = dmaengine_chan_dev(dchan);
|
||||
int val, ret;
|
||||
|
||||
val = *lli_phys & LS1X_DMA_LLI_ADDR_MASK;
|
||||
|
|
@ -143,7 +138,7 @@ static inline void ls1x_dma_stop(struct ls1x_dma_chan *chan)
|
|||
static void ls1x_dma_free_chan_resources(struct dma_chan *dchan)
|
||||
{
|
||||
struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
|
||||
struct device *dev = chan2dev(dchan);
|
||||
struct device *dev = dmaengine_chan_dev(dchan);
|
||||
|
||||
dma_free_coherent(dev, sizeof(struct ls1x_dma_lli),
|
||||
chan->curr_lli, chan->curr_lli->phys);
|
||||
|
|
@ -156,7 +151,7 @@ static void ls1x_dma_free_chan_resources(struct dma_chan *dchan)
|
|||
static int ls1x_dma_alloc_chan_resources(struct dma_chan *dchan)
|
||||
{
|
||||
struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
|
||||
struct device *dev = chan2dev(dchan);
|
||||
struct device *dev = dmaengine_chan_dev(dchan);
|
||||
dma_addr_t phys;
|
||||
int ret;
|
||||
|
||||
|
|
@ -219,7 +214,7 @@ static int ls1x_dma_prep_lli(struct dma_chan *dchan, struct ls1x_dma_desc *desc,
|
|||
{
|
||||
struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
|
||||
struct ls1x_dma_lli *lli, *prev = NULL, *first = NULL;
|
||||
struct device *dev = chan2dev(dchan);
|
||||
struct device *dev = dmaengine_chan_dev(dchan);
|
||||
struct list_head *pos = NULL;
|
||||
struct scatterlist *sg;
|
||||
unsigned int dev_addr, cmd, i;
|
||||
|
|
@ -299,7 +294,7 @@ ls1x_dma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
|||
{
|
||||
struct ls1x_dma_desc *desc;
|
||||
|
||||
dev_dbg(chan2dev(dchan), "sg_len=%u flags=0x%lx dir=%s\n",
|
||||
dev_dbg(dmaengine_chan_dev(dchan), "sg_len=%u flags=0x%lx dir=%s\n",
|
||||
sg_len, flags, dmaengine_get_direction_text(dir));
|
||||
|
||||
desc = ls1x_dma_alloc_desc();
|
||||
|
|
@ -325,7 +320,7 @@ ls1x_dma_prep_dma_cyclic(struct dma_chan *dchan, dma_addr_t buf_addr,
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
dev_dbg(chan2dev(dchan),
|
||||
dev_dbg(dmaengine_chan_dev(dchan),
|
||||
"buf_len=%zu period_len=%zu flags=0x%lx dir=%s\n",
|
||||
buf_len, period_len, flags, dmaengine_get_direction_text(dir));
|
||||
|
||||
|
|
@ -450,7 +445,7 @@ static enum dma_status ls1x_dma_tx_status(struct dma_chan *dchan,
|
|||
if (lli->hw[LS1X_DMADESC_NEXT] == next_phys)
|
||||
break;
|
||||
|
||||
dev_dbg(chan2dev(dchan), "current lli_phys=%pad",
|
||||
dev_dbg(dmaengine_chan_dev(dchan), "current lli_phys=%pad",
|
||||
&lli->phys);
|
||||
|
||||
/* count the residues */
|
||||
|
|
@ -489,7 +484,7 @@ static irqreturn_t ls1x_dma_irq_handler(int irq, void *data)
|
|||
{
|
||||
struct ls1x_dma_chan *chan = data;
|
||||
struct dma_chan *dchan = &chan->vc.chan;
|
||||
struct device *dev = chan2dev(dchan);
|
||||
struct device *dev = dmaengine_chan_dev(dchan);
|
||||
struct virt_dma_desc *vd;
|
||||
|
||||
scoped_guard(spinlock, &chan->vc.lock) {
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ struct loongson2_cmc_dma_chan {
|
|||
struct dma_slave_config dma_sconfig;
|
||||
struct loongson2_cmc_dma_desc *desc;
|
||||
u32 id;
|
||||
u32 irq;
|
||||
int irq;
|
||||
u32 next_sg;
|
||||
struct loongson2_cmc_dma_chan_reg chan_reg;
|
||||
};
|
||||
|
|
@ -134,11 +134,6 @@ static struct loongson2_cmc_dma_desc *to_lmdma_desc(struct virt_dma_desc *vdesc)
|
|||
return container_of(vdesc, struct loongson2_cmc_dma_desc, vdesc);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct loongson2_cmc_dma_chan *lchan)
|
||||
{
|
||||
return &lchan->vchan.chan.dev->device;
|
||||
}
|
||||
|
||||
static u32 loongson2_cmc_dma_read(struct loongson2_cmc_dma_dev *lddev, u32 reg, u32 id)
|
||||
{
|
||||
return readl(lddev->base + (reg + lddev->chan_reg_offset * id));
|
||||
|
|
@ -302,7 +297,7 @@ static irqreturn_t loongson2_cmc_dma_chan_irq(int irq, void *devid)
|
|||
{
|
||||
struct loongson2_cmc_dma_chan *lchan = devid;
|
||||
struct loongson2_cmc_dma_dev *lddev = lmdma_get_dev(lchan);
|
||||
struct device *dev = chan2dev(lchan);
|
||||
struct device *dev = vchan_chan_dev(&lchan->vchan);
|
||||
u32 ists, status, ccr;
|
||||
|
||||
scoped_guard(spinlock, &lchan->vchan.lock) {
|
||||
|
|
@ -337,7 +332,7 @@ static void loongson2_cmc_dma_issue_pending(struct dma_chan *chan)
|
|||
guard(spinlock_irqsave)(&lchan->vchan.lock);
|
||||
|
||||
if (vchan_issue_pending(&lchan->vchan) && !lchan->desc) {
|
||||
dev_dbg(chan2dev(lchan), "vchan %pK: issued\n", &lchan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&lchan->vchan), "vchan %pK: issued\n", &lchan->vchan);
|
||||
loongson2_cmc_dma_start_transfer(lchan);
|
||||
}
|
||||
}
|
||||
|
|
@ -347,7 +342,7 @@ static int loongson2_cmc_dma_set_xfer_param(struct loongson2_cmc_dma_chan *lchan
|
|||
enum dma_slave_buswidth *buswidth, u32 buf_len)
|
||||
{
|
||||
struct dma_slave_config sconfig = lchan->dma_sconfig;
|
||||
struct device *dev = chan2dev(lchan);
|
||||
struct device *dev = vchan_chan_dev(&lchan->vchan);
|
||||
int dev_width;
|
||||
u32 ccr;
|
||||
|
||||
|
|
@ -404,12 +399,14 @@ loongson2_cmc_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
ret = loongson2_cmc_dma_set_xfer_param(lchan, direction, &buswidth, sg_dma_len(sg));
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kfree(desc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
num_items = DIV_ROUND_UP(sg_dma_len(sg), buswidth);
|
||||
if (num_items >= LOONSON2_CMCDMA_MAX_DATA_ITEMS) {
|
||||
dev_err(chan2dev(lchan), "Number of items not supported\n");
|
||||
dev_err(vchan_chan_dev(&lchan->vchan), "Number of items not supported\n");
|
||||
kfree(desc);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
@ -447,7 +444,7 @@ loongson2_cmc_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, si
|
|||
|
||||
num_items = DIV_ROUND_UP(period_len, buswidth);
|
||||
if (num_items >= LOONSON2_CMCDMA_MAX_DATA_ITEMS) {
|
||||
dev_err(chan2dev(lchan), "Number of items not supported\n");
|
||||
dev_err(vchan_chan_dev(&lchan->vchan), "Number of items not supported\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
|
@ -678,7 +675,7 @@ static int loongson2_cmc_dma_probe(struct platform_device *pdev)
|
|||
return lchan->irq;
|
||||
|
||||
ret = devm_request_irq(dev, lchan->irq, loongson2_cmc_dma_chan_irq, IRQF_SHARED,
|
||||
dev_name(chan2dev(lchan)), lchan);
|
||||
vchan_chan_name(&lchan->vchan), lchan);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -709,8 +706,8 @@ static const struct of_device_id loongson2_cmc_dma_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, loongson2_cmc_dma_of_match);
|
||||
|
||||
static const struct acpi_device_id loongson2_cmc_dma_acpi_match[] = {
|
||||
{ "LOON0014", .driver_data = (kernel_ulong_t)&ls2k3000_cmc_dma_config },
|
||||
{ /* sentinel */ }
|
||||
{ .id = "LOON0014", .driver_data = (kernel_ulong_t)&ls2k3000_cmc_dma_config },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, loongson2_cmc_dma_acpi_match);
|
||||
|
||||
|
|
|
|||
|
|
@ -161,11 +161,6 @@ static inline struct ls2x_dma_priv *to_ldma_priv(struct dma_device *ddev)
|
|||
return container_of(ddev, struct ls2x_dma_priv, ddev);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static void ls2x_dma_desc_free(struct virt_dma_desc *vdesc)
|
||||
{
|
||||
struct ls2x_dma_chan *lchan = to_ldma_chan(vdesc->tx.chan);
|
||||
|
|
@ -282,11 +277,11 @@ static int ls2x_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct ls2x_dma_chan *lchan = to_ldma_chan(chan);
|
||||
|
||||
/* Create a pool of consistent memory blocks for hardware descriptors */
|
||||
lchan->pool = dma_pool_create(dev_name(chan2dev(chan)),
|
||||
lchan->pool = dma_pool_create(dma_chan_name(chan),
|
||||
chan->device->dev, PAGE_SIZE,
|
||||
__alignof__(struct ls2x_dma_hw_desc), 0);
|
||||
if (!lchan->pool) {
|
||||
dev_err(chan2dev(chan), "No memory for descriptors\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "No memory for descriptors\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -848,17 +848,27 @@ static int mtk_hsdma_hw_init(struct mtk_hsdma_device *hsdma)
|
|||
{
|
||||
int err;
|
||||
|
||||
pm_runtime_enable(hsdma2dev(hsdma));
|
||||
pm_runtime_get_sync(hsdma2dev(hsdma));
|
||||
err = devm_pm_runtime_enable(hsdma2dev(hsdma));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = pm_runtime_resume_and_get(hsdma2dev(hsdma));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = clk_prepare_enable(hsdma->clk);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_put_pm;
|
||||
|
||||
mtk_dma_write(hsdma, MTK_HSDMA_INT_ENABLE, 0);
|
||||
mtk_dma_write(hsdma, MTK_HSDMA_GLO, MTK_HSDMA_GLO_DEFAULT);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_pm:
|
||||
pm_runtime_put_sync(hsdma2dev(hsdma));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mtk_hsdma_hw_deinit(struct mtk_hsdma_device *hsdma)
|
||||
|
|
@ -868,7 +878,6 @@ static int mtk_hsdma_hw_deinit(struct mtk_hsdma_device *hsdma)
|
|||
clk_disable_unprepare(hsdma->clk);
|
||||
|
||||
pm_runtime_put_sync(hsdma2dev(hsdma));
|
||||
pm_runtime_disable(hsdma2dev(hsdma));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -983,7 +992,9 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
|
|||
goto err_unregister;
|
||||
}
|
||||
|
||||
mtk_hsdma_hw_init(hsdma);
|
||||
err = mtk_hsdma_hw_init(hsdma);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, hsdma->irq,
|
||||
mtk_hsdma_irq, 0,
|
||||
|
|
@ -991,7 +1002,7 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
|
|||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"request_irq failed with err %d\n", err);
|
||||
goto err_free;
|
||||
goto err_deinit;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, hsdma);
|
||||
|
|
@ -1000,8 +1011,9 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
err_deinit:
|
||||
mtk_hsdma_hw_deinit(hsdma);
|
||||
err_free:
|
||||
of_dma_controller_free(pdev->dev.of_node);
|
||||
err_unregister:
|
||||
dma_async_device_unregister(dd);
|
||||
|
|
|
|||
|
|
@ -564,8 +564,7 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
|
|||
if (chan->desc_pool)
|
||||
return 1;
|
||||
|
||||
chan->desc_pool = dma_pool_create(dev_name(&dchan->dev->device),
|
||||
chan->dev,
|
||||
chan->desc_pool = dma_pool_create(dma_chan_name(dchan), chan->dev,
|
||||
sizeof(struct mmp_pdma_desc_sw),
|
||||
__alignof__(struct mmp_pdma_desc_sw),
|
||||
0);
|
||||
|
|
|
|||
|
|
@ -154,11 +154,6 @@ static const unsigned int es_bytes[] = {
|
|||
[MOXART_DMA_DATA_TYPE_S32] = 4,
|
||||
};
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline struct moxart_chan *to_moxart_dma_chan(struct dma_chan *c)
|
||||
{
|
||||
return container_of(c, struct moxart_chan, vc.chan);
|
||||
|
|
@ -182,7 +177,7 @@ static int moxart_terminate_all(struct dma_chan *chan)
|
|||
LIST_HEAD(head);
|
||||
u32 ctrl;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: ch=%p\n", __func__, ch);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: ch=%p\n", __func__, ch);
|
||||
|
||||
spin_lock_irqsave(&ch->vc.lock, flags);
|
||||
|
||||
|
|
@ -272,7 +267,7 @@ static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
|
|||
unsigned int i;
|
||||
|
||||
if (!is_slave_direction(dir)) {
|
||||
dev_err(chan2dev(chan), "%s: invalid DMA direction\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: invalid DMA direction\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -296,7 +291,7 @@ static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
|
|||
es = MOXART_DMA_DATA_TYPE_S32;
|
||||
break;
|
||||
default:
|
||||
dev_err(chan2dev(chan), "%s: unsupported data width (%u)\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: unsupported data width (%u)\n",
|
||||
__func__, dev_width);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -341,7 +336,7 @@ static int moxart_alloc_chan_resources(struct dma_chan *chan)
|
|||
{
|
||||
struct moxart_chan *ch = to_moxart_dma_chan(chan);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: allocating channel #%u\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: allocating channel #%u\n",
|
||||
__func__, ch->ch_num);
|
||||
ch->allocated = 1;
|
||||
|
||||
|
|
@ -354,7 +349,7 @@ static void moxart_free_chan_resources(struct dma_chan *chan)
|
|||
|
||||
vchan_free_chan_resources(&ch->vc);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: freeing channel #%u\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: freeing channel #%u\n",
|
||||
__func__, ch->ch_num);
|
||||
ch->allocated = 0;
|
||||
}
|
||||
|
|
@ -379,7 +374,7 @@ static void moxart_set_transfer_params(struct moxart_chan *ch, unsigned int len)
|
|||
*/
|
||||
writel(d->dma_cycles, ch->base + REG_OFF_CYCLES);
|
||||
|
||||
dev_dbg(chan2dev(&ch->vc.chan), "%s: set %u DMA cycles (len=%u)\n",
|
||||
dev_dbg(vchan_chan_dev(&ch->vc), "%s: set %u DMA cycles (len=%u)\n",
|
||||
__func__, d->dma_cycles, len);
|
||||
}
|
||||
|
||||
|
|
@ -460,7 +455,7 @@ static size_t moxart_dma_desc_size_in_flight(struct moxart_chan *ch)
|
|||
completed_cycles = (ch->desc->dma_cycles - cycles);
|
||||
size -= completed_cycles << es_bytes[ch->desc->es];
|
||||
|
||||
dev_dbg(chan2dev(&ch->vc.chan), "%s: size=%zu\n", __func__, size);
|
||||
dev_dbg(vchan_chan_dev(&ch->vc), "%s: size=%zu\n", __func__, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
@ -517,7 +512,7 @@ static irqreturn_t moxart_dma_interrupt(int irq, void *devid)
|
|||
unsigned int i;
|
||||
u32 ctrl;
|
||||
|
||||
dev_dbg(chan2dev(&ch->vc.chan), "%s\n", __func__);
|
||||
dev_dbg(vchan_chan_dev(&ch->vc), "%s\n", __func__);
|
||||
|
||||
for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, ch++) {
|
||||
if (!ch->allocated)
|
||||
|
|
@ -525,7 +520,7 @@ static irqreturn_t moxart_dma_interrupt(int irq, void *devid)
|
|||
|
||||
ctrl = readl(ch->base + REG_OFF_CTRL);
|
||||
|
||||
dev_dbg(chan2dev(&ch->vc.chan), "%s: ch=%p ch->base=%p ctrl=%x\n",
|
||||
dev_dbg(vchan_chan_dev(&ch->vc), "%s: ch=%p ch->base=%p ctrl=%x\n",
|
||||
__func__, ch, ch->base, ctrl);
|
||||
|
||||
if (ctrl & APB_DMA_FIN_INT_STS) {
|
||||
|
|
|
|||
|
|
@ -583,8 +583,13 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
|
|||
while (src_cnt--) {
|
||||
/* Check if a new window needs to get added for 'src' */
|
||||
ret = mv_xor_add_io_win(mv_chan, src[src_cnt]);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
spin_lock_bh(&mv_chan->lock);
|
||||
list_move_tail(&sw_desc->node,
|
||||
&mv_chan->free_slots);
|
||||
spin_unlock_bh(&mv_chan->lock);
|
||||
return NULL;
|
||||
}
|
||||
mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1162,6 +1167,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
|
|||
|
||||
err_free_irq:
|
||||
free_irq(mv_chan->irq, mv_chan);
|
||||
tasklet_kill(&mv_chan->irq_tasklet);
|
||||
err_free_dma:
|
||||
dma_free_wc(&pdev->dev, MV_XOR_POOL_SIZE,
|
||||
mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool);
|
||||
|
|
|
|||
|
|
@ -1202,7 +1202,7 @@ static irqreturn_t nbpf_chan_irq(int irq, void *dev)
|
|||
|
||||
nbpf_status_ack(chan);
|
||||
|
||||
dev_dbg(&chan->dma_chan.dev->device, "%s()\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(&chan->dma_chan), "%s()\n", __func__);
|
||||
|
||||
spin_lock(&chan->lock);
|
||||
desc = chan->running;
|
||||
|
|
|
|||
|
|
@ -292,11 +292,6 @@ static inline struct owl_dma *to_owl_dma(struct dma_device *dd)
|
|||
return container_of(dd, struct owl_dma, dma);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline struct owl_dma_vchan *to_owl_vchan(struct dma_chan *chan)
|
||||
{
|
||||
return container_of(chan, struct owl_dma_vchan, vc.chan);
|
||||
|
|
@ -573,7 +568,7 @@ static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
|
|||
|
||||
spin_unlock_irqrestore(&od->lock, flags);
|
||||
|
||||
dev_dbg(chan2dev(&vchan->vc.chan), "starting pchan %d\n", pchan->id);
|
||||
dev_dbg(vchan_chan_dev(&vchan->vc), "starting pchan %d\n", pchan->id);
|
||||
|
||||
/* Start DMA transfer for this pchan */
|
||||
pchan_writel(pchan, OWL_DMAX_START, 0x1);
|
||||
|
|
@ -757,7 +752,7 @@ static int owl_dma_resume(struct dma_chan *chan)
|
|||
if (!vchan->pchan && !vchan->txd)
|
||||
return 0;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "vchan %p: resume\n", &vchan->vc);
|
||||
|
||||
spin_lock_irqsave(&vchan->vc.lock, flags);
|
||||
|
||||
|
|
@ -888,7 +883,7 @@ static struct dma_async_tx_descriptor
|
|||
for (offset = 0; offset < len; offset += bytes) {
|
||||
lli = owl_dma_alloc_lli(od);
|
||||
if (!lli) {
|
||||
dev_warn(chan2dev(chan), "failed to allocate lli\n");
|
||||
dev_warn(dmaengine_chan_dev(chan), "failed to allocate lli\n");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
@ -898,7 +893,7 @@ static struct dma_async_tx_descriptor
|
|||
bytes, DMA_MEM_TO_MEM,
|
||||
&vchan->cfg, txd->cyclic);
|
||||
if (ret) {
|
||||
dev_warn(chan2dev(chan), "failed to config lli\n");
|
||||
dev_warn(dmaengine_chan_dev(chan), "failed to config lli\n");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
@ -947,7 +942,7 @@ static struct dma_async_tx_descriptor
|
|||
|
||||
lli = owl_dma_alloc_lli(od);
|
||||
if (!lli) {
|
||||
dev_err(chan2dev(chan), "failed to allocate lli");
|
||||
dev_err(dmaengine_chan_dev(chan), "failed to allocate lli");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
@ -962,7 +957,7 @@ static struct dma_async_tx_descriptor
|
|||
ret = owl_dma_cfg_lli(vchan, lli, src, dst, len, dir, sconfig,
|
||||
txd->cyclic);
|
||||
if (ret) {
|
||||
dev_warn(chan2dev(chan), "failed to config lli");
|
||||
dev_warn(dmaengine_chan_dev(chan), "failed to config lli");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
@ -1003,7 +998,7 @@ static struct dma_async_tx_descriptor
|
|||
for (i = 0; i < periods; i++) {
|
||||
lli = owl_dma_alloc_lli(od);
|
||||
if (!lli) {
|
||||
dev_warn(chan2dev(chan), "failed to allocate lli");
|
||||
dev_warn(dmaengine_chan_dev(chan), "failed to allocate lli");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
@ -1018,7 +1013,7 @@ static struct dma_async_tx_descriptor
|
|||
ret = owl_dma_cfg_lli(vchan, lli, src, dst, period_len,
|
||||
dir, sconfig, txd->cyclic);
|
||||
if (ret) {
|
||||
dev_warn(chan2dev(chan), "failed to config lli");
|
||||
dev_warn(dmaengine_chan_dev(chan), "failed to config lli");
|
||||
goto err_txd_free;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,11 +150,6 @@ static inline struct pch_dma *to_pd(struct dma_device *ddev)
|
|||
return container_of(ddev, struct pch_dma, dma);
|
||||
}
|
||||
|
||||
static inline struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct pch_dma_desc *pdc_first_active(struct pch_dma_chan *pd_chan)
|
||||
{
|
||||
|
|
@ -189,7 +184,7 @@ static void pdc_enable_irq(struct dma_chan *chan, int enable)
|
|||
|
||||
dma_writel(pd, CTL2, val);
|
||||
|
||||
dev_dbg(chan2dev(chan), "pdc_enable_irq: chan %d -> %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "pdc_enable_irq: chan %d -> %x\n",
|
||||
chan->chan_id, val);
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +232,7 @@ static void pdc_set_dir(struct dma_chan *chan)
|
|||
dma_writel(pd, CTL3, val);
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(chan), "pdc_set_dir: chan %d -> %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "pdc_set_dir: chan %d -> %x\n",
|
||||
chan->chan_id, val);
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +266,7 @@ static void pdc_set_mode(struct dma_chan *chan, u32 mode)
|
|||
dma_writel(pd, CTL3, val);
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(chan), "pdc_set_mode: chan %d -> %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "pdc_set_mode: chan %d -> %x\n",
|
||||
chan->chan_id, val);
|
||||
}
|
||||
|
||||
|
|
@ -314,18 +309,18 @@ static bool pdc_is_idle(struct pch_dma_chan *pd_chan)
|
|||
static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc)
|
||||
{
|
||||
if (!pdc_is_idle(pd_chan)) {
|
||||
dev_err(chan2dev(&pd_chan->chan),
|
||||
dev_err(dmaengine_chan_dev(&pd_chan->chan),
|
||||
"BUG: Attempt to start non-idle channel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n",
|
||||
pd_chan->chan.chan_id, desc->regs.dev_addr);
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n",
|
||||
pd_chan->chan.chan_id, desc->regs.mem_addr);
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> size: %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "chan %d -> size: %x\n",
|
||||
pd_chan->chan.chan_id, desc->regs.size);
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n",
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "chan %d -> next: %x\n",
|
||||
pd_chan->chan.chan_id, desc->regs.next);
|
||||
|
||||
if (list_empty(&desc->tx_list)) {
|
||||
|
|
@ -382,8 +377,8 @@ static void pdc_handle_error(struct pch_dma_chan *pd_chan)
|
|||
if (!list_empty(&pd_chan->active_list))
|
||||
pdc_dostart(pd_chan, pdc_first_active(pd_chan));
|
||||
|
||||
dev_crit(chan2dev(&pd_chan->chan), "Bad descriptor submitted\n");
|
||||
dev_crit(chan2dev(&pd_chan->chan), "descriptor cookie: %d\n",
|
||||
dev_crit(dmaengine_chan_dev(&pd_chan->chan), "Bad descriptor submitted\n");
|
||||
dev_crit(dmaengine_chan_dev(&pd_chan->chan), "descriptor cookie: %d\n",
|
||||
bad_desc->txd.cookie);
|
||||
|
||||
pdc_chain_complete(pd_chan, bad_desc);
|
||||
|
|
@ -450,10 +445,10 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan)
|
|||
ret = desc;
|
||||
break;
|
||||
}
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "desc %p not ACKed\n", desc);
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "desc %p not ACKed\n", desc);
|
||||
}
|
||||
spin_unlock(&pd_chan->lock);
|
||||
dev_dbg(chan2dev(&pd_chan->chan), "scanned %d descriptors\n", i);
|
||||
dev_dbg(dmaengine_chan_dev(&pd_chan->chan), "scanned %d descriptors\n", i);
|
||||
|
||||
if (!ret) {
|
||||
ret = pdc_alloc_desc(&pd_chan->chan, GFP_ATOMIC);
|
||||
|
|
@ -462,7 +457,7 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan)
|
|||
pd_chan->descs_allocated++;
|
||||
spin_unlock(&pd_chan->lock);
|
||||
} else {
|
||||
dev_err(chan2dev(&pd_chan->chan),
|
||||
dev_err(dmaengine_chan_dev(&pd_chan->chan),
|
||||
"failed to alloc desc\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -489,7 +484,7 @@ static int pd_alloc_chan_resources(struct dma_chan *chan)
|
|||
int i;
|
||||
|
||||
if (!pdc_is_idle(pd_chan)) {
|
||||
dev_dbg(chan2dev(chan), "DMA channel not idle ?\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "DMA channel not idle ?\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -500,7 +495,7 @@ static int pd_alloc_chan_resources(struct dma_chan *chan)
|
|||
desc = pdc_alloc_desc(chan, GFP_KERNEL);
|
||||
|
||||
if (!desc) {
|
||||
dev_warn(chan2dev(chan),
|
||||
dev_warn(dmaengine_chan_dev(chan),
|
||||
"Only allocated %d initial descriptors\n", i);
|
||||
break;
|
||||
}
|
||||
|
|
@ -573,7 +568,7 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
|
|||
int i;
|
||||
|
||||
if (unlikely(!sg_len)) {
|
||||
dev_info(chan2dev(chan), "prep_slave_sg: length is zero!\n");
|
||||
dev_info(dmaengine_chan_dev(chan), "prep_slave_sg: length is zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -639,7 +634,7 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
|
|||
return &first->txd;
|
||||
|
||||
err_desc_get:
|
||||
dev_err(chan2dev(chan), "failed to get desc or wrong parameters\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "failed to get desc or wrong parameters\n");
|
||||
pdc_desc_put(pd_chan, first);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -671,7 +666,7 @@ static void pdc_tasklet(struct tasklet_struct *t)
|
|||
unsigned long flags;
|
||||
|
||||
if (!pdc_is_idle(pd_chan)) {
|
||||
dev_err(chan2dev(&pd_chan->chan),
|
||||
dev_err(dmaengine_chan_dev(&pd_chan->chan),
|
||||
"BUG: handle non-idle channel in tasklet\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2953,8 +2953,8 @@ DEFINE_SHOW_ATTRIBUTE(pl330_debugfs);
|
|||
|
||||
static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
|
||||
{
|
||||
pl330->dbgfs = debugfs_create_file(dev_name(pl330->ddma.dev),
|
||||
S_IFREG | 0444, NULL, pl330,
|
||||
pl330->dbgfs = debugfs_create_file("stats", 0444,
|
||||
pl330->ddma.dbg_dev_root, pl330,
|
||||
&pl330_debugfs_fops);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -504,17 +504,17 @@ static int plx_dma_create(struct pci_dev *pdev)
|
|||
if (!plxdev)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = request_irq(pci_irq_vector(pdev, 0), plx_dma_isr, 0,
|
||||
KBUILD_MODNAME, plxdev);
|
||||
if (rc)
|
||||
goto free_plx;
|
||||
|
||||
spin_lock_init(&plxdev->ring_lock);
|
||||
tasklet_setup(&plxdev->desc_task, plx_dma_desc_task);
|
||||
|
||||
RCU_INIT_POINTER(plxdev->pdev, pdev);
|
||||
plxdev->bar = pcim_iomap_table(pdev)[0];
|
||||
|
||||
rc = request_irq(pci_irq_vector(pdev, 0), plx_dma_isr, 0,
|
||||
KBUILD_MODNAME, plxdev);
|
||||
if (rc)
|
||||
goto free_plx;
|
||||
|
||||
dma = &plxdev->dma_dev;
|
||||
INIT_LIST_HEAD(&dma->channels);
|
||||
dma_cap_set(DMA_MEMCPY, dma->cap_mask);
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ static int ppc440spe_chan_xor_slot_count(size_t len, int src_cnt,
|
|||
if (likely(len <= PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT))
|
||||
return slot_cnt;
|
||||
|
||||
printk(KERN_ERR "%s: len %d > max %d !!\n",
|
||||
printk(KERN_ERR "%s: len %zu > max %d !!\n",
|
||||
__func__, len, PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT);
|
||||
BUG();
|
||||
return slot_cnt;
|
||||
|
|
@ -1989,7 +1989,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memcpy(
|
|||
spin_lock_bh(&ppc440spe_chan->lock);
|
||||
|
||||
dev_dbg(ppc440spe_chan->device->common.dev,
|
||||
"ppc440spe adma%d: %s len: %u int_en %d\n",
|
||||
"ppc440spe adma%d: %s len: %zu int_en %d\n",
|
||||
ppc440spe_chan->device->id, __func__, len,
|
||||
flags & DMA_PREP_INTERRUPT ? 1 : 0);
|
||||
slot_cnt = slots_per_op = 1;
|
||||
|
|
@ -2030,7 +2030,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_xor(
|
|||
BUG_ON(len > PPC440SPE_ADMA_XOR_MAX_BYTE_COUNT);
|
||||
|
||||
dev_dbg(ppc440spe_chan->device->common.dev,
|
||||
"ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
|
||||
"ppc440spe adma%d: %s src_cnt: %d len: %zu int_en: %d\n",
|
||||
ppc440spe_chan->device->id, __func__, src_cnt, len,
|
||||
flags & DMA_PREP_INTERRUPT ? 1 : 0);
|
||||
|
||||
|
|
@ -2279,7 +2279,7 @@ static struct ppc440spe_adma_desc_slot *ppc440spe_dma01_prep_pq(
|
|||
unsigned long op = 0;
|
||||
unsigned char mult = 1;
|
||||
|
||||
pr_debug("%s: dst_cnt %d, src_cnt %d, len %d\n",
|
||||
pr_debug("%s: dst_cnt %d, src_cnt %d, len %zu\n",
|
||||
__func__, dst_cnt, src_cnt, len);
|
||||
/* select operations WXOR/RXOR depending on the
|
||||
* source addresses of operators and the number
|
||||
|
|
@ -2553,7 +2553,7 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_pq(
|
|||
BUG_ON(!dst_cnt);
|
||||
|
||||
dev_dbg(ppc440spe_chan->device->common.dev,
|
||||
"ppc440spe adma%d: %s src_cnt: %d len: %u int_en: %d\n",
|
||||
"ppc440spe adma%d: %s src_cnt: %d len: %zu int_en: %d\n",
|
||||
ppc440spe_chan->device->id, __func__, src_cnt, len,
|
||||
flags & DMA_PREP_INTERRUPT ? 1 : 0);
|
||||
|
||||
|
|
@ -4077,7 +4077,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
|
|||
adev->pool_size, &adev->dma_desc_pool,
|
||||
GFP_KERNEL);
|
||||
if (adev->dma_desc_pool_virt == NULL) {
|
||||
dev_err(&ofdev->dev, "failed to allocate %d bytes of coherent "
|
||||
dev_err(&ofdev->dev, "failed to allocate %zu bytes of coherent "
|
||||
"memory for hardware descriptors\n",
|
||||
adev->pool_size);
|
||||
initcode = PPC_ADMA_INIT_COHERENT;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Number of XOR engines available on the contoller */
|
||||
/* Number of XOR engines available on the controller */
|
||||
#define XOR_ENGINES_NUM 1
|
||||
|
||||
/* Number of operands supported in the h/w */
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ struct pxad_device {
|
|||
({ \
|
||||
u32 _v; \
|
||||
_v = readl_relaxed((phy)->base + _reg((phy)->idx)); \
|
||||
dev_vdbg(&phy->vchan->vc.chan.dev->device, \
|
||||
dev_vdbg(vchan_chan_dev(&phy->vchan->vc), \
|
||||
"%s(): readl(%s): 0x%08x\n", __func__, #_reg, \
|
||||
_v); \
|
||||
_v; \
|
||||
|
|
@ -157,14 +157,14 @@ struct pxad_device {
|
|||
#define phy_writel(phy, val, _reg) \
|
||||
do { \
|
||||
writel((val), (phy)->base + _reg((phy)->idx)); \
|
||||
dev_vdbg(&phy->vchan->vc.chan.dev->device, \
|
||||
dev_vdbg(vchan_chan_dev(&phy->vchan->vc), \
|
||||
"%s(): writel(0x%08x, %s)\n", \
|
||||
__func__, (u32)(val), #_reg); \
|
||||
} while (0)
|
||||
#define phy_writel_relaxed(phy, val, _reg) \
|
||||
do { \
|
||||
writel_relaxed((val), (phy)->base + _reg((phy)->idx)); \
|
||||
dev_vdbg(&phy->vchan->vc.chan.dev->device, \
|
||||
dev_vdbg(vchan_chan_dev(&phy->vchan->vc), \
|
||||
"%s(): writel_relaxed(0x%08x, %s)\n", \
|
||||
__func__, (u32)(val), #_reg); \
|
||||
} while (0)
|
||||
|
|
@ -396,7 +396,7 @@ static struct pxad_phy *lookup_phy(struct pxad_chan *pchan)
|
|||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&pdev->phy_lock, flags);
|
||||
dev_dbg(&pchan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&pchan->vc),
|
||||
"%s(): phy=%p(%d)\n", __func__, found,
|
||||
found ? found->idx : -1);
|
||||
|
||||
|
|
@ -409,7 +409,7 @@ static void pxad_free_phy(struct pxad_chan *chan)
|
|||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): freeing\n", __func__);
|
||||
if (!chan->phy)
|
||||
return;
|
||||
|
|
@ -454,7 +454,7 @@ static void phy_enable(struct pxad_phy *phy, bool misaligned)
|
|||
if (!phy->vchan)
|
||||
return;
|
||||
|
||||
dev_dbg(&phy->vchan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&phy->vchan->vc),
|
||||
"%s(); phy=%p(%d) misaligned=%d\n", __func__,
|
||||
phy, phy->idx, misaligned);
|
||||
|
||||
|
|
@ -483,7 +483,7 @@ static void phy_disable(struct pxad_phy *phy)
|
|||
return;
|
||||
|
||||
dcsr = phy_readl_relaxed(phy, DCSR);
|
||||
dev_dbg(&phy->vchan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&phy->vchan->vc),
|
||||
"%s(): phy=%p(%d)\n", __func__, phy, phy->idx);
|
||||
phy_writel(phy, dcsr & ~PXA_DCSR_RUN & ~PXA_DCSR_STOPIRQEN, DCSR);
|
||||
}
|
||||
|
|
@ -491,12 +491,12 @@ static void phy_disable(struct pxad_phy *phy)
|
|||
static void pxad_launch_chan(struct pxad_chan *chan,
|
||||
struct pxad_desc_sw *desc)
|
||||
{
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): desc=%p\n", __func__, desc);
|
||||
if (!chan->phy) {
|
||||
chan->phy = lookup_phy(chan);
|
||||
if (!chan->phy) {
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): no free dma channel\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
|
@ -592,7 +592,7 @@ static unsigned int clear_chan_irq(struct pxad_phy *phy)
|
|||
dcsr = phy_readl_relaxed(phy, DCSR);
|
||||
phy_writel(phy, dcsr, DCSR);
|
||||
if ((dcsr & PXA_DCSR_BUSERR) && (phy->vchan))
|
||||
dev_warn(&phy->vchan->vc.chan.dev->device,
|
||||
dev_warn(vchan_chan_dev(&phy->vchan->vc),
|
||||
"%s(chan=%p): PXA_DCSR_BUSERR\n",
|
||||
__func__, &phy->vchan);
|
||||
|
||||
|
|
@ -617,7 +617,7 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
|
|||
spin_lock(&chan->vc.lock);
|
||||
list_for_each_entry_safe(vd, tmp, &chan->vc.desc_issued, node) {
|
||||
vd_completed = is_desc_completed(vd);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): checking txd %p[%x]: completed=%d dcsr=0x%x\n",
|
||||
__func__, vd, vd->tx.cookie, vd_completed,
|
||||
dcsr);
|
||||
|
|
@ -640,7 +640,7 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (!chan->bus_error && dcsr & PXA_DCSR_STOPSTATE) {
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): channel stopped, submitted_empty=%d issued_empty=%d",
|
||||
__func__,
|
||||
list_empty(&chan->vc.desc_submitted),
|
||||
|
|
@ -694,7 +694,7 @@ static int pxad_alloc_chan_resources(struct dma_chan *dchan)
|
|||
__alignof__(struct pxad_desc_hw),
|
||||
0);
|
||||
if (!chan->desc_pool) {
|
||||
dev_err(&chan->vc.chan.dev->device,
|
||||
dev_err(vchan_chan_dev(&chan->vc),
|
||||
"%s(): unable to allocate descriptor pool\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
|
|
@ -750,7 +750,7 @@ pxad_alloc_desc(struct pxad_chan *chan, unsigned int nb_hw_desc)
|
|||
for (i = 0; i < nb_hw_desc; i++) {
|
||||
desc = dma_pool_alloc(sw_desc->desc_pool, GFP_NOWAIT, &dma);
|
||||
if (!desc) {
|
||||
dev_err(&chan->vc.chan.dev->device,
|
||||
dev_err(vchan_chan_dev(&chan->vc),
|
||||
"%s(): Couldn't allocate the %dth hw_desc from dma_pool %p\n",
|
||||
__func__, i, sw_desc->desc_pool);
|
||||
sw_desc->nb_desc = i;
|
||||
|
|
@ -787,7 +787,7 @@ static dma_cookie_t pxad_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
|
||||
if (list_empty(&vc->desc_submitted) && pxad_try_hotchain(vc, vd)) {
|
||||
list_move_tail(&vd->node, &vc->desc_issued);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): txd %p[%x]: submitted (hot linked)\n",
|
||||
__func__, vd, cookie);
|
||||
goto out;
|
||||
|
|
@ -810,7 +810,7 @@ static dma_cookie_t pxad_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
else
|
||||
vd_chained = NULL;
|
||||
}
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): txd %p[%x]: submitted (%s linked)\n",
|
||||
__func__, vd, cookie, vd_chained ? "cold" : "not");
|
||||
list_move_tail(&vd->node, &vc->desc_submitted);
|
||||
|
|
@ -833,7 +833,7 @@ static void pxad_issue_pending(struct dma_chan *dchan)
|
|||
|
||||
vd_first = list_first_entry(&chan->vc.desc_submitted,
|
||||
struct virt_dma_desc, node);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): txd %p[%x]", __func__, vd_first, vd_first->tx.cookie);
|
||||
|
||||
vchan_issue_pending(&chan->vc);
|
||||
|
|
@ -853,7 +853,7 @@ pxad_tx_prep(struct virt_dma_chan *vc, struct virt_dma_desc *vd,
|
|||
INIT_LIST_HEAD(&vd->node);
|
||||
tx = vchan_tx_prep(vc, vd, tx_flags);
|
||||
tx->tx_submit = pxad_tx_submit;
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): vc=%p txd=%p[%x] flags=0x%lx\n", __func__,
|
||||
vc, vd, vd->tx.cookie,
|
||||
tx_flags);
|
||||
|
|
@ -892,7 +892,7 @@ static void pxad_get_config(struct pxad_chan *chan,
|
|||
*dcmd |= PXA_DCMD_BURST32 | PXA_DCMD_INCTRGADDR |
|
||||
PXA_DCMD_INCSRCADDR;
|
||||
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): dev_addr=0x%x maxburst=%d width=%d dir=%d\n",
|
||||
__func__, dev_addr, maxburst, width, dir);
|
||||
|
||||
|
|
@ -926,7 +926,7 @@ pxad_prep_memcpy(struct dma_chan *dchan,
|
|||
if (!dchan || !len)
|
||||
return NULL;
|
||||
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): dma_dst=0x%lx dma_src=0x%lx len=%zu flags=%lx\n",
|
||||
__func__, (unsigned long)dma_dst, (unsigned long)dma_src,
|
||||
len, flags);
|
||||
|
|
@ -975,7 +975,7 @@ pxad_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
|||
return NULL;
|
||||
|
||||
pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): dir=%d flags=%lx\n", __func__, dir, flags);
|
||||
|
||||
nb_desc = sg_nents_for_dma(sgl, sg_len, PDMA_MAX_DESC_BYTES);
|
||||
|
|
@ -1022,7 +1022,7 @@ pxad_prep_dma_cyclic(struct dma_chan *dchan,
|
|||
if (!dchan || !len || !period_len)
|
||||
return NULL;
|
||||
if ((dir != DMA_DEV_TO_MEM) && (dir != DMA_MEM_TO_DEV)) {
|
||||
dev_err(&chan->vc.chan.dev->device,
|
||||
dev_err(vchan_chan_dev(&chan->vc),
|
||||
"Unsupported direction for cyclic DMA\n");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1033,7 +1033,7 @@ pxad_prep_dma_cyclic(struct dma_chan *dchan,
|
|||
|
||||
pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr);
|
||||
dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH & period_len);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): buf_addr=0x%lx len=%zu period=%zu dir=%d flags=%lx\n",
|
||||
__func__, (unsigned long)buf_addr, len, period_len, dir, flags);
|
||||
|
||||
|
|
@ -1081,14 +1081,14 @@ static int pxad_terminate_all(struct dma_chan *dchan)
|
|||
struct pxad_phy *phy;
|
||||
LIST_HEAD(head);
|
||||
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): vchan %p: terminate all\n", __func__, &chan->vc);
|
||||
|
||||
spin_lock_irqsave(&chan->vc.lock, flags);
|
||||
vchan_get_all_descriptors(&chan->vc, &head);
|
||||
|
||||
list_for_each_entry(vd, &head, node) {
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): cancelling txd %p[%x] (completed=%d)", __func__,
|
||||
vd, vd->tx.cookie, is_desc_completed(vd));
|
||||
}
|
||||
|
|
@ -1178,7 +1178,7 @@ static unsigned int pxad_residue(struct pxad_chan *chan,
|
|||
|
||||
out:
|
||||
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
dev_dbg(&chan->vc.chan.dev->device,
|
||||
dev_dbg(vchan_chan_dev(&chan->vc),
|
||||
"%s(): txd %p[%x] sw_desc=%p: %d\n",
|
||||
__func__, vd, cookie, sw_desc, residue);
|
||||
return residue;
|
||||
|
|
|
|||
|
|
@ -1332,8 +1332,8 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < bdev->num_channels; i++)
|
||||
bam_channel_init(bdev, &bdev->channels[i], i);
|
||||
|
||||
ret = devm_request_irq(bdev->dev, bdev->irq, bam_dma_irq,
|
||||
IRQF_TRIGGER_HIGH, "bam_dma", bdev);
|
||||
ret = request_irq(bdev->irq, bam_dma_irq, IRQF_TRIGGER_NONE,
|
||||
"bam_dma", bdev);
|
||||
if (ret)
|
||||
goto err_bam_channel_exit;
|
||||
|
||||
|
|
@ -1366,7 +1366,7 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
ret = dma_async_device_register(&bdev->common);
|
||||
if (ret) {
|
||||
dev_err(bdev->dev, "failed to register dma async device\n");
|
||||
goto err_bam_channel_exit;
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = of_dma_controller_register(pdev->dev.of_node, bam_dma_xlate,
|
||||
|
|
@ -1385,6 +1385,8 @@ static int bam_dma_probe(struct platform_device *pdev)
|
|||
|
||||
err_unregister_dma:
|
||||
dma_async_device_unregister(&bdev->common);
|
||||
err_free_irq:
|
||||
free_irq(bdev->irq, bdev);
|
||||
err_bam_channel_exit:
|
||||
for (i = 0; i < bdev->num_channels; i++)
|
||||
tasklet_kill(&bdev->channels[i].vc.task);
|
||||
|
|
@ -1410,7 +1412,7 @@ static void bam_dma_remove(struct platform_device *pdev)
|
|||
/* mask all interrupts for this execution environment */
|
||||
writel_relaxed(0, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
|
||||
|
||||
devm_free_irq(bdev->dev, bdev->irq, bdev);
|
||||
free_irq(bdev->irq, bdev);
|
||||
|
||||
for (i = 0; i < bdev->num_channels; i++) {
|
||||
bam_dma_terminate_all(&bdev->channels[i].vc.chan);
|
||||
|
|
|
|||
|
|
@ -1965,16 +1965,19 @@ static int gpi_ch_init(struct gchan *gchan)
|
|||
error_start_chan:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
gpi_stop_chan(&gpii->gchan[i]);
|
||||
gpi_send_cmd(gpii, gchan, GPI_CH_CMD_RESET);
|
||||
gpi_send_cmd(gpii, &gpii->gchan[i], GPI_CH_CMD_RESET);
|
||||
}
|
||||
i = 2;
|
||||
error_alloc_chan:
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
gpi_reset_chan(gchan, GPI_CH_CMD_DE_ALLOC);
|
||||
gpi_reset_chan(&gpii->gchan[i], GPI_CH_CMD_DE_ALLOC);
|
||||
error_alloc_ev_ring:
|
||||
gpi_disable_interrupts(gpii);
|
||||
error_config_int:
|
||||
gpi_free_ring(&gpii->ev_ring, gpii);
|
||||
write_lock_irq(&gpii->pm_lock);
|
||||
gpii->pm_state = DISABLE_STATE;
|
||||
write_unlock_irq(&gpii->pm_lock);
|
||||
exit_gpi_init:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2065,6 +2068,8 @@ static int gpi_alloc_chan_resources(struct dma_chan *chan)
|
|||
goto xfer_alloc_err;
|
||||
|
||||
ret = gpi_ch_init(gchan);
|
||||
if (ret)
|
||||
gpi_free_ring(&gchan->ch_ring, gpii);
|
||||
|
||||
mutex_unlock(&gpii->ctrl_lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -935,10 +935,10 @@ static void hidma_remove(struct platform_device *pdev)
|
|||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
static const struct acpi_device_id hidma_acpi_ids[] = {
|
||||
{"QCOM8061"},
|
||||
{"QCOM8062", HIDMA_MSI_CAP},
|
||||
{"QCOM8063", (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP)},
|
||||
{},
|
||||
{ .id = "QCOM8061" },
|
||||
{ .id = "QCOM8062", .driver_data = HIDMA_MSI_CAP },
|
||||
{ .id = "QCOM8063", .driver_data = (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -219,10 +219,12 @@ struct rcar_dmac {
|
|||
* struct rcar_dmac_of_data - This driver's OF data
|
||||
* @chan_offset_base: DMAC channels base offset
|
||||
* @chan_offset_stride: DMAC channels offset stride
|
||||
* @broken_ipmmu_microTLB0: flag if the connected IPMMU has microTLB0 issues
|
||||
*/
|
||||
struct rcar_dmac_of_data {
|
||||
u32 chan_offset_base;
|
||||
u32 chan_offset_stride;
|
||||
unsigned int broken_ipmmu_microTLB0:1;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
|
@ -1877,8 +1879,9 @@ static int rcar_dmac_probe(struct platform_device *pdev)
|
|||
* can't use it with the IPMMU. As the IOMMU API operates at the device
|
||||
* level we can't disable it selectively, so ignore channel 0 for now if
|
||||
* the device is part of an IOMMU group.
|
||||
* Not applicable if system uses something else than IPMMU like SMMU.
|
||||
*/
|
||||
if (device_iommu_mapped(&pdev->dev))
|
||||
if (data->broken_ipmmu_microTLB0 && device_iommu_mapped(&pdev->dev))
|
||||
dmac->channels_mask &= ~BIT(0);
|
||||
|
||||
dmac->channels = devm_kcalloc(&pdev->dev, dmac->n_channels,
|
||||
|
|
@ -1998,13 +2001,21 @@ static void rcar_dmac_shutdown(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct rcar_dmac_of_data rcar_dmac_data = {
|
||||
.chan_offset_base = 0x8000,
|
||||
.chan_offset_stride = 0x80,
|
||||
.chan_offset_base = 0x8000,
|
||||
.chan_offset_stride = 0x80,
|
||||
.broken_ipmmu_microTLB0 = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_dmac_of_data rcar_gen4_dmac_data = {
|
||||
.chan_offset_base = 0x0,
|
||||
.chan_offset_stride = 0x1000,
|
||||
.chan_offset_base = 0x0,
|
||||
.chan_offset_stride = 0x1000,
|
||||
/* Set to play safe. Needs testing if Gen4 is really affected */
|
||||
.broken_ipmmu_microTLB0 = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_dmac_of_data rcar_gen5_dmac_data = {
|
||||
.chan_offset_base = 0x0,
|
||||
.chan_offset_stride = 0x1000,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_dmac_of_ids[] = {
|
||||
|
|
@ -2014,6 +2025,9 @@ static const struct of_device_id rcar_dmac_of_ids[] = {
|
|||
}, {
|
||||
.compatible = "renesas,rcar-gen4-dmac",
|
||||
.data = &rcar_gen4_dmac_data,
|
||||
}, {
|
||||
.compatible = "renesas,rcar-gen5-dmac",
|
||||
.data = &rcar_gen5_dmac_data,
|
||||
}, {
|
||||
/*
|
||||
* Backward compatibility for between v5.12 - v5.19
|
||||
|
|
@ -2039,6 +2053,6 @@ static struct platform_driver rcar_dmac_driver = {
|
|||
|
||||
module_platform_driver(rcar_dmac_driver);
|
||||
|
||||
MODULE_DESCRIPTION("R-Car Gen2 DMA Controller Driver");
|
||||
MODULE_DESCRIPTION("R-Car DMA Controller Driver");
|
||||
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -937,7 +937,7 @@ static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel,
|
|||
struct rz_dmac *dmac = to_rz_dmac(chan->device);
|
||||
u32 residue = 0, i = 0;
|
||||
|
||||
while (lmdesc->nxla != crla) {
|
||||
while (rz_dmac_lmdesc_addr(channel, lmdesc) != crla) {
|
||||
lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc);
|
||||
if (++i >= DMAC_NR_LMDESC)
|
||||
return 0;
|
||||
|
|
@ -948,13 +948,13 @@ static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel,
|
|||
u32 start_lmdesc_addr = rz_dmac_lmdesc_addr(channel, desc->start_lmdesc);
|
||||
|
||||
while (lmdesc->nxla != start_lmdesc_addr) {
|
||||
residue += lmdesc->tb;
|
||||
lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc);
|
||||
residue += lmdesc->tb;
|
||||
}
|
||||
} else {
|
||||
while (lmdesc->chcfg & CHCFG_DEM) {
|
||||
residue += lmdesc->tb;
|
||||
lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc);
|
||||
residue += lmdesc->tb;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,8 +208,7 @@ struct sprd_dma_chn {
|
|||
struct sprd_dma_dev {
|
||||
struct dma_device dma_dev;
|
||||
void __iomem *glb_base;
|
||||
struct clk *clk;
|
||||
struct clk *ashb_clk;
|
||||
struct clk_bulk_data clks[2];
|
||||
int irq;
|
||||
u32 total_chns;
|
||||
struct sprd_dma_chn channels[] __counted_by(total_chns);
|
||||
|
|
@ -260,31 +259,12 @@ static void sprd_dma_chn_update(struct sprd_dma_chn *schan, u32 reg,
|
|||
|
||||
static int sprd_dma_enable(struct sprd_dma_dev *sdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sdev->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The ashb_clk is optional and only for AGCP DMA controller, so we
|
||||
* need add one condition to check if the ashb_clk need enable.
|
||||
*/
|
||||
if (!IS_ERR(sdev->ashb_clk))
|
||||
ret = clk_prepare_enable(sdev->ashb_clk);
|
||||
|
||||
return ret;
|
||||
return clk_bulk_prepare_enable(ARRAY_SIZE(sdev->clks), sdev->clks);
|
||||
}
|
||||
|
||||
static void sprd_dma_disable(struct sprd_dma_dev *sdev)
|
||||
{
|
||||
clk_disable_unprepare(sdev->clk);
|
||||
|
||||
/*
|
||||
* Need to check if we need disable the optional ashb_clk for AGCP DMA.
|
||||
*/
|
||||
if (!IS_ERR(sdev->ashb_clk))
|
||||
clk_disable_unprepare(sdev->ashb_clk);
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(sdev->clks), sdev->clks);
|
||||
}
|
||||
|
||||
static void sprd_dma_set_uid(struct sprd_dma_chn *schan)
|
||||
|
|
@ -1140,16 +1120,17 @@ static int sprd_dma_probe(struct platform_device *pdev)
|
|||
if (!sdev)
|
||||
return -ENOMEM;
|
||||
|
||||
sdev->clk = devm_clk_get(&pdev->dev, "enable");
|
||||
if (IS_ERR(sdev->clk)) {
|
||||
dev_err(&pdev->dev, "get enable clock failed\n");
|
||||
return PTR_ERR(sdev->clk);
|
||||
}
|
||||
/* The ashb_eb clock is optional and only present for AGCP DMA */
|
||||
sdev->clks[0].id = "enable";
|
||||
sdev->clks[1].id = "ashb_eb";
|
||||
ret = devm_clk_bulk_get_optional(&pdev->dev, ARRAY_SIZE(sdev->clks),
|
||||
sdev->clks);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "get clocks failed\n");
|
||||
|
||||
/* ashb clock is optional for AGCP DMA */
|
||||
sdev->ashb_clk = devm_clk_get(&pdev->dev, "ashb_eb");
|
||||
if (IS_ERR(sdev->ashb_clk))
|
||||
dev_warn(&pdev->dev, "no optional ashb eb clock\n");
|
||||
if (!sdev->clks[0].clk)
|
||||
return dev_err_probe(&pdev->dev, -ENOENT,
|
||||
"get enable clock failed\n");
|
||||
|
||||
/*
|
||||
* We have three DMA controllers: AP DMA, AON DMA and AGCP DMA. For AGCP
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ static int st_fdma_alloc_chan_res(struct dma_chan *chan)
|
|||
struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
|
||||
|
||||
/* Create the dma pool for descriptor allocation */
|
||||
fchan->node_pool = dma_pool_create(dev_name(&chan->dev->device),
|
||||
fchan->node_pool = dma_pool_create(dma_chan_name(chan),
|
||||
fchan->fdev->dev,
|
||||
sizeof(struct st_fdma_hw_node),
|
||||
__alignof__(struct st_fdma_hw_node),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -333,10 +333,10 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst,
|
|||
(dlos << D40_MEM_LCSP1_SLOS_POS);
|
||||
}
|
||||
|
||||
void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
|
||||
struct d40_log_lli *lli_dst,
|
||||
struct d40_log_lli *lli_src,
|
||||
int next, unsigned int flags)
|
||||
void d40_log_lli_lcpa_write(struct d40_log_lli_full __iomem *lcpa,
|
||||
struct d40_log_lli *lli_dst,
|
||||
struct d40_log_lli *lli_src,
|
||||
int next, unsigned int flags)
|
||||
{
|
||||
d40_log_lli_link(lli_dst, lli_src, next, flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
#define D40_TYPE_TO_GROUP(type) (type / 16)
|
||||
#define D40_TYPE_TO_EVENT(type) (type % 16)
|
||||
#define D40_GROUP_SIZE 8
|
||||
#define D40_PHYS_TO_GROUP(phys) ((phys & (D40_GROUP_SIZE - 1)) / 2)
|
||||
|
||||
/* Most bits of the CFG register are the same in log as in phy mode */
|
||||
#define D40_SREG_CFG_MST_POS 15
|
||||
|
|
@ -457,7 +455,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
|
|||
u32 lcsp13, /* src or dst*/
|
||||
u32 data_width1, u32 data_width2);
|
||||
|
||||
void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
|
||||
void d40_log_lli_lcpa_write(struct d40_log_lli_full __iomem *lcpa,
|
||||
struct d40_log_lli *lli_dst,
|
||||
struct d40_log_lli *lli_src,
|
||||
int next, unsigned int flags);
|
||||
|
|
|
|||
|
|
@ -248,11 +248,6 @@ static struct stm32_dma_desc *to_stm32_dma_desc(struct virt_dma_desc *vdesc)
|
|||
return container_of(vdesc, struct stm32_dma_desc, vdesc);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct stm32_dma_chan *chan)
|
||||
{
|
||||
return &chan->vchan.chan.dev->device;
|
||||
}
|
||||
|
||||
static u32 stm32_dma_read(struct stm32_dma_device *dmadev, u32 reg)
|
||||
{
|
||||
return readl_relaxed(dmadev->base + reg);
|
||||
|
|
@ -274,7 +269,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan,
|
|||
case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||
return STM32_DMA_WORD;
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Dma bus width not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Dma bus width not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -374,7 +369,7 @@ static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst)
|
|||
case 16:
|
||||
return STM32_DMA_BURST_INCR16;
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Dma burst size not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Dma burst size not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -487,7 +482,7 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan)
|
|||
/* Clear interrupt status if it is there */
|
||||
status = stm32_dma_irq_status(chan);
|
||||
if (status) {
|
||||
dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "%s(): clearing interrupt: 0x%08x\n",
|
||||
__func__, status);
|
||||
stm32_dma_irq_clear(chan, status);
|
||||
}
|
||||
|
|
@ -536,12 +531,12 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
|
|||
u32 sm1ar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id));
|
||||
u32 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
|
||||
|
||||
dev_dbg(chan2dev(chan), "SCR: 0x%08x\n", scr);
|
||||
dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n", ndtr);
|
||||
dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n", spar);
|
||||
dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n", sm0ar);
|
||||
dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n", sm1ar);
|
||||
dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "SCR: 0x%08x\n", scr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "NDTR: 0x%08x\n", ndtr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "SPAR: 0x%08x\n", spar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "SM0AR: 0x%08x\n", sm0ar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "SM1AR: 0x%08x\n", sm1ar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "SFCR: 0x%08x\n", sfcr);
|
||||
}
|
||||
|
||||
static void stm32_dma_sg_inc(struct stm32_dma_chan *chan)
|
||||
|
|
@ -613,7 +608,7 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan)
|
|||
reg->dma_scr |= STM32_DMA_SCR_EN;
|
||||
stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: started\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: started\n", &chan->vchan);
|
||||
}
|
||||
|
||||
static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
|
||||
|
|
@ -630,12 +625,12 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
|
|||
if (dma_scr & STM32_DMA_SCR_CT) {
|
||||
dma_sm0ar = sg_req->chan_reg.dma_sm0ar;
|
||||
stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar);
|
||||
dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CT=1 <=> SM0AR: 0x%08x\n",
|
||||
stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)));
|
||||
} else {
|
||||
dma_sm1ar = sg_req->chan_reg.dma_sm1ar;
|
||||
stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar);
|
||||
dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CT=0 <=> SM1AR: 0x%08x\n",
|
||||
stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)));
|
||||
}
|
||||
}
|
||||
|
|
@ -676,7 +671,7 @@ static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan)
|
|||
|
||||
chan->status = DMA_PAUSED;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: paused\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: paused\n", &chan->vchan);
|
||||
}
|
||||
|
||||
static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan)
|
||||
|
|
@ -728,7 +723,7 @@ static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan)
|
|||
dma_scr |= STM32_DMA_SCR_EN;
|
||||
stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: reconfigured after pause/resume\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: reconfigured after pause/resume\n", &chan->vchan);
|
||||
}
|
||||
|
||||
static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr)
|
||||
|
|
@ -775,16 +770,16 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
|
|||
if (sfcr & STM32_DMA_SFCR_FEIE) {
|
||||
if (!(scr & STM32_DMA_SCR_EN) &&
|
||||
!(status & STM32_DMA_TCI))
|
||||
dev_err(chan2dev(chan), "FIFO Error\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "FIFO Error\n");
|
||||
else
|
||||
dev_dbg(chan2dev(chan), "FIFO over/underrun\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "FIFO over/underrun\n");
|
||||
}
|
||||
}
|
||||
if (status & STM32_DMA_DMEI) {
|
||||
stm32_dma_irq_clear(chan, STM32_DMA_DMEI);
|
||||
status &= ~STM32_DMA_DMEI;
|
||||
if (sfcr & STM32_DMA_SCR_DMEIE)
|
||||
dev_dbg(chan2dev(chan), "Direct mode overrun\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "Direct mode overrun\n");
|
||||
}
|
||||
|
||||
if (status & STM32_DMA_TCI) {
|
||||
|
|
@ -803,9 +798,9 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
|
|||
|
||||
if (status) {
|
||||
stm32_dma_irq_clear(chan, status);
|
||||
dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "DMA error: status=0x%08x\n", status);
|
||||
if (!(scr & STM32_DMA_SCR_EN))
|
||||
dev_err(chan2dev(chan), "chan disabled by HW\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "chan disabled by HW\n");
|
||||
}
|
||||
|
||||
spin_unlock(&chan->vchan.lock);
|
||||
|
|
@ -820,7 +815,7 @@ static void stm32_dma_issue_pending(struct dma_chan *c)
|
|||
|
||||
spin_lock_irqsave(&chan->vchan.lock, flags);
|
||||
if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) {
|
||||
dev_dbg(chan2dev(chan), "vchan %p: issued\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: issued\n", &chan->vchan);
|
||||
stm32_dma_start_transfer(chan);
|
||||
|
||||
}
|
||||
|
|
@ -922,7 +917,7 @@ static int stm32_dma_resume(struct dma_chan *c)
|
|||
|
||||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: resumed\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: resumed\n", &chan->vchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1059,7 +1054,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Dma direction is not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Dma direction is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1092,12 +1087,12 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
|
|||
int i, ret;
|
||||
|
||||
if (!chan->config_init) {
|
||||
dev_err(chan2dev(chan), "dma channel is not configured\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "dma channel is not configured\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sg_len < 1) {
|
||||
dev_err(chan2dev(chan), "Invalid segment length %d\n", sg_len);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid segment length %d\n", sg_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1129,7 +1124,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
|
|||
|
||||
nb_data_items = desc->sg_req[i].len / buswidth;
|
||||
if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) {
|
||||
dev_err(chan2dev(chan), "nb items not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "nb items not supported\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -1164,17 +1159,17 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic(
|
|||
int i, ret;
|
||||
|
||||
if (!buf_len || !period_len) {
|
||||
dev_err(chan2dev(chan), "Invalid buffer/period len\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid buffer/period len\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!chan->config_init) {
|
||||
dev_err(chan2dev(chan), "dma channel is not configured\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "dma channel is not configured\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf_len % period_len) {
|
||||
dev_err(chan2dev(chan), "buf_len not multiple of period_len\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "buf_len not multiple of period_len\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1185,7 +1180,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic(
|
|||
* terminating the DMA.
|
||||
*/
|
||||
if (chan->busy) {
|
||||
dev_err(chan2dev(chan), "Request not allowed when dma busy\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Request not allowed when dma busy\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1196,7 +1191,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic(
|
|||
|
||||
nb_data_items = period_len / buswidth;
|
||||
if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) {
|
||||
dev_err(chan2dev(chan), "number of items not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "number of items not supported\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1478,7 +1473,7 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c)
|
|||
struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "Freeing channel %d\n", chan->id);
|
||||
|
||||
if (chan->busy) {
|
||||
spin_lock_irqsave(&chan->vchan.lock, flags);
|
||||
|
|
@ -1668,7 +1663,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_irq(&pdev->dev, chan->irq,
|
||||
stm32_dma_chan_irq, 0,
|
||||
dev_name(chan2dev(chan)), chan);
|
||||
vchan_chan_name(&chan->vchan), chan);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"request_irq failed with err %d channel %d\n",
|
||||
|
|
|
|||
|
|
@ -328,11 +328,6 @@ static inline struct stm32_dma3_swdesc *to_stm32_dma3_swdesc(struct virt_dma_des
|
|||
return container_of(vdesc, struct stm32_dma3_swdesc, vdesc);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct stm32_dma3_chan *chan)
|
||||
{
|
||||
return &chan->vchan.chan.dev->device;
|
||||
}
|
||||
|
||||
static struct device *ddata2dev(struct stm32_dma3_ddata *ddata)
|
||||
{
|
||||
return ddata->dma_dev.dev;
|
||||
|
|
@ -341,7 +336,7 @@ static struct device *ddata2dev(struct stm32_dma3_ddata *ddata)
|
|||
static void stm32_dma3_chan_dump_reg(struct stm32_dma3_chan *chan)
|
||||
{
|
||||
struct stm32_dma3_ddata *ddata = to_stm32_dma3_ddata(chan);
|
||||
struct device *dev = chan2dev(chan);
|
||||
struct device *dev = vchan_chan_dev(&chan->vchan);
|
||||
u32 id = chan->id, offset;
|
||||
|
||||
offset = STM32_DMA3_SECCFGR;
|
||||
|
|
@ -381,21 +376,21 @@ static void stm32_dma3_chan_dump_hwdesc(struct stm32_dma3_chan *chan,
|
|||
for (i = 0; i < swdesc->lli_size; i++) {
|
||||
hwdesc = swdesc->lli[i].hwdesc;
|
||||
if (i)
|
||||
dev_dbg(chan2dev(chan), "V\n");
|
||||
dev_dbg(chan2dev(chan), "[%d]@%pad\n", i, &swdesc->lli[i].hwdesc_addr);
|
||||
dev_dbg(chan2dev(chan), "| C%dTR1: %08x\n", chan->id, hwdesc->ctr1);
|
||||
dev_dbg(chan2dev(chan), "| C%dTR2: %08x\n", chan->id, hwdesc->ctr2);
|
||||
dev_dbg(chan2dev(chan), "| C%dBR1: %08x\n", chan->id, hwdesc->cbr1);
|
||||
dev_dbg(chan2dev(chan), "| C%dSAR: %08x\n", chan->id, hwdesc->csar);
|
||||
dev_dbg(chan2dev(chan), "| C%dDAR: %08x\n", chan->id, hwdesc->cdar);
|
||||
dev_dbg(chan2dev(chan), "| C%dLLR: %08x\n", chan->id, hwdesc->cllr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "V\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "[%d]@%pad\n", i, &swdesc->lli[i].hwdesc_addr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dTR1: %08x\n", chan->id, hwdesc->ctr1);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dTR2: %08x\n", chan->id, hwdesc->ctr2);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dBR1: %08x\n", chan->id, hwdesc->cbr1);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dSAR: %08x\n", chan->id, hwdesc->csar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dDAR: %08x\n", chan->id, hwdesc->cdar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "| C%dLLR: %08x\n", chan->id, hwdesc->cllr);
|
||||
}
|
||||
|
||||
if (swdesc->cyclic) {
|
||||
dev_dbg(chan2dev(chan), "|\n");
|
||||
dev_dbg(chan2dev(chan), "-->[0]@%pad\n", &swdesc->lli[0].hwdesc_addr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "|\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "-->[0]@%pad\n", &swdesc->lli[0].hwdesc_addr);
|
||||
} else {
|
||||
dev_dbg(chan2dev(chan), "X\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "X\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -411,7 +406,7 @@ static struct stm32_dma3_swdesc *stm32_dma3_chan_desc_alloc(struct stm32_dma3_ch
|
|||
* addressed, so abort the allocation.
|
||||
*/
|
||||
if ((count * 32) > CLLR_LA) {
|
||||
dev_err(chan2dev(chan), "Transfer is too big (> %luB)\n", STM32_DMA3_MAX_SEG_SIZE);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Transfer is too big (> %luB)\n", STM32_DMA3_MAX_SEG_SIZE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +433,7 @@ static struct stm32_dma3_swdesc *stm32_dma3_chan_desc_alloc(struct stm32_dma3_ch
|
|||
return swdesc;
|
||||
|
||||
err_pool_free:
|
||||
dev_err(chan2dev(chan), "Failed to alloc descriptors\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Failed to alloc descriptors\n");
|
||||
while (--i >= 0)
|
||||
dma_pool_free(chan->lli_pool, swdesc->lli[i].hwdesc, swdesc->lli[i].hwdesc_addr);
|
||||
kfree(swdesc);
|
||||
|
|
@ -468,7 +463,7 @@ static void stm32_dma3_chan_vdesc_free(struct virt_dma_desc *vdesc)
|
|||
static void stm32_dma3_check_user_setting(struct stm32_dma3_chan *chan)
|
||||
{
|
||||
struct stm32_dma3_ddata *ddata = to_stm32_dma3_ddata(chan);
|
||||
struct device *dev = chan2dev(chan);
|
||||
struct device *dev = vchan_chan_dev(&chan->vchan);
|
||||
u32 ctr1 = readl_relaxed(ddata->base + STM32_DMA3_CTR1(chan->id));
|
||||
u32 cbr1 = readl_relaxed(ddata->base + STM32_DMA3_CBR1(chan->id));
|
||||
u32 csar = readl_relaxed(ddata->base + STM32_DMA3_CSAR(chan->id));
|
||||
|
|
@ -579,7 +574,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
u32 sap = FIELD_GET(STM32_DMA3_DT_SAP, tr_conf), sap_max_dw;
|
||||
u32 dap = FIELD_GET(STM32_DMA3_DT_DAP, tr_conf), dap_max_dw;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s from %pad to %pad\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "%s from %pad to %pad\n",
|
||||
dmaengine_get_direction_text(dir), &src_addr, &dst_addr);
|
||||
|
||||
sdw = chan->dma_config.src_addr_width ? : get_chan_max_dw(sap, chan->max_burst);
|
||||
|
|
@ -589,12 +584,12 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
|
||||
/* Following conditions would raise User Setting Error interrupt */
|
||||
if (!(dma_device.src_addr_widths & BIT(sdw)) || !(dma_device.dst_addr_widths & BIT(ddw))) {
|
||||
dev_err(chan2dev(chan), "Bus width (src=%u, dst=%u) not supported\n", sdw, ddw);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Bus width (src=%u, dst=%u) not supported\n", sdw, ddw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ddata->ports_max_dw[1] == DW_INVALID && (sap || dap)) {
|
||||
dev_err(chan2dev(chan), "Only one master port, port 1 is not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Only one master port, port 1 is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -602,7 +597,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
dap_max_dw = ddata->ports_max_dw[dap];
|
||||
if ((port_is_ahb(sap_max_dw) && sdw == DMA_SLAVE_BUSWIDTH_8_BYTES) ||
|
||||
(port_is_ahb(dap_max_dw) && ddw == DMA_SLAVE_BUSWIDTH_8_BYTES)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"8 bytes buswidth (src=%u, dst=%u) not supported on port (sap=%u, dap=%u\n",
|
||||
sdw, ddw, sap, dap);
|
||||
return -EINVAL;
|
||||
|
|
@ -659,7 +654,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
_ctr1 |= FIELD_PREP(CTR1_PAM, CTR1_PAM_PACK_UNPACK);
|
||||
/* Should never reach this case as ddw is clamped down */
|
||||
if (len & (ddw - 1)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Packing mode is enabled and len is not multiple of ddw");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -695,7 +690,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
_ctr1 |= FIELD_PREP(CTR1_PAM, CTR1_PAM_PACK_UNPACK);
|
||||
/* Should never reach this case as ddw is clamped down */
|
||||
if (len & (ddw - 1)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Packing mode is enabled and len is not multiple of ddw\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -740,7 +735,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
_ctr1 |= FIELD_PREP(CTR1_PAM, CTR1_PAM_PACK_UNPACK);
|
||||
/* Should never reach this case as ddw is clamped down */
|
||||
if (len & (ddw - 1)) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Packing mode is enabled and len is not multiple of ddw");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -752,7 +747,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Direction %s not supported\n",
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Direction %s not supported\n",
|
||||
dmaengine_get_direction_text(dir));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -761,7 +756,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
|
|||
*ctr1 = _ctr1;
|
||||
*ctr2 = _ctr2;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: sdw=%u bytes sbl=%u beats ddw=%u bytes dbl=%u beats\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "%s: sdw=%u bytes sbl=%u beats ddw=%u bytes dbl=%u beats\n",
|
||||
__func__, sdw, sbl_max, ddw, dbl_max);
|
||||
|
||||
return 0;
|
||||
|
|
@ -807,7 +802,7 @@ static void stm32_dma3_chan_start(struct stm32_dma3_chan *chan)
|
|||
|
||||
chan->dma_status = DMA_IN_PROGRESS;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: started\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: started\n", &chan->vchan);
|
||||
}
|
||||
|
||||
static int stm32_dma3_chan_suspend(struct stm32_dma3_chan *chan, bool susp)
|
||||
|
|
@ -871,7 +866,7 @@ static void stm32_dma3_chan_set_residue(struct stm32_dma3_chan *chan,
|
|||
struct dma_tx_state *txstate)
|
||||
{
|
||||
struct stm32_dma3_ddata *ddata = to_stm32_dma3_ddata(chan);
|
||||
struct device *dev = chan2dev(chan);
|
||||
struct device *dev = vchan_chan_dev(&chan->vchan);
|
||||
struct stm32_dma3_hwdesc *hwdesc;
|
||||
u32 residue, curr_lli, csr, cdar, cbr1, cllr, bndt, fifol;
|
||||
bool pack_unpack;
|
||||
|
|
@ -921,7 +916,7 @@ static void stm32_dma3_chan_set_residue(struct stm32_dma3_chan *chan,
|
|||
/* Get current hwdesc and cumulate residue of pending hwdesc BNDT */
|
||||
ret = stm32_dma3_chan_get_curr_hwdesc(swdesc, cllr, &residue);
|
||||
if (ret < 0) {
|
||||
dev_err(chan2dev(chan), "Can't get residue: current hwdesc not found\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Can't get residue: current hwdesc not found\n");
|
||||
return;
|
||||
}
|
||||
curr_lli = ret;
|
||||
|
|
@ -957,7 +952,7 @@ static void stm32_dma3_chan_set_residue(struct stm32_dma3_chan *chan,
|
|||
|
||||
skip_fifol_update:
|
||||
if (fifol) {
|
||||
dev_dbg(chan2dev(chan), "%u byte(s) in the FIFO\n", fifol);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "%u byte(s) in the FIFO\n", fifol);
|
||||
dma_set_in_flight_bytes(txstate, fifol);
|
||||
/*
|
||||
* Residue is already accurate for DMA_MEM_TO_DEV as BNDT reflects data read from
|
||||
|
|
@ -987,7 +982,7 @@ static int stm32_dma3_chan_stop(struct stm32_dma3_chan *chan)
|
|||
/* Suspend the channel */
|
||||
ret = stm32_dma3_chan_suspend(chan, true);
|
||||
if (ret)
|
||||
dev_warn(chan2dev(chan), "%s: timeout, data might be lost\n", __func__);
|
||||
dev_warn(vchan_chan_dev(&chan->vchan), "%s: timeout, data might be lost\n", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1034,7 +1029,7 @@ static irqreturn_t stm32_dma3_chan_irq(int irq, void *devid)
|
|||
}
|
||||
|
||||
if (csr & CSR_USEF && ccr & CCR_USEIE) {
|
||||
dev_err(chan2dev(chan), "User setting error\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "User setting error\n");
|
||||
chan->dma_status = DMA_ERROR;
|
||||
/* CCR.EN automatically cleared by HW */
|
||||
stm32_dma3_check_user_setting(chan);
|
||||
|
|
@ -1042,14 +1037,14 @@ static irqreturn_t stm32_dma3_chan_irq(int irq, void *devid)
|
|||
}
|
||||
|
||||
if (csr & CSR_ULEF && ccr & CCR_ULEIE) {
|
||||
dev_err(chan2dev(chan), "Update link transfer error\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Update link transfer error\n");
|
||||
chan->dma_status = DMA_ERROR;
|
||||
/* CCR.EN automatically cleared by HW */
|
||||
stm32_dma3_chan_reset(chan);
|
||||
}
|
||||
|
||||
if (csr & CSR_DTEF && ccr & CCR_DTEIE) {
|
||||
dev_err(chan2dev(chan), "Data transfer error\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Data transfer error\n");
|
||||
chan->dma_status = DMA_ERROR;
|
||||
/* CCR.EN automatically cleared by HW */
|
||||
stm32_dma3_chan_reset(chan);
|
||||
|
|
@ -1087,13 +1082,13 @@ static int stm32_dma3_get_chan_sem(struct stm32_dma3_chan *chan)
|
|||
goto bad_cid;
|
||||
|
||||
chan->semaphore_taken = true;
|
||||
dev_dbg(chan2dev(chan), "under CID1 control (semcr=0x%08x)\n", csemcr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "under CID1 control (semcr=0x%08x)\n", csemcr);
|
||||
|
||||
return 0;
|
||||
|
||||
bad_cid:
|
||||
chan->semaphore_taken = false;
|
||||
dev_err(chan2dev(chan), "not under CID1 control (in-use by CID%d)\n", ccid);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "not under CID1 control (in-use by CID%d)\n", ccid);
|
||||
|
||||
return -EACCES;
|
||||
}
|
||||
|
|
@ -1105,7 +1100,7 @@ static void stm32_dma3_put_chan_sem(struct stm32_dma3_chan *chan)
|
|||
if (chan->semaphore_taken) {
|
||||
writel_relaxed(0, ddata->base + STM32_DMA3_CSEMCR(chan->id));
|
||||
chan->semaphore_taken = false;
|
||||
dev_dbg(chan2dev(chan), "no more under CID1 control\n");
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "no more under CID1 control\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1126,11 +1121,11 @@ static int stm32_dma3_alloc_chan_resources(struct dma_chan *c)
|
|||
goto err_put_sync;
|
||||
}
|
||||
|
||||
chan->lli_pool = dmam_pool_create(dev_name(&c->dev->device), c->device->dev,
|
||||
chan->lli_pool = dmam_pool_create(dma_chan_name(c), c->device->dev,
|
||||
sizeof(struct stm32_dma3_hwdesc),
|
||||
__alignof__(struct stm32_dma3_hwdesc), SZ_64K);
|
||||
if (!chan->lli_pool) {
|
||||
dev_err(chan2dev(chan), "Failed to create LLI pool\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Failed to create LLI pool\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_put_sync;
|
||||
}
|
||||
|
|
@ -1366,7 +1361,7 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_slave_sg(struct dma_chan
|
|||
}
|
||||
|
||||
if (count != sg_len && chan->tcem != CTR2_TCEM_CHANNEL)
|
||||
dev_warn(chan2dev(chan), "Linked-list refactored, %d items instead of %d\n",
|
||||
dev_warn(vchan_chan_dev(&chan->vchan), "Linked-list refactored, %d items instead of %d\n",
|
||||
count, sg_len);
|
||||
|
||||
/* Enable Error interrupts */
|
||||
|
|
@ -1401,12 +1396,12 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_dma_cyclic(struct dma_cha
|
|||
return NULL;
|
||||
|
||||
if (!buf_len || !period_len || period_len > STM32_DMA3_MAX_BLOCK_SIZE) {
|
||||
dev_err(chan2dev(chan), "Invalid buffer/period length\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid buffer/period length\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf_len % period_len) {
|
||||
dev_err(chan2dev(chan), "Buffer length not multiple of period length\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Buffer length not multiple of period length\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1428,7 +1423,7 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_dma_cyclic(struct dma_cha
|
|||
ret = stm32_dma3_chan_prep_hw(chan, DMA_DEV_TO_MEM, &swdesc->ccr, &ctr1, &ctr2,
|
||||
src, dst, period_len);
|
||||
} else {
|
||||
dev_err(chan2dev(chan), "Invalid direction\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid direction\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1502,7 +1497,7 @@ static int stm32_dma3_pause(struct dma_chan *c)
|
|||
|
||||
chan->dma_status = DMA_PAUSED;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: paused\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: paused\n", &chan->vchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1515,7 +1510,7 @@ static int stm32_dma3_resume(struct dma_chan *c)
|
|||
|
||||
chan->dma_status = DMA_IN_PROGRESS;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: resumed\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: resumed\n", &chan->vchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1540,7 +1535,7 @@ static int stm32_dma3_terminate_all(struct dma_chan *c)
|
|||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
vchan_dma_desc_free_list(&chan->vchan, &head);
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: terminated\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: terminated\n", &chan->vchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1593,7 +1588,7 @@ static void stm32_dma3_issue_pending(struct dma_chan *c)
|
|||
spin_lock_irqsave(&chan->vchan.lock, flags);
|
||||
|
||||
if (vchan_issue_pending(&chan->vchan) && !chan->swdesc) {
|
||||
dev_dbg(chan2dev(chan), "vchan %p: issued\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: issued\n", &chan->vchan);
|
||||
stm32_dma3_chan_start(chan);
|
||||
}
|
||||
|
||||
|
|
@ -1892,10 +1887,10 @@ static int stm32_dma3_probe(struct platform_device *pdev)
|
|||
chan->irq = ret;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, chan->irq, stm32_dma3_chan_irq, 0,
|
||||
dev_name(chan2dev(chan)), chan);
|
||||
vchan_chan_name(&chan->vchan), chan);
|
||||
if (ret) {
|
||||
dev_err_probe(&pdev->dev, ret, "Failed to request channel %s IRQ\n",
|
||||
dev_name(chan2dev(chan)));
|
||||
vchan_chan_name(&chan->vchan));
|
||||
goto err_clk_disable;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,11 +276,6 @@ static struct stm32_mdma_desc *to_stm32_mdma_desc(struct virt_dma_desc *vdesc)
|
|||
return container_of(vdesc, struct stm32_mdma_desc, vdesc);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct stm32_mdma_chan *chan)
|
||||
{
|
||||
return &chan->vchan.chan.dev->device;
|
||||
}
|
||||
|
||||
static struct device *mdma2dev(struct stm32_mdma_device *mdma_dev)
|
||||
{
|
||||
return mdma_dev->ddev.dev;
|
||||
|
|
@ -334,7 +329,7 @@ static struct stm32_mdma_desc *stm32_mdma_alloc_desc(
|
|||
return desc;
|
||||
|
||||
err:
|
||||
dev_err(chan2dev(chan), "Failed to allocate descriptor\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Failed to allocate descriptor\n");
|
||||
while (--i >= 0)
|
||||
dma_pool_free(chan->desc_pool, desc->node[i].hwdesc,
|
||||
desc->node[i].hwdesc_phys);
|
||||
|
|
@ -364,7 +359,7 @@ static int stm32_mdma_get_width(struct stm32_mdma_chan *chan,
|
|||
case DMA_SLAVE_BUSWIDTH_8_BYTES:
|
||||
return ffs(width) - 1;
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Dma bus width %i not supported\n",
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Dma bus width %i not supported\n",
|
||||
width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -422,7 +417,7 @@ static int stm32_mdma_disable_chan(struct stm32_mdma_chan *chan)
|
|||
dmadev->base + STM32_MDMA_CISR(id), cisr,
|
||||
(cisr & STM32_MDMA_CISR_CTCIF), 10, 1000);
|
||||
if (ret) {
|
||||
dev_err(chan2dev(chan), "%s: timeout!\n", __func__);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "%s: timeout!\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
|
@ -444,7 +439,7 @@ static void stm32_mdma_stop(struct stm32_mdma_chan *chan)
|
|||
/* Clear interrupt status if it is there */
|
||||
status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id));
|
||||
if (status) {
|
||||
dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "%s(): clearing interrupt: 0x%08x\n",
|
||||
__func__, status);
|
||||
stm32_mdma_set_bits(dmadev, STM32_MDMA_CIFCR(chan->id), status);
|
||||
}
|
||||
|
|
@ -513,7 +508,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
|
|||
/* Check burst size constraints */
|
||||
if (src_maxburst * src_addr_width > STM32_MDMA_MAX_BURST ||
|
||||
dst_maxburst * dst_addr_width > STM32_MDMA_MAX_BURST) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"burst size * bus width higher than %d bytes\n",
|
||||
STM32_MDMA_MAX_BURST);
|
||||
return -EINVAL;
|
||||
|
|
@ -521,7 +516,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
|
|||
|
||||
if ((!is_power_of_2(src_maxburst) && src_maxburst > 0) ||
|
||||
(!is_power_of_2(dst_maxburst) && dst_maxburst > 0)) {
|
||||
dev_err(chan2dev(chan), "burst size must be a power of 2\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "burst size must be a power of 2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -658,7 +653,7 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_err(chan2dev(chan), "Dma direction is not supported\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Dma direction is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -672,16 +667,16 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
|
|||
static void stm32_mdma_dump_hwdesc(struct stm32_mdma_chan *chan,
|
||||
struct stm32_mdma_desc_node *node)
|
||||
{
|
||||
dev_dbg(chan2dev(chan), "hwdesc: %pad\n", &node->hwdesc_phys);
|
||||
dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n", node->hwdesc->ctcr);
|
||||
dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n", node->hwdesc->cbndtr);
|
||||
dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n", node->hwdesc->csar);
|
||||
dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n", node->hwdesc->cdar);
|
||||
dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n", node->hwdesc->cbrur);
|
||||
dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n", node->hwdesc->clar);
|
||||
dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n", node->hwdesc->ctbr);
|
||||
dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n", node->hwdesc->cmar);
|
||||
dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n\n", node->hwdesc->cmdr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "hwdesc: %pad\n", &node->hwdesc_phys);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CTCR: 0x%08x\n", node->hwdesc->ctcr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CBNDTR: 0x%08x\n", node->hwdesc->cbndtr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CSAR: 0x%08x\n", node->hwdesc->csar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CDAR: 0x%08x\n", node->hwdesc->cdar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CBRUR: 0x%08x\n", node->hwdesc->cbrur);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CLAR: 0x%08x\n", node->hwdesc->clar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CTBR: 0x%08x\n", node->hwdesc->ctbr);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CMAR: 0x%08x\n", node->hwdesc->cmar);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CMDR: 0x%08x\n\n", node->hwdesc->cmdr);
|
||||
}
|
||||
|
||||
static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan,
|
||||
|
|
@ -739,7 +734,7 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
|
|||
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
if (sg_dma_len(sg) > STM32_MDMA_MAX_BLOCK_LEN) {
|
||||
dev_err(chan2dev(chan), "Invalid block len\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid block len\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -797,7 +792,7 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl,
|
|||
* for allowing another request.
|
||||
*/
|
||||
if (chan->desc && chan->desc->cyclic) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Request not allowed when dma in cyclic mode\n");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -858,18 +853,18 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr,
|
|||
* for allowing another request.
|
||||
*/
|
||||
if (chan->desc && chan->desc->cyclic) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Request not allowed when dma in cyclic mode\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!buf_len || !period_len || period_len > STM32_MDMA_MAX_BLOCK_LEN) {
|
||||
dev_err(chan2dev(chan), "Invalid buffer/period len\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Invalid buffer/period len\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf_len % period_len) {
|
||||
dev_err(chan2dev(chan), "buf_len not multiple of period_len\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "buf_len not multiple of period_len\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -954,7 +949,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
|
|||
* to allow another request
|
||||
*/
|
||||
if (chan->desc && chan->desc->cyclic) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(vchan_chan_dev(&chan->vchan),
|
||||
"Request not allowed when dma in cyclic mode\n");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1116,25 +1111,25 @@ static void stm32_mdma_dump_reg(struct stm32_mdma_chan *chan)
|
|||
{
|
||||
struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
|
||||
|
||||
dev_dbg(chan2dev(chan), "CCR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CCR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CTCR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CBNDTR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CSAR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CSAR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CDAR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CDAR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CBRUR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CBRUR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CLAR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CLAR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CTBR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CMAR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CMAR(chan->id)));
|
||||
dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n",
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "CMDR: 0x%08x\n",
|
||||
stm32_mdma_read(dmadev, STM32_MDMA_CMDR(chan->id)));
|
||||
}
|
||||
|
||||
|
|
@ -1187,7 +1182,7 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan)
|
|||
|
||||
chan->busy = true;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: started\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: started\n", &chan->vchan);
|
||||
}
|
||||
|
||||
static void stm32_mdma_issue_pending(struct dma_chan *c)
|
||||
|
|
@ -1200,7 +1195,7 @@ static void stm32_mdma_issue_pending(struct dma_chan *c)
|
|||
if (!vchan_issue_pending(&chan->vchan))
|
||||
goto end;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: issued\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: issued\n", &chan->vchan);
|
||||
|
||||
if (!chan->desc && !chan->busy)
|
||||
stm32_mdma_start_transfer(chan);
|
||||
|
|
@ -1220,7 +1215,7 @@ static int stm32_mdma_pause(struct dma_chan *c)
|
|||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
|
||||
if (!ret)
|
||||
dev_dbg(chan2dev(chan), "vchan %p: pause\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: pause\n", &chan->vchan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1261,7 +1256,7 @@ static int stm32_mdma_resume(struct dma_chan *c)
|
|||
|
||||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: resume\n", &chan->vchan);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "vchan %p: resume\n", &chan->vchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1422,10 +1417,10 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
|
|||
if (!(status & ien)) {
|
||||
spin_unlock(&chan->vchan.lock);
|
||||
if (chan->busy)
|
||||
dev_warn(chan2dev(chan),
|
||||
dev_warn(vchan_chan_dev(&chan->vchan),
|
||||
"spurious it (status=0x%04x, ien=0x%04x)\n", status, ien);
|
||||
else
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan),
|
||||
"spurious it (status=0x%04x, ien=0x%04x)\n", status, ien);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
|
@ -1433,7 +1428,7 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
|
|||
reg = STM32_MDMA_CIFCR(id);
|
||||
|
||||
if (status & STM32_MDMA_CISR_TEIF) {
|
||||
dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n",
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "Transfer Err: stat=0x%08x\n",
|
||||
readl_relaxed(dmadev->base + STM32_MDMA_CESR(id)));
|
||||
stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CTEIF);
|
||||
status &= ~STM32_MDMA_CISR_TEIF;
|
||||
|
|
@ -1468,9 +1463,9 @@ static irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
|
|||
|
||||
if (status) {
|
||||
stm32_mdma_set_bits(dmadev, reg, status);
|
||||
dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "DMA error: status=0x%08x\n", status);
|
||||
if (!(ccr & STM32_MDMA_CCR_EN))
|
||||
dev_err(chan2dev(chan), "chan disabled by HW\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "chan disabled by HW\n");
|
||||
}
|
||||
|
||||
spin_unlock(&chan->vchan.lock);
|
||||
|
|
@ -1484,13 +1479,12 @@ static int stm32_mdma_alloc_chan_resources(struct dma_chan *c)
|
|||
struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
|
||||
int ret;
|
||||
|
||||
chan->desc_pool = dmam_pool_create(dev_name(&c->dev->device),
|
||||
c->device->dev,
|
||||
chan->desc_pool = dmam_pool_create(dma_chan_name(c), c->device->dev,
|
||||
sizeof(struct stm32_mdma_hwdesc),
|
||||
__alignof__(struct stm32_mdma_hwdesc),
|
||||
0);
|
||||
if (!chan->desc_pool) {
|
||||
dev_err(chan2dev(chan), "failed to allocate descriptor pool\n");
|
||||
dev_err(vchan_chan_dev(&chan->vchan), "failed to allocate descriptor pool\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -1511,7 +1505,7 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c)
|
|||
struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id);
|
||||
dev_dbg(vchan_chan_dev(&chan->vchan), "Freeing channel %d\n", chan->id);
|
||||
|
||||
if (chan->busy) {
|
||||
spin_lock_irqsave(&chan->vchan.lock, flags);
|
||||
|
|
|
|||
|
|
@ -246,11 +246,6 @@ static struct sun4i_dma_contract *to_sun4i_dma_contract(struct virt_dma_desc *vd
|
|||
return container_of(vd, struct sun4i_dma_contract, vd);
|
||||
}
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static void set_dst_data_width_a10(u32 *p_cfg, s8 data_width)
|
||||
{
|
||||
*p_cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(data_width);
|
||||
|
|
@ -428,7 +423,7 @@ static int __execute_vchan_pending(struct sun4i_dma_dev *priv,
|
|||
* has already submitted some work, we can't do anything else
|
||||
*/
|
||||
if (vchan->processing) {
|
||||
dev_dbg(chan2dev(&vchan->vc.chan),
|
||||
dev_dbg(vchan_chan_dev(&vchan->vc),
|
||||
"processing something to this endpoint already\n");
|
||||
ret = -EBUSY;
|
||||
goto release_pchan;
|
||||
|
|
@ -438,7 +433,7 @@ static int __execute_vchan_pending(struct sun4i_dma_dev *priv,
|
|||
/* Figure out which contract we're working with today */
|
||||
vd = vchan_next_desc(&vchan->vc);
|
||||
if (!vd) {
|
||||
dev_dbg(chan2dev(&vchan->vc.chan),
|
||||
dev_dbg(vchan_chan_dev(&vchan->vc),
|
||||
"No pending contract found");
|
||||
ret = 0;
|
||||
goto release_pchan;
|
||||
|
|
@ -449,7 +444,7 @@ static int __execute_vchan_pending(struct sun4i_dma_dev *priv,
|
|||
/* The contract has been completed so mark it as such */
|
||||
list_del(&contract->vd.node);
|
||||
vchan_cookie_complete(&contract->vd);
|
||||
dev_dbg(chan2dev(&vchan->vc.chan),
|
||||
dev_dbg(vchan_chan_dev(&vchan->vc),
|
||||
"Empty contract found and marked complete");
|
||||
}
|
||||
} while (list_empty(&contract->demands));
|
||||
|
|
@ -542,7 +537,7 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
|
|||
promise->cfg = SUN4I_DMA_CFG_LOADING |
|
||||
SUN4I_NDMA_CFG_BYTE_COUNT_MODE_REMAIN;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"src burst %d, dst burst %d, src buswidth %d, dst buswidth %d",
|
||||
sconfig->src_maxburst, sconfig->dst_maxburst,
|
||||
sconfig->src_addr_width, sconfig->dst_addr_width);
|
||||
|
|
@ -769,7 +764,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
|
|||
u8 ram_type, io_mode, linear_mode;
|
||||
|
||||
if (!is_slave_direction(dir)) {
|
||||
dev_err(chan2dev(chan), "Invalid DMA direction\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "Invalid DMA direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -894,7 +889,7 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
return NULL;
|
||||
|
||||
if (!is_slave_direction(dir)) {
|
||||
dev_err(chan2dev(chan), "Invalid DMA direction\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "Invalid DMA direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
|
@ -27,21 +28,17 @@
|
|||
/*
|
||||
* Common registers
|
||||
*/
|
||||
#define DMA_IRQ_EN(x) ((x) * 0x04)
|
||||
#define DMA_IRQ_HALF BIT(0)
|
||||
#define DMA_IRQ_PKG BIT(1)
|
||||
#define DMA_IRQ_QUEUE BIT(2)
|
||||
|
||||
#define DMA_IRQ_CHAN_NR 8
|
||||
#define DMA_IRQ_CHAN_WIDTH 4
|
||||
|
||||
|
||||
#define DMA_IRQ_STAT(x) ((x) * 0x04 + 0x10)
|
||||
|
||||
#define DMA_STAT 0x30
|
||||
|
||||
/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */
|
||||
#define DMA_MAX_CHANNELS (DMA_IRQ_CHAN_NR * 0x10 / 4)
|
||||
#define DMA_MAX_CHANNELS 16
|
||||
|
||||
/*
|
||||
* sun8i specific registers
|
||||
|
|
@ -52,6 +49,20 @@
|
|||
#define SUNXI_H3_SECURE_REG 0x20
|
||||
#define SUNXI_H3_DMA_GATE 0x28
|
||||
#define SUNXI_H3_DMA_GATE_ENABLE 0x4
|
||||
|
||||
/*
|
||||
* Interrupts specific registers
|
||||
*/
|
||||
#define DMA_IRQ_STRIDE_A31 0x04
|
||||
#define DMA_IRQ_STRIDE_A733 0x40
|
||||
#define DMA_IRQ_EN_OFFSET_A31 0x00
|
||||
#define DMA_IRQ_EN_OFFSET_A733 0x134
|
||||
#define DMA_IRQ_STAT_OFFSET_A31 0x10
|
||||
#define DMA_IRQ_STAT_OFFSET_A733 0x138
|
||||
|
||||
#define DMA_IRQ_CHAN_NR_A31 8
|
||||
#define DMA_IRQ_CHAN_NR_A733 1
|
||||
|
||||
/*
|
||||
* Channels specific registers
|
||||
*/
|
||||
|
|
@ -98,8 +109,10 @@
|
|||
* The LLI link physical address is also mangled, but we avoid dealing
|
||||
* with that by allocating LLIs from the DMA32 zone.
|
||||
*/
|
||||
#define SRC_HIGH_ADDR(x) (((x) & 0x3U) << 16)
|
||||
#define DST_HIGH_ADDR(x) (((x) & 0x3U) << 18)
|
||||
#define SRC_HIGH_ADDR_MASK GENMASK(17, 16)
|
||||
#define DST_HIGH_ADDR_MASK GENMASK(19, 18)
|
||||
#define SRC_HIGH_ADDR_32G_MASK GENMASK(13, 11)
|
||||
#define DST_HIGH_ADDR_32G_MASK GENMASK(17, 15)
|
||||
|
||||
/*
|
||||
* Various hardware related defines
|
||||
|
|
@ -142,8 +155,13 @@ struct sun6i_dma_config {
|
|||
u32 dst_burst_lengths;
|
||||
u32 src_addr_widths;
|
||||
u32 dst_addr_widths;
|
||||
bool has_high_addr;
|
||||
u32 src_high_addr_mask;
|
||||
u32 dst_high_addr_mask;
|
||||
bool has_mbus_clk;
|
||||
u32 irq_stride;
|
||||
u32 irq_en_offset;
|
||||
u32 irq_stat_offset;
|
||||
u32 num_channels_per_reg;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -213,11 +231,6 @@ struct sun6i_dma_dev {
|
|||
u32 max_request;
|
||||
};
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
|
||||
static inline struct sun6i_dma_dev *to_sun6i_dma_dev(struct dma_device *d)
|
||||
{
|
||||
return container_of(d, struct sun6i_dma_dev, slave);
|
||||
|
|
@ -234,19 +247,43 @@ to_sun6i_desc(struct dma_async_tx_descriptor *tx)
|
|||
return container_of(tx, struct sun6i_desc, vd.tx);
|
||||
}
|
||||
|
||||
static u32 sun6i_read_irq_en(struct sun6i_dma_dev *sdev, u32 irq_reg)
|
||||
{
|
||||
return readl(sdev->base + irq_reg * sdev->cfg->irq_stride + sdev->cfg->irq_en_offset);
|
||||
}
|
||||
|
||||
static void sun6i_write_irq_en(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 irq_val)
|
||||
{
|
||||
writel(irq_val, sdev->base + irq_reg * sdev->cfg->irq_stride + sdev->cfg->irq_en_offset);
|
||||
}
|
||||
|
||||
static u32 sun6i_read_irq_stat(struct sun6i_dma_dev *sdev, u32 irq_reg)
|
||||
{
|
||||
return readl(sdev->base + irq_reg * sdev->cfg->irq_stride + sdev->cfg->irq_stat_offset);
|
||||
}
|
||||
|
||||
static void sun6i_write_irq_stat(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 status)
|
||||
{
|
||||
writel(status, sdev->base + irq_reg * sdev->cfg->irq_stride + sdev->cfg->irq_stat_offset);
|
||||
}
|
||||
|
||||
static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
|
||||
{
|
||||
dev_dbg(sdev->slave.dev, "Common register:\n"
|
||||
"\tmask0(%04x): 0x%08x\n"
|
||||
"\tmask1(%04x): 0x%08x\n"
|
||||
"\tpend0(%04x): 0x%08x\n"
|
||||
"\tpend1(%04x): 0x%08x\n"
|
||||
"\tstats(%04x): 0x%08x\n",
|
||||
DMA_IRQ_EN(0), readl(sdev->base + DMA_IRQ_EN(0)),
|
||||
DMA_IRQ_EN(1), readl(sdev->base + DMA_IRQ_EN(1)),
|
||||
DMA_IRQ_STAT(0), readl(sdev->base + DMA_IRQ_STAT(0)),
|
||||
DMA_IRQ_STAT(1), readl(sdev->base + DMA_IRQ_STAT(1)),
|
||||
DMA_STAT, readl(sdev->base + DMA_STAT));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(sdev->num_pchans, sdev->cfg->num_channels_per_reg); i++) {
|
||||
dev_dbg(sdev->slave.dev, "Common register:\n"
|
||||
"chan num %d\n"
|
||||
"\tmask(%04x): 0x%08x\n"
|
||||
"\tpend(%04x): 0x%08x\n"
|
||||
"\tstats(%04x): 0x%08x\n",
|
||||
i,
|
||||
i * sdev->cfg->irq_stride + sdev->cfg->irq_en_offset,
|
||||
sun6i_read_irq_en(sdev, i),
|
||||
i * sdev->cfg->irq_stride + sdev->cfg->irq_stat_offset,
|
||||
sun6i_read_irq_stat(sdev, i),
|
||||
DMA_STAT, readl(sdev->base + DMA_STAT));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
|
||||
|
|
@ -399,7 +436,7 @@ static inline void sun6i_dma_dump_lli(struct sun6i_vchan *vchan,
|
|||
struct sun6i_dma_lli *v_lli,
|
||||
dma_addr_t p_lli)
|
||||
{
|
||||
dev_dbg(chan2dev(&vchan->vc.chan),
|
||||
dev_dbg(vchan_chan_dev(&vchan->vc),
|
||||
"\n\tdesc:\tp - %pad v - 0x%p\n"
|
||||
"\t\tc - 0x%08x s - 0x%08x d - 0x%08x\n"
|
||||
"\t\tl - 0x%08x p - 0x%08x n - 0x%08x\n",
|
||||
|
|
@ -408,16 +445,12 @@ static inline void sun6i_dma_dump_lli(struct sun6i_vchan *vchan,
|
|||
v_lli->len, v_lli->para, v_lli->p_lli_next);
|
||||
}
|
||||
|
||||
static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
|
||||
static void sun6i_dma_free_desc(struct sun6i_dma_dev *sdev,
|
||||
struct sun6i_desc *txd)
|
||||
{
|
||||
struct sun6i_desc *txd = to_sun6i_desc(&vd->tx);
|
||||
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vd->tx.chan->device);
|
||||
struct sun6i_dma_lli *v_lli, *v_next;
|
||||
dma_addr_t p_lli, p_next;
|
||||
|
||||
if (unlikely(!txd))
|
||||
return;
|
||||
|
||||
p_lli = txd->p_lli;
|
||||
v_lli = txd->v_lli;
|
||||
|
||||
|
|
@ -434,6 +467,17 @@ static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
|
|||
kfree(txd);
|
||||
}
|
||||
|
||||
static void sun6i_dma_free_desc_virt(struct virt_dma_desc *vd)
|
||||
{
|
||||
struct sun6i_desc *txd = to_sun6i_desc(&vd->tx);
|
||||
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vd->tx.chan->device);
|
||||
|
||||
if (unlikely(!txd))
|
||||
return;
|
||||
|
||||
sun6i_dma_free_desc(sdev, txd);
|
||||
}
|
||||
|
||||
static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
|
||||
{
|
||||
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
|
||||
|
|
@ -457,16 +501,16 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
|
|||
|
||||
sun6i_dma_dump_lli(vchan, pchan->desc->v_lli, pchan->desc->p_lli);
|
||||
|
||||
irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
|
||||
irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
|
||||
irq_reg = pchan->idx / sdev->cfg->num_channels_per_reg;
|
||||
irq_offset = pchan->idx % sdev->cfg->num_channels_per_reg;
|
||||
|
||||
vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
|
||||
|
||||
irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
|
||||
irq_val = sun6i_read_irq_en(sdev, irq_reg);
|
||||
irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) <<
|
||||
(irq_offset * DMA_IRQ_CHAN_WIDTH));
|
||||
irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH);
|
||||
writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
|
||||
sun6i_write_irq_en(sdev, irq_reg, irq_val);
|
||||
|
||||
writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
|
||||
writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE);
|
||||
|
|
@ -550,17 +594,17 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
|
|||
int i, j, ret = IRQ_NONE;
|
||||
u32 status;
|
||||
|
||||
for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
|
||||
status = readl(sdev->base + DMA_IRQ_STAT(i));
|
||||
for (i = 0; i < sdev->num_pchans / sdev->cfg->num_channels_per_reg; i++) {
|
||||
status = sun6i_read_irq_stat(sdev, i);
|
||||
if (!status)
|
||||
continue;
|
||||
|
||||
dev_dbg(sdev->slave.dev, "DMA irq status %s: 0x%x\n",
|
||||
str_high_low(i), status);
|
||||
|
||||
writel(status, sdev->base + DMA_IRQ_STAT(i));
|
||||
sun6i_write_irq_stat(sdev, i, status);
|
||||
|
||||
for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
|
||||
for (j = 0; (j < sdev->cfg->num_channels_per_reg) && status; j++) {
|
||||
pchan = sdev->pchans + j;
|
||||
vchan = pchan->vchan;
|
||||
if (vchan && (status & vchan->irq_type)) {
|
||||
|
|
@ -657,9 +701,10 @@ static inline void sun6i_dma_set_addr(struct sun6i_dma_dev *sdev,
|
|||
v_lli->src = lower_32_bits(src);
|
||||
v_lli->dst = lower_32_bits(dst);
|
||||
|
||||
if (sdev->cfg->has_high_addr)
|
||||
v_lli->para |= SRC_HIGH_ADDR(upper_32_bits(src)) |
|
||||
DST_HIGH_ADDR(upper_32_bits(dst));
|
||||
if (sdev->cfg->src_high_addr_mask)
|
||||
v_lli->para |=
|
||||
field_prep(sdev->cfg->src_high_addr_mask, upper_32_bits(src)) |
|
||||
field_prep(sdev->cfg->dst_high_addr_mask, upper_32_bits(dst));
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
|
||||
|
|
@ -673,7 +718,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
|
|||
dma_addr_t p_lli;
|
||||
s8 burst, width;
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
|
||||
__func__, vchan->vc.chan.chan_id, &dest, &src, len, flags);
|
||||
|
||||
|
|
@ -734,7 +779,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
|
|||
|
||||
ret = set_config(sdev, sconfig, dir, &lli_cfg);
|
||||
if (ret) {
|
||||
dev_err(chan2dev(chan), "Invalid DMA configuration\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "Invalid DMA configuration\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -758,7 +803,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
|
|||
sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
|
||||
sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
|
||||
__func__, vchan->vc.chan.chan_id,
|
||||
&sconfig->dst_addr, &sg_dma_address(sg),
|
||||
|
|
@ -772,7 +817,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
|
|||
sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
|
||||
sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n",
|
||||
__func__, vchan->vc.chan.chan_id,
|
||||
&sg_dma_address(sg), &sconfig->src_addr,
|
||||
|
|
@ -782,7 +827,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
|
|||
prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(chan), "First: %pad\n", &txd->p_lli);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "First: %pad\n", &txd->p_lli);
|
||||
for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
|
||||
p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
|
||||
sun6i_dma_dump_lli(vchan, v_lli, p_lli);
|
||||
|
|
@ -790,10 +835,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
|
|||
return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
|
||||
|
||||
err_lli_free:
|
||||
for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
|
||||
p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
|
||||
dma_pool_free(sdev->pool, v_lli, p_lli);
|
||||
kfree(txd);
|
||||
sun6i_dma_free_desc(sdev, txd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -817,7 +859,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
|
|||
|
||||
ret = set_config(sdev, sconfig, dir, &lli_cfg);
|
||||
if (ret) {
|
||||
dev_err(chan2dev(chan), "Invalid DMA configuration\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "Invalid DMA configuration\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -842,7 +884,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
|
|||
v_lli->cfg = lli_cfg;
|
||||
sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
|
||||
sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
|
||||
__func__, vchan->vc.chan.chan_id,
|
||||
&sconfig->dst_addr, &buf_addr,
|
||||
|
|
@ -854,7 +896,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
|
|||
v_lli->cfg = lli_cfg;
|
||||
sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
|
||||
sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
|
||||
__func__, vchan->vc.chan.chan_id,
|
||||
&buf_addr, &sconfig->src_addr,
|
||||
|
|
@ -871,10 +913,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
|
|||
return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
|
||||
|
||||
err_lli_free:
|
||||
for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli;
|
||||
p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next)
|
||||
dma_pool_free(sdev->pool, v_lli, p_lli);
|
||||
kfree(txd);
|
||||
sun6i_dma_free_desc(sdev, txd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -894,7 +933,7 @@ static int sun6i_dma_pause(struct dma_chan *chan)
|
|||
struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
|
||||
struct sun6i_pchan *pchan = vchan->phy;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "vchan %p: pause\n", &vchan->vc);
|
||||
|
||||
if (pchan) {
|
||||
writel(DMA_CHAN_PAUSE_PAUSE,
|
||||
|
|
@ -915,7 +954,7 @@ static int sun6i_dma_resume(struct dma_chan *chan)
|
|||
struct sun6i_pchan *pchan = vchan->phy;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "vchan %p: resume\n", &vchan->vc);
|
||||
|
||||
spin_lock_irqsave(&vchan->vc.lock, flags);
|
||||
|
||||
|
|
@ -1024,13 +1063,13 @@ static void sun6i_dma_issue_pending(struct dma_chan *chan)
|
|||
if (!vchan->phy && list_empty(&vchan->node)) {
|
||||
list_add_tail(&vchan->node, &sdev->pending);
|
||||
tasklet_schedule(&sdev->task);
|
||||
dev_dbg(chan2dev(chan), "vchan %p: issued\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "vchan %p: issued\n",
|
||||
&vchan->vc);
|
||||
}
|
||||
|
||||
spin_unlock(&sdev->lock);
|
||||
} else {
|
||||
dev_dbg(chan2dev(chan), "vchan %p: nothing to issue\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "vchan %p: nothing to issue\n",
|
||||
&vchan->vc);
|
||||
}
|
||||
|
||||
|
|
@ -1073,9 +1112,11 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
|
|||
|
||||
static inline void sun6i_kill_tasklet(struct sun6i_dma_dev *sdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Disable all interrupts from DMA */
|
||||
writel(0, sdev->base + DMA_IRQ_EN(0));
|
||||
writel(0, sdev->base + DMA_IRQ_EN(1));
|
||||
for (i = 0; i < DMA_MAX_CHANNELS / sdev->cfg->num_channels_per_reg; i++)
|
||||
sun6i_write_irq_en(sdev, i, 0);
|
||||
|
||||
/* Prevent spurious interrupts from scheduling the tasklet */
|
||||
atomic_inc(&sdev->tasklet_shutdown);
|
||||
|
|
@ -1099,6 +1140,12 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
|
|||
}
|
||||
}
|
||||
|
||||
#define SUN6I_DMA_IRQ_A31_COMMON_CFG \
|
||||
.irq_stride = DMA_IRQ_STRIDE_A31, \
|
||||
.irq_en_offset = DMA_IRQ_EN_OFFSET_A31, \
|
||||
.irq_stat_offset = DMA_IRQ_STAT_OFFSET_A31, \
|
||||
.num_channels_per_reg = DMA_IRQ_CHAN_NR_A31,
|
||||
|
||||
/*
|
||||
* For A31:
|
||||
*
|
||||
|
|
@ -1130,6 +1177,7 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
|
|||
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1153,6 +1201,7 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
|
|||
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
|
||||
|
|
@ -1171,6 +1220,7 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
|
|||
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1198,6 +1248,7 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
|
|||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1219,6 +1270,7 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
|
|||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1240,8 +1292,10 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
|
|||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
|
||||
.has_high_addr = true,
|
||||
.src_high_addr_mask = SRC_HIGH_ADDR_MASK,
|
||||
.dst_high_addr_mask = DST_HIGH_ADDR_MASK,
|
||||
.has_mbus_clk = true,
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1264,6 +1318,33 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
|
|||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
|
||||
.has_mbus_clk = true,
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
/*
|
||||
* The A733 binding uses the number of dma channels from the
|
||||
* device tree node.
|
||||
*/
|
||||
static struct sun6i_dma_config sun60i_a733_dma_cfg = {
|
||||
.clock_autogate_enable = sun6i_enable_clock_autogate_h3,
|
||||
.set_burst_length = sun6i_set_burst_length_h3,
|
||||
.set_drq = sun6i_set_drq_h6,
|
||||
.set_mode = sun6i_set_mode_h6,
|
||||
.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
|
||||
.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
|
||||
.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
.src_high_addr_mask = SRC_HIGH_ADDR_32G_MASK,
|
||||
.dst_high_addr_mask = DST_HIGH_ADDR_32G_MASK,
|
||||
.has_mbus_clk = true,
|
||||
.irq_stride = DMA_IRQ_STRIDE_A733,
|
||||
.irq_en_offset = DMA_IRQ_EN_OFFSET_A733,
|
||||
.irq_stat_offset = DMA_IRQ_STAT_OFFSET_A733,
|
||||
.num_channels_per_reg = DMA_IRQ_CHAN_NR_A733,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1287,6 +1368,7 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
|
|||
.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
|
||||
SUN6I_DMA_IRQ_A31_COMMON_CFG
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_dma_match[] = {
|
||||
|
|
@ -1299,6 +1381,7 @@ static const struct of_device_id sun6i_dma_match[] = {
|
|||
{ .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
|
||||
{ .compatible = "allwinner,sun50i-a100-dma", .data = &sun50i_a100_dma_cfg },
|
||||
{ .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg },
|
||||
{ .compatible = "allwinner,sun60i-a733-dma", .data = &sun60i_a733_dma_cfg },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun6i_dma_match);
|
||||
|
|
@ -1429,7 +1512,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
|
|||
struct sun6i_vchan *vchan = &sdc->vchans[i];
|
||||
|
||||
INIT_LIST_HEAD(&vchan->node);
|
||||
vchan->vc.desc_free = sun6i_dma_free_desc;
|
||||
vchan->vc.desc_free = sun6i_dma_free_desc_virt;
|
||||
vchan_init(&vchan->vc, &sdc->slave);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ static int disable_channel(struct switchtec_dma_chan *swdma_chan)
|
|||
static void
|
||||
switchtec_dma_cleanup_completed(struct switchtec_dma_chan *swdma_chan)
|
||||
{
|
||||
struct device *chan_dev = &swdma_chan->dma_chan.dev->device;
|
||||
struct device *chan_dev = dmaengine_chan_dev(&swdma_chan->dma_chan);
|
||||
struct switchtec_dma_desc *desc;
|
||||
struct switchtec_dma_hw_ce *ce;
|
||||
struct dmaengine_result res;
|
||||
|
|
@ -851,7 +851,7 @@ static irqreturn_t switchtec_dma_chan_status_isr(int irq, void *dma)
|
|||
list_for_each_entry(chan, &dma_dev->channels, device_node) {
|
||||
swdma_chan = container_of(chan, struct switchtec_dma_chan,
|
||||
dma_chan);
|
||||
chan_dev = &swdma_chan->dma_chan.dev->device;
|
||||
chan_dev = dmaengine_chan_dev(&swdma_chan->dma_chan);
|
||||
chan_hw = swdma_chan->mmio_chan_hw;
|
||||
|
||||
rcu_read_lock();
|
||||
|
|
@ -886,14 +886,18 @@ static void switchtec_dma_free_desc(struct switchtec_dma_chan *swdma_chan)
|
|||
if (swdma_chan->hw_sq)
|
||||
dma_free_coherent(swdma_dev->dma_dev.dev, size,
|
||||
swdma_chan->hw_sq, swdma_chan->dma_addr_sq);
|
||||
swdma_chan->hw_sq = NULL;
|
||||
|
||||
size = SWITCHTEC_DMA_CQ_SIZE * sizeof(*swdma_chan->hw_cq);
|
||||
if (swdma_chan->hw_cq)
|
||||
dma_free_coherent(swdma_dev->dma_dev.dev, size,
|
||||
swdma_chan->hw_cq, swdma_chan->dma_addr_cq);
|
||||
swdma_chan->hw_cq = NULL;
|
||||
|
||||
for (i = 0; i < SWITCHTEC_DMA_RING_SIZE; i++)
|
||||
for (i = 0; i < SWITCHTEC_DMA_RING_SIZE; i++) {
|
||||
kfree(swdma_chan->desc_ring[i]);
|
||||
swdma_chan->desc_ring[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int switchtec_dma_alloc_desc(struct switchtec_dma_chan *swdma_chan)
|
||||
|
|
@ -984,15 +988,15 @@ static int switchtec_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
|
||||
rc = enable_channel(swdma_chan);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err_free_desc;
|
||||
|
||||
rc = reset_channel(swdma_chan);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err_disable_channel;
|
||||
|
||||
rc = unhalt_channel(swdma_chan);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err_disable_channel;
|
||||
|
||||
swdma_chan->ring_active = true;
|
||||
swdma_chan->comp_ring_active = true;
|
||||
|
|
@ -1003,28 +1007,43 @@ static int switchtec_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
rcu_read_lock();
|
||||
if (!rcu_dereference(swdma_dev->pdev)) {
|
||||
rcu_read_unlock();
|
||||
return -ENODEV;
|
||||
rc = -ENODEV;
|
||||
goto err_ring_inactive;
|
||||
}
|
||||
|
||||
perf_cfg = readl(&swdma_chan->mmio_chan_fw->perf_cfg);
|
||||
rcu_read_unlock();
|
||||
|
||||
dev_dbg(&chan->dev->device, "Burst Size: 0x%x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "Burst Size: 0x%x\n",
|
||||
FIELD_GET(PERF_BURST_SIZE_MASK, perf_cfg));
|
||||
|
||||
dev_dbg(&chan->dev->device, "Burst Scale: 0x%x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "Burst Scale: 0x%x\n",
|
||||
FIELD_GET(PERF_BURST_SCALE_MASK, perf_cfg));
|
||||
|
||||
dev_dbg(&chan->dev->device, "Interval: 0x%x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "Interval: 0x%x\n",
|
||||
FIELD_GET(PERF_INTERVAL_MASK, perf_cfg));
|
||||
|
||||
dev_dbg(&chan->dev->device, "Arb Weight: 0x%x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "Arb Weight: 0x%x\n",
|
||||
FIELD_GET(PERF_ARB_WEIGHT_MASK, perf_cfg));
|
||||
|
||||
dev_dbg(&chan->dev->device, "MRRS: 0x%x\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "MRRS: 0x%x\n",
|
||||
FIELD_GET(PERF_MRRS_MASK, perf_cfg));
|
||||
|
||||
return SWITCHTEC_DMA_SQ_SIZE;
|
||||
|
||||
err_ring_inactive:
|
||||
spin_lock_bh(&swdma_chan->submit_lock);
|
||||
swdma_chan->ring_active = false;
|
||||
spin_unlock_bh(&swdma_chan->submit_lock);
|
||||
|
||||
spin_lock_bh(&swdma_chan->complete_lock);
|
||||
swdma_chan->comp_ring_active = false;
|
||||
spin_unlock_bh(&swdma_chan->complete_lock);
|
||||
err_disable_channel:
|
||||
disable_channel(swdma_chan);
|
||||
err_free_desc:
|
||||
switchtec_dma_free_desc(swdma_chan);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void switchtec_dma_free_chan_resources(struct dma_chan *chan)
|
||||
|
|
@ -1145,15 +1164,34 @@ static int switchtec_dma_chan_free(struct pci_dev *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int switchtec_dma_chans_release(struct pci_dev *pdev,
|
||||
struct switchtec_dma_dev *swdma_dev)
|
||||
static void switchtec_dma_chans_release(struct pci_dev *pdev,
|
||||
struct switchtec_dma_dev *swdma_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < swdma_dev->chan_cnt; i++)
|
||||
switchtec_dma_chan_free(pdev, swdma_dev->swdma_chans[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void switchtec_dma_chans_free(struct switchtec_dma_dev *swdma_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < swdma_dev->chan_cnt; i++) {
|
||||
list_del(&swdma_dev->swdma_chans[i]->dma_chan.device_node);
|
||||
kfree(swdma_dev->swdma_chans[i]);
|
||||
}
|
||||
|
||||
kfree(swdma_dev->swdma_chans);
|
||||
}
|
||||
|
||||
static void switchtec_dma_chans_disable(struct pci_dev *pdev,
|
||||
struct switchtec_dma_dev *swdma_dev)
|
||||
{
|
||||
if (swdma_dev->chan_status_irq >= 0) {
|
||||
pci_free_irq(pdev, swdma_dev->chan_status_irq, swdma_dev);
|
||||
swdma_dev->chan_status_irq = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
|
||||
|
|
@ -1180,7 +1218,7 @@ static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
|
|||
if (rc) {
|
||||
dev_err(&pdev->dev, "Channel %d: init channel failed\n",
|
||||
i);
|
||||
chan_cnt = i;
|
||||
swdma_dev->chan_cnt = i;
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
|
@ -1188,10 +1226,9 @@ static int switchtec_dma_chans_enumerate(struct switchtec_dma_dev *swdma_dev,
|
|||
return chan_cnt;
|
||||
|
||||
err_exit:
|
||||
for (i = 0; i < chan_cnt; i++)
|
||||
switchtec_dma_chan_free(pdev, swdma_dev->swdma_chans[i]);
|
||||
|
||||
kfree(swdma_dev->swdma_chans);
|
||||
switchtec_dma_chans_disable(pdev, swdma_dev);
|
||||
switchtec_dma_chans_release(pdev, swdma_dev);
|
||||
switchtec_dma_chans_free(swdma_dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1200,12 +1237,8 @@ static void switchtec_dma_release(struct dma_device *dma_dev)
|
|||
{
|
||||
struct switchtec_dma_dev *swdma_dev =
|
||||
container_of(dma_dev, struct switchtec_dma_dev, dma_dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < swdma_dev->chan_cnt; i++)
|
||||
kfree(swdma_dev->swdma_chans[i]);
|
||||
|
||||
kfree(swdma_dev->swdma_chans);
|
||||
switchtec_dma_chans_free(swdma_dev);
|
||||
|
||||
put_device(dma_dev->dev);
|
||||
kfree(swdma_dev);
|
||||
|
|
@ -1225,6 +1258,8 @@ static int switchtec_dma_create(struct pci_dev *pdev)
|
|||
if (!swdma_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
swdma_dev->chan_status_irq = -1;
|
||||
|
||||
swdma_dev->bar = ioremap(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
|
||||
|
|
@ -1295,11 +1330,13 @@ static int switchtec_dma_create(struct pci_dev *pdev)
|
|||
return 0;
|
||||
|
||||
err_chans_release_exit:
|
||||
switchtec_dma_chans_disable(pdev, swdma_dev);
|
||||
switchtec_dma_chans_release(pdev, swdma_dev);
|
||||
switchtec_dma_chans_free(swdma_dev);
|
||||
|
||||
err_exit:
|
||||
if (swdma_dev->chan_status_irq)
|
||||
free_irq(swdma_dev->chan_status_irq, swdma_dev);
|
||||
if (swdma_dev->chan_status_irq >= 0)
|
||||
pci_free_irq(pdev, swdma_dev->chan_status_irq, swdma_dev);
|
||||
|
||||
iounmap(swdma_dev->bar);
|
||||
kfree(swdma_dev);
|
||||
|
|
@ -1342,6 +1379,7 @@ static int switchtec_dma_probe(struct pci_dev *pdev,
|
|||
static void switchtec_dma_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct switchtec_dma_dev *swdma_dev = pci_get_drvdata(pdev);
|
||||
void __iomem *bar = swdma_dev->bar;
|
||||
|
||||
switchtec_dma_chans_release(pdev, swdma_dev);
|
||||
|
||||
|
|
@ -1354,7 +1392,7 @@ static void switchtec_dma_remove(struct pci_dev *pdev)
|
|||
|
||||
dma_async_device_unregister(&swdma_dev->dma_dev);
|
||||
|
||||
iounmap(swdma_dev->bar);
|
||||
iounmap(bar);
|
||||
pci_release_mem_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1537,7 +1537,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
|
|||
* the channels available and registered for the DMA device are used.
|
||||
*/
|
||||
list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) {
|
||||
chdev = &chan->dev->device;
|
||||
chdev = dmaengine_chan_dev(chan);
|
||||
tdc = to_tegra_dma_chan(chan);
|
||||
|
||||
if (use_iommu_map) {
|
||||
|
|
@ -1554,7 +1554,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
|
|||
return dev_err_probe(chdev, -EINVAL,
|
||||
"Failed to get stream ID for channel %d\n", tdc->id);
|
||||
|
||||
chan->dev->chan_dma_dev = true;
|
||||
chan->chan_dev->chan_dma_dev = true;
|
||||
}
|
||||
|
||||
/* program stream-id for this channel */
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ txd_to_tegra_dma_desc(struct dma_async_tx_descriptor *td)
|
|||
|
||||
static inline struct device *tdc2dev(struct tegra_dma_channel *tdc)
|
||||
{
|
||||
return &tdc->dma_chan.dev->device;
|
||||
return dmaengine_chan_dev(&tdc->dma_chan);
|
||||
}
|
||||
|
||||
static dma_cookie_t tegra_dma_tx_submit(struct dma_async_tx_descriptor *tx);
|
||||
|
|
|
|||
|
|
@ -422,16 +422,16 @@ static int navss_psil_unpair(struct udma_dev *ud, u32 src_thread,
|
|||
|
||||
static void k3_configure_chan_coherency(struct dma_chan *chan, u32 asel)
|
||||
{
|
||||
struct device *chan_dev = &chan->dev->device;
|
||||
struct device *chan_dev = dmaengine_chan_dev(chan);
|
||||
|
||||
if (asel == 0) {
|
||||
/* No special handling for the channel */
|
||||
chan->dev->chan_dma_dev = false;
|
||||
chan->chan_dev->chan_dma_dev = false;
|
||||
|
||||
dev_clear_dma_coherent(chan_dev);
|
||||
chan_dev->dma_parms = NULL;
|
||||
} else if (asel == 14 || asel == 15) {
|
||||
chan->dev->chan_dma_dev = true;
|
||||
chan->chan_dev->chan_dma_dev = true;
|
||||
|
||||
dev_set_dma_coherent(chan_dev);
|
||||
dma_coerce_mask_and_coherent(chan_dev, DMA_BIT_MASK(48));
|
||||
|
|
|
|||
|
|
@ -90,14 +90,9 @@ struct timb_dma {
|
|||
struct tasklet_struct tasklet;
|
||||
struct timb_dma_chan channels[];
|
||||
};
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
static struct device *chan2dmadev(struct dma_chan *chan)
|
||||
{
|
||||
return chan2dev(chan)->parent->parent;
|
||||
return dmaengine_chan_dev(chan)->parent->parent;
|
||||
}
|
||||
|
||||
static struct timb_dma *tdchantotd(struct timb_dma_chan *td_chan)
|
||||
|
|
@ -117,7 +112,7 @@ static void __td_enable_chan_irq(struct timb_dma_chan *td_chan)
|
|||
/* enable interrupt for this channel */
|
||||
ier = ioread32(td->membase + TIMBDMA_IER);
|
||||
ier |= 1 << id;
|
||||
dev_dbg(chan2dev(&td_chan->chan), "Enabling irq: %d, IER: 0x%x\n", id,
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "Enabling irq: %d, IER: 0x%x\n", id,
|
||||
ier);
|
||||
iowrite32(ier, td->membase + TIMBDMA_IER);
|
||||
}
|
||||
|
|
@ -131,7 +126,7 @@ static bool __td_dma_done_ack(struct timb_dma_chan *td_chan)
|
|||
u32 isr;
|
||||
bool done = false;
|
||||
|
||||
dev_dbg(chan2dev(&td_chan->chan), "Checking irq: %d, td: %p\n", id, td);
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "Checking irq: %d, td: %p\n", id, td);
|
||||
|
||||
isr = ioread32(td->membase + TIMBDMA_ISR) & (1 << id);
|
||||
if (isr) {
|
||||
|
|
@ -146,18 +141,18 @@ static int td_fill_desc(struct timb_dma_chan *td_chan, u8 *dma_desc,
|
|||
struct scatterlist *sg, bool last)
|
||||
{
|
||||
if (sg_dma_len(sg) > USHRT_MAX) {
|
||||
dev_err(chan2dev(&td_chan->chan), "Too big sg element\n");
|
||||
dev_err(dmaengine_chan_dev(&td_chan->chan), "Too big sg element\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* length must be word aligned */
|
||||
if (sg_dma_len(sg) % sizeof(u32)) {
|
||||
dev_err(chan2dev(&td_chan->chan), "Incorrect length: %d\n",
|
||||
dev_err(dmaengine_chan_dev(&td_chan->chan), "Incorrect length: %d\n",
|
||||
sg_dma_len(sg));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(chan2dev(&td_chan->chan), "desc: %p, addr: 0x%llx\n",
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "desc: %p, addr: 0x%llx\n",
|
||||
dma_desc, (unsigned long long)sg_dma_address(sg));
|
||||
|
||||
dma_desc[7] = (sg_dma_address(sg) >> 24) & 0xff;
|
||||
|
|
@ -180,7 +175,7 @@ static void __td_start_dma(struct timb_dma_chan *td_chan)
|
|||
struct timb_dma_desc *td_desc;
|
||||
|
||||
if (td_chan->ongoing) {
|
||||
dev_err(chan2dev(&td_chan->chan),
|
||||
dev_err(dmaengine_chan_dev(&td_chan->chan),
|
||||
"Transfer already ongoing\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -188,7 +183,7 @@ static void __td_start_dma(struct timb_dma_chan *td_chan)
|
|||
td_desc = list_entry(td_chan->active_list.next, struct timb_dma_desc,
|
||||
desc_node);
|
||||
|
||||
dev_dbg(chan2dev(&td_chan->chan),
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan),
|
||||
"td_chan: %p, chan: %d, membase: %p\n",
|
||||
td_chan, td_chan->chan.chan_id, td_chan->membase);
|
||||
|
||||
|
|
@ -230,7 +225,7 @@ static void __td_finish(struct timb_dma_chan *td_chan)
|
|||
desc_node);
|
||||
txd = &td_desc->txd;
|
||||
|
||||
dev_dbg(chan2dev(&td_chan->chan), "descriptor %u complete\n",
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "descriptor %u complete\n",
|
||||
txd->cookie);
|
||||
|
||||
/* make sure to stop the transfer */
|
||||
|
|
@ -284,7 +279,7 @@ static void __td_start_next(struct timb_dma_chan *td_chan)
|
|||
td_desc = list_entry(td_chan->queue.next, struct timb_dma_desc,
|
||||
desc_node);
|
||||
|
||||
dev_dbg(chan2dev(&td_chan->chan), "%s: started %u\n",
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "%s: started %u\n",
|
||||
__func__, td_desc->txd.cookie);
|
||||
|
||||
list_move(&td_desc->desc_node, &td_chan->active_list);
|
||||
|
|
@ -303,12 +298,12 @@ static dma_cookie_t td_tx_submit(struct dma_async_tx_descriptor *txd)
|
|||
cookie = dma_cookie_assign(txd);
|
||||
|
||||
if (list_empty(&td_chan->active_list)) {
|
||||
dev_dbg(chan2dev(txd->chan), "%s: started %u\n", __func__,
|
||||
dev_dbg(dmaengine_chan_dev(txd->chan), "%s: started %u\n", __func__,
|
||||
txd->cookie);
|
||||
list_add_tail(&td_desc->desc_node, &td_chan->active_list);
|
||||
__td_start_dma(td_chan);
|
||||
} else {
|
||||
dev_dbg(chan2dev(txd->chan), "tx_submit: queued %u\n",
|
||||
dev_dbg(dmaengine_chan_dev(txd->chan), "tx_submit: queued %u\n",
|
||||
txd->cookie);
|
||||
|
||||
list_add_tail(&td_desc->desc_node, &td_chan->queue);
|
||||
|
|
@ -344,7 +339,7 @@ static struct timb_dma_desc *td_alloc_init_desc(struct timb_dma_chan *td_chan)
|
|||
|
||||
err = dma_mapping_error(chan2dmadev(chan), td_desc->txd.phys);
|
||||
if (err) {
|
||||
dev_err(chan2dev(chan), "DMA mapping error: %d\n", err);
|
||||
dev_err(dmaengine_chan_dev(chan), "DMA mapping error: %d\n", err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +354,7 @@ static struct timb_dma_desc *td_alloc_init_desc(struct timb_dma_chan *td_chan)
|
|||
|
||||
static void td_free_desc(struct timb_dma_desc *td_desc)
|
||||
{
|
||||
dev_dbg(chan2dev(td_desc->txd.chan), "Freeing desc: %p\n", td_desc);
|
||||
dev_dbg(dmaengine_chan_dev(td_desc->txd.chan), "Freeing desc: %p\n", td_desc);
|
||||
dma_unmap_single(chan2dmadev(td_desc->txd.chan), td_desc->txd.phys,
|
||||
td_desc->desc_list_len, DMA_TO_DEVICE);
|
||||
|
||||
|
|
@ -370,7 +365,7 @@ static void td_free_desc(struct timb_dma_desc *td_desc)
|
|||
static void td_desc_put(struct timb_dma_chan *td_chan,
|
||||
struct timb_dma_desc *td_desc)
|
||||
{
|
||||
dev_dbg(chan2dev(&td_chan->chan), "Putting desc: %p\n", td_desc);
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "Putting desc: %p\n", td_desc);
|
||||
|
||||
spin_lock_bh(&td_chan->lock);
|
||||
list_add(&td_desc->desc_node, &td_chan->free_list);
|
||||
|
|
@ -390,7 +385,7 @@ static struct timb_dma_desc *td_desc_get(struct timb_dma_chan *td_chan)
|
|||
ret = td_desc;
|
||||
break;
|
||||
}
|
||||
dev_dbg(chan2dev(&td_chan->chan), "desc %p not ACKed\n",
|
||||
dev_dbg(dmaengine_chan_dev(&td_chan->chan), "desc %p not ACKed\n",
|
||||
td_desc);
|
||||
}
|
||||
spin_unlock_bh(&td_chan->lock);
|
||||
|
|
@ -404,7 +399,7 @@ static int td_alloc_chan_resources(struct dma_chan *chan)
|
|||
container_of(chan, struct timb_dma_chan, chan);
|
||||
int i;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: entry\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: entry\n", __func__);
|
||||
|
||||
BUG_ON(!list_empty(&td_chan->free_list));
|
||||
for (i = 0; i < td_chan->descs; i++) {
|
||||
|
|
@ -413,7 +408,7 @@ static int td_alloc_chan_resources(struct dma_chan *chan)
|
|||
if (i)
|
||||
break;
|
||||
else {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"Couldn't allocate any descriptors\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -436,7 +431,7 @@ static void td_free_chan_resources(struct dma_chan *chan)
|
|||
struct timb_dma_desc *td_desc, *_td_desc;
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: Entry\n", __func__);
|
||||
|
||||
/* check that all descriptors are free */
|
||||
BUG_ON(!list_empty(&td_chan->active_list));
|
||||
|
|
@ -447,7 +442,7 @@ static void td_free_chan_resources(struct dma_chan *chan)
|
|||
spin_unlock_bh(&td_chan->lock);
|
||||
|
||||
list_for_each_entry_safe(td_desc, _td_desc, &list, desc_node) {
|
||||
dev_dbg(chan2dev(chan), "%s: Freeing desc: %p\n", __func__,
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: Freeing desc: %p\n", __func__,
|
||||
td_desc);
|
||||
td_free_desc(td_desc);
|
||||
}
|
||||
|
|
@ -458,11 +453,11 @@ static enum dma_status td_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
|||
{
|
||||
enum dma_status ret;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: Entry\n", __func__);
|
||||
|
||||
ret = dma_cookie_status(chan, cookie, txstate);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: exit, ret: %d\n", __func__, ret);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: exit, ret: %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -472,7 +467,7 @@ static void td_issue_pending(struct dma_chan *chan)
|
|||
struct timb_dma_chan *td_chan =
|
||||
container_of(chan, struct timb_dma_chan, chan);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: Entry\n", __func__);
|
||||
spin_lock_bh(&td_chan->lock);
|
||||
|
||||
if (!list_empty(&td_chan->active_list))
|
||||
|
|
@ -499,20 +494,20 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
|
|||
unsigned int desc_usage = 0;
|
||||
|
||||
if (!sgl || !sg_len) {
|
||||
dev_err(chan2dev(chan), "%s: No SG list\n", __func__);
|
||||
dev_err(dmaengine_chan_dev(chan), "%s: No SG list\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* even channels are for RX, odd for TX */
|
||||
if (td_chan->direction != direction) {
|
||||
dev_err(chan2dev(chan),
|
||||
dev_err(dmaengine_chan_dev(chan),
|
||||
"Requesting channel in wrong direction\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
td_desc = td_desc_get(td_chan);
|
||||
if (!td_desc) {
|
||||
dev_err(chan2dev(chan), "Not enough descriptors available\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "Not enough descriptors available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -521,14 +516,14 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
|
|||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
int err;
|
||||
if (desc_usage > td_desc->desc_list_len) {
|
||||
dev_err(chan2dev(chan), "No descriptor space\n");
|
||||
dev_err(dmaengine_chan_dev(chan), "No descriptor space\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = td_fill_desc(td_chan, td_desc->desc_list + desc_usage, sg,
|
||||
i == (sg_len - 1));
|
||||
if (err) {
|
||||
dev_err(chan2dev(chan), "Failed to update desc: %d\n",
|
||||
dev_err(dmaengine_chan_dev(chan), "Failed to update desc: %d\n",
|
||||
err);
|
||||
td_desc_put(td_chan, td_desc);
|
||||
return NULL;
|
||||
|
|
@ -548,7 +543,7 @@ static int td_terminate_all(struct dma_chan *chan)
|
|||
container_of(chan, struct timb_dma_chan, chan);
|
||||
struct timb_dma_desc *td_desc, *_td_desc;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
|
||||
dev_dbg(dmaengine_chan_dev(chan), "%s: Entry\n", __func__);
|
||||
|
||||
/* first the easy part, put the queue into the free list */
|
||||
spin_lock_bh(&td_chan->lock);
|
||||
|
|
|
|||
|
|
@ -125,14 +125,9 @@ static struct txx9dmac_regs32 __iomem *__txx9dmac_regs32(
|
|||
#define dma_writel(ddev, name, val) \
|
||||
(__is_dmac64(ddev) ? \
|
||||
dma64_writel(ddev, name, val) : dma32_writel(ddev, name, val))
|
||||
|
||||
static struct device *chan2dev(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->dev->device;
|
||||
}
|
||||
static struct device *chan2parent(struct dma_chan *chan)
|
||||
{
|
||||
return chan->dev->device.parent;
|
||||
return dmaengine_chan_dev(chan)->parent;
|
||||
}
|
||||
|
||||
static struct txx9dmac_desc *
|
||||
|
|
@ -218,12 +213,12 @@ static struct txx9dmac_desc *txx9dmac_desc_get(struct txx9dmac_chan *dc)
|
|||
ret = desc;
|
||||
break;
|
||||
}
|
||||
dev_dbg(chan2dev(&dc->chan), "desc %p not ACKed\n", desc);
|
||||
dev_dbg(dmaengine_chan_dev(&dc->chan), "desc %p not ACKed\n", desc);
|
||||
i++;
|
||||
}
|
||||
spin_unlock_bh(&dc->lock);
|
||||
|
||||
dev_vdbg(chan2dev(&dc->chan), "scanned %u descriptors on freelist\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "scanned %u descriptors on freelist\n",
|
||||
i);
|
||||
if (!ret) {
|
||||
ret = txx9dmac_desc_alloc(dc, GFP_ATOMIC);
|
||||
|
|
@ -232,7 +227,7 @@ static struct txx9dmac_desc *txx9dmac_desc_get(struct txx9dmac_chan *dc)
|
|||
dc->descs_allocated++;
|
||||
spin_unlock_bh(&dc->lock);
|
||||
} else
|
||||
dev_err(chan2dev(&dc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dc->chan),
|
||||
"not enough descriptors available\n");
|
||||
}
|
||||
return ret;
|
||||
|
|
@ -267,11 +262,11 @@ static void txx9dmac_desc_put(struct txx9dmac_chan *dc,
|
|||
|
||||
spin_lock_bh(&dc->lock);
|
||||
list_for_each_entry(child, &desc->tx_list, desc_node)
|
||||
dev_vdbg(chan2dev(&dc->chan),
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan),
|
||||
"moving child desc %p to freelist\n",
|
||||
child);
|
||||
list_splice_init(&desc->tx_list, &dc->free_list);
|
||||
dev_vdbg(chan2dev(&dc->chan), "moving desc %p to freelist\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "moving desc %p to freelist\n",
|
||||
desc);
|
||||
list_add(&desc->desc_node, &dc->free_list);
|
||||
spin_unlock_bh(&dc->lock);
|
||||
|
|
@ -283,7 +278,7 @@ static void txx9dmac_desc_put(struct txx9dmac_chan *dc,
|
|||
static void txx9dmac_dump_regs(struct txx9dmac_chan *dc)
|
||||
{
|
||||
if (is_dmac64(dc))
|
||||
dev_err(chan2dev(&dc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dc->chan),
|
||||
" CHAR: %#llx SAR: %#llx DAR: %#llx CNTR: %#x"
|
||||
" SAIR: %#x DAIR: %#x CCR: %#x CSR: %#x\n",
|
||||
(u64)channel64_read_CHAR(dc),
|
||||
|
|
@ -295,7 +290,7 @@ static void txx9dmac_dump_regs(struct txx9dmac_chan *dc)
|
|||
channel64_readl(dc, CCR),
|
||||
channel64_readl(dc, CSR));
|
||||
else
|
||||
dev_err(chan2dev(&dc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dc->chan),
|
||||
" CHAR: %#x SAR: %#x DAR: %#x CNTR: %#x"
|
||||
" SAIR: %#x DAIR: %#x CCR: %#x CSR: %#x\n",
|
||||
channel32_readl(dc, CHAR),
|
||||
|
|
@ -333,11 +328,11 @@ static void txx9dmac_dostart(struct txx9dmac_chan *dc,
|
|||
struct txx9dmac_slave *ds = dc->chan.private;
|
||||
u32 sai, dai;
|
||||
|
||||
dev_vdbg(chan2dev(&dc->chan), "dostart %u %p\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "dostart %u %p\n",
|
||||
first->txd.cookie, first);
|
||||
/* ASSERT: channel is idle */
|
||||
if (channel_readl(dc, CSR) & TXX9_DMA_CSR_XFACT) {
|
||||
dev_err(chan2dev(&dc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dc->chan),
|
||||
"BUG: Attempted to start non-idle channel\n");
|
||||
txx9dmac_dump_regs(dc);
|
||||
/* The tasklet will hopefully advance the queue... */
|
||||
|
|
@ -402,7 +397,7 @@ txx9dmac_descriptor_complete(struct txx9dmac_chan *dc,
|
|||
struct dmaengine_desc_callback cb;
|
||||
struct dma_async_tx_descriptor *txd = &desc->txd;
|
||||
|
||||
dev_vdbg(chan2dev(&dc->chan), "descriptor %u %p complete\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "descriptor %u %p complete\n",
|
||||
txd->cookie, desc);
|
||||
|
||||
dma_cookie_complete(txd);
|
||||
|
|
@ -469,11 +464,11 @@ static void txx9dmac_dump_desc(struct txx9dmac_chan *dc,
|
|||
{
|
||||
if (is_dmac64(dc)) {
|
||||
#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
|
||||
dev_crit(chan2dev(&dc->chan),
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan),
|
||||
" desc: ch%#llx s%#llx d%#llx c%#x\n",
|
||||
(u64)desc->CHAR, desc->SAR, desc->DAR, desc->CNTR);
|
||||
#else
|
||||
dev_crit(chan2dev(&dc->chan),
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan),
|
||||
" desc: ch%#llx s%#llx d%#llx c%#x"
|
||||
" si%#x di%#x cc%#x cs%#x\n",
|
||||
(u64)desc->CHAR, desc->SAR, desc->DAR, desc->CNTR,
|
||||
|
|
@ -482,11 +477,11 @@ static void txx9dmac_dump_desc(struct txx9dmac_chan *dc,
|
|||
} else {
|
||||
struct txx9dmac_hwdesc32 *d = (struct txx9dmac_hwdesc32 *)desc;
|
||||
#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
|
||||
dev_crit(chan2dev(&dc->chan),
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan),
|
||||
" desc: ch%#x s%#x d%#x c%#x\n",
|
||||
d->CHAR, d->SAR, d->DAR, d->CNTR);
|
||||
#else
|
||||
dev_crit(chan2dev(&dc->chan),
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan),
|
||||
" desc: ch%#x s%#x d%#x c%#x"
|
||||
" si%#x di%#x cc%#x cs%#x\n",
|
||||
d->CHAR, d->SAR, d->DAR, d->CNTR,
|
||||
|
|
@ -506,7 +501,7 @@ static void txx9dmac_handle_error(struct txx9dmac_chan *dc, u32 csr)
|
|||
* borked. Since we don't have any way to report errors, we'll
|
||||
* just have to scream loudly and try to carry on.
|
||||
*/
|
||||
dev_crit(chan2dev(&dc->chan), "Abnormal Chain Completion\n");
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan), "Abnormal Chain Completion\n");
|
||||
txx9dmac_dump_regs(dc);
|
||||
|
||||
bad_desc = txx9dmac_first_active(dc);
|
||||
|
|
@ -523,7 +518,7 @@ static void txx9dmac_handle_error(struct txx9dmac_chan *dc, u32 csr)
|
|||
if (!list_empty(&dc->active_list))
|
||||
txx9dmac_dostart(dc, txx9dmac_first_active(dc));
|
||||
|
||||
dev_crit(chan2dev(&dc->chan),
|
||||
dev_crit(dmaengine_chan_dev(&dc->chan),
|
||||
"Bad descriptor submitted for DMA! (cookie: %d)\n",
|
||||
bad_desc->txd.cookie);
|
||||
txx9dmac_dump_desc(dc, &bad_desc->hwdesc);
|
||||
|
|
@ -558,7 +553,7 @@ static void txx9dmac_scan_descriptors(struct txx9dmac_chan *dc)
|
|||
if (!(csr & TXX9_DMA_CSR_CHNEN))
|
||||
chain = 0; /* last descriptor of this chain */
|
||||
|
||||
dev_vdbg(chan2dev(&dc->chan), "scan_descriptors: char=%#llx\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "scan_descriptors: char=%#llx\n",
|
||||
(u64)chain);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &dc->active_list, desc_node) {
|
||||
|
|
@ -589,7 +584,7 @@ static void txx9dmac_scan_descriptors(struct txx9dmac_chan *dc)
|
|||
return;
|
||||
}
|
||||
|
||||
dev_err(chan2dev(&dc->chan),
|
||||
dev_err(dmaengine_chan_dev(&dc->chan),
|
||||
"BUG: All descriptors done, but channel not idle!\n");
|
||||
|
||||
/* Try to continue after resetting the channel... */
|
||||
|
|
@ -609,7 +604,7 @@ static void txx9dmac_chan_tasklet(struct tasklet_struct *t)
|
|||
|
||||
dc = from_tasklet(dc, t, tasklet);
|
||||
csr = channel_readl(dc, CSR);
|
||||
dev_vdbg(chan2dev(&dc->chan), "tasklet: status=%x\n", csr);
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "tasklet: status=%x\n", csr);
|
||||
|
||||
spin_lock(&dc->lock);
|
||||
if (csr & (TXX9_DMA_CSR_ABCHC | TXX9_DMA_CSR_NCHNC |
|
||||
|
|
@ -625,7 +620,7 @@ static irqreturn_t txx9dmac_chan_interrupt(int irq, void *dev_id)
|
|||
{
|
||||
struct txx9dmac_chan *dc = dev_id;
|
||||
|
||||
dev_vdbg(chan2dev(&dc->chan), "interrupt: status=%#x\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "interrupt: status=%#x\n",
|
||||
channel_readl(dc, CSR));
|
||||
|
||||
tasklet_schedule(&dc->tasklet);
|
||||
|
|
@ -654,7 +649,7 @@ static void txx9dmac_tasklet(struct tasklet_struct *t)
|
|||
if ((mcr >> (24 + i)) & 0x11) {
|
||||
dc = ddev->chan[i];
|
||||
csr = channel_readl(dc, CSR);
|
||||
dev_vdbg(chan2dev(&dc->chan), "tasklet: status=%x\n",
|
||||
dev_vdbg(dmaengine_chan_dev(&dc->chan), "tasklet: status=%x\n",
|
||||
csr);
|
||||
spin_lock(&dc->lock);
|
||||
if (csr & (TXX9_DMA_CSR_ABCHC | TXX9_DMA_CSR_NCHNC |
|
||||
|
|
@ -696,7 +691,7 @@ static dma_cookie_t txx9dmac_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
spin_lock_bh(&dc->lock);
|
||||
cookie = dma_cookie_assign(tx);
|
||||
|
||||
dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u %p\n",
|
||||
dev_vdbg(dmaengine_chan_dev(tx->chan), "tx_submit: queued %u %p\n",
|
||||
desc->txd.cookie, desc);
|
||||
|
||||
list_add_tail(&desc->desc_node, &dc->queue);
|
||||
|
|
@ -717,11 +712,11 @@ txx9dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
size_t xfer_count;
|
||||
size_t offset;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "prep_dma_memcpy d%#llx s%#llx l%#zx f%#lx\n",
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "prep_dma_memcpy d%#llx s%#llx l%#zx f%#lx\n",
|
||||
(u64)dest, (u64)src, len, flags);
|
||||
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "prep_dma_memcpy: length is zero!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +807,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
unsigned int i;
|
||||
struct scatterlist *sg;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "prep_dma_slave\n");
|
||||
|
||||
BUG_ON(!ds || !ds->reg_width);
|
||||
if (ds->tx_reg)
|
||||
|
|
@ -900,7 +895,7 @@ static int txx9dmac_terminate_all(struct dma_chan *chan)
|
|||
struct txx9dmac_desc *desc, *_desc;
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "terminate_all\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "terminate_all\n");
|
||||
spin_lock_bh(&dc->lock);
|
||||
|
||||
txx9dmac_reset_chan(dc);
|
||||
|
|
@ -988,11 +983,11 @@ static int txx9dmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct txx9dmac_desc *desc;
|
||||
int i;
|
||||
|
||||
dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "alloc_chan_resources\n");
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
if (channel_readl(dc, CSR) & TXX9_DMA_CSR_XFACT) {
|
||||
dev_dbg(chan2dev(chan), "DMA channel not idle?\n");
|
||||
dev_dbg(dmaengine_chan_dev(chan), "DMA channel not idle?\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -1022,7 +1017,7 @@ static int txx9dmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
|
||||
desc = txx9dmac_desc_alloc(dc, GFP_KERNEL);
|
||||
if (!desc) {
|
||||
dev_info(chan2dev(chan),
|
||||
dev_info(dmaengine_chan_dev(chan),
|
||||
"only allocated %d descriptors\n", i);
|
||||
spin_lock_bh(&dc->lock);
|
||||
break;
|
||||
|
|
@ -1034,7 +1029,7 @@ static int txx9dmac_alloc_chan_resources(struct dma_chan *chan)
|
|||
}
|
||||
spin_unlock_bh(&dc->lock);
|
||||
|
||||
dev_dbg(chan2dev(chan),
|
||||
dev_dbg(dmaengine_chan_dev(chan),
|
||||
"alloc_chan_resources allocated %d descriptors\n", i);
|
||||
|
||||
return i;
|
||||
|
|
@ -1047,7 +1042,7 @@ static void txx9dmac_free_chan_resources(struct dma_chan *chan)
|
|||
struct txx9dmac_desc *desc, *_desc;
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
|
||||
dev_dbg(dmaengine_chan_dev(chan), "free_chan_resources (descs allocated=%u)\n",
|
||||
dc->descs_allocated);
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
|
|
@ -1061,13 +1056,13 @@ static void txx9dmac_free_chan_resources(struct dma_chan *chan)
|
|||
spin_unlock_bh(&dc->lock);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &list, desc_node) {
|
||||
dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc);
|
||||
dev_vdbg(dmaengine_chan_dev(chan), " freeing descriptor %p\n", desc);
|
||||
dma_unmap_single(chan2parent(chan), desc->txd.phys,
|
||||
ddev->descsize, DMA_TO_DEVICE);
|
||||
kfree(desc);
|
||||
}
|
||||
|
||||
dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
|
||||
dev_vdbg(dmaengine_chan_dev(chan), "free_chan_resources done\n");
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
|
@ -1167,26 +1162,20 @@ static void txx9dmac_chan_remove(struct platform_device *pdev)
|
|||
static int __init txx9dmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct txx9dmac_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct resource *io;
|
||||
struct txx9dmac_dev *ddev;
|
||||
void __iomem *regs;
|
||||
u32 mcr;
|
||||
int err;
|
||||
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!io)
|
||||
return -EINVAL;
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
ddev = devm_kzalloc(&pdev->dev, sizeof(*ddev), GFP_KERNEL);
|
||||
if (!ddev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, io->start, resource_size(io),
|
||||
dev_name(&pdev->dev)))
|
||||
return -EBUSY;
|
||||
|
||||
ddev->regs = devm_ioremap(&pdev->dev, io->start, resource_size(io));
|
||||
if (!ddev->regs)
|
||||
return -ENOMEM;
|
||||
ddev->regs = regs;
|
||||
ddev->have_64bit_regs = pdata->have_64bit_regs;
|
||||
if (__is_dmac64(ddev))
|
||||
ddev->descsize = sizeof(struct txx9dmac_hwdesc);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
|
|||
return container_of(chan, struct virt_dma_chan, chan);
|
||||
}
|
||||
|
||||
static inline struct device *vchan_chan_dev(struct virt_dma_chan *vc)
|
||||
{
|
||||
return dmaengine_chan_dev(&vc->chan);
|
||||
}
|
||||
|
||||
void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head);
|
||||
void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev);
|
||||
struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t);
|
||||
|
|
@ -209,6 +214,17 @@ static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
|
|||
vchan_dma_desc_free_list(vc, &head);
|
||||
}
|
||||
|
||||
/**
|
||||
* vchan_chan_name - Return vchan DMA channel device name
|
||||
* @vc: virtual channel
|
||||
*
|
||||
* Return: The name of the DMA channel device
|
||||
*/
|
||||
static inline const char *vchan_chan_name(struct virt_dma_chan *vc)
|
||||
{
|
||||
return dma_chan_name(&vc->chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* vchan_synchronize() - synchronize callback execution to the current context
|
||||
* @vc: virtual channel to synchronize
|
||||
|
|
|
|||
|
|
@ -1800,8 +1800,8 @@ static void xgene_dma_remove(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id xgene_dma_acpi_match_ptr[] = {
|
||||
{"APMC0D43", 0},
|
||||
{},
|
||||
{ .id = "APMC0D43" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, xgene_dma_acpi_match_ptr);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@
|
|||
#define XILINX_MCDMA_IRQ_ERR_MASK BIT(7)
|
||||
#define XILINX_MCDMA_BD_EOP BIT(30)
|
||||
#define XILINX_MCDMA_BD_SOP BIT(31)
|
||||
#define XILINX_MCDMA_BD_HW_SIZE 64
|
||||
|
||||
/**
|
||||
* struct xilinx_vdma_desc_hw - Hardware Descriptor
|
||||
|
|
@ -277,8 +278,10 @@ struct xilinx_axidma_desc_hw {
|
|||
* @buf_addr_msb: MSB of Buffer address @0x0C
|
||||
* @rsvd: Reserved field @0x10
|
||||
* @control: Control Information field @0x14
|
||||
* @status: Status field @0x18
|
||||
* @sideband_status: Status of sideband signals @0x1C
|
||||
* @mm2s_ctrl_sideband: Sideband control info for mm2s @0x18
|
||||
* @s2mm_status: Status field for s2mm @0x18
|
||||
* @mm2s_status: Status field for mm2s @0x1C
|
||||
* @s2mm_sideband_status: Sideband status for s2mm @0x1C
|
||||
* @app: APP Fields @0x20 - 0x30
|
||||
*/
|
||||
struct xilinx_aximcdma_desc_hw {
|
||||
|
|
@ -288,10 +291,17 @@ struct xilinx_aximcdma_desc_hw {
|
|||
u32 buf_addr_msb;
|
||||
u32 rsvd;
|
||||
u32 control;
|
||||
u32 status;
|
||||
u32 sideband_status;
|
||||
union {
|
||||
u32 mm2s_ctrl_sideband;
|
||||
u32 s2mm_status;
|
||||
};
|
||||
union {
|
||||
u32 mm2s_status;
|
||||
u32 s2mm_sideband_status;
|
||||
};
|
||||
u32 app[XILINX_DMA_NUM_APP_WORDS];
|
||||
} __aligned(64);
|
||||
static_assert(sizeof(struct xilinx_aximcdma_desc_hw) == XILINX_MCDMA_BD_HW_SIZE);
|
||||
|
||||
/**
|
||||
* struct xilinx_cdma_desc_hw - Hardware Descriptor
|
||||
|
|
@ -641,17 +651,51 @@ static inline void xilinx_aximcdma_buf(struct xilinx_dma_chan *chan,
|
|||
* @tx: async transaction descriptor
|
||||
* @payload_len: metadata payload length
|
||||
* @max_len: metadata max length
|
||||
* Return: The app field pointer.
|
||||
*
|
||||
* The metadata lives in the SOP descriptor for TX and the EOF descriptor for RX.
|
||||
* Field order depends on dmatype and direction:
|
||||
*
|
||||
* AXI DMA: [0..] app
|
||||
* AXI MCDMA (TX): [0] ctrl_sideband, [1] status, [2..] app
|
||||
* AXI MCDMA (RX): [0] status, [1] sideband, [2..] app
|
||||
*
|
||||
* Return: Pointer to the first metadata word.
|
||||
*/
|
||||
static void *xilinx_dma_get_metadata_ptr(struct dma_async_tx_descriptor *tx,
|
||||
size_t *payload_len, size_t *max_len)
|
||||
{
|
||||
struct xilinx_dma_tx_descriptor *desc = to_dma_tx_descriptor(tx);
|
||||
struct xilinx_dma_chan *chan = to_xilinx_chan(tx->chan);
|
||||
|
||||
if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
|
||||
struct xilinx_aximcdma_tx_segment *seg;
|
||||
|
||||
if (chan->direction == DMA_DEV_TO_MEM) {
|
||||
seg = list_last_entry(&desc->segments,
|
||||
struct xilinx_aximcdma_tx_segment, node);
|
||||
*max_len = *payload_len = sizeof(seg->hw.s2mm_status) +
|
||||
sizeof(seg->hw.s2mm_sideband_status) +
|
||||
sizeof(seg->hw.app);
|
||||
return &seg->hw.s2mm_status;
|
||||
}
|
||||
seg = list_first_entry(&desc->segments,
|
||||
struct xilinx_aximcdma_tx_segment, node);
|
||||
*max_len = *payload_len = sizeof(seg->hw.mm2s_ctrl_sideband) +
|
||||
sizeof(seg->hw.mm2s_status) +
|
||||
sizeof(seg->hw.app);
|
||||
return &seg->hw.mm2s_ctrl_sideband;
|
||||
}
|
||||
|
||||
struct xilinx_axidma_tx_segment *seg;
|
||||
|
||||
*max_len = *payload_len = sizeof(u32) * XILINX_DMA_NUM_APP_WORDS;
|
||||
seg = list_first_entry(&desc->segments,
|
||||
struct xilinx_axidma_tx_segment, node);
|
||||
if (chan->direction == DMA_DEV_TO_MEM)
|
||||
seg = list_last_entry(&desc->segments,
|
||||
struct xilinx_axidma_tx_segment, node);
|
||||
else
|
||||
seg = list_first_entry(&desc->segments,
|
||||
struct xilinx_axidma_tx_segment, node);
|
||||
|
||||
*max_len = *payload_len = sizeof(seg->hw.app);
|
||||
return seg->hw.app;
|
||||
}
|
||||
|
||||
|
|
@ -1025,9 +1069,11 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
|
|||
struct xilinx_aximcdma_tx_segment,
|
||||
node);
|
||||
aximcdma_hw = &aximcdma_seg->hw;
|
||||
residue +=
|
||||
(aximcdma_hw->control & chan->xdev->max_buffer_len) -
|
||||
(aximcdma_hw->status & chan->xdev->max_buffer_len);
|
||||
residue += aximcdma_hw->control & chan->xdev->max_buffer_len;
|
||||
if (chan->direction == DMA_DEV_TO_MEM)
|
||||
residue -= aximcdma_hw->s2mm_status & chan->xdev->max_buffer_len;
|
||||
else
|
||||
residue -= aximcdma_hw->mm2s_status & chan->xdev->max_buffer_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1782,6 +1828,17 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
|
|||
struct xilinx_axidma_tx_segment, node);
|
||||
if (!(seg->hw.status & XILINX_DMA_BD_COMP_MASK) && chan->has_sg)
|
||||
break;
|
||||
} else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
|
||||
struct xilinx_aximcdma_tx_segment *seg;
|
||||
u32 status;
|
||||
|
||||
seg = list_last_entry(&desc->segments,
|
||||
struct xilinx_aximcdma_tx_segment,
|
||||
node);
|
||||
status = (chan->direction == DMA_DEV_TO_MEM) ?
|
||||
seg->hw.s2mm_status : seg->hw.mm2s_status;
|
||||
if (!(status & XILINX_DMA_BD_COMP_MASK))
|
||||
break;
|
||||
}
|
||||
if (chan->has_sg && chan->xdev->dma_config->dmatype !=
|
||||
XDMA_TYPE_VDMA)
|
||||
|
|
@ -2626,6 +2683,9 @@ xilinx_mcdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
|||
segment->hw.control |= XILINX_MCDMA_BD_EOP;
|
||||
}
|
||||
|
||||
if (chan->xdev->has_axistream_connected)
|
||||
desc->async_tx.metadata_ops = &xilinx_dma_metadata_ops;
|
||||
|
||||
return &desc->async_tx;
|
||||
|
||||
error:
|
||||
|
|
@ -3274,7 +3334,8 @@ static int xilinx_dma_probe(struct platform_device *pdev)
|
|||
|
||||
dma_set_max_seg_size(xdev->dev, xdev->max_buffer_len);
|
||||
|
||||
if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
|
||||
if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA ||
|
||||
xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
|
||||
xdev->has_axistream_connected =
|
||||
of_property_read_bool(node, "xlnx,axistream-connected");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -112,8 +113,7 @@
|
|||
#define ZYNQMP_DMA_INT_DONE (ZYNQMP_DMA_DONE | ZYNQMP_DMA_DST_DSCR_DONE)
|
||||
#define ZYNQMP_DMA_INT_EN_DEFAULT_MASK (ZYNQMP_DMA_INT_DONE | \
|
||||
ZYNQMP_DMA_INT_ERR | \
|
||||
ZYNQMP_DMA_INT_OVRFL | \
|
||||
ZYNQMP_DMA_DST_DSCR_DONE)
|
||||
ZYNQMP_DMA_INT_OVRFL)
|
||||
|
||||
/* Max number of descriptors per channel */
|
||||
#define ZYNQMP_DMA_NUM_DESCS 32
|
||||
|
|
@ -128,8 +128,6 @@
|
|||
/* Reset values for data attributes */
|
||||
#define ZYNQMP_DMA_AXCACHE_VAL 0xF
|
||||
|
||||
#define ZYNQMP_DMA_SRC_ISSUE_RST_VAL 0x1F
|
||||
|
||||
#define ZYNQMP_DMA_IDS_DEFAULT_MASK 0xFFF
|
||||
|
||||
/* Bus width in bits */
|
||||
|
|
@ -205,10 +203,10 @@ struct zynqmp_dma_desc_sw {
|
|||
* @desc_pool_p: Physical allocated descriptor base
|
||||
* @desc_free_cnt: Descriptor available count
|
||||
* @dev: The dma device
|
||||
* @irq: Channel IRQ
|
||||
* @irq: Linux IRQ number, or -1 when not registered
|
||||
* @is_dmacoherent: Tells whether dma operations are coherent or not
|
||||
* @tasklet: Cleanup work after irq
|
||||
* @idle : Channel status;
|
||||
* @idle: Channel status
|
||||
* @desc_size: Size of the low level descriptor
|
||||
* @err: Channel has errors
|
||||
* @bus_width: Bus width
|
||||
|
|
@ -435,7 +433,7 @@ zynqmp_dma_get_descriptor(struct zynqmp_dma_chan *chan)
|
|||
}
|
||||
|
||||
/**
|
||||
* zynqmp_dma_free_descriptor - Issue pending transactions
|
||||
* zynqmp_dma_free_descriptor - Return a descriptor to the free pool
|
||||
* @chan: ZynqMP DMA channel pointer
|
||||
* @sdesc: Transaction descriptor pointer
|
||||
*/
|
||||
|
|
@ -483,8 +481,10 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
|
|||
return ret;
|
||||
|
||||
chan->sw_desc_pool = kzalloc_objs(*desc, ZYNQMP_DMA_NUM_DESCS);
|
||||
if (!chan->sw_desc_pool)
|
||||
return -ENOMEM;
|
||||
if (!chan->sw_desc_pool) {
|
||||
ret = -ENOMEM;
|
||||
goto err_pm;
|
||||
}
|
||||
|
||||
chan->idle = true;
|
||||
chan->desc_free_cnt = ZYNQMP_DMA_NUM_DESCS;
|
||||
|
|
@ -502,8 +502,10 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
|
|||
(2 * ZYNQMP_DMA_DESC_SIZE(chan) *
|
||||
ZYNQMP_DMA_NUM_DESCS),
|
||||
&chan->desc_pool_p, GFP_KERNEL);
|
||||
if (!chan->desc_pool_v)
|
||||
return -ENOMEM;
|
||||
if (!chan->desc_pool_v) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_sw_desc_pool;
|
||||
}
|
||||
|
||||
for (i = 0; i < ZYNQMP_DMA_NUM_DESCS; i++) {
|
||||
desc = chan->sw_desc_pool + i;
|
||||
|
|
@ -516,6 +518,13 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
|
|||
}
|
||||
|
||||
return ZYNQMP_DMA_NUM_DESCS;
|
||||
|
||||
err_free_sw_desc_pool:
|
||||
kfree(chan->sw_desc_pool);
|
||||
chan->sw_desc_pool = NULL;
|
||||
err_pm:
|
||||
pm_runtime_put_autosuspend(chan->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -606,7 +615,6 @@ static void zynqmp_dma_start_transfer(struct zynqmp_dma_chan *chan)
|
|||
zynqmp_dma_start(chan);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* zynqmp_dma_chan_desc_cleanup - Cleanup the completed descriptors
|
||||
* @chan: ZynqMP DMA channel
|
||||
|
|
@ -826,7 +834,8 @@ static void zynqmp_dma_synchronize(struct dma_chan *dchan)
|
|||
* @len: Transfer length
|
||||
* @flags: transfer ack flags
|
||||
*
|
||||
* Return: Async transaction descriptor on success and NULL on failure
|
||||
* Return: Async transaction descriptor on success and NULL on failure or
|
||||
* zero length transfer
|
||||
*/
|
||||
static struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy(
|
||||
struct dma_chan *dchan, dma_addr_t dma_dst,
|
||||
|
|
@ -841,6 +850,9 @@ static struct dma_async_tx_descriptor *zynqmp_dma_prep_memcpy(
|
|||
|
||||
chan = to_chan(dchan);
|
||||
|
||||
if (!len)
|
||||
return NULL;
|
||||
|
||||
desc_cnt = DIV_ROUND_UP(len, ZYNQMP_DMA_MAX_TRANS_LEN);
|
||||
|
||||
spin_lock_irqsave(&chan->lock, irqflags);
|
||||
|
|
@ -885,10 +897,11 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
|
|||
if (!chan)
|
||||
return;
|
||||
|
||||
if (chan->irq)
|
||||
if (chan->irq >= 0)
|
||||
devm_free_irq(chan->zdev->dev, chan->irq, chan);
|
||||
tasklet_kill(&chan->tasklet);
|
||||
list_del(&chan->common.device_node);
|
||||
if (!list_empty(&chan->common.device_node))
|
||||
list_del(&chan->common.device_node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -896,7 +909,7 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
|
|||
* @zdev: Driver specific device structure
|
||||
* @pdev: Pointer to the platform_device structure
|
||||
*
|
||||
* Return: '0' on success and failure value on error
|
||||
* Return: 0 on success and negative error code on failure
|
||||
*/
|
||||
static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
|
||||
struct platform_device *pdev)
|
||||
|
|
@ -904,13 +917,14 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
|
|||
struct zynqmp_dma_chan *chan;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct zynqmp_dma_config *match_data;
|
||||
int err;
|
||||
int err, ret;
|
||||
|
||||
chan = devm_kzalloc(zdev->dev, sizeof(*chan), GFP_KERNEL);
|
||||
if (!chan)
|
||||
return -ENOMEM;
|
||||
chan->dev = zdev->dev;
|
||||
chan->zdev = zdev;
|
||||
chan->irq = -1;
|
||||
|
||||
chan->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(chan->regs))
|
||||
|
|
@ -935,7 +949,7 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
|
|||
if (match_data)
|
||||
chan->irq_offset = match_data->offset;
|
||||
|
||||
chan->is_dmacoherent = of_property_read_bool(node, "dma-coherent");
|
||||
chan->is_dmacoherent = of_dma_is_coherent(node);
|
||||
zdev->chan = chan;
|
||||
tasklet_setup(&chan->tasklet, zynqmp_dma_do_tasklet);
|
||||
spin_lock_init(&chan->lock);
|
||||
|
|
@ -943,22 +957,27 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
|
|||
INIT_LIST_HEAD(&chan->pending_list);
|
||||
INIT_LIST_HEAD(&chan->done_list);
|
||||
INIT_LIST_HEAD(&chan->free_list);
|
||||
INIT_LIST_HEAD(&chan->common.device_node);
|
||||
|
||||
dma_cookie_init(&chan->common);
|
||||
chan->common.device = &zdev->common;
|
||||
list_add_tail(&chan->common.device_node, &zdev->common.channels);
|
||||
|
||||
zynqmp_dma_init(chan);
|
||||
chan->irq = platform_get_irq(pdev, 0);
|
||||
if (chan->irq < 0)
|
||||
return -ENXIO;
|
||||
err = devm_request_irq(&pdev->dev, chan->irq, zynqmp_dma_irq_handler, 0,
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, ret, zynqmp_dma_irq_handler, 0,
|
||||
"zynqmp-dma", chan);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
chan->irq = ret;
|
||||
|
||||
chan->desc_size = sizeof(struct zynqmp_dma_desc_ll);
|
||||
chan->idle = true;
|
||||
list_add_tail(&chan->common.device_node, &zdev->common.channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1025,11 +1044,11 @@ static int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* zynqmp_dma_runtime_resume - Runtime suspend method for the driver
|
||||
* zynqmp_dma_runtime_resume - Runtime resume method for the driver
|
||||
* @dev: Address of the device structure
|
||||
*
|
||||
* Put the driver into low power mode.
|
||||
* Return: 0 always
|
||||
* Enable device clocks.
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
static int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev)
|
||||
{
|
||||
|
|
@ -1123,7 +1142,7 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
|
|||
ret = zynqmp_dma_chan_probe(zdev, pdev);
|
||||
if (ret) {
|
||||
dev_err_probe(&pdev->dev, ret, "Probing channel failed\n");
|
||||
goto err_disable_pm;
|
||||
goto free_chan_resources;
|
||||
}
|
||||
|
||||
p->dst_addr_widths = BIT(zdev->chan->bus_width / 8);
|
||||
|
|
@ -1149,7 +1168,6 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
|
|||
|
||||
free_chan_resources:
|
||||
zynqmp_dma_chan_remove(zdev->chan);
|
||||
err_disable_pm:
|
||||
if (!pm_runtime_enabled(zdev->dev))
|
||||
zynqmp_dma_runtime_suspend(zdev->dev);
|
||||
pm_runtime_disable(zdev->dev);
|
||||
|
|
|
|||
|
|
@ -1041,6 +1041,7 @@ static void dw_pcie_edma_init_data(struct dw_pcie *pci)
|
|||
pci->edma.ops = &dw_pcie_edma_ops;
|
||||
|
||||
pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
|
||||
pci->edma.ch_space_sz = 256;
|
||||
}
|
||||
|
||||
static int dw_pcie_edma_find_mf(struct dw_pcie *pci)
|
||||
|
|
|
|||
8
include/dt-bindings/dma/amlogic,a9-dma.h
Normal file
8
include/dt-bindings/dma/amlogic,a9-dma.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
|
||||
#ifndef __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
|
||||
#define __DT_BINDINGS_DMA_AMLOGIC_DMA_H__
|
||||
|
||||
#define AMLOGIC_A9_DMA_TX 0
|
||||
#define AMLOGIC_A9_DMA_RX 1
|
||||
#endif /* __DT_BINDINGS_DMA_AMLOGIC_DMA_H__ */
|
||||
|
|
@ -101,6 +101,27 @@ enum dw_edma_ch_irq_mode {
|
|||
DW_EDMA_CH_IRQ_REMOTE,
|
||||
};
|
||||
|
||||
#define DW_EDMA_CH_CONFIG_NON_LL BIT(0)
|
||||
#define DW_EDMA_CH_CONFIG_IRQ_MODE BIT(1)
|
||||
|
||||
/**
|
||||
* struct dw_edma_chan_config - dw-edma channel configuration
|
||||
* @flags: fields selected by DW_EDMA_CH_CONFIG_*
|
||||
* @non_ll: use HDMA non-linked-list mode
|
||||
* @irq_mode: interrupt routing mode
|
||||
*
|
||||
* Pass this structure through dma_slave_config.peripheral_config. Before
|
||||
* synchronizing a remote-routed channel, the client must stop remote
|
||||
* programming and own every channel affected by the hardware quiesce: the
|
||||
* entire direction for eDMA-compatible layouts, or the individual channel for
|
||||
* native HDMA.
|
||||
*/
|
||||
struct dw_edma_chan_config {
|
||||
u32 flags;
|
||||
bool non_ll;
|
||||
enum dw_edma_ch_irq_mode irq_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dw_edma_chip - representation of DesignWare eDMA controller hardware
|
||||
* @dev: struct device of the eDMA controller
|
||||
|
|
@ -130,7 +151,7 @@ struct dw_edma_chip {
|
|||
|
||||
u16 ll_wr_cnt;
|
||||
u16 ll_rd_cnt;
|
||||
/* link list address */
|
||||
/* Linked-list regions must not cross a 4 GiB address boundary. */
|
||||
struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH];
|
||||
struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH];
|
||||
|
||||
|
|
@ -147,6 +168,7 @@ struct dw_edma_chip {
|
|||
|
||||
struct dw_edma *dw;
|
||||
bool cfg_non_ll;
|
||||
u32 ch_space_sz;
|
||||
};
|
||||
|
||||
/* Export to the platform drivers */
|
||||
|
|
|
|||
|
|
@ -57,15 +57,12 @@ struct imx_dma_data {
|
|||
int priority;
|
||||
};
|
||||
|
||||
static inline int imx_dma_is_ipu(struct dma_chan *chan)
|
||||
{
|
||||
return !strcmp(dev_name(chan->device->dev), "ipu-core");
|
||||
}
|
||||
|
||||
static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
|
||||
{
|
||||
return !strcmp(chan->device->dev->driver->name, "imx-sdma") ||
|
||||
!strcmp(chan->device->dev->driver->name, "imx-dma");
|
||||
struct device *dev = dmaengine_get_provider_device(chan);
|
||||
|
||||
return !strcmp(dev->driver->name, "imx-sdma") ||
|
||||
!strcmp(dev->driver->name, "imx-dma");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -325,7 +325,8 @@ struct dma_router {
|
|||
* @lock: protect between config and prepare transfer when driver have not
|
||||
* implemented callback device_prep_config_sg().
|
||||
* @chan_id: channel ID for sysfs
|
||||
* @dev: class device for sysfs
|
||||
* @chan_dev: class channel device for sysfs, some device use it for per-channel
|
||||
* IOMMU mapping.
|
||||
* @name: backlink name for sysfs
|
||||
* @dbg_client_name: slave name for debugfs in format:
|
||||
* dev_name(requester's dev):channel name, for example: "2b00000.mcasp:tx"
|
||||
|
|
@ -351,7 +352,14 @@ struct dma_chan {
|
|||
|
||||
/* sysfs */
|
||||
int chan_id;
|
||||
struct dma_chan_dev *dev;
|
||||
union {
|
||||
struct dma_chan_dev *chan_dev;
|
||||
/*
|
||||
* Use chan_dev; dev will be removed once all users are
|
||||
* converted.
|
||||
*/
|
||||
struct dma_chan_dev *dev;
|
||||
};
|
||||
const char *name;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
char *dbg_client_name;
|
||||
|
|
@ -369,6 +377,26 @@ struct dma_chan {
|
|||
void *private;
|
||||
};
|
||||
|
||||
#define DMA_CHAN_ID_STATIC BIT(30)
|
||||
|
||||
/**
|
||||
* dmaengine_set_static_chan_id - request an exact DMA engine channel ID
|
||||
* @chan: DMA channel
|
||||
* @id: channel ID, unique within the DMA device
|
||||
*
|
||||
* Drivers may call this after initializing @chan and before registering its
|
||||
* DMA device. The dmaengine core reserves @id from the device IDA instead of
|
||||
* assigning the next available ID.
|
||||
*/
|
||||
static inline void dmaengine_set_static_chan_id(struct dma_chan *chan,
|
||||
unsigned int id)
|
||||
{
|
||||
if (WARN_ON_ONCE(id >= DMA_CHAN_ID_STATIC))
|
||||
return;
|
||||
|
||||
chan->chan_id = DMA_CHAN_ID_STATIC | id;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dma_chan_dev - relate sysfs device node to backing channel device
|
||||
* @chan: driver channel device
|
||||
|
|
@ -532,7 +560,7 @@ struct dma_slave_caps {
|
|||
|
||||
static inline const char *dma_chan_name(struct dma_chan *chan)
|
||||
{
|
||||
return dev_name(&chan->dev->device);
|
||||
return dev_name(&chan->chan_dev->device);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -981,12 +1009,6 @@ static inline int dmaengine_slave_config(struct dma_chan *chan,
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline bool is_slave_direction(enum dma_transfer_direction direction)
|
||||
{
|
||||
return (direction == DMA_MEM_TO_DEV) || (direction == DMA_DEV_TO_MEM) ||
|
||||
(direction == DMA_DEV_TO_DEV);
|
||||
}
|
||||
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_config_single(struct dma_chan *chan, dma_addr_t buf, size_t len,
|
||||
enum dma_transfer_direction dir,
|
||||
|
|
@ -1224,6 +1246,137 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
|
|||
len, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_max_xor - get the maximum number of XOR sources for a channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Returns the maximum number of source buffers supported by the XOR engine
|
||||
* behind @chan, or 0 if the channel does not support XOR operations.
|
||||
*/
|
||||
static inline unsigned int dmaengine_get_max_xor(struct dma_chan *chan)
|
||||
{
|
||||
if (!chan || !chan->device)
|
||||
return 0;
|
||||
|
||||
return chan->device->max_xor;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_dma_xor - prepare a DMA XOR operation
|
||||
* @chan: the channel to use for this operation
|
||||
* @dst: destination buffer address
|
||||
* @src: array of source buffer addresses
|
||||
* @src_cnt: number of source buffers
|
||||
* @len: length in bytes of each source and destination buffer
|
||||
* @flags: DMA engine flags (e.g. DMA_PREP_INTERRUPT)
|
||||
*
|
||||
* Prepare an XOR parity generation transaction. The engine computes:
|
||||
* dst = src[0] XOR src[1] XOR ... XOR src[src_cnt - 1]
|
||||
*
|
||||
* Returns a descriptor on success, or NULL if the channel does not support
|
||||
* this operation or the request could not be queued.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_dma_xor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
|
||||
unsigned int src_cnt, size_t len, unsigned long flags)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_dma_xor)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_dma_xor(chan, dst, src,
|
||||
src_cnt, len, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_dma_xor_val - prepare a DMA XOR zero-sum validation operation
|
||||
* @chan: the channel to use for this operation
|
||||
* @src: array of source buffer addresses
|
||||
* @src_cnt: number of source buffers
|
||||
* @len: length in bytes of each source buffer
|
||||
* @result: output flag set to SUM_CHECK_P_RESULT if the XOR of all sources
|
||||
* is non-zero (i.e. parity error), cleared otherwise
|
||||
* @flags: DMA engine flags (e.g. DMA_PREP_INTERRUPT)
|
||||
*
|
||||
* Prepare an XOR zero-sum validation transaction. The engine XORs all
|
||||
* source buffers and checks whether the result is zero. The outcome is
|
||||
* written to @result on completion.
|
||||
*
|
||||
* Returns a descriptor on success, or NULL if the channel does not support
|
||||
* this operation or the request could not be queued.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *src,
|
||||
unsigned int src_cnt, size_t len,
|
||||
enum sum_check_flags *result, unsigned long flags)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_dma_xor_val)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_dma_xor_val(chan, src, src_cnt,
|
||||
len, result, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_dma_pq - prepare a DMA PQ (RAID-6 P+Q) operation
|
||||
* @chan: the channel to use for this operation
|
||||
* @dst: array of two destination addresses: dst[0] for P, dst[1] for Q
|
||||
* @src: array of source buffer addresses
|
||||
* @src_cnt: number of source buffers
|
||||
* @scf: array of scaling coefficients, one per source buffer
|
||||
* @len: length in bytes of each source and destination buffer
|
||||
* @flags: DMA engine flags (e.g. DMA_PREP_INTERRUPT)
|
||||
*
|
||||
* Prepare a P+Q parity generation transaction. The engine computes:
|
||||
* P = XOR of all source buffers
|
||||
* Q = Galois field sum of (scf[i] * src[i]) over all sources
|
||||
*
|
||||
* Returns a descriptor on success, or NULL if the channel does not support
|
||||
* this operation or the request could not be queued.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
|
||||
unsigned int src_cnt, const unsigned char *scf,
|
||||
size_t len, unsigned long flags)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_dma_pq)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_dma_pq(chan, dst, src,
|
||||
src_cnt, scf, len, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_prep_dma_pq_val - prepare a DMA PQ validation operation
|
||||
* @chan: the channel to use for this operation
|
||||
* @pq: array of two addresses holding existing P and Q parity buffers
|
||||
* @src: array of source buffer addresses
|
||||
* @src_cnt: number of source buffers
|
||||
* @scf: array of scaling coefficients, one per source buffer
|
||||
* @len: length in bytes of each buffer
|
||||
* @pqres: output flags indicating P and/or Q check results (SUM_CHECK_P_VALID,
|
||||
* SUM_CHECK_Q_VALID)
|
||||
* @flags: DMA engine flags (e.g. DMA_PREP_INTERRUPT)
|
||||
*
|
||||
* Prepare a PQ validation transaction. The engine recomputes P and Q from the
|
||||
* source buffers and compares them against the existing parity stored at @pq.
|
||||
* The result of each comparison is reported through @pqres.
|
||||
*
|
||||
* Returns a descriptor on success, or NULL if the channel does not support
|
||||
* this operation or the request could not be queued.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
|
||||
unsigned int src_cnt, const unsigned char *scf,
|
||||
size_t len, enum sum_check_flags *pqres, unsigned long flags)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_dma_pq_val)
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_dma_pq_val(chan, pq, src,
|
||||
src_cnt, scf, len,
|
||||
pqres, flags);
|
||||
}
|
||||
|
||||
static inline bool dmaengine_is_metadata_mode_supported(struct dma_chan *chan,
|
||||
enum dma_desc_metadata_mode mode)
|
||||
{
|
||||
|
|
@ -1413,6 +1566,130 @@ static inline bool is_dma_fill_aligned(struct dma_device *dev, size_t off1,
|
|||
return dmaengine_check_align(dev->fill_align, off1, off2, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_copy_align - get copy alignment requirement of a DMA channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return the copy alignment requirement of @chan as a power-of-2 exponent.
|
||||
*/
|
||||
static inline enum dmaengine_alignment
|
||||
dmaengine_get_copy_align(struct dma_chan *chan)
|
||||
{
|
||||
return chan->device->copy_align;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_xor_align - get xor alignment requirement of a DMA channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return the xor alignment requirement of @chan as a power-of-2 exponent.
|
||||
*/
|
||||
static inline enum dmaengine_alignment
|
||||
dmaengine_get_xor_align(struct dma_chan *chan)
|
||||
{
|
||||
return chan->device->xor_align;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_pq_align - get pq alignment requirement of a DMA channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return the pq alignment requirement of @chan as a power-of-2 exponent.
|
||||
*/
|
||||
static inline enum dmaengine_alignment
|
||||
dmaengine_get_pq_align(struct dma_chan *chan)
|
||||
{
|
||||
return chan->device->pq_align;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_fill_align - get fill alignment requirement of a DMA channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return the fill alignment requirement of @chan as a power-of-2 exponent.
|
||||
*/
|
||||
static inline enum dmaengine_alignment
|
||||
dmaengine_get_fill_align(struct dma_chan *chan)
|
||||
{
|
||||
return chan->device->fill_align;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_get_cap_mask - get capability mask of a DMA channel
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return a pointer to the capability mask of the DMA device backing @chan.
|
||||
*/
|
||||
static inline const dma_cap_mask_t *
|
||||
dmaengine_get_cap_mask(struct dma_chan *chan)
|
||||
{
|
||||
return &chan->device->cap_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_is_copy_aligned - test copy alignment
|
||||
* @chan: DMA channel
|
||||
* @off1: first buffer offset
|
||||
* @off2: second buffer offset
|
||||
* @len: transfer length
|
||||
*
|
||||
* Return true if off1, off2 and len satisfy the copy alignment requirement of
|
||||
* the DMA channel, false otherwise.
|
||||
*/
|
||||
static inline bool dmaengine_is_copy_aligned(struct dma_chan *chan, size_t off1,
|
||||
size_t off2, size_t len)
|
||||
{
|
||||
return dmaengine_check_align(chan->device->copy_align, off1, off2, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_is_xor_aligned - test xor alignment
|
||||
* @chan: DMA channel
|
||||
* @off1: first buffer offset
|
||||
* @off2: second buffer offset
|
||||
* @len: transfer length
|
||||
*
|
||||
* Return true if off1, off2 and len satisfy the xor alignment requirement of
|
||||
* the DMA channel, false otherwise.
|
||||
*/
|
||||
static inline bool dmaengine_is_xor_aligned(struct dma_chan *chan, size_t off1,
|
||||
size_t off2, size_t len)
|
||||
{
|
||||
return dmaengine_check_align(chan->device->xor_align, off1, off2, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_is_pq_aligned - test pq alignment
|
||||
* @chan: DMA channel
|
||||
* @off1: first buffer offset
|
||||
* @off2: second buffer offset
|
||||
* @len: transfer length
|
||||
*
|
||||
* Return true if off1, off2 and len satisfy the pq alignment requirement of
|
||||
* the DMA channel, false otherwise.
|
||||
*/
|
||||
static inline bool dmaengine_is_pq_aligned(struct dma_chan *chan, size_t off1,
|
||||
size_t off2, size_t len)
|
||||
{
|
||||
return dmaengine_check_align(chan->device->pq_align, off1, off2, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_is_fill_aligned - test fill alignment
|
||||
* @chan: DMA channel
|
||||
* @off1: first buffer offset
|
||||
* @off2: second buffer offset
|
||||
* @len: transfer length
|
||||
*
|
||||
* Return true if off1, off2 and len satisfy the fill alignment requirement of
|
||||
* the DMA channel, false otherwise.
|
||||
*/
|
||||
static inline bool dmaengine_is_fill_aligned(struct dma_chan *chan, size_t off1,
|
||||
size_t off2, size_t len)
|
||||
{
|
||||
return dmaengine_check_align(chan->device->fill_align, off1, off2, len);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dma_set_maxpq(struct dma_device *dma, int maxpq, int has_pq_continue)
|
||||
{
|
||||
|
|
@ -1574,9 +1851,40 @@ __dma_has_cap(enum dma_transaction_type tx_type, dma_cap_mask_t *srcp)
|
|||
return test_bit(tx_type, srcp->bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_has_cap - test whether a DMA channel supports a transaction type
|
||||
* @chan: DMA channel
|
||||
* @tx_type: transaction type to test
|
||||
*
|
||||
* Return true if @chan supports @tx_type, false otherwise.
|
||||
*/
|
||||
static inline bool
|
||||
dmaengine_has_cap(struct dma_chan *chan, enum dma_transaction_type tx_type)
|
||||
{
|
||||
return dma_has_cap(tx_type, chan->device->cap_mask);
|
||||
}
|
||||
|
||||
#define for_each_dma_cap_mask(cap, mask) \
|
||||
for_each_set_bit(cap, mask.bits, DMA_TX_TYPE_END)
|
||||
|
||||
/**
|
||||
* dmaengine_prep_dma_interrupt() - Prepare a DMA interrupt descriptor.
|
||||
* @chan: The channel to be used for this descriptor
|
||||
* @flags: DMA engine flags
|
||||
*
|
||||
* Returns a descriptor for an interrupt transaction, or NULL if the
|
||||
* channel does not support DMA_INTERRUPT.
|
||||
*/
|
||||
static inline struct dma_async_tx_descriptor *
|
||||
dmaengine_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
|
||||
{
|
||||
if (!chan || !chan->device || !chan->device->device_prep_dma_interrupt ||
|
||||
!dma_has_cap(DMA_INTERRUPT, chan->device->cap_mask))
|
||||
return NULL;
|
||||
|
||||
return chan->device->device_prep_dma_interrupt(chan, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_async_issue_pending - flush pending transactions to HW
|
||||
* @chan: target DMA channel
|
||||
|
|
@ -1746,16 +2054,33 @@ static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc)
|
|||
return desc->desc_free(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* dmaengine_desc_set_callback - set the callback, callback_result and
|
||||
* parameter on a descriptor
|
||||
* @tx: the descriptor to set the callback on
|
||||
* @cb: the plain completion callback, or NULL
|
||||
* @cb_result: the result-bearing completion callback, or NULL
|
||||
* @cb_param: the parameter to pass to the callback
|
||||
*
|
||||
* Sets the completion callbacks and their shared parameter on a DMA
|
||||
* transaction descriptor. Use this helper instead of assigning the fields
|
||||
* directly to ensure all three related fields are updated consistently.
|
||||
* Only one of @cb and @cb_result should be non-NULL; if both are provided
|
||||
* @cb_result takes precedence in drivers that support it.
|
||||
*/
|
||||
static inline void
|
||||
dmaengine_desc_set_callback(struct dma_async_tx_descriptor *tx,
|
||||
dma_async_tx_callback cb,
|
||||
dma_async_tx_callback_result cb_result,
|
||||
void *cb_param)
|
||||
{
|
||||
tx->callback = cb;
|
||||
tx->callback_result = cb_result;
|
||||
tx->callback_param = cb_param;
|
||||
}
|
||||
|
||||
/* --- DMA device --- */
|
||||
|
||||
int dma_async_device_register(struct dma_device *device);
|
||||
int dmaenginem_async_device_register(struct dma_device *device);
|
||||
void dma_async_device_unregister(struct dma_device *device);
|
||||
int dma_async_device_channel_register(struct dma_device *device,
|
||||
struct dma_chan *chan,
|
||||
const char *name);
|
||||
void dma_async_device_channel_unregister(struct dma_device *device,
|
||||
struct dma_chan *chan);
|
||||
void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
|
||||
#define dma_request_channel(mask, x, y) \
|
||||
__dma_request_channel(&(mask), x, y, NULL)
|
||||
|
|
@ -1777,29 +2102,36 @@ static inline struct dma_chan
|
|||
return dma_request_channel(mask, fn, fn_param);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
dmaengine_get_direction_text(enum dma_transfer_direction dir)
|
||||
static inline struct device *dmaengine_chan_dev(struct dma_chan *chan)
|
||||
{
|
||||
switch (dir) {
|
||||
case DMA_DEV_TO_MEM:
|
||||
return "DEV_TO_MEM";
|
||||
case DMA_MEM_TO_DEV:
|
||||
return "MEM_TO_DEV";
|
||||
case DMA_MEM_TO_MEM:
|
||||
return "MEM_TO_MEM";
|
||||
case DMA_DEV_TO_DEV:
|
||||
return "DEV_TO_DEV";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
return &chan->chan_dev->device;
|
||||
}
|
||||
|
||||
static inline struct device *dmaengine_get_dma_device(struct dma_chan *chan)
|
||||
/*
|
||||
* dmaengine_get_provider_device() - Get DMA engine provider device. Typical
|
||||
* use is to find a DMA channel by filter.
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return: Pointer to the DMA engine provider device.
|
||||
*/
|
||||
static inline struct device *dmaengine_get_provider_device(struct dma_chan *chan)
|
||||
{
|
||||
if (chan->dev->chan_dma_dev)
|
||||
return &chan->dev->device;
|
||||
|
||||
return chan->device->dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* dmaengine_get_dma_device() - Get DMA device used for DMA mapping. Some
|
||||
* DMA engines provide per-channel iommu mapping.
|
||||
* @chan: DMA channel
|
||||
*
|
||||
* Return: Pointer to the device used for DMA mapping.
|
||||
*/
|
||||
static inline struct device *dmaengine_get_dma_device(struct dma_chan *chan)
|
||||
{
|
||||
if (chan->chan_dev->chan_dma_dev)
|
||||
return dmaengine_chan_dev(chan);
|
||||
|
||||
return dmaengine_get_provider_device(chan);
|
||||
}
|
||||
|
||||
#endif /* DMAENGINE_H */
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@ struct bcom_gen_bd {
|
|||
};
|
||||
|
||||
|
||||
extern struct bcom_task *
|
||||
bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
|
||||
int initiator, int ipr, int maxbufsize);
|
||||
|
||||
extern int
|
||||
bcom_gen_bd_rx_reset(struct bcom_task *tsk);
|
||||
|
||||
|
|
@ -27,10 +23,6 @@ extern void
|
|||
bcom_gen_bd_rx_release(struct bcom_task *tsk);
|
||||
|
||||
|
||||
extern struct bcom_task *
|
||||
bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
|
||||
int initiator, int ipr);
|
||||
|
||||
extern int
|
||||
bcom_gen_bd_tx_reset(struct bcom_task *tsk);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ TRACE_EVENT(tegra_dma_tx_status,
|
|||
TP_PROTO(struct dma_chan *dc, dma_cookie_t cookie, struct dma_tx_state *state),
|
||||
TP_ARGS(dc, cookie, state),
|
||||
TP_STRUCT__entry(
|
||||
__string(chan, dev_name(&dc->dev->device))
|
||||
__string(chan, dma_chan_name(dc))
|
||||
__field(dma_cookie_t, cookie)
|
||||
__field(__u32, residue)
|
||||
),
|
||||
|
|
@ -28,7 +28,7 @@ TRACE_EVENT(tegra_dma_complete_cb,
|
|||
TP_PROTO(struct dma_chan *dc, int count, void *ptr),
|
||||
TP_ARGS(dc, count, ptr),
|
||||
TP_STRUCT__entry(
|
||||
__string(chan, dev_name(&dc->dev->device))
|
||||
__string(chan, dma_chan_name(dc))
|
||||
__field(int, count)
|
||||
__field(void *, ptr)
|
||||
),
|
||||
|
|
@ -45,7 +45,7 @@ TRACE_EVENT(tegra_dma_isr,
|
|||
TP_PROTO(struct dma_chan *dc, int irq),
|
||||
TP_ARGS(dc, irq),
|
||||
TP_STRUCT__entry(
|
||||
__string(chan, dev_name(&dc->dev->device))
|
||||
__string(chan, dma_chan_name(dc))
|
||||
__field(int, irq)
|
||||
),
|
||||
TP_fast_assign(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user