@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -84,7 +85,7 @@
static DEFINE_IDA(pci_endpoint_test_ida);
#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
- miscdev)
+ miscdev)
static bool no_msi;
module_param(no_msi, bool, 0444);
@@ -132,16 +133,119 @@ static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
}
static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
- u32 offset, u32 value)
+ u32 offset, u32 value)
{
writel(value, test->base + offset);
}
static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test,
- int bar, int offset)
+ int bar, int offset)
{
return readl(test->bar[bar] + offset);
}
+static bool pci_endpoint_test_transfer_data(struct pci_endpoint_test *test,
+ unsigned long arg, const int operation)
+{
+ struct pci_endpoint_test_xfer_param param;
+ bool ret = false;
+ u32 flags = 0;
+ bool use_dma;
+ void *addr;
+ dma_addr_t phys_addr;
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ void *orig_addr;
+ dma_addr_t orig_phys_addr;
+ size_t offset;
+ size_t alignment = test->alignment;
+ int irq_type = test->irq_type;
+ size_t size;
+ int err;
+
+ err = copy_from_user(¶m, (void __user *)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.flags & PCITEST_FLAGS_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;
+ }
+
+ orig_addr = kzalloc(size + alignment, GFP_KERNEL);
+ if (!orig_addr)
+ goto err;
+
+ if (operation == WRITE)
+ get_random_bytes(orig_addr, size + alignment);
+
+ orig_phys_addr = dma_map_single(dev, orig_addr, size + alignment,
+ operation == WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, orig_phys_addr)) {
+ dev_err(dev, "failed to map source buffer address\n");
+ 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;
+ addr = orig_addr + offset;
+ } else {
+ phys_addr = orig_phys_addr;
+ addr = orig_addr;
+ }
+
+ if (operation == WRITE) {
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
+ crc32_le(~0, addr, size));
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
+ lower_32_bits(phys_addr));
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_SRC_ADDR,
+ upper_32_bits(phys_addr));
+ } else {
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
+ lower_32_bits(phys_addr));
+ 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_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);
+
+ // if we ask rc to write to ep, then ep should do read operation, and vice versa.
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+ operation == WRITE ? COMMAND_READ : COMMAND_WRITE);
+
+ wait_for_completion(&test->irq_raised);
+
+ dma_unmap_single(dev, orig_phys_addr, size + alignment,
+ operation == WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ if (operation == WRITE)
+ ret = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS) & STATUS_READ_SUCCESS;
+ else
+ ret = crc32_le(~0, addr, size) ==
+ pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM);
+
+err_phys_addr:
+ kfree(orig_addr);
+
+err:
+ return ret;
+}
static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test,
int bar, u32 offset, u32 value)
@@ -234,8 +338,8 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
for (i = 0; i < test->num_irqs; i++) {
err = devm_request_irq(dev, pci_irq_vector(pdev, i),
- pci_endpoint_test_irqhandler,
- IRQF_SHARED, test->name, test);
+ pci_endpoint_test_irqhandler,
+ IRQF_SHARED, test->name, test);
if (err)
goto fail;
}
@@ -309,7 +413,7 @@ static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
}
static bool pci_endpoint_test_msi_irq(struct pci_endpoint_test *test,
- u16 msi_num, bool msix)
+ u16 msi_num, bool msix)
{
u32 val;
struct pci_dev *pdev = test->pdev;
@@ -385,7 +489,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
get_random_bytes(orig_src_addr, size + alignment);
orig_src_phys_addr = dma_map_single(dev, orig_src_addr,
- size + alignment, DMA_TO_DEVICE);
+ 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;
@@ -417,7 +521,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);
+ 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;
@@ -471,193 +575,15 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
}
static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
- unsigned long arg)
+ 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;
- struct pci_dev *pdev = test->pdev;
- struct device *dev = &pdev->dev;
- void *orig_addr;
- dma_addr_t orig_phys_addr;
- size_t offset;
- size_t alignment = test->alignment;
- int irq_type = test->irq_type;
- size_t size;
- u32 crc32;
- int err;
-
- err = copy_from_user(¶m, (void __user *)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.flags & PCITEST_FLAGS_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;
- }
-
- 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;
- addr = orig_addr + offset;
- } else {
- phys_addr = orig_phys_addr;
- addr = orig_addr;
- }
-
- crc32 = crc32_le(~0, addr, size);
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_CHECKSUM,
- crc32);
-
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
- lower_32_bits(phys_addr));
- 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_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,
- COMMAND_READ);
-
- wait_for_completion(&test->irq_raised);
-
- reg = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
- if (reg & STATUS_READ_SUCCESS)
- ret = true;
-
- dma_unmap_single(dev, orig_phys_addr, size + alignment,
- DMA_TO_DEVICE);
-
-err_phys_addr:
- kfree(orig_addr);
-
-err:
- return ret;
+ return pci_endpoint_test_transfer_data(test, arg, WRITE);
}
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;
- struct device *dev = &pdev->dev;
- void *orig_addr;
- dma_addr_t orig_phys_addr;
- size_t offset;
- size_t alignment = test->alignment;
- int irq_type = test->irq_type;
- u32 crc32;
- int err;
-
- err = copy_from_user(¶m, (void __user *)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.flags & PCITEST_FLAGS_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;
- }
-
- 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;
- addr = orig_addr + offset;
- } else {
- phys_addr = orig_phys_addr;
- addr = orig_addr;
- }
-
- pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
- lower_32_bits(phys_addr));
- 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_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,
- COMMAND_WRITE);
-
- 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;
-
-err_phys_addr:
- kfree(orig_addr);
-err:
- return ret;
+ return pci_endpoint_test_transfer_data(test, arg, READ);
}
static bool pci_endpoint_test_clear_irq(struct pci_endpoint_test *test)
@@ -668,7 +594,7 @@ static bool pci_endpoint_test_clear_irq(struct pci_endpoint_test *test)
}
static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
- int req_irq_type)
+ int req_irq_type)
{
struct pci_dev *pdev = test->pdev;
struct device *dev = &pdev->dev;
@@ -698,7 +624,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
}
static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
int ret = -EINVAL;
enum pci_barno bar;
@@ -793,7 +719,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
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) {
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
dev_err(dev, "Cannot set DMA mask\n");
return -EINVAL;
}