2020-02-25 09:07:38

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 0/5] PCI: functions/pci-epf-test: Add DMA data transfer

Patch series uses dma engine APIs in pci-epf-test to transfer data using
DMA. It also adds an option "-d" in pcitest for the user to indicate
whether DMA has to be used for data transfer. This also prints
throughput information for data transfer.

Kishon Vijay Abraham I (5):
PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer
data
PCI: endpoint: functions/pci-epf-test: Print throughput information
misc: pci_endpoint_test: Use streaming DMA APIs for buffer allocation
tools: PCI: Add 'd' command line option to support DMA
misc: pci_endpoint_test: Add support to get DMA option from userspace

drivers/misc/pci_endpoint_test.c | 165 ++++++++++--
drivers/pci/endpoint/functions/pci-epf-test.c | 253 +++++++++++++++++-
include/uapi/linux/pcitest.h | 5 +
tools/pci/pcitest.c | 20 +-
4 files changed, 412 insertions(+), 31 deletions(-)

--
2.17.1


2020-02-25 09:07:43

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

Use dmaengine API and add support for transferring data using DMA.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 205 +++++++++++++++++-
1 file changed, 202 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index bddff15052cc..4e5ed37110ed 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -8,6 +8,7 @@

#include <linux/crc32.h>
#include <linux/delay.h>
+#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -39,6 +40,8 @@
#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;
@@ -48,6 +51,9 @@ struct pci_epf_test {
struct pci_epf *epf;
enum pci_barno test_reg_bar;
struct delayed_work cmd_handler;
+ struct dma_chan *dma_chan;
+ struct completion transfer_complete;
+ bool dma_supported;
const struct pci_epc_features *epc_features;
};

@@ -61,6 +67,7 @@ struct pci_epf_test_reg {
u32 checksum;
u32 irq_type;
u32 irq_number;
+ u32 flags;
} __packed;

static struct pci_epf_header test_header = {
@@ -72,9 +79,121 @@ static struct pci_epf_header test_header = {

static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };

+static void pci_epf_test_dma_callback(void *param)
+{
+ struct pci_epf_test *epf_test = param;
+
+ complete(&epf_test->transfer_complete);
+}
+
+/**
+ * pci_epf_test_data_transfer() - Helper to use dmaengine API to transfer data
+ * between PCIe EP and remote PCIe RC
+ * @epf: the EPF device that performs the data transfer operation
+ * @dma_dst: The destination address of the data transfer. It can be a physical
+ * address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @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
+ *
+ * Helper to use dmaengine API to transfer data between PCIe EP and remote PCIe
+ * RC. The source and destination address can be a physical address given by
+ * pci_epc_mem_alloc_addr or the one obtained using DMA mapping APIs.
+ *
+ * The function returns '0' on success and negative value on failure.
+ */
+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)
+{
+ enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+ struct dma_chan *chan = epf_test->dma_chan;
+ struct pci_epf *epf = epf_test->epf;
+ struct dma_async_tx_descriptor *tx;
+ struct device *dev = &epf->dev;
+ dma_cookie_t cookie;
+ int ret;
+
+ if (IS_ERR_OR_NULL(chan)) {
+ dev_err(dev, "Invalid DMA memcpy channel\n");
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ tx->callback = pci_epf_test_dma_callback;
+ tx->callback_param = epf_test;
+ cookie = tx->tx_submit(tx);
+ reinit_completion(&epf_test->transfer_complete);
+
+ 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);
+ ret = wait_for_completion_interruptible(&epf_test->transfer_complete);
+ if (ret < 0) {
+ dmaengine_terminate_sync(chan);
+ dev_err(dev, "DMA wait_for_completion_timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * pci_epf_init_dma_chan() - Helper to initialize EPF DMA channel
+ * @epf: the EPF device that has to perform the data transfer operation
+ *
+ * Helper to initialize EPF DMA channel.
+ */
+static int pci_epf_init_dma_chan(struct pci_epf_test *epf_test)
+{
+ struct pci_epf *epf = epf_test->epf;
+ struct device *dev = &epf->dev;
+ struct dma_chan *dma_chan;
+ dma_cap_mask_t mask;
+ int ret;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+
+ dma_chan = dma_request_chan_by_mask(&mask);
+ if (IS_ERR(dma_chan)) {
+ ret = PTR_ERR(dma_chan);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get DMA channel\n");
+ return ret;
+ }
+ init_completion(&epf_test->transfer_complete);
+
+ epf_test->dma_chan = dma_chan;
+
+ return 0;
+}
+
+/**
+ * pci_epf_clean_dma_chan() - Helper to cleanup EPF DMA channel
+ * @epf: the EPF device that performed the data transfer operation
+ *
+ * Helper to cleanup EPF DMA channel.
+ */
+static void pci_epf_clean_dma_chan(struct pci_epf_test *epf_test)
+{
+ dma_release_channel(epf_test->dma_chan);
+ epf_test->dma_chan = NULL;
+}
+
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
{
int ret;
+ bool use_dma;
void __iomem *src_addr;
void __iomem *dst_addr;
phys_addr_t src_phys_addr;
@@ -117,8 +236,23 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
goto err_dst_addr;
}

- memcpy(dst_addr, src_addr, reg->size);
+ use_dma = !!(reg->flags & FLAG_USE_DMA);
+ if (use_dma) {
+ if (!epf_test->dma_supported) {
+ dev_err(dev, "Cannot transfer data using DMA\n");
+ ret = -EINVAL;
+ goto err_map_addr;
+ }

+ ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
+ src_phys_addr, reg->size);
+ if (ret)
+ dev_err(dev, "Data transfer failed\n");
+ } else {
+ memcpy(dst_addr, src_addr, reg->size);
+ }
+
+err_map_addr:
pci_epc_unmap_addr(epc, epf->func_no, dst_phys_addr);

err_dst_addr:
@@ -140,10 +274,13 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
void __iomem *src_addr;
void *buf;
u32 crc32;
+ bool use_dma;
phys_addr_t phys_addr;
+ phys_addr_t dst_phys_addr;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
+ 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];

@@ -169,12 +306,38 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
goto err_map_addr;
}

- memcpy_fromio(buf, src_addr, reg->size);
+ use_dma = !!(reg->flags & FLAG_USE_DMA);
+ if (use_dma) {
+ if (!epf_test->dma_supported) {
+ dev_err(dev, "Cannot transfer data using DMA\n");
+ ret = -EINVAL;
+ goto err_map_addr;
+ }
+
+ dst_phys_addr = dma_map_single(dma_dev, buf, reg->size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma_dev, dst_phys_addr)) {
+ dev_err(dev, "Failed to map destination buffer addr\n");
+ ret = -ENOMEM;
+ goto err_dma_map;
+ }
+
+ ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
+ phys_addr, reg->size);
+ if (ret)
+ dev_err(dev, "Data transfer failed\n");
+
+ dma_unmap_single(dma_dev, dst_phys_addr, reg->size,
+ DMA_FROM_DEVICE);
+ } else {
+ memcpy_fromio(buf, src_addr, reg->size);
+ }

crc32 = crc32_le(~0, buf, reg->size);
if (crc32 != reg->checksum)
ret = -EIO;

+err_dma_map:
kfree(buf);

err_map_addr:
@@ -192,10 +355,13 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
int ret;
void __iomem *dst_addr;
void *buf;
+ bool use_dma;
phys_addr_t phys_addr;
+ phys_addr_t src_phys_addr;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
+ 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];

@@ -224,7 +390,32 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
get_random_bytes(buf, reg->size);
reg->checksum = crc32_le(~0, buf, reg->size);

- memcpy_toio(dst_addr, buf, reg->size);
+ use_dma = !!(reg->flags & FLAG_USE_DMA);
+ if (use_dma) {
+ if (!epf_test->dma_supported) {
+ dev_err(dev, "Cannot transfer data using DMA\n");
+ ret = -EINVAL;
+ goto err_map_addr;
+ }
+
+ src_phys_addr = dma_map_single(dma_dev, buf, reg->size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dma_dev, src_phys_addr)) {
+ dev_err(dev, "Failed to map source buffer addr\n");
+ ret = -ENOMEM;
+ goto err_dma_map;
+ }
+
+ ret = pci_epf_test_data_transfer(epf_test, phys_addr,
+ src_phys_addr, reg->size);
+ if (ret)
+ dev_err(dev, "Data transfer failed\n");
+
+ dma_unmap_single(dma_dev, src_phys_addr, reg->size,
+ DMA_TO_DEVICE);
+ } else {
+ memcpy_toio(dst_addr, buf, reg->size);
+ }

/*
* wait 1ms inorder for the write to complete. Without this delay L3
@@ -232,6 +423,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
*/
usleep_range(1000, 2000);

+err_dma_map:
kfree(buf);

err_map_addr:
@@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
int bar;

cancel_delayed_work(&epf_test->cmd_handler);
+ pci_epf_clean_dma_chan(epf_test);
pci_epc_stop(epc);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
epf_bar = &epf->bar[bar];
@@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
}
}

+ epf_test->dma_supported = true;
+
+ ret = pci_epf_init_dma_chan(epf_test);
+ if (ret)
+ epf_test->dma_supported = false;
+
if (linkup_notifier) {
epf->nb.notifier_call = pci_epf_test_notifier;
pci_epc_register_notifier(epc, &epf->nb);
--
2.17.1

2020-02-25 09:07:48

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 2/5] PCI: endpoint: functions/pci-epf-test: Print throughput information

Print throughput information in KB/s after every completed transfer,
including information on whether DMA is used or not.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/endpoint/functions/pci-epf-test.c | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 4e5ed37110ed..db15b080519d 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -190,6 +190,36 @@ static void pci_epf_clean_dma_chan(struct pci_epf_test *epf_test)
epf_test->dma_chan = NULL;
}

+static void pci_epf_print_rate(const char *ops, u64 size,
+ struct timespec64 *start, struct timespec64 *end,
+ bool dma)
+{
+ struct timespec64 ts;
+ u64 rate, ns;
+
+ ts = timespec64_sub(*end, *start);
+
+ /* convert both size (stored in 'rate') and time in terms of 'ns' */
+ ns = timespec64_to_ns(&ts);
+ rate = size * NSEC_PER_SEC;
+
+ /* Divide both size (stored in 'rate') and ns by a common factor */
+ while (ns > UINT_MAX) {
+ rate >>= 1;
+ ns >>= 1;
+ }
+
+ if (!ns)
+ return;
+
+ /* 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",
+ (u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
+}
+
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
{
int ret;
@@ -198,6 +228,7 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
void __iomem *dst_addr;
phys_addr_t src_phys_addr;
phys_addr_t dst_phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -236,6 +267,7 @@ 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) {
@@ -251,6 +283,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
} else {
memcpy(dst_addr, src_addr, reg->size);
}
+ ktime_get_ts64(&end);
+ pci_epf_print_rate("COPY", reg->size, &start, &end, use_dma);

err_map_addr:
pci_epc_unmap_addr(epc, epf->func_no, dst_phys_addr);
@@ -277,6 +311,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
bool use_dma;
phys_addr_t phys_addr;
phys_addr_t dst_phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -322,17 +357,23 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
goto err_dma_map;
}

+ ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
phys_addr, reg->size);
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);
} else {
+ ktime_get_ts64(&start);
memcpy_fromio(buf, src_addr, reg->size);
+ ktime_get_ts64(&end);
}

+ pci_epf_print_rate("READ", reg->size, &start, &end, use_dma);
+
crc32 = crc32_le(~0, buf, reg->size);
if (crc32 != reg->checksum)
ret = -EIO;
@@ -358,6 +399,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
bool use_dma;
phys_addr_t phys_addr;
phys_addr_t src_phys_addr;
+ struct timespec64 start, end;
struct pci_epf *epf = epf_test->epf;
struct device *dev = &epf->dev;
struct pci_epc *epc = epf->epc;
@@ -406,17 +448,23 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
goto err_dma_map;
}

+ ktime_get_ts64(&start);
ret = pci_epf_test_data_transfer(epf_test, phys_addr,
src_phys_addr, reg->size);
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);
} else {
+ ktime_get_ts64(&start);
memcpy_toio(dst_addr, buf, reg->size);
+ ktime_get_ts64(&end);
}

+ pci_epf_print_rate("WRITE", reg->size, &start, &end, use_dma);
+
/*
* wait 1ms inorder for the write to complete. Without this delay L3
* error in observed in the host system.
--
2.17.1

2020-02-25 09:08:18

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 4/5] tools: PCI: Add 'd' command line option to support DMA

Add a new command line option 'd' to use DMA for data transfers.
It should be used with read, write or copy commands.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
include/uapi/linux/pcitest.h | 5 +++++
tools/pci/pcitest.c | 20 ++++++++++++++++----
2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index cbf422e56696..1a63999e3deb 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -20,4 +20,9 @@
#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
#define PCITEST_GET_IRQTYPE _IO('P', 0x9)

+struct pci_endpoint_test_xfer_param {
+ unsigned long size;
+ bool use_dma;
+};
+
#endif /* __UAPI_LINUX_PCITEST_H */
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c
index 32b7c6f9043d..be79ec10cefc 100644
--- a/tools/pci/pcitest.c
+++ b/tools/pci/pcitest.c
@@ -34,10 +34,12 @@ struct pci_test {
bool write;
bool copy;
unsigned long size;
+ bool use_dma;
};

static int run_test(struct pci_test *test)
{
+ struct pci_endpoint_test_xfer_param param;
int ret = -EINVAL;
int fd;

@@ -102,7 +104,9 @@ static int run_test(struct pci_test *test)
}

if (test->write) {
- ret = ioctl(fd, PCITEST_WRITE, test->size);
+ param.size = test->size;
+ param.use_dma = test->use_dma;
+ ret = ioctl(fd, PCITEST_WRITE, &param);
fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size);
if (ret < 0)
fprintf(stdout, "TEST FAILED\n");
@@ -111,7 +115,9 @@ static int run_test(struct pci_test *test)
}

if (test->read) {
- ret = ioctl(fd, PCITEST_READ, test->size);
+ param.size = test->size;
+ param.use_dma = test->use_dma;
+ ret = ioctl(fd, PCITEST_READ, &param);
fprintf(stdout, "READ (%7ld bytes):\t\t", test->size);
if (ret < 0)
fprintf(stdout, "TEST FAILED\n");
@@ -120,7 +126,9 @@ static int run_test(struct pci_test *test)
}

if (test->copy) {
- ret = ioctl(fd, PCITEST_COPY, test->size);
+ param.size = test->size;
+ param.use_dma = test->use_dma;
+ ret = ioctl(fd, PCITEST_COPY, &param);
fprintf(stdout, "COPY (%7ld bytes):\t\t", test->size);
if (ret < 0)
fprintf(stdout, "TEST FAILED\n");
@@ -153,7 +161,7 @@ int main(int argc, char **argv)
/* set default endpoint device */
test->device = "/dev/pci-endpoint-test.0";

- while ((c = getopt(argc, argv, "D:b:m:x:i:Ilhrwcs:")) != EOF)
+ while ((c = getopt(argc, argv, "D:b:m:x:i:dIlhrwcs:")) != EOF)
switch (c) {
case 'D':
test->device = optarg;
@@ -197,6 +205,9 @@ int main(int argc, char **argv)
case 's':
test->size = strtoul(optarg, NULL, 0);
continue;
+ case 'd':
+ test->use_dma = true;
+ continue;
case 'h':
default:
usage:
@@ -209,6 +220,7 @@ int main(int argc, char **argv)
"\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n"
"\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n"
"\t-I Get current IRQ type configured\n"
+ "\t-d Use DMA\n"
"\t-l Legacy IRQ test\n"
"\t-r Read buffer test\n"
"\t-w Write buffer test\n"
--
2.17.1

2020-02-25 09:08:37

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 5/5] misc: pci_endpoint_test: Add support to get DMA option from userspace

'pcitest' utility now uses '-d' option to allow the user to test DMA.
Add support to parse option to use DMA from userspace application.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 65 ++++++++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 3 deletions(-)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 5998df1c84e9..3f102356b600 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>

@@ -52,6 +53,7 @@
#define STATUS_SRC_ADDR_INVALID BIT(7)
#define STATUS_DST_ADDR_INVALID BIT(8)

+#define PCI_ENDPOINT_TEST_STATUS 0x8
#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10

@@ -64,6 +66,9 @@
#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 is_am654_pci_dev(pdev) \
@@ -315,11 +320,16 @@ static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
return false;
}

-static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
+ unsigned long arg)
{
+ struct pci_endpoint_test_xfer_param param;
bool ret = false;
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;
struct pci_dev *pdev = test->pdev;
@@ -332,10 +342,22 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
size_t alignment = test->alignment;
u32 src_crc32;
u32 dst_crc32;
+ int err;
+
+ err = copy_from_user(&param, (void *)arg, sizeof(param));
+ if (err) {
+ dev_err(dev, "Failed to get transfer param\n");
+ return false;
+ }

+ size = param.size;
if (size > SIZE_MAX - alignment)
goto err;

+ use_dma = param.use_dma;
+ 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;
@@ -406,6 +428,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE,
size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -434,9 +457,13 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
return ret;
}

-static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
+ unsigned long arg)
{
+ 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;
@@ -446,11 +473,24 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
dma_addr_t orig_phys_addr;
size_t offset;
size_t alignment = test->alignment;
+ size_t size;
u32 crc32;
+ int err;

+ err = copy_from_user(&param, (void *)arg, sizeof(param));
+ if (err != 0) {
+ dev_err(dev, "Failed to get transfer param\n");
+ return false;
+ }
+
+ size = param.size;
if (size > SIZE_MAX - alignment)
goto err;

+ use_dma = param.use_dma;
+ 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;
@@ -493,6 +533,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
@@ -514,9 +555,14 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
return ret;
}

-static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
+static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
+ unsigned long arg)
{
+ 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;
struct pci_dev *pdev = test->pdev;
@@ -526,10 +572,22 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
size_t offset;
size_t alignment = test->alignment;
u32 crc32;
+ int err;

+ err = copy_from_user(&param, (void *)arg, sizeof(param));
+ if (err) {
+ dev_err(dev, "Failed to get transfer param\n");
+ return false;
+ }
+
+ size = param.size;
if (size > SIZE_MAX - alignment)
goto err;

+ use_dma = param.use_dma;
+ 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;
@@ -566,6 +624,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, size);

+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_FLAGS, flags);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
--
2.17.1

2020-02-25 09:09:40

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH 3/5] misc: pci_endpoint_test: Use streaming DMA APIs for buffer allocation

Use streaming DMA APIs (dma_map_single/dma_unmap_single) for buffers
transmitted/received by the endpoint device instead of allocating
a coherent memory. Also add default_data to set the alignment to
4KB since dma_map_single might not return a 4KB aligned address.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
Signed-off-by: Sekhar Nori <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 100 ++++++++++++++++++++++++-------
1 file changed, 79 insertions(+), 21 deletions(-)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index a5e317073d95..5998df1c84e9 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -341,14 +341,22 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
goto err;
}

- orig_src_addr = dma_alloc_coherent(dev, size + alignment,
- &orig_src_phys_addr, GFP_KERNEL);
+ orig_src_addr = kzalloc(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);
+ orig_src_phys_addr = dma_map_single(dev, orig_src_addr,
+ 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;
+ goto err_src_phys_addr;
+ }
+
if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
offset = src_phys_addr - orig_src_phys_addr;
@@ -364,15 +372,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
upper_32_bits(src_phys_addr));

- get_random_bytes(src_addr, size);
src_crc32 = crc32_le(~0, src_addr, size);

- orig_dst_addr = dma_alloc_coherent(dev, size + alignment,
- &orig_dst_phys_addr, GFP_KERNEL);
+ orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
if (!orig_dst_addr) {
dev_err(dev, "Failed to allocate destination address\n");
ret = false;
- goto err_orig_src_addr;
+ goto err_dst_addr;
+ }
+
+ orig_dst_phys_addr = dma_map_single(dev, orig_dst_addr,
+ 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;
+ goto err_dst_phys_addr;
}

if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
@@ -399,16 +413,22 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)

wait_for_completion(&test->irq_raised);

+ dma_unmap_single(dev, orig_dst_phys_addr, size + alignment,
+ DMA_FROM_DEVICE);
+
dst_crc32 = crc32_le(~0, dst_addr, size);
if (dst_crc32 == src_crc32)
ret = true;

- dma_free_coherent(dev, size + alignment, orig_dst_addr,
- orig_dst_phys_addr);
+err_dst_phys_addr:
+ kfree(orig_dst_addr);

-err_orig_src_addr:
- dma_free_coherent(dev, size + alignment, orig_src_addr,
- orig_src_phys_addr);
+err_dst_addr:
+ dma_unmap_single(dev, orig_src_phys_addr, size + alignment,
+ DMA_TO_DEVICE);
+
+err_src_phys_addr:
+ kfree(orig_src_addr);

err:
return ret;
@@ -436,14 +456,23 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
goto err;
}

- orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
- GFP_KERNEL);
+ orig_addr = kzalloc(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);
+
+ orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, orig_phys_addr)) {
+ dev_err(dev, "failed to map source buffer address\n");
+ ret = false;
+ goto err_phys_addr;
+ }
+
if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
offset = phys_addr - orig_phys_addr;
@@ -453,8 +482,6 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
addr = orig_addr;
}

- get_random_bytes(addr, size);
-
crc32 = crc32_le(~0, addr, size);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
crc32);
@@ -477,7 +504,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
if (reg & STATUS_READ_SUCCESS)
ret = true;

- dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
+ dma_unmap_single(dev, orig_phys_addr, size + alignment,
+ DMA_TO_DEVICE);
+
+err_phys_addr:
+ kfree(orig_addr);

err:
return ret;
@@ -504,14 +535,21 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
goto err;
}

- orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
- GFP_KERNEL);
+ orig_addr = kzalloc(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,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, orig_phys_addr)) {
+ dev_err(dev, "failed to map source buffer address\n");
+ ret = false;
+ goto err_phys_addr;
+ }
+
if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
offset = phys_addr - orig_phys_addr;
@@ -535,11 +573,15 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)

wait_for_completion(&test->irq_raised);

+ dma_unmap_single(dev, orig_phys_addr, size + alignment,
+ DMA_FROM_DEVICE);
+
crc32 = crc32_le(~0, addr, size);
if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
ret = true;

- dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
+err_phys_addr:
+ kfree(orig_addr);
err:
return ret;
}
@@ -667,6 +709,12 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
init_completion(&test->irq_raised);
mutex_init(&test->mutex);

+ if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) &&
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
+ dev_err(dev, "Cannot set DMA mask\n");
+ return -EINVAL;
+ }
+
err = pci_enable_device(pdev);
if (err) {
dev_err(dev, "Cannot enable PCI device\n");
@@ -783,6 +831,12 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}

+static const struct pci_endpoint_test_data default_data = {
+ .test_reg_bar = BAR_0,
+ .alignment = SZ_4K,
+ .irq_type = IRQ_TYPE_MSI,
+};
+
static const struct pci_endpoint_test_data am654_data = {
.test_reg_bar = BAR_2,
.alignment = SZ_64K,
@@ -790,8 +844,12 @@ static const struct pci_endpoint_test_data am654_data = {
};

static const struct pci_device_id pci_endpoint_test_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
- { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
+ .driver_data = (kernel_ulong_t)&default_data,
+ },
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
+ .driver_data = (kernel_ulong_t)&default_data,
+ },
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
--
2.17.1

2020-02-25 21:12:48

by Alan Mikhak

[permalink] [raw]
Subject: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

@@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
int bar;

cancel_delayed_work(&epf_test->cmd_handler);
+ pci_epf_clean_dma_chan(epf_test);
pci_epc_stop(epc);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
epf_bar = &epf->bar[bar];
@@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
}
}

+ epf_test->dma_supported = true;
+
+ ret = pci_epf_init_dma_chan(epf_test);
+ if (ret)
+ epf_test->dma_supported = false;
+
if (linkup_notifier) {
epf->nb.notifier_call = pci_epf_test_notifier;
pci_epc_register_notifier(epc, &epf->nb);

Hi Kishon,

Looking forward to building and trying this patch series on
a platform I work on.

Would you please point me to where I can find the patches
which add pci_epf_init_dma_chan() and pci_epf_clean_dma_chan()
to Linux PCI Endpoint Framework?

Regards,
Alan Mikhak

2020-02-26 05:06:45

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

Hi Alan,

On 26/02/20 2:41 am, Alan Mikhak wrote:
> @@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
> int bar;
>
> cancel_delayed_work(&epf_test->cmd_handler);
> + pci_epf_clean_dma_chan(epf_test);
> pci_epc_stop(epc);
> for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> epf_bar = &epf->bar[bar];
> @@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> }
> }
>
> + epf_test->dma_supported = true;
> +
> + ret = pci_epf_init_dma_chan(epf_test);
> + if (ret)
> + epf_test->dma_supported = false;
> +
> if (linkup_notifier) {
> epf->nb.notifier_call = pci_epf_test_notifier;
> pci_epc_register_notifier(epc, &epf->nb);
>
> Hi Kishon,
>
> Looking forward to building and trying this patch series on
> a platform I work on.
>
> Would you please point me to where I can find the patches
> which add pci_epf_init_dma_chan() and pci_epf_clean_dma_chan()
> to Linux PCI Endpoint Framework?

I've added these functions in pci-epf-test itself instead of adding in
the core files. I realized adding it in core files may not be helpful if
the endpoint function decides to use more number of DMA channels etc.,

Thanks
Kishon

2020-02-26 17:40:00

by Alan Mikhak

[permalink] [raw]
Subject: Re: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

On Tue, Feb 25, 2020 at 9:27 PM Kishon Vijay Abraham I <[email protected]> wrote:
>
> Hi Alan,
>
> On 26/02/20 2:41 am, Alan Mikhak wrote:
> > @@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
> > int bar;
> >
> > cancel_delayed_work(&epf_test->cmd_handler);
> > + pci_epf_clean_dma_chan(epf_test);
> > pci_epc_stop(epc);
> > for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > epf_bar = &epf->bar[bar];
> > @@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> > }
> > }
> >
> > + epf_test->dma_supported = true;
> > +
> > + ret = pci_epf_init_dma_chan(epf_test);
> > + if (ret)
> > + epf_test->dma_supported = false;
> > +
> > if (linkup_notifier) {
> > epf->nb.notifier_call = pci_epf_test_notifier;
> > pci_epc_register_notifier(epc, &epf->nb);
> >
> > Hi Kishon,
> >
> > Looking forward to building and trying this patch series on
> > a platform I work on.
> >
> > Would you please point me to where I can find the patches
> > which add pci_epf_init_dma_chan() and pci_epf_clean_dma_chan()
> > to Linux PCI Endpoint Framework?
>
> I've added these functions in pci-epf-test itself instead of adding in
> the core files. I realized adding it in core files may not be helpful if
> the endpoint function decides to use more number of DMA channels etc.,

Thanks Kishon,

I now realize they are in [PATCH 1/5] of this series. May I suggest renaming
them to pci_epf_test_init_dma_chan() and pci_epf_test_cleanup_dma_chan()?
With just pci_epf in their name, I was looking for them in pci-epf-core.c.

Regards,
Alan

>
> Thanks
> Kishon

2020-03-03 23:57:45

by Alan Mikhak

[permalink] [raw]
Subject: Re: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

On Wed, Feb 26, 2020 at 9:39 AM Alan Mikhak <[email protected]> wrote:
>
> On Tue, Feb 25, 2020 at 9:27 PM Kishon Vijay Abraham I <[email protected]> wrote:
> >
> > Hi Alan,
> >
> > On 26/02/20 2:41 am, Alan Mikhak wrote:
> > > @@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
> > > int bar;
> > >
> > > cancel_delayed_work(&epf_test->cmd_handler);
> > > + pci_epf_clean_dma_chan(epf_test);
> > > pci_epc_stop(epc);
> > > for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> > > epf_bar = &epf->bar[bar];
> > > @@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
> > > }
> > > }
> > >
> > > + epf_test->dma_supported = true;
> > > +
> > > + ret = pci_epf_init_dma_chan(epf_test);
> > > + if (ret)
> > > + epf_test->dma_supported = false;
> > > +
> > > if (linkup_notifier) {
> > > epf->nb.notifier_call = pci_epf_test_notifier;
> > > pci_epc_register_notifier(epc, &epf->nb);
> > >
> > > Hi Kishon,
> > >
> > > Looking forward to building and trying this patch series on
> > > a platform I work on.

Hi Kishon,

I applied this v1 patch series to kernel.org linux 5.6-rc3 and built for
x86_64 Debian and riscv. I verified that when I execute the pcitest
command on the x86_64 host with -d flag, the riscv endpoint performs
the transfer by using an available dma channel.

Regards,
Alan

> > >
> > > Would you please point me to where I can find the patches
> > > which add pci_epf_init_dma_chan() and pci_epf_clean_dma_chan()
> > > to Linux PCI Endpoint Framework?
> >
> > I've added these functions in pci-epf-test itself instead of adding in
> > the core files. I realized adding it in core files may not be helpful if
> > the endpoint function decides to use more number of DMA channels etc.,
>
> Thanks Kishon,
>
> I now realize they are in [PATCH 1/5] of this series. May I suggest renaming
> them to pci_epf_test_init_dma_chan() and pci_epf_test_cleanup_dma_chan()?
> With just pci_epf in their name, I was looking for them in pci-epf-core.c.
>
> Regards,
> Alan
>
> >
> > Thanks
> > Kishon

2020-03-04 05:11:36

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH 1/5] PCI: endpoint: functions/pci-epf-test: Add DMA support to transfer data

Hi Alan,

On 04/03/20 5:27 am, Alan Mikhak wrote:
> On Wed, Feb 26, 2020 at 9:39 AM Alan Mikhak <[email protected]> wrote:
>>
>> On Tue, Feb 25, 2020 at 9:27 PM Kishon Vijay Abraham I <[email protected]> wrote:
>>>
>>> Hi Alan,
>>>
>>> On 26/02/20 2:41 am, Alan Mikhak wrote:
>>>> @@ -380,6 +572,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
>>>> int bar;
>>>>
>>>> cancel_delayed_work(&epf_test->cmd_handler);
>>>> + pci_epf_clean_dma_chan(epf_test);
>>>> pci_epc_stop(epc);
>>>> for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
>>>> epf_bar = &epf->bar[bar];
>>>> @@ -550,6 +743,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
>>>> }
>>>> }
>>>>
>>>> + epf_test->dma_supported = true;
>>>> +
>>>> + ret = pci_epf_init_dma_chan(epf_test);
>>>> + if (ret)
>>>> + epf_test->dma_supported = false;
>>>> +
>>>> if (linkup_notifier) {
>>>> epf->nb.notifier_call = pci_epf_test_notifier;
>>>> pci_epc_register_notifier(epc, &epf->nb);
>>>>
>>>> Hi Kishon,
>>>>
>>>> Looking forward to building and trying this patch series on
>>>> a platform I work on.
>
> Hi Kishon,
>
> I applied this v1 patch series to kernel.org linux 5.6-rc3 and built for
> x86_64 Debian and riscv. I verified that when I execute the pcitest
> command on the x86_64 host with -d flag, the riscv endpoint performs
> the transfer by using an available dma channel.

Thank you for testing this.
I've posted a new version after renaming the function names to
pci_epf_test_init_dma_chan() and pci_epf_test_cleanup_dma_chan() [1]
Can you add your "Tested-by: " tag in that series so that Lorenzo can
pick it up?

Thanks
Kishon

[1] -> http://lore.kernel.org/r/[email protected]

>
> Regards,
> Alan
>
>>>>
>>>> Would you please point me to where I can find the patches
>>>> which add pci_epf_init_dma_chan() and pci_epf_clean_dma_chan()
>>>> to Linux PCI Endpoint Framework?
>>>
>>> I've added these functions in pci-epf-test itself instead of adding in
>>> the core files. I realized adding it in core files may not be helpful if
>>> the endpoint function decides to use more number of DMA channels etc.,
>>
>> Thanks Kishon,
>>
>> I now realize they are in [PATCH 1/5] of this series. May I suggest renaming
>> them to pci_epf_test_init_dma_chan() and pci_epf_test_cleanup_dma_chan()?
>> With just pci_epf in their name, I was looking for them in pci-epf-core.c.
>>
>> Regards,
>> Alan
>>
>>>
>>> Thanks
>>> Kishon