This patchset introduces testing through continuous transfer to the PCI
endpoint tests. The purpose is to find bugs that may exist in the endpoint
controller driver. This changes able to find bugs in the DW EDMA driver and
this patchset includes the fix.
This bug does not appear in the current tests because these synchronize to
finish with every data transfer. However, the problem occurs with
continuous DMA issuances. The continuous transfers are required to get high
throughput and low latency. Therefore, the added tests will enable
realistic transfer testing.
This patchset is divided into three parts:
- Remove duplicated definitions and improve some code [1-6/11]
- Add continuous transfer tests [7-9/11]
- Fix for the DW EDMA driver bug [10,11/11]
This patchset has beed tested on RCar Spidar that has dw pci edma chip.
Shunsuke Mie (11):
misc: pci_endpoint_test: Aggregate irq_type checking
misc: pci_endpoint_test: Remove an unused variable
pci: endpoint: function/pci-epf-test: Unify a range of time
measurement
PCI: endpoint: functions/pci-epf-test: Move common difinitions to
header file
MAINTAINERS: Add a header file for pci-epf-test
misc: pci_endpoint_test: Use a common header file between endpoint
driver
PCI: endpoint: functions/pci-epf-test: Extend the test for continuous
transfers
misc: pci_endpoint_test: Support a test of continuous transfer
tools: PCI: Add 'C' option to support continuous transfer
dmaengine: dw-edma: Fix to change for continuous transfer
dmaengine: dw-edma: Fix to enable to issue dma request on DMA
processing
MAINTAINERS | 1 +
drivers/dma/dw-edma/dw-edma-core.c | 30 ++-
drivers/misc/pci_endpoint_test.c | 132 ++++--------
drivers/pci/endpoint/functions/pci-epf-test.c | 199 ++++++++----------
include/linux/pci-epf-test.h | 67 ++++++
include/uapi/linux/pcitest.h | 1 +
tools/pci/pcitest.c | 13 +-
7 files changed, 231 insertions(+), 212 deletions(-)
create mode 100644 include/linux/pci-epf-test.h
--
2.25.1
There are the same checkings in each test, so merge the redundant checks.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 1d8f72b42c0a..22e0cc0b75d3 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -347,6 +347,11 @@ static int pci_endpoint_test_validate_xfer_params(struct device *dev,
return -EINVAL;
}
+ if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
+ dev_dbg(dev, "Invalid IRQ type option\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -391,11 +396,6 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
- dev_err(dev, "Invalid IRQ type option\n");
- goto err;
- }
-
orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
if (!orig_src_addr) {
dev_err(dev, "Failed to allocate source buffer\n");
@@ -527,11 +527,6 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
- dev_err(dev, "Invalid IRQ type option\n");
- goto err;
- }
-
orig_addr = kzalloc(size + alignment, GFP_KERNEL);
if (!orig_addr) {
dev_err(dev, "Failed to allocate address\n");
@@ -627,11 +622,6 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
- dev_err(dev, "Invalid IRQ type option\n");
- goto err;
- }
-
orig_addr = kzalloc(size + alignment, GFP_KERNEL);
if (!orig_addr) {
dev_err(dev, "Failed to allocate destination address\n");
--
2.25.1
The use_dma variables are used only once. Remove those.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 22e0cc0b75d3..55733dee95ad 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -363,7 +363,6 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
void *src_addr;
void *dst_addr;
u32 flags = 0;
- bool use_dma;
size_t size;
dma_addr_t src_phys_addr;
dma_addr_t dst_phys_addr;
@@ -392,8 +391,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
size = param.size;
- use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
- if (use_dma)
+ if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
@@ -496,7 +494,6 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
struct pci_endpoint_test_xfer_param param;
bool ret = false;
u32 flags = 0;
- bool use_dma;
u32 reg;
void *addr;
dma_addr_t phys_addr;
@@ -523,8 +520,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
size = param.size;
- use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
- if (use_dma)
+ if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
orig_addr = kzalloc(size + alignment, GFP_KERNEL);
@@ -592,7 +588,6 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
struct pci_endpoint_test_xfer_param param;
bool ret = false;
u32 flags = 0;
- bool use_dma;
size_t size;
void *addr;
dma_addr_t phys_addr;
@@ -618,8 +613,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
size = param.size;
- use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
- if (use_dma)
+ if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
orig_addr = kzalloc(size + alignment, GFP_KERNEL);
--
2.25.1
This test code measures a time of data transfer. Some measurements include
print, preparation and error checking. Change to measure during data
tansfer.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 172e5ac0bd96..6955a3d2eb7e 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -356,7 +356,6 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
goto err_dst_addr;
}
- ktime_get_ts64(&start);
use_dma = !!(reg->flags & FLAG_USE_DMA);
if (use_dma) {
if (!epf_test->dma_supported) {
@@ -371,9 +370,11 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
goto err_map_addr;
}
+ ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
src_phys_addr, reg->size, 0,
DMA_MEM_TO_MEM);
+ ktime_get_ts64(&end);
if (ret)
dev_err(dev, "Data transfer failed\n");
} else {
@@ -385,11 +386,13 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
goto err_map_addr;
}
+ ktime_get_ts64(&start);
memcpy_fromio(buf, src_addr, reg->size);
memcpy_toio(dst_addr, buf, reg->size);
+ ktime_get_ts64(&end);
kfree(buf);
}
- ktime_get_ts64(&end);
+
pci_epf_test_print_rate("COPY", reg->size, &start, &end, use_dma);
err_map_addr:
@@ -467,9 +470,9 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
phys_addr, reg->size,
reg->src_addr, DMA_DEV_TO_MEM);
+ ktime_get_ts64(&end);
if (ret)
dev_err(dev, "Data transfer failed\n");
- ktime_get_ts64(&end);
dma_unmap_single(dma_dev, dst_phys_addr, reg->size,
DMA_FROM_DEVICE);
@@ -556,14 +559,13 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
}
ktime_get_ts64(&start);
-
ret = pci_epf_test_data_transfer(epf_test, phys_addr,
src_phys_addr, reg->size,
reg->dst_addr,
DMA_MEM_TO_DEV);
+ ktime_get_ts64(&end);
if (ret)
dev_err(dev, "Data transfer failed\n");
- ktime_get_ts64(&end);
dma_unmap_single(dma_dev, src_phys_addr, reg->size,
DMA_TO_DEVICE);
--
2.25.1
The pci-epf-test and pci_endpoint_test drivers communicate by registers on
PCIe BAR. The register details are duplicated in their code respectively.
Move a common part to an introduced header file from pci-epf-test.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 37 +---------
include/linux/pci-epf-test.h | 67 +++++++++++++++++++
2 files changed, 68 insertions(+), 36 deletions(-)
create mode 100644 include/linux/pci-epf-test.h
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 6955a3d2eb7e..99d8a05b8507 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -17,31 +17,9 @@
#include <linux/pci-epc.h>
#include <linux/pci-epf.h>
+#include <linux/pci-epf-test.h>
#include <linux/pci_regs.h>
-#define IRQ_TYPE_LEGACY 0
-#define IRQ_TYPE_MSI 1
-#define IRQ_TYPE_MSIX 2
-
-#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
-#define COMMAND_RAISE_MSI_IRQ BIT(1)
-#define COMMAND_RAISE_MSIX_IRQ BIT(2)
-#define COMMAND_READ BIT(3)
-#define COMMAND_WRITE BIT(4)
-#define COMMAND_COPY BIT(5)
-
-#define STATUS_READ_SUCCESS BIT(0)
-#define STATUS_READ_FAIL BIT(1)
-#define STATUS_WRITE_SUCCESS BIT(2)
-#define STATUS_WRITE_FAIL BIT(3)
-#define STATUS_COPY_SUCCESS BIT(4)
-#define STATUS_COPY_FAIL BIT(5)
-#define STATUS_IRQ_RAISED BIT(6)
-#define STATUS_SRC_ADDR_INVALID BIT(7)
-#define STATUS_DST_ADDR_INVALID BIT(8)
-
-#define FLAG_USE_DMA BIT(0)
-
#define TIMER_RESOLUTION 1
static struct workqueue_struct *kpcitest_workqueue;
@@ -60,19 +38,6 @@ struct pci_epf_test {
const struct pci_epc_features *epc_features;
};
-struct pci_epf_test_reg {
- u32 magic;
- u32 command;
- u32 status;
- u64 src_addr;
- u64 dst_addr;
- u32 size;
- u32 checksum;
- u32 irq_type;
- u32 irq_number;
- u32 flags;
-} __packed;
-
static struct pci_epf_header test_header = {
.vendorid = PCI_ANY_ID,
.deviceid = PCI_ANY_ID,
diff --git a/include/linux/pci-epf-test.h b/include/linux/pci-epf-test.h
new file mode 100644
index 000000000000..636057c3377f
--- /dev/null
+++ b/include/linux/pci-epf-test.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __PCI_EPF_TEST_H
+#define __PCI_EPF_TEST_H
+
+struct pci_epf_test_reg {
+#define PCI_ENDPOINT_TEST_MAGIC offsetof(struct pci_epf_test_reg, magic)
+ u32 magic;
+#define PCI_ENDPOINT_TEST_COMMAND offsetof(struct pci_epf_test_reg, command)
+#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
+#define COMMAND_RAISE_MSI_IRQ BIT(1)
+#define COMMAND_RAISE_MSIX_IRQ BIT(2)
+#define COMMAND_READ BIT(3)
+#define COMMAND_WRITE BIT(4)
+#define COMMAND_COPY BIT(5)
+ u32 command;
+#define STATUS_READ_SUCCESS BIT(0)
+#define STATUS_READ_FAIL BIT(1)
+#define STATUS_WRITE_SUCCESS BIT(2)
+#define STATUS_WRITE_FAIL BIT(3)
+#define STATUS_COPY_SUCCESS BIT(4)
+#define STATUS_COPY_FAIL BIT(5)
+#define STATUS_IRQ_RAISED BIT(6)
+#define STATUS_SRC_ADDR_INVALID BIT(7)
+#define STATUS_DST_ADDR_INVALID BIT(8)
+#define PCI_ENDPOINT_TEST_STATUS offsetof(struct pci_epf_test_reg, status)
+ u32 status;
+ union {
+#define PCI_ENDPOINT_TEST_SRC_ADDR offsetof(struct pci_epf_test_reg, src_addr)
+ u64 src_addr;
+ struct {
+#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR offsetof(struct pci_epf_test_reg, src_low)
+ u32 src_low;
+#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR offsetof(struct pci_epf_test_reg, src_high)
+ u32 src_high;
+ } __packed;
+ };
+ union {
+#define PCI_ENDPOINT_TEST_DST_ADDR offsetof(struct pci_epf_test_reg, dst_addr)
+ u64 dst_addr;
+ struct {
+#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR offsetof(struct pci_epf_test_reg, dst_low)
+ u32 dst_low;
+#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR offsetof(struct pci_epf_test_reg, dst_high)
+ u32 dst_high;
+ } __packed;
+ };
+#define PCI_ENDPOINT_TEST_SIZE offsetof(struct pci_epf_test_reg, size)
+ u32 size;
+#define PCI_ENDPOINT_TEST_COUNT offsetof(struct pci_epf_test_reg, count)
+ u32 count;
+#define PCI_ENDPOINT_TEST_CHECKSUM offsetof(struct pci_epf_test_reg, checksum)
+ u32 checksum;
+#define PCI_ENDPOINT_TEST_IRQ_TYPE offsetof(struct pci_epf_test_reg, irq_type)
+#define IRQ_TYPE_UNDEFINED -1
+#define IRQ_TYPE_LEGACY 0
+#define IRQ_TYPE_MSI 1
+#define IRQ_TYPE_MSIX 2
+ u32 irq_type;
+#define PCI_ENDPOINT_TEST_IRQ_NUMBER offsetof(struct pci_epf_test_reg, irq_number)
+ u32 irq_number;
+#define PCI_ENDPOINT_TEST_FLAGS offsetof(struct pci_epf_test_reg, flags)
+#define FLAG_USE_DMA BIT(0)
+ u32 flags;
+} __packed;
+
+#endif /* __PCI_EPF_TEST_H */
--
2.25.1
Common definitions between pci-epf-test and pci_endpoint_test drivers moves
into the new header file.
Signed-off-by: Shunsuke Mie <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 092f9500e0e7..440a7d0d4ac4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16131,6 +16131,7 @@ F: Documentation/misc-devices/pci-endpoint-test.rst
F: drivers/misc/pci_endpoint_test.c
F: drivers/pci/endpoint/
F: tools/pci/
+F: include/linux/pci-epf-test.h
PCI ENHANCED ERROR HANDLING (EEH) FOR POWERPC
M: Mahesh J Salgaonkar <[email protected]>
--
2.25.1
Duplicated definitions between pci-epf-test and pci_endpoint_test are
already moved to a header file. Remove the common definitions and include
the header file. In addition, the separate register address writes were
combined into a single write.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 42 +-------------------------------
1 file changed, 1 insertion(+), 41 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 55733dee95ad..d4a42e9ab86a 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -22,52 +22,12 @@
#include <linux/pci_ids.h>
#include <linux/pci_regs.h>
+#include <linux/pci-epf-test.h>
#include <uapi/linux/pcitest.h>
#define DRV_MODULE_NAME "pci-endpoint-test"
-#define IRQ_TYPE_UNDEFINED -1
-#define IRQ_TYPE_LEGACY 0
-#define IRQ_TYPE_MSI 1
-#define IRQ_TYPE_MSIX 2
-
-#define PCI_ENDPOINT_TEST_MAGIC 0x0
-
-#define PCI_ENDPOINT_TEST_COMMAND 0x4
-#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
-#define COMMAND_RAISE_MSI_IRQ BIT(1)
-#define COMMAND_RAISE_MSIX_IRQ BIT(2)
-#define COMMAND_READ BIT(3)
-#define COMMAND_WRITE BIT(4)
-#define COMMAND_COPY BIT(5)
-
-#define PCI_ENDPOINT_TEST_STATUS 0x8
-#define STATUS_READ_SUCCESS BIT(0)
-#define STATUS_READ_FAIL BIT(1)
-#define STATUS_WRITE_SUCCESS BIT(2)
-#define STATUS_WRITE_FAIL BIT(3)
-#define STATUS_COPY_SUCCESS BIT(4)
-#define STATUS_COPY_FAIL BIT(5)
-#define STATUS_IRQ_RAISED BIT(6)
-#define STATUS_SRC_ADDR_INVALID BIT(7)
-#define STATUS_DST_ADDR_INVALID BIT(8)
-
-#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
-#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
-
-#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
-#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
-
-#define PCI_ENDPOINT_TEST_SIZE 0x1c
-#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
-
-#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
-#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
-
-#define PCI_ENDPOINT_TEST_FLAGS 0x2c
-#define FLAG_USE_DMA BIT(0)
-
#define PCI_DEVICE_ID_TI_AM654 0xb00c
#define PCI_DEVICE_ID_TI_J7200 0xb00f
#define PCI_DEVICE_ID_TI_AM64 0xb010
--
2.25.1
The test could not test continuous DMAs because it was only synchronously
issuing a single DMA and waiting for it to complete.
Add a new parameter, `count` and extend the test for continuous transfers
to improve the test coverage.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 152 ++++++++++--------
1 file changed, 84 insertions(+), 68 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 99d8a05b8507..7898dfd956db 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -63,6 +63,7 @@ static void pci_epf_test_dma_callback(void *param)
* @dma_src: The source address of the data transfer. It can be a physical
* address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
* @len: The size of the data transfer
+ * @count: The number of DMAs issuing in consecutive
* @dma_remote: remote RC physical address
* @dir: DMA transfer direction
*
@@ -74,7 +75,7 @@ static void pci_epf_test_dma_callback(void *param)
*/
static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
dma_addr_t dma_dst, dma_addr_t dma_src,
- size_t len, dma_addr_t dma_remote,
+ size_t len, size_t count, dma_addr_t dma_remote,
enum dma_transfer_direction dir)
{
struct dma_chan *chan = (dir == DMA_MEM_TO_DEV) ?
@@ -87,47 +88,56 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
struct device *dev = &epf->dev;
dma_cookie_t cookie;
int ret;
+ int i;
+ size_t offset;
if (IS_ERR_OR_NULL(chan)) {
dev_err(dev, "Invalid DMA memcpy channel\n");
return -EINVAL;
}
- if (epf_test->dma_private) {
- sconf.direction = dir;
- if (dir == DMA_MEM_TO_DEV)
- sconf.dst_addr = dma_remote;
- else
- sconf.src_addr = dma_remote;
+ for (i = 0, offset = 0; i < count; i++, offset += len) {
+ if (epf_test->dma_private) {
+ sconf.direction = dir;
+ if (dir == DMA_MEM_TO_DEV)
+ sconf.dst_addr = dma_remote + offset;
+ else
+ sconf.src_addr = dma_remote + offset;
+
+ if (dmaengine_slave_config(chan, &sconf)) {
+ dev_err(dev, "DMA slave config fail\n");
+ return -EIO;
+ }
+ tx = dmaengine_prep_slave_single(
+ chan, dma_local + offset, len, dir, flags);
+ } else {
+ tx = dmaengine_prep_dma_memcpy(chan, dma_dst + offset,
+ dma_src + offset, len,
+ flags);
+ }
- if (dmaengine_slave_config(chan, &sconf)) {
- dev_err(dev, "DMA slave config fail\n");
+ if (!tx) {
+ dev_err(dev, "Failed to prepare DMA memcpy\n");
return -EIO;
}
- tx = dmaengine_prep_slave_single(chan, dma_local, len, dir,
- flags);
- } else {
- tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
- flags);
- }
- if (!tx) {
- dev_err(dev, "Failed to prepare DMA memcpy\n");
- return -EIO;
- }
+ if (i == count - 1) {
+ tx->callback = pci_epf_test_dma_callback;
+ tx->callback_param = epf_test;
+ reinit_completion(&epf_test->transfer_complete);
+ }
- tx->callback = pci_epf_test_dma_callback;
- tx->callback_param = epf_test;
- cookie = tx->tx_submit(tx);
- reinit_completion(&epf_test->transfer_complete);
+ cookie = tx->tx_submit(tx);
- ret = dma_submit_error(cookie);
- if (ret) {
- dev_err(dev, "Failed to do DMA tx_submit %d\n", cookie);
- return -EIO;
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dev_err(dev, "Failed to do DMA tx_submit %d\n", cookie);
+ return -EIO;
+ }
+
+ dma_async_issue_pending(chan);
}
- dma_async_issue_pending(chan);
ret = wait_for_completion_interruptible(&epf_test->transfer_complete);
if (ret < 0) {
dmaengine_terminate_sync(chan);
@@ -244,7 +254,7 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
return;
}
-static void pci_epf_test_print_rate(const char *ops, u64 size,
+static void pci_epf_test_print_rate(const char *ops, u64 size, u32 count,
struct timespec64 *start,
struct timespec64 *end, bool dma)
{
@@ -255,7 +265,7 @@ static void pci_epf_test_print_rate(const char *ops, u64 size,
/* convert both size (stored in 'rate') and time in terms of 'ns' */
ns = timespec64_to_ns(&ts);
- rate = size * NSEC_PER_SEC;
+ rate = size * count * NSEC_PER_SEC;
/* Divide both size (stored in 'rate') and ns by a common factor */
while (ns > UINT_MAX) {
@@ -269,14 +279,14 @@ static void pci_epf_test_print_rate(const char *ops, u64 size,
/* calculate the rate */
do_div(rate, (uint32_t)ns);
- pr_info("\n%s => Size: %llu bytes\t DMA: %s\t Time: %llu.%09u seconds\t"
- "Rate: %llu KB/s\n", ops, size, dma ? "YES" : "NO",
+ pr_info("\n%s => Size: %llu bytes\tcount %d\t DMA: %s\t Time: %llu.%09u seconds\t"
+ "Rate: %llu KB/s\n", ops, size, count, dma ? "YES" : "NO",
(u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
}
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
{
- int ret;
+ int ret, i;
bool use_dma;
void __iomem *src_addr;
void __iomem *dst_addr;
@@ -288,8 +298,9 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
struct pci_epc *epc = epf->epc;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+ size_t offset;
- src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
+ src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size * reg->count);
if (!src_addr) {
dev_err(dev, "Failed to allocate source address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
@@ -298,14 +309,14 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
}
ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, src_phys_addr,
- reg->src_addr, reg->size);
+ reg->src_addr, reg->size * reg->count);
if (ret) {
dev_err(dev, "Failed to map source address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
goto err_src_addr;
}
- dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size);
+ dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size * reg->count);
if (!dst_addr) {
dev_err(dev, "Failed to allocate destination address\n");
reg->status = STATUS_DST_ADDR_INVALID;
@@ -314,7 +325,7 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
}
ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, dst_phys_addr,
- reg->dst_addr, reg->size);
+ reg->dst_addr, reg->size * reg->count);
if (ret) {
dev_err(dev, "Failed to map destination address\n");
reg->status = STATUS_DST_ADDR_INVALID;
@@ -337,7 +348,7 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
- src_phys_addr, reg->size, 0,
+ src_phys_addr, reg->size, reg->count, 0,
DMA_MEM_TO_MEM);
ktime_get_ts64(&end);
if (ret)
@@ -345,32 +356,33 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
} else {
void *buf;
- buf = kzalloc(reg->size, GFP_KERNEL);
+ buf = kzalloc(reg->size * reg->count, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_map_addr;
}
ktime_get_ts64(&start);
- memcpy_fromio(buf, src_addr, reg->size);
- memcpy_toio(dst_addr, buf, reg->size);
+ for (i = 0, offset = 0; i < reg->count; i++, offset += reg->size) {
+ memcpy_fromio(buf + offset, src_addr + offset, reg->size);
+ memcpy_toio(dst_addr + offset, buf + offset, reg->size);
+ }
ktime_get_ts64(&end);
kfree(buf);
}
-
- pci_epf_test_print_rate("COPY", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("COPY", reg->size, reg->count, &start, &end, use_dma);
err_map_addr:
pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, dst_phys_addr);
err_dst_addr:
- pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size);
+ pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size * reg->count);
err_src_map_addr:
pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, src_phys_addr);
err_src_addr:
- pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size);
+ pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size * reg->count);
err:
return ret;
@@ -378,7 +390,7 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
static int pci_epf_test_read(struct pci_epf_test *epf_test)
{
- int ret;
+ int ret, i;
void __iomem *src_addr;
void *buf;
u32 crc32;
@@ -392,8 +404,9 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
struct device *dma_dev = epf->epc->dev.parent;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+ size_t offset;
- src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
+ src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size * reg->count);
if (!src_addr) {
dev_err(dev, "Failed to allocate address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
@@ -402,14 +415,14 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
}
ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
- reg->src_addr, reg->size);
+ reg->src_addr, reg->size * reg->count);
if (ret) {
dev_err(dev, "Failed to map address\n");
reg->status = STATUS_SRC_ADDR_INVALID;
goto err_addr;
}
- buf = kzalloc(reg->size, GFP_KERNEL);
+ buf = kzalloc(reg->size * reg->count, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_map_addr;
@@ -423,7 +436,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
goto err_dma_map;
}
- dst_phys_addr = dma_map_single(dma_dev, buf, reg->size,
+ dst_phys_addr = dma_map_single(dma_dev, buf, reg->size * reg->count,
DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dst_phys_addr)) {
dev_err(dev, "Failed to map destination buffer addr\n");
@@ -433,23 +446,24 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
- phys_addr, reg->size,
+ phys_addr, reg->size, reg->count,
reg->src_addr, DMA_DEV_TO_MEM);
ktime_get_ts64(&end);
if (ret)
dev_err(dev, "Data transfer failed\n");
- dma_unmap_single(dma_dev, dst_phys_addr, reg->size,
+ dma_unmap_single(dma_dev, dst_phys_addr, reg->size * reg->count,
DMA_FROM_DEVICE);
} else {
ktime_get_ts64(&start);
- memcpy_fromio(buf, src_addr, reg->size);
+ for (i = 0, offset = 0; i < reg->count; i++, offset += reg->size)
+ memcpy_fromio(buf + offset, src_addr + offset, reg->size);
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("READ", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("READ", reg->size, reg->count, &start, &end, use_dma);
- crc32 = crc32_le(~0, buf, reg->size);
+ crc32 = crc32_le(~0, buf, reg->size * reg->count);
if (crc32 != reg->checksum)
ret = -EIO;
@@ -460,7 +474,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
err_addr:
- pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
+ pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size * reg->count);
err:
return ret;
@@ -468,7 +482,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
static int pci_epf_test_write(struct pci_epf_test *epf_test)
{
- int ret;
+ int ret, i;
void __iomem *dst_addr;
void *buf;
bool use_dma;
@@ -481,8 +495,9 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
struct device *dma_dev = epf->epc->dev.parent;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+ size_t offset;
- dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
+ dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size * reg->count);
if (!dst_addr) {
dev_err(dev, "Failed to allocate address\n");
reg->status = STATUS_DST_ADDR_INVALID;
@@ -491,21 +506,21 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
}
ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
- reg->dst_addr, reg->size);
+ reg->dst_addr, reg->size * reg->count);
if (ret) {
dev_err(dev, "Failed to map address\n");
reg->status = STATUS_DST_ADDR_INVALID;
goto err_addr;
}
- buf = kzalloc(reg->size, GFP_KERNEL);
+ buf = kzalloc(reg->size * reg->count, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_map_addr;
}
- get_random_bytes(buf, reg->size);
- reg->checksum = crc32_le(~0, buf, reg->size);
+ get_random_bytes(buf, reg->size * reg->count);
+ reg->checksum = crc32_le(~0, buf, reg->size * reg->count);
use_dma = !!(reg->flags & FLAG_USE_DMA);
if (use_dma) {
@@ -515,7 +530,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
goto err_dma_map;
}
- src_phys_addr = dma_map_single(dma_dev, buf, reg->size,
+ src_phys_addr = dma_map_single(dma_dev, buf, reg->size * reg->count,
DMA_TO_DEVICE);
if (dma_mapping_error(dma_dev, src_phys_addr)) {
dev_err(dev, "Failed to map source buffer addr\n");
@@ -525,22 +540,23 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, phys_addr,
- src_phys_addr, reg->size,
+ src_phys_addr, reg->size, reg->count,
reg->dst_addr,
DMA_MEM_TO_DEV);
ktime_get_ts64(&end);
if (ret)
dev_err(dev, "Data transfer failed\n");
- dma_unmap_single(dma_dev, src_phys_addr, reg->size,
+ dma_unmap_single(dma_dev, src_phys_addr, reg->size * reg->count,
DMA_TO_DEVICE);
} else {
ktime_get_ts64(&start);
- memcpy_toio(dst_addr, buf, reg->size);
+ for (i = 0, offset = 0; i < reg->count; i++, offset += reg->size)
+ memcpy_toio(dst_addr + offset, buf + offset, reg->size);
ktime_get_ts64(&end);
}
- pci_epf_test_print_rate("WRITE", reg->size, &start, &end, use_dma);
+ pci_epf_test_print_rate("WRITE", reg->size, reg->count, &start, &end, use_dma);
/*
* wait 1ms inorder for the write to complete. Without this delay L3
@@ -555,7 +571,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
err_addr:
- pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
+ pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size * reg->count);
err:
return ret;
--
2.25.1
Add a `count` parameter that indicates a number of transfer continuously in
a test. Buffers for the test will be allocated with a size equal to size *
count, and passed address of the buffer to epf-test.
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 60 +++++++++++++++++---------------
include/uapi/linux/pcitest.h | 1 +
2 files changed, 33 insertions(+), 28 deletions(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index d4a42e9ab86a..a49303f8c987 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -302,7 +302,7 @@ static int pci_endpoint_test_validate_xfer_params(struct device *dev,
return -EINVAL;
}
- if (param->size > SIZE_MAX - alignment) {
+ if (param->size * param->count > SIZE_MAX - alignment) {
dev_dbg(dev, "Maximum transfer data size exceeded\n");
return -EINVAL;
}
@@ -323,7 +323,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
void *src_addr;
void *dst_addr;
u32 flags = 0;
- size_t size;
+ size_t xfer_size;
dma_addr_t src_phys_addr;
dma_addr_t dst_phys_addr;
struct pci_dev *pdev = test->pdev;
@@ -349,21 +349,22 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
if (err)
return false;
- size = param.size;
+ xfer_size = param.size * param.count;
if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
- orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
+
+ orig_src_addr = kzalloc(xfer_size + alignment, GFP_KERNEL);
if (!orig_src_addr) {
dev_err(dev, "Failed to allocate source buffer\n");
ret = false;
goto err;
}
- get_random_bytes(orig_src_addr, size + alignment);
+ get_random_bytes(orig_src_addr, xfer_size + alignment);
orig_src_phys_addr = dma_map_single(dev, orig_src_addr,
- size + alignment, DMA_TO_DEVICE);
+ xfer_size + alignment, DMA_TO_DEVICE);
if (dma_mapping_error(dev, orig_src_phys_addr)) {
dev_err(dev, "failed to map source buffer address\n");
ret = false;
@@ -385,9 +386,9 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
upper_32_bits(src_phys_addr));
- src_crc32 = crc32_le(~0, src_addr, size);
+ src_crc32 = crc32_le(~0, src_addr, xfer_size);
- orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
+ orig_dst_addr = kzalloc(xfer_size + alignment, GFP_KERNEL);
if (!orig_dst_addr) {
dev_err(dev, "Failed to allocate destination address\n");
ret = false;
@@ -395,7 +396,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
}
orig_dst_phys_addr = dma_map_single(dev, orig_dst_addr,
- size + alignment, DMA_FROM_DEVICE);
+ xfer_size + alignment, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, orig_dst_phys_addr)) {
dev_err(dev, "failed to map destination buffer address\n");
ret = false;
@@ -417,7 +418,8 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
upper_32_bits(dst_phys_addr));
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
- size);
+ param.size);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COUNT, param.count);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
@@ -427,10 +429,10 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
wait_for_completion(&test->irq_raised);
- dma_unmap_single(dev, orig_dst_phys_addr, size + alignment,
+ dma_unmap_single(dev, orig_dst_phys_addr, xfer_size + alignment,
DMA_FROM_DEVICE);
- dst_crc32 = crc32_le(~0, dst_addr, size);
+ dst_crc32 = crc32_le(~0, dst_addr, xfer_size);
if (dst_crc32 == src_crc32)
ret = true;
@@ -438,7 +440,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
kfree(orig_dst_addr);
err_dst_addr:
- dma_unmap_single(dev, orig_src_phys_addr, size + alignment,
+ dma_unmap_single(dev, orig_src_phys_addr, xfer_size + alignment,
DMA_TO_DEVICE);
err_src_phys_addr:
@@ -464,7 +466,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
size_t offset;
size_t alignment = test->alignment;
int irq_type = test->irq_type;
- size_t size;
+ size_t xfer_size;
u32 crc32;
int err;
@@ -478,21 +480,21 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
if (err)
return false;
- size = param.size;
+ xfer_size = param.size * param.count;
if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
- orig_addr = kzalloc(size + alignment, GFP_KERNEL);
+ orig_addr = kzalloc(xfer_size + alignment, GFP_KERNEL);
if (!orig_addr) {
dev_err(dev, "Failed to allocate address\n");
ret = false;
goto err;
}
- get_random_bytes(orig_addr, size + alignment);
+ get_random_bytes(orig_addr, xfer_size + alignment);
- orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
+ orig_phys_addr = dma_map_single(dev, orig_addr, xfer_size + alignment,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, orig_phys_addr)) {
dev_err(dev, "failed to map source buffer address\n");
@@ -509,7 +511,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
addr = orig_addr;
}
- crc32 = crc32_le(~0, addr, size);
+ crc32 = crc32_le(~0, addr, xfer_size);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
crc32);
@@ -518,7 +520,8 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
upper_32_bits(phys_addr));
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, param.size);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COUNT, param.count);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
@@ -532,7 +535,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
if (reg & STATUS_READ_SUCCESS)
ret = true;
- dma_unmap_single(dev, orig_phys_addr, size + alignment,
+ dma_unmap_single(dev, orig_phys_addr, xfer_size + alignment,
DMA_TO_DEVICE);
err_phys_addr:
@@ -548,7 +551,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
struct pci_endpoint_test_xfer_param param;
bool ret = false;
u32 flags = 0;
- size_t size;
+ size_t xfer_size;
void *addr;
dma_addr_t phys_addr;
struct pci_dev *pdev = test->pdev;
@@ -571,19 +574,19 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
if (err)
return false;
- size = param.size;
+ xfer_size = param.size * param.count;
if (param.flags & PCITEST_FLAGS_USE_DMA)
flags |= FLAG_USE_DMA;
- orig_addr = kzalloc(size + alignment, GFP_KERNEL);
+ orig_addr = kzalloc(xfer_size + alignment, GFP_KERNEL);
if (!orig_addr) {
dev_err(dev, "Failed to allocate destination address\n");
ret = false;
goto err;
}
- orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
+ orig_phys_addr = dma_map_single(dev, orig_addr, xfer_size + alignment,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, orig_phys_addr)) {
dev_err(dev, "failed to map source buffer address\n");
@@ -605,7 +608,8 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
upper_32_bits(phys_addr));
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, param.size);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COUNT, param.count);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
@@ -615,10 +619,10 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
wait_for_completion(&test->irq_raised);
- dma_unmap_single(dev, orig_phys_addr, size + alignment,
+ dma_unmap_single(dev, orig_phys_addr, xfer_size + alignment,
DMA_FROM_DEVICE);
- crc32 = crc32_le(~0, addr, size);
+ crc32 = crc32_le(~0, addr, xfer_size);
if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
ret = true;
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index f9c1af8d141b..8f05df4f95a6 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -25,6 +25,7 @@
struct pci_endpoint_test_xfer_param {
unsigned long size;
+ unsigned long count;
unsigned char flags;
};
--
2.25.1
Add a new command line option 'C' to specify the number of transfers to
perform continuously. This option helps to detect problem of DMAC in DMA
transfers. By default, the number is set to 1.
Signed-off-by: Shunsuke Mie <[email protected]>
---
tools/pci/pcitest.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c
index 441b54234635..a66b28e1e65e 100644
--- a/tools/pci/pcitest.c
+++ b/tools/pci/pcitest.c
@@ -35,6 +35,7 @@ struct pci_test {
bool write;
bool copy;
unsigned long size;
+ unsigned long count;
bool use_dma;
};
@@ -115,6 +116,7 @@ static int run_test(struct pci_test *test)
if (test->write) {
param.size = test->size;
+ param.count = test->count;
if (test->use_dma)
param.flags = PCITEST_FLAGS_USE_DMA;
ret = ioctl(fd, PCITEST_WRITE, ¶m);
@@ -127,6 +129,7 @@ static int run_test(struct pci_test *test)
if (test->read) {
param.size = test->size;
+ param.count = test->count;
if (test->use_dma)
param.flags = PCITEST_FLAGS_USE_DMA;
ret = ioctl(fd, PCITEST_READ, ¶m);
@@ -139,6 +142,7 @@ static int run_test(struct pci_test *test)
if (test->copy) {
param.size = test->size;
+ param.count = test->count;
if (test->use_dma)
param.flags = PCITEST_FLAGS_USE_DMA;
ret = ioctl(fd, PCITEST_COPY, ¶m);
@@ -171,10 +175,13 @@ int main(int argc, char **argv)
/* set default size as 100KB */
test->size = 0x19000;
+ /* set default transfer count */
+ test->count = 1;
+
/* set default endpoint device */
test->device = "/dev/pci-endpoint-test.0";
- while ((c = getopt(argc, argv, "D:b:m:x:i:deIlhrwcs:")) != EOF)
+ while ((c = getopt(argc, argv, "D:b:m:x:i:deIlhrwcs:C:")) != EOF)
switch (c) {
case 'D':
test->device = optarg;
@@ -221,6 +228,9 @@ int main(int argc, char **argv)
case 's':
test->size = strtoul(optarg, NULL, 0);
continue;
+ case 'C':
+ test->count = strtoul(optarg, NULL, 0);
+ continue;
case 'd':
test->use_dma = true;
continue;
@@ -243,6 +253,7 @@ int main(int argc, char **argv)
"\t-w Write buffer test\n"
"\t-c Copy buffer test\n"
"\t-s <size> Size of buffer {default: 100KB}\n"
+ "\t-C <count> Number of The continuous data transfers {default: 1}\n"
"\t-h Print this help message\n",
argv[0]);
return -EINVAL;
--
2.25.1
The dw-edma driver stops after processing a DMA request even if a request
remains in the issued queue, which is not the expected behavior. The DMA
engine API requires continuous processing.
Add a trigger to start after one processing finished if there are requests
remain.
Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/dma/dw-edma/dw-edma-core.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 1906a836f0aa..c527af00ff4e 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -181,7 +181,7 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)
dw_edma_free_desc(vd2dw_edma_desc(vdesc));
}
-static void dw_edma_start_transfer(struct dw_edma_chan *chan)
+static int dw_edma_start_transfer(struct dw_edma_chan *chan)
{
struct dw_edma_chunk *child;
struct dw_edma_desc *desc;
@@ -189,16 +189,16 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
vd = vchan_next_desc(&chan->vc);
if (!vd)
- return;
+ return 0;
desc = vd2dw_edma_desc(vd);
if (!desc)
- return;
+ return 0;
child = list_first_entry_or_null(&desc->chunk->list,
struct dw_edma_chunk, list);
if (!child)
- return;
+ return 0;
dw_edma_v0_core_start(child, !desc->xfer_sz);
desc->xfer_sz += child->ll_region.sz;
@@ -206,6 +206,8 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
list_del(&child->list);
kfree(child);
desc->chunks_alloc--;
+
+ return 1;
}
static void dw_edma_device_caps(struct dma_chan *dchan,
@@ -602,14 +604,17 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
switch (chan->request) {
case EDMA_REQ_NONE:
desc = vd2dw_edma_desc(vd);
- if (desc->chunks_alloc) {
- chan->status = EDMA_ST_BUSY;
- dw_edma_start_transfer(chan);
- } else {
+ if (!desc->chunks_alloc) {
list_del(&vd->node);
vchan_cookie_complete(vd);
- chan->status = EDMA_ST_IDLE;
}
+
+ /* Continue to transfer in case of there are rest chunks, or issued
+ * requests remain.
+ */
+ chan->status = EDMA_ST_BUSY;
+ if (!dw_edma_start_transfer(chan))
+ chan->status = EDMA_ST_IDLE;
break;
case EDMA_REQ_STOP:
--
2.25.1
The issue_pending request is ignored while driver is processing a DMA
request. Fix to issue the pending requests on any dma channel status.
Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
Signed-off-by: Shunsuke Mie <[email protected]>
---
drivers/dma/dw-edma/dw-edma-core.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index c527af00ff4e..430f9ee0d9e8 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -308,9 +308,12 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
unsigned long flags;
+ if (!chan->configured)
+ return;
+
spin_lock_irqsave(&chan->vc.lock, flags);
- if (chan->configured && chan->request == EDMA_REQ_NONE &&
- chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) {
+ if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE &&
+ chan->status == EDMA_ST_IDLE) {
chan->status = EDMA_ST_BUSY;
dw_edma_start_transfer(chan);
}
--
2.25.1
> [email protected]
> Subject: [EXT] [RFC PATCH 06/11] misc: pci_endpoint_test: Use a common
> header file between endpoint driver
>
> Caution: EXT Email
>
> Duplicated definitions between pci-epf-test and pci_endpoint_test are
> already moved to a header file. Remove the common definitions and include
> the header file. In addition, the separate register address writes were
> combined into a single write.
>
> Signed-off-by: Shunsuke Mie <[email protected]>
> ---
> drivers/misc/pci_endpoint_test.c | 42 +-------------------------------
> 1 file changed, 1 insertion(+), 41 deletions(-)
>
> diff --git a/drivers/misc/pci_endpoint_test.c
> b/drivers/misc/pci_endpoint_test.c
> index 55733dee95ad..d4a42e9ab86a 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -22,52 +22,12 @@
> #include <linux/pci_ids.h>
>
> #include <linux/pci_regs.h>
> +#include <linux/pci-epf-test.h>
Pci-epf-test.h was only used by these two files.
Actually, I think move drivers/misc/pci_endpoint_test.c to under drivers/pci/endpoint/functions/
And shared one private header is more reasonable.
These two files should be stay together because tight coupling.
>
> #include <uapi/linux/pcitest.h>
>
> #define DRV_MODULE_NAME "pci-endpoint-test"
>
> -#define IRQ_TYPE_UNDEFINED -1
> -#define IRQ_TYPE_LEGACY 0
> -#define IRQ_TYPE_MSI 1
> -#define IRQ_TYPE_MSIX 2
> -
> -#define PCI_ENDPOINT_TEST_MAGIC 0x0
> -
> -#define PCI_ENDPOINT_TEST_COMMAND 0x4
> -#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
> -#define COMMAND_RAISE_MSI_IRQ BIT(1)
> -#define COMMAND_RAISE_MSIX_IRQ BIT(2)
> -#define COMMAND_READ BIT(3)
> -#define COMMAND_WRITE BIT(4)
> -#define COMMAND_COPY BIT(5)
> -
> -#define PCI_ENDPOINT_TEST_STATUS 0x8
> -#define STATUS_READ_SUCCESS BIT(0)
> -#define STATUS_READ_FAIL BIT(1)
> -#define STATUS_WRITE_SUCCESS BIT(2)
> -#define STATUS_WRITE_FAIL BIT(3)
> -#define STATUS_COPY_SUCCESS BIT(4)
> -#define STATUS_COPY_FAIL BIT(5)
> -#define STATUS_IRQ_RAISED BIT(6)
> -#define STATUS_SRC_ADDR_INVALID BIT(7)
> -#define STATUS_DST_ADDR_INVALID BIT(8)
> -
> -#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
> -#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
> -
> -#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
> -#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
> -
> -#define PCI_ENDPOINT_TEST_SIZE 0x1c
> -#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
> -
> -#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
> -#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
> -
> -#define PCI_ENDPOINT_TEST_FLAGS 0x2c
> -#define FLAG_USE_DMA BIT(0)
> -
> #define PCI_DEVICE_ID_TI_AM654 0xb00c
> #define PCI_DEVICE_ID_TI_J7200 0xb00f
> #define PCI_DEVICE_ID_TI_AM64 0xb010
> --
> 2.25.1
On Fri, Mar 17, 2023 at 08:32:27PM +0900, Shunsuke Mie wrote:
> This patchset introduces testing through continuous transfer to the PCI
> endpoint tests. The purpose is to find bugs that may exist in the endpoint
> controller driver. This changes able to find bugs in the DW EDMA driver and
> this patchset includes the fix.
>
> This bug does not appear in the current tests because these synchronize to
> finish with every data transfer. However, the problem occurs with
> continuous DMA issuances. The continuous transfers are required to get high
> throughput and low latency. Therefore, the added tests will enable
> realistic transfer testing.
>
> This patchset is divided into three parts:
> - Remove duplicated definitions and improve some code [1-6/11]
> - Add continuous transfer tests [7-9/11]
> - Fix for the DW EDMA driver bug [10,11/11]
>
> This patchset has beed tested on RCar Spidar that has dw pci edma chip.
>
If you want maintainers to review the patches separately, please remove the RFC
tag. Unless you are looking for some overall feedback about the approach.
But we are in the process of migrating the existing test under tools to
Kselftest framework [1]. Until then, we cannot accept patches improving the
existing test code. So please respin the patches on top of the Kselftest patch
once it got posted. It's already due for some time :/
Also the subject should mention "PCI endpoint".
- Mani
[1] https://lore.kernel.org/all/[email protected]/
> Shunsuke Mie (11):
> misc: pci_endpoint_test: Aggregate irq_type checking
> misc: pci_endpoint_test: Remove an unused variable
> pci: endpoint: function/pci-epf-test: Unify a range of time
> measurement
> PCI: endpoint: functions/pci-epf-test: Move common difinitions to
> header file
> MAINTAINERS: Add a header file for pci-epf-test
> misc: pci_endpoint_test: Use a common header file between endpoint
> driver
> PCI: endpoint: functions/pci-epf-test: Extend the test for continuous
> transfers
> misc: pci_endpoint_test: Support a test of continuous transfer
> tools: PCI: Add 'C' option to support continuous transfer
> dmaengine: dw-edma: Fix to change for continuous transfer
> dmaengine: dw-edma: Fix to enable to issue dma request on DMA
> processing
>
> MAINTAINERS | 1 +
> drivers/dma/dw-edma/dw-edma-core.c | 30 ++-
> drivers/misc/pci_endpoint_test.c | 132 ++++--------
> drivers/pci/endpoint/functions/pci-epf-test.c | 199 ++++++++----------
> include/linux/pci-epf-test.h | 67 ++++++
> include/uapi/linux/pcitest.h | 1 +
> tools/pci/pcitest.c | 13 +-
> 7 files changed, 231 insertions(+), 212 deletions(-)
> create mode 100644 include/linux/pci-epf-test.h
>
> --
> 2.25.1
>
--
மணிவண்ணன் சதாசிவம்
On 2023/03/31 14:38, Manivannan Sadhasivam wrote:
> On Fri, Mar 17, 2023 at 08:32:27PM +0900, Shunsuke Mie wrote:
>> This patchset introduces testing through continuous transfer to the PCI
>> endpoint tests. The purpose is to find bugs that may exist in the endpoint
>> controller driver. This changes able to find bugs in the DW EDMA driver and
>> this patchset includes the fix.
>>
>> This bug does not appear in the current tests because these synchronize to
>> finish with every data transfer. However, the problem occurs with
>> continuous DMA issuances. The continuous transfers are required to get high
>> throughput and low latency. Therefore, the added tests will enable
>> realistic transfer testing.
>>
>> This patchset is divided into three parts:
>> - Remove duplicated definitions and improve some code [1-6/11]
>> - Add continuous transfer tests [7-9/11]
>> - Fix for the DW EDMA driver bug [10,11/11]
>>
>> This patchset has beed tested on RCar Spidar that has dw pci edma chip.
>>
> If you want maintainers to review the patches separately, please remove the RFC
> tag. Unless you are looking for some overall feedback about the approach.
Got it.
>
> But we are in the process of migrating the existing test under tools to
> Kselftest framework [1]. Until then, we cannot accept patches improving the
> existing test code. So please respin the patches on top of the Kselftest patch
> once it got posted. It's already due for some time :/
I understood. I'll track the work of Kselftest migration.
>
> Also the subject should mention "PCI endpoint".
Yes.
>
> - Mani
>
> [1] https://lore.kernel.org/all/[email protected]/
Thank you for your comments.
>> Shunsuke Mie (11):
>> misc: pci_endpoint_test: Aggregate irq_type checking
>> misc: pci_endpoint_test: Remove an unused variable
>> pci: endpoint: function/pci-epf-test: Unify a range of time
>> measurement
>> PCI: endpoint: functions/pci-epf-test: Move common difinitions to
>> header file
>> MAINTAINERS: Add a header file for pci-epf-test
>> misc: pci_endpoint_test: Use a common header file between endpoint
>> driver
>> PCI: endpoint: functions/pci-epf-test: Extend the test for continuous
>> transfers
>> misc: pci_endpoint_test: Support a test of continuous transfer
>> tools: PCI: Add 'C' option to support continuous transfer
>> dmaengine: dw-edma: Fix to change for continuous transfer
>> dmaengine: dw-edma: Fix to enable to issue dma request on DMA
>> processing
>>
>> MAINTAINERS | 1 +
>> drivers/dma/dw-edma/dw-edma-core.c | 30 ++-
>> drivers/misc/pci_endpoint_test.c | 132 ++++--------
>> drivers/pci/endpoint/functions/pci-epf-test.c | 199 ++++++++----------
>> include/linux/pci-epf-test.h | 67 ++++++
>> include/uapi/linux/pcitest.h | 1 +
>> tools/pci/pcitest.c | 13 +-
>> 7 files changed, 231 insertions(+), 212 deletions(-)
>> create mode 100644 include/linux/pci-epf-test.h
>>
>> --
>> 2.25.1
>>
Best,
Shunsuke.
On 2023/03/17 23:47, Frank Li wrote:
>> [email protected]
>> Subject: [EXT] [RFC PATCH 06/11] misc: pci_endpoint_test: Use a common
>> header file between endpoint driver
>>
>> Caution: EXT Email
>>
>> Duplicated definitions between pci-epf-test and pci_endpoint_test are
>> already moved to a header file. Remove the common definitions and include
>> the header file. In addition, the separate register address writes were
>> combined into a single write.
>>
>> Signed-off-by: Shunsuke Mie <[email protected]>
>> ---
>> drivers/misc/pci_endpoint_test.c | 42 +-------------------------------
>> 1 file changed, 1 insertion(+), 41 deletions(-)
>>
>> diff --git a/drivers/misc/pci_endpoint_test.c
>> b/drivers/misc/pci_endpoint_test.c
>> index 55733dee95ad..d4a42e9ab86a 100644
>> --- a/drivers/misc/pci_endpoint_test.c
>> +++ b/drivers/misc/pci_endpoint_test.c
>> @@ -22,52 +22,12 @@
>> #include <linux/pci_ids.h>
>>
>> #include <linux/pci_regs.h>
>> +#include <linux/pci-epf-test.h>
> Pci-epf-test.h was only used by these two files.
>
> Actually, I think move drivers/misc/pci_endpoint_test.c to under drivers/pci/endpoint/functions/
> And shared one private header is more reasonable.
> These two files should be stay together because tight coupling.
I agree that the shared header is not reasonable. However, it seems
difficult to move pci_endpoint_test.c
because it is not an endpoint function driver. Furthermore, since
Kselftest adaption [1] is being worked
on, I'd like to reconsider how we can apply the Kselftest patch.
[1]
https://lore.kernel.org/all/[email protected]/
>
>> #include <uapi/linux/pcitest.h>
>>
>> #define DRV_MODULE_NAME "pci-endpoint-test"
>>
>> -#define IRQ_TYPE_UNDEFINED -1
>> -#define IRQ_TYPE_LEGACY 0
>> -#define IRQ_TYPE_MSI 1
>> -#define IRQ_TYPE_MSIX 2
>> -
>> -#define PCI_ENDPOINT_TEST_MAGIC 0x0
>> -
>> -#define PCI_ENDPOINT_TEST_COMMAND 0x4
>> -#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
>> -#define COMMAND_RAISE_MSI_IRQ BIT(1)
>> -#define COMMAND_RAISE_MSIX_IRQ BIT(2)
>> -#define COMMAND_READ BIT(3)
>> -#define COMMAND_WRITE BIT(4)
>> -#define COMMAND_COPY BIT(5)
>> -
>> -#define PCI_ENDPOINT_TEST_STATUS 0x8
>> -#define STATUS_READ_SUCCESS BIT(0)
>> -#define STATUS_READ_FAIL BIT(1)
>> -#define STATUS_WRITE_SUCCESS BIT(2)
>> -#define STATUS_WRITE_FAIL BIT(3)
>> -#define STATUS_COPY_SUCCESS BIT(4)
>> -#define STATUS_COPY_FAIL BIT(5)
>> -#define STATUS_IRQ_RAISED BIT(6)
>> -#define STATUS_SRC_ADDR_INVALID BIT(7)
>> -#define STATUS_DST_ADDR_INVALID BIT(8)
>> -
>> -#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
>> -#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
>> -
>> -#define PCI_ENDPOINT_TEST_LOWER_DST_ADDR 0x14
>> -#define PCI_ENDPOINT_TEST_UPPER_DST_ADDR 0x18
>> -
>> -#define PCI_ENDPOINT_TEST_SIZE 0x1c
>> -#define PCI_ENDPOINT_TEST_CHECKSUM 0x20
>> -
>> -#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
>> -#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
>> -
>> -#define PCI_ENDPOINT_TEST_FLAGS 0x2c
>> -#define FLAG_USE_DMA BIT(0)
>> -
>> #define PCI_DEVICE_ID_TI_AM654 0xb00c
>> #define PCI_DEVICE_ID_TI_J7200 0xb00f
>> #define PCI_DEVICE_ID_TI_AM64 0xb010
>> --
>> 2.25.1
Best,
Shunsuke.