return true;
}
+static u32 bar_test_pattern_with_offset(enum pci_barno barno, int offset)
+{
+ u32 val;
+
+ /* Keep the BAR pattern in the top byte. */
+ val = bar_test_pattern[barno] & 0xff000000;
+ /* Store the (partial) offset in the remaining bytes. */
+ val |= offset & 0x00ffffff;
+
+ return val;
+}
+
+static bool pci_endpoint_test_bars_write_bar(struct pci_endpoint_test *test,
+ enum pci_barno barno)
+{
+ struct pci_dev *pdev = test->pdev;
+ int j, size;
+
+ size = pci_resource_len(pdev, barno);
+
+ if (barno == test->test_reg_bar)
+ size = 0x4;
+
+ for (j = 0; j < size; j += 4)
+ writel_relaxed(bar_test_pattern_with_offset(barno, j),
+ test->bar[barno] + j);
+
+ return true;
+}
+
+static bool pci_endpoint_test_bars_read_bar(struct pci_endpoint_test *test,
+ enum pci_barno barno)
+{
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ int j, size;
+ u32 val;
+
+ size = pci_resource_len(pdev, barno);
+
+ if (barno == test->test_reg_bar)
+ size = 0x4;
+
+ for (j = 0; j < size; j += 4) {
+ u32 expected = bar_test_pattern_with_offset(barno, j);
+
+ val = readl_relaxed(test->bar[barno] + j);
+ if (val != expected) {
+ dev_err(dev,
+ "BAR%d incorrect data at offset: %#x, got: %#x expected: %#x\n",
+ barno, j, val, expected);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool pci_endpoint_test_bars(struct pci_endpoint_test *test)
+{
+ enum pci_barno bar;
+ bool ret;
+
+ /* Write all BARs in order (without reading). */
+ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+ if (test->bar[bar])
+ pci_endpoint_test_bars_write_bar(test, bar);
+
+ /*
+ * Read all BARs in order (without writing).
+ * If there is an address translation issue on the EP, writing one BAR
+ * might have overwritten another BAR. Ensure that this is not the case.
+ * (Reading back the BAR directly after writing can not detect this.)
+ */
+ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+ if (test->bar[bar]) {
+ ret = pci_endpoint_test_bars_read_bar(test, bar);
+ if (!ret)
+ return ret;
+ }
+ }
+
+ return true;
+}
+
static bool pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)
{
u32 val;
goto ret;
ret = pci_endpoint_test_bar(test, bar);
break;
+ case PCITEST_BARS:
+ ret = pci_endpoint_test_bars(test);
+ break;
case PCITEST_INTX_IRQ:
ret = pci_endpoint_test_intx_irq(test);
break;
#define PCITEST_MSIX _IOW('P', 0x7, int)
#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
#define PCITEST_GET_IRQTYPE _IO('P', 0x9)
+#define PCITEST_BARS _IO('P', 0xa)
#define PCITEST_CLEAR_IRQ _IO('P', 0x10)
#define PCITEST_FLAGS_USE_DMA 0x00000001
struct pci_test {
char *device;
char barnum;
+ bool consecutive_bar_test;
bool legacyirq;
unsigned int msinum;
unsigned int msixnum;
fprintf(stdout, "%s\n", result[ret]);
}
+ if (test->consecutive_bar_test) {
+ ret = ioctl(fd, PCITEST_BARS);
+ fprintf(stdout, "Consecutive BAR test:\t\t");
+ if (ret < 0)
+ fprintf(stdout, "TEST FAILED\n");
+ else
+ fprintf(stdout, "%s\n", result[ret]);
+ }
+
if (test->set_irqtype) {
ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype);
fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]);
/* 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:Cm:x:i:deIlhrwcs:")) != EOF)
switch (c) {
case 'D':
test->device = optarg;
if (test->barnum < 0 || test->barnum > 5)
goto usage;
continue;
+ case 'C':
+ test->consecutive_bar_test = true;
+ continue;
case 'l':
test->legacyirq = true;
continue;
"Options:\n"
"\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n"
"\t-b <bar num> BAR test (bar number between 0..5)\n"
+ "\t-C Consecutive BAR test\n"
"\t-m <msi num> MSI test (msi number between 1..32)\n"
"\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"