Skip to content

Commit 8353813

Browse files
nxpfranklibjorn-helgaas
authored andcommitted
PCI: endpoint: Enable DMA tests for endpoints with DMA capabilities
Some PCI Endpoint controllers integrate an eDMA (embedded DMA). eDMA can bypass the outbound memory address translation unit to access all RC memory space. Add eDMA support for pci-epf-test. Depending on HW availability, the EPF test can use either eDMA or general system DMA controllers to perform DMA. The test tries to use eDMA first and falls back to general system DMA controllers if there's no eDMA Separate dma_chan to dma_chan_tx and dma_chan_rx. Search for an eDMA channel first, then search for a memory-to-memory DMA channel. If general memory to memory channels are used, dma_chan_rx = dma_chan_tx. Add dma_addr_t dma_remote in pci_epf_test_data_transfer() because eDMA uses remote RC physical address directly. Add enum dma_transfer_direction dir in pci_epf_test_data_transfer() because eDMA chooses the correct RX/TX channel by dir. The overall steps are: 1. Execute dma_request_channel() and filter function to find correct eDMA RX and TX Channel. If a channel does not exist, fallback to try to allocate general memory to memory DMA channel. 2. Execute dmaengine_slave_config() to configure remote side physical address. 3. Execute dmaengine_prep_slave_single() to create transfer descriptor. 4. Execute tx_submit(). 5. Execute dma_async_issue_pending() [bhelgaas: squash in fix from Dan Carpenter <[email protected]>: https://lore.kernel.org/r/Ys2GSTnZhuLzzQG5@kili, also previously posted by Peng Wu <[email protected]>: https://lore.kernel.org/all/CANXvt5rK98-cEMgpzopY9POOK8a5=VDib8uKPLgJakOG=hRfwQ@mail.gmail.com/] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Frank Li <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Acked-by: Manivannan Sadhasivam <[email protected]> Acked-by: Kishon Vijay Abraham I <[email protected]> Acked-By: Vinod Koul <[email protected]>
1 parent d6b0317 commit 8353813

File tree

1 file changed

+106
-10
lines changed

1 file changed

+106
-10
lines changed

drivers/pci/endpoint/functions/pci-epf-test.c

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ struct pci_epf_test {
5252
enum pci_barno test_reg_bar;
5353
size_t msix_table_offset;
5454
struct delayed_work cmd_handler;
55-
struct dma_chan *dma_chan;
55+
struct dma_chan *dma_chan_tx;
56+
struct dma_chan *dma_chan_rx;
5657
struct completion transfer_complete;
5758
bool dma_supported;
59+
bool dma_private;
5860
const struct pci_epc_features *epc_features;
5961
};
6062

@@ -96,6 +98,8 @@ static void pci_epf_test_dma_callback(void *param)
9698
* @dma_src: The source address of the data transfer. It can be a physical
9799
* address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
98100
* @len: The size of the data transfer
101+
* @dma_remote: remote RC physical address
102+
* @dir: DMA transfer direction
99103
*
100104
* Function that uses dmaengine API to transfer data between PCIe EP and remote
101105
* PCIe RC. The source and destination address can be a physical address given
@@ -105,12 +109,16 @@ static void pci_epf_test_dma_callback(void *param)
105109
*/
106110
static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
107111
dma_addr_t dma_dst, dma_addr_t dma_src,
108-
size_t len)
112+
size_t len, dma_addr_t dma_remote,
113+
enum dma_transfer_direction dir)
109114
{
115+
struct dma_chan *chan = (dir == DMA_DEV_TO_MEM) ?
116+
epf_test->dma_chan_tx : epf_test->dma_chan_rx;
117+
dma_addr_t dma_local = (dir == DMA_MEM_TO_DEV) ? dma_src : dma_dst;
110118
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
111-
struct dma_chan *chan = epf_test->dma_chan;
112119
struct pci_epf *epf = epf_test->epf;
113120
struct dma_async_tx_descriptor *tx;
121+
struct dma_slave_config sconf = {};
114122
struct device *dev = &epf->dev;
115123
dma_cookie_t cookie;
116124
int ret;
@@ -120,7 +128,24 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
120128
return -EINVAL;
121129
}
122130

123-
tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
131+
if (epf_test->dma_private) {
132+
sconf.direction = dir;
133+
if (dir == DMA_MEM_TO_DEV)
134+
sconf.dst_addr = dma_remote;
135+
else
136+
sconf.src_addr = dma_remote;
137+
138+
if (dmaengine_slave_config(chan, &sconf)) {
139+
dev_err(dev, "DMA slave config fail\n");
140+
return -EIO;
141+
}
142+
tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
143+
flags);
144+
} else {
145+
tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
146+
flags);
147+
}
148+
124149
if (!tx) {
125150
dev_err(dev, "Failed to prepare DMA memcpy\n");
126151
return -EIO;
@@ -148,6 +173,23 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
148173
return 0;
149174
}
150175

176+
struct epf_dma_filter {
177+
struct device *dev;
178+
u32 dma_mask;
179+
};
180+
181+
static bool epf_dma_filter_fn(struct dma_chan *chan, void *node)
182+
{
183+
struct epf_dma_filter *filter = node;
184+
struct dma_slave_caps caps;
185+
186+
memset(&caps, 0, sizeof(caps));
187+
dma_get_slave_caps(chan, &caps);
188+
189+
return chan->device->dev == filter->dev
190+
&& (filter->dma_mask & caps.directions);
191+
}
192+
151193
/**
152194
* pci_epf_test_init_dma_chan() - Function to initialize EPF test DMA channel
153195
* @epf_test: the EPF test device that performs data transfer operation
@@ -158,10 +200,44 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
158200
{
159201
struct pci_epf *epf = epf_test->epf;
160202
struct device *dev = &epf->dev;
203+
struct epf_dma_filter filter;
161204
struct dma_chan *dma_chan;
162205
dma_cap_mask_t mask;
163206
int ret;
164207

208+
filter.dev = epf->epc->dev.parent;
209+
filter.dma_mask = BIT(DMA_DEV_TO_MEM);
210+
211+
dma_cap_zero(mask);
212+
dma_cap_set(DMA_SLAVE, mask);
213+
dma_chan = dma_request_channel(mask, epf_dma_filter_fn, &filter);
214+
if (!dma_chan) {
215+
dev_info(dev, "Failed to get private DMA rx channel. Falling back to generic one\n");
216+
goto fail_back_tx;
217+
}
218+
219+
epf_test->dma_chan_rx = dma_chan;
220+
221+
filter.dma_mask = BIT(DMA_MEM_TO_DEV);
222+
dma_chan = dma_request_channel(mask, epf_dma_filter_fn, &filter);
223+
224+
if (!dma_chan) {
225+
dev_info(dev, "Failed to get private DMA tx channel. Falling back to generic one\n");
226+
goto fail_back_rx;
227+
}
228+
229+
epf_test->dma_chan_tx = dma_chan;
230+
epf_test->dma_private = true;
231+
232+
init_completion(&epf_test->transfer_complete);
233+
234+
return 0;
235+
236+
fail_back_rx:
237+
dma_release_channel(epf_test->dma_chan_rx);
238+
epf_test->dma_chan_tx = NULL;
239+
240+
fail_back_tx:
165241
dma_cap_zero(mask);
166242
dma_cap_set(DMA_MEMCPY, mask);
167243

@@ -174,7 +250,7 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
174250
}
175251
init_completion(&epf_test->transfer_complete);
176252

177-
epf_test->dma_chan = dma_chan;
253+
epf_test->dma_chan_tx = epf_test->dma_chan_rx = dma_chan;
178254

179255
return 0;
180256
}
@@ -190,8 +266,17 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
190266
if (!epf_test->dma_supported)
191267
return;
192268

193-
dma_release_channel(epf_test->dma_chan);
194-
epf_test->dma_chan = NULL;
269+
dma_release_channel(epf_test->dma_chan_tx);
270+
if (epf_test->dma_chan_tx == epf_test->dma_chan_rx) {
271+
epf_test->dma_chan_tx = NULL;
272+
epf_test->dma_chan_rx = NULL;
273+
return;
274+
}
275+
276+
dma_release_channel(epf_test->dma_chan_rx);
277+
epf_test->dma_chan_rx = NULL;
278+
279+
return;
195280
}
196281

197282
static void pci_epf_test_print_rate(const char *ops, u64 size,
@@ -280,8 +365,15 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
280365
goto err_map_addr;
281366
}
282367

368+
if (epf_test->dma_private) {
369+
dev_err(dev, "Cannot transfer data using DMA\n");
370+
ret = -EINVAL;
371+
goto err_map_addr;
372+
}
373+
283374
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
284-
src_phys_addr, reg->size);
375+
src_phys_addr, reg->size, 0,
376+
DMA_MEM_TO_MEM);
285377
if (ret)
286378
dev_err(dev, "Data transfer failed\n");
287379
} else {
@@ -373,7 +465,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
373465

374466
ktime_get_ts64(&start);
375467
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
376-
phys_addr, reg->size);
468+
phys_addr, reg->size,
469+
reg->src_addr, DMA_DEV_TO_MEM);
377470
if (ret)
378471
dev_err(dev, "Data transfer failed\n");
379472
ktime_get_ts64(&end);
@@ -463,8 +556,11 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
463556
}
464557

465558
ktime_get_ts64(&start);
559+
466560
ret = pci_epf_test_data_transfer(epf_test, phys_addr,
467-
src_phys_addr, reg->size);
561+
src_phys_addr, reg->size,
562+
reg->dst_addr,
563+
DMA_MEM_TO_DEV);
468564
if (ret)
469565
dev_err(dev, "Data transfer failed\n");
470566
ktime_get_ts64(&end);

0 commit comments

Comments
 (0)