1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2021-2022 Digiteq Automotive
4 * author: Martin Tuma <martin.tuma@digiteqautomotive.com>
6 * This module handles the DMA transfers. A standard dmaengine API as provided
7 * by the XDMA module is used.
10 #include <linux/pci.h>
11 #include <linux/dma-direction.h>
12 #include "mgb4_core.h"
15 static void chan_irq(void *param
)
17 struct mgb4_dma_channel
*chan
= param
;
19 complete(&chan
->req_compl
);
22 int mgb4_dma_transfer(struct mgb4_dev
*mgbdev
, u32 channel
, bool write
,
23 u64 paddr
, struct sg_table
*sgt
)
25 struct dma_slave_config cfg
;
26 struct mgb4_dma_channel
*chan
;
27 struct dma_async_tx_descriptor
*tx
;
28 struct pci_dev
*pdev
= mgbdev
->pdev
;
31 memset(&cfg
, 0, sizeof(cfg
));
34 cfg
.direction
= DMA_MEM_TO_DEV
;
36 cfg
.dst_addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
37 chan
= &mgbdev
->h2c_chan
[channel
];
39 cfg
.direction
= DMA_DEV_TO_MEM
;
41 cfg
.src_addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
42 chan
= &mgbdev
->c2h_chan
[channel
];
45 ret
= dmaengine_slave_config(chan
->chan
, &cfg
);
47 dev_err(&pdev
->dev
, "failed to config dma: %d\n", ret
);
51 tx
= dmaengine_prep_slave_sg(chan
->chan
, sgt
->sgl
, sgt
->nents
,
54 dev_err(&pdev
->dev
, "failed to prep slave sg\n");
58 tx
->callback
= chan_irq
;
59 tx
->callback_param
= chan
;
61 ret
= dma_submit_error(dmaengine_submit(tx
));
63 dev_err(&pdev
->dev
, "failed to submit sg\n");
67 dma_async_issue_pending(chan
->chan
);
69 if (!wait_for_completion_timeout(&chan
->req_compl
,
70 msecs_to_jiffies(10000))) {
71 dev_err(&pdev
->dev
, "dma timeout\n");
72 dmaengine_terminate_sync(chan
->chan
);
79 int mgb4_dma_channel_init(struct mgb4_dev
*mgbdev
)
83 struct pci_dev
*pdev
= mgbdev
->pdev
;
85 for (i
= 0; i
< MGB4_VIN_DEVICES
; i
++) {
86 sprintf(name
, "c2h%d", i
);
87 mgbdev
->c2h_chan
[i
].chan
= dma_request_chan(&pdev
->dev
, name
);
88 if (IS_ERR(mgbdev
->c2h_chan
[i
].chan
)) {
89 dev_err(&pdev
->dev
, "failed to initialize %s", name
);
90 ret
= PTR_ERR(mgbdev
->c2h_chan
[i
].chan
);
91 mgbdev
->c2h_chan
[i
].chan
= NULL
;
94 init_completion(&mgbdev
->c2h_chan
[i
].req_compl
);
96 for (i
= 0; i
< MGB4_VOUT_DEVICES
; i
++) {
97 sprintf(name
, "h2c%d", i
);
98 mgbdev
->h2c_chan
[i
].chan
= dma_request_chan(&pdev
->dev
, name
);
99 if (IS_ERR(mgbdev
->h2c_chan
[i
].chan
)) {
100 dev_err(&pdev
->dev
, "failed to initialize %s", name
);
101 ret
= PTR_ERR(mgbdev
->h2c_chan
[i
].chan
);
102 mgbdev
->h2c_chan
[i
].chan
= NULL
;
105 init_completion(&mgbdev
->h2c_chan
[i
].req_compl
);
111 void mgb4_dma_channel_free(struct mgb4_dev
*mgbdev
)
115 for (i
= 0; i
< MGB4_VIN_DEVICES
; i
++) {
116 if (mgbdev
->c2h_chan
[i
].chan
)
117 dma_release_channel(mgbdev
->c2h_chan
[i
].chan
);
119 for (i
= 0; i
< MGB4_VOUT_DEVICES
; i
++) {
120 if (mgbdev
->h2c_chan
[i
].chan
)
121 dma_release_channel(mgbdev
->h2c_chan
[i
].chan
);