Skip to content

Commit d6658d3

Browse files
floatiousbjorn-helgaas
authored andcommitted
misc: pci_endpoint_test: Add consecutive BAR test
Add a more advanced BAR test that writes all BARs in one go, and then reads them back and verifies that the value matches the BAR number bitwise OR'ed with offset, this allows us to verify: - The BAR number was what we intended to read - The offset was what we intended to read This allows us to detect potential address translation issues on the EP. Reading back the BAR directly after writing will not allow us to detect the case where inbound address translation on the endpoint incorrectly causes multiple BARs to be redirected to the same memory region (within the EP). Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Niklas Cassel <[email protected]> Signed-off-by: Krzysztof Wilczyński <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]>
1 parent 0d292a1 commit d6658d3

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

drivers/misc/pci_endpoint_test.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,91 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
325325
return true;
326326
}
327327

328+
static u32 bar_test_pattern_with_offset(enum pci_barno barno, int offset)
329+
{
330+
u32 val;
331+
332+
/* Keep the BAR pattern in the top byte. */
333+
val = bar_test_pattern[barno] & 0xff000000;
334+
/* Store the (partial) offset in the remaining bytes. */
335+
val |= offset & 0x00ffffff;
336+
337+
return val;
338+
}
339+
340+
static bool pci_endpoint_test_bars_write_bar(struct pci_endpoint_test *test,
341+
enum pci_barno barno)
342+
{
343+
struct pci_dev *pdev = test->pdev;
344+
int j, size;
345+
346+
size = pci_resource_len(pdev, barno);
347+
348+
if (barno == test->test_reg_bar)
349+
size = 0x4;
350+
351+
for (j = 0; j < size; j += 4)
352+
writel_relaxed(bar_test_pattern_with_offset(barno, j),
353+
test->bar[barno] + j);
354+
355+
return true;
356+
}
357+
358+
static bool pci_endpoint_test_bars_read_bar(struct pci_endpoint_test *test,
359+
enum pci_barno barno)
360+
{
361+
struct pci_dev *pdev = test->pdev;
362+
struct device *dev = &pdev->dev;
363+
int j, size;
364+
u32 val;
365+
366+
size = pci_resource_len(pdev, barno);
367+
368+
if (barno == test->test_reg_bar)
369+
size = 0x4;
370+
371+
for (j = 0; j < size; j += 4) {
372+
u32 expected = bar_test_pattern_with_offset(barno, j);
373+
374+
val = readl_relaxed(test->bar[barno] + j);
375+
if (val != expected) {
376+
dev_err(dev,
377+
"BAR%d incorrect data at offset: %#x, got: %#x expected: %#x\n",
378+
barno, j, val, expected);
379+
return false;
380+
}
381+
}
382+
383+
return true;
384+
}
385+
386+
static bool pci_endpoint_test_bars(struct pci_endpoint_test *test)
387+
{
388+
enum pci_barno bar;
389+
bool ret;
390+
391+
/* Write all BARs in order (without reading). */
392+
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
393+
if (test->bar[bar])
394+
pci_endpoint_test_bars_write_bar(test, bar);
395+
396+
/*
397+
* Read all BARs in order (without writing).
398+
* If there is an address translation issue on the EP, writing one BAR
399+
* might have overwritten another BAR. Ensure that this is not the case.
400+
* (Reading back the BAR directly after writing can not detect this.)
401+
*/
402+
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
403+
if (test->bar[bar]) {
404+
ret = pci_endpoint_test_bars_read_bar(test, bar);
405+
if (!ret)
406+
return ret;
407+
}
408+
}
409+
410+
return true;
411+
}
412+
328413
static bool pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)
329414
{
330415
u32 val;
@@ -771,6 +856,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
771856
goto ret;
772857
ret = pci_endpoint_test_bar(test, bar);
773858
break;
859+
case PCITEST_BARS:
860+
ret = pci_endpoint_test_bars(test);
861+
break;
774862
case PCITEST_INTX_IRQ:
775863
ret = pci_endpoint_test_intx_irq(test);
776864
break;

include/uapi/linux/pcitest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define PCITEST_MSIX _IOW('P', 0x7, int)
2121
#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
2222
#define PCITEST_GET_IRQTYPE _IO('P', 0x9)
23+
#define PCITEST_BARS _IO('P', 0xa)
2324
#define PCITEST_CLEAR_IRQ _IO('P', 0x10)
2425

2526
#define PCITEST_FLAGS_USE_DMA 0x00000001

tools/pci/pcitest.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static char *irq[] = { "LEGACY", "MSI", "MSI-X" };
2222
struct pci_test {
2323
char *device;
2424
char barnum;
25+
bool consecutive_bar_test;
2526
bool legacyirq;
2627
unsigned int msinum;
2728
unsigned int msixnum;
@@ -57,6 +58,15 @@ static int run_test(struct pci_test *test)
5758
fprintf(stdout, "%s\n", result[ret]);
5859
}
5960

61+
if (test->consecutive_bar_test) {
62+
ret = ioctl(fd, PCITEST_BARS);
63+
fprintf(stdout, "Consecutive BAR test:\t\t");
64+
if (ret < 0)
65+
fprintf(stdout, "TEST FAILED\n");
66+
else
67+
fprintf(stdout, "%s\n", result[ret]);
68+
}
69+
6070
if (test->set_irqtype) {
6171
ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype);
6272
fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]);
@@ -172,7 +182,7 @@ int main(int argc, char **argv)
172182
/* set default endpoint device */
173183
test->device = "/dev/pci-endpoint-test.0";
174184

175-
while ((c = getopt(argc, argv, "D:b:m:x:i:deIlhrwcs:")) != EOF)
185+
while ((c = getopt(argc, argv, "D:b:Cm:x:i:deIlhrwcs:")) != EOF)
176186
switch (c) {
177187
case 'D':
178188
test->device = optarg;
@@ -182,6 +192,9 @@ int main(int argc, char **argv)
182192
if (test->barnum < 0 || test->barnum > 5)
183193
goto usage;
184194
continue;
195+
case 'C':
196+
test->consecutive_bar_test = true;
197+
continue;
185198
case 'l':
186199
test->legacyirq = true;
187200
continue;
@@ -230,6 +243,7 @@ int main(int argc, char **argv)
230243
"Options:\n"
231244
"\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n"
232245
"\t-b <bar num> BAR test (bar number between 0..5)\n"
246+
"\t-C Consecutive BAR test\n"
233247
"\t-m <msi num> MSI test (msi number between 1..32)\n"
234248
"\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n"
235249
"\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n"

tools/pci/pcitest.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ do
1111
pcitest -b $bar
1212
bar=`expr $bar + 1`
1313
done
14+
pcitest -C
1415
echo
1516

1617
echo "Interrupt tests"

0 commit comments

Comments
 (0)