1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**
3*4882a593Smuzhiyun * Userspace PCI Endpoint Test Module
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2017 Texas Instruments
6*4882a593Smuzhiyun * Author: Kishon Vijay Abraham I <kishon@ti.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <fcntl.h>
11*4882a593Smuzhiyun #include <stdbool.h>
12*4882a593Smuzhiyun #include <stdio.h>
13*4882a593Smuzhiyun #include <stdlib.h>
14*4882a593Smuzhiyun #include <sys/ioctl.h>
15*4882a593Smuzhiyun #include <unistd.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/pcitest.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define BILLION 1E9
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun static char *result[] = { "NOT OKAY", "OKAY" };
22*4882a593Smuzhiyun static char *irq[] = { "LEGACY", "MSI", "MSI-X" };
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun struct pci_test {
25*4882a593Smuzhiyun char *device;
26*4882a593Smuzhiyun char barnum;
27*4882a593Smuzhiyun bool legacyirq;
28*4882a593Smuzhiyun unsigned int msinum;
29*4882a593Smuzhiyun unsigned int msixnum;
30*4882a593Smuzhiyun int irqtype;
31*4882a593Smuzhiyun bool set_irqtype;
32*4882a593Smuzhiyun bool get_irqtype;
33*4882a593Smuzhiyun bool clear_irq;
34*4882a593Smuzhiyun bool read;
35*4882a593Smuzhiyun bool write;
36*4882a593Smuzhiyun bool copy;
37*4882a593Smuzhiyun unsigned long size;
38*4882a593Smuzhiyun bool use_dma;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
run_test(struct pci_test * test)41*4882a593Smuzhiyun static int run_test(struct pci_test *test)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct pci_endpoint_test_xfer_param param;
44*4882a593Smuzhiyun int ret = -EINVAL;
45*4882a593Smuzhiyun int fd;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun fd = open(test->device, O_RDWR);
48*4882a593Smuzhiyun if (fd < 0) {
49*4882a593Smuzhiyun perror("can't open PCI Endpoint Test device");
50*4882a593Smuzhiyun return -ENODEV;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (test->barnum >= 0 && test->barnum <= 5) {
54*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_BAR, test->barnum);
55*4882a593Smuzhiyun fprintf(stdout, "BAR%d:\t\t", test->barnum);
56*4882a593Smuzhiyun if (ret < 0)
57*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
58*4882a593Smuzhiyun else
59*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (test->set_irqtype) {
63*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype);
64*4882a593Smuzhiyun fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]);
65*4882a593Smuzhiyun if (ret < 0)
66*4882a593Smuzhiyun fprintf(stdout, "FAILED\n");
67*4882a593Smuzhiyun else
68*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (test->get_irqtype) {
72*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_GET_IRQTYPE);
73*4882a593Smuzhiyun fprintf(stdout, "GET IRQ TYPE:\t\t");
74*4882a593Smuzhiyun if (ret < 0)
75*4882a593Smuzhiyun fprintf(stdout, "FAILED\n");
76*4882a593Smuzhiyun else
77*4882a593Smuzhiyun fprintf(stdout, "%s\n", irq[ret]);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (test->clear_irq) {
81*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_CLEAR_IRQ);
82*4882a593Smuzhiyun fprintf(stdout, "CLEAR IRQ:\t\t");
83*4882a593Smuzhiyun if (ret < 0)
84*4882a593Smuzhiyun fprintf(stdout, "FAILED\n");
85*4882a593Smuzhiyun else
86*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (test->legacyirq) {
90*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0);
91*4882a593Smuzhiyun fprintf(stdout, "LEGACY IRQ:\t");
92*4882a593Smuzhiyun if (ret < 0)
93*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
94*4882a593Smuzhiyun else
95*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (test->msinum > 0 && test->msinum <= 32) {
99*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_MSI, test->msinum);
100*4882a593Smuzhiyun fprintf(stdout, "MSI%d:\t\t", test->msinum);
101*4882a593Smuzhiyun if (ret < 0)
102*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
103*4882a593Smuzhiyun else
104*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (test->msixnum > 0 && test->msixnum <= 2048) {
108*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_MSIX, test->msixnum);
109*4882a593Smuzhiyun fprintf(stdout, "MSI-X%d:\t\t", test->msixnum);
110*4882a593Smuzhiyun if (ret < 0)
111*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
112*4882a593Smuzhiyun else
113*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (test->write) {
117*4882a593Smuzhiyun param.size = test->size;
118*4882a593Smuzhiyun if (test->use_dma)
119*4882a593Smuzhiyun param.flags = PCITEST_FLAGS_USE_DMA;
120*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_WRITE, ¶m);
121*4882a593Smuzhiyun fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size);
122*4882a593Smuzhiyun if (ret < 0)
123*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
124*4882a593Smuzhiyun else
125*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (test->read) {
129*4882a593Smuzhiyun param.size = test->size;
130*4882a593Smuzhiyun if (test->use_dma)
131*4882a593Smuzhiyun param.flags = PCITEST_FLAGS_USE_DMA;
132*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_READ, ¶m);
133*4882a593Smuzhiyun fprintf(stdout, "READ (%7ld bytes):\t\t", test->size);
134*4882a593Smuzhiyun if (ret < 0)
135*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
136*4882a593Smuzhiyun else
137*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (test->copy) {
141*4882a593Smuzhiyun param.size = test->size;
142*4882a593Smuzhiyun if (test->use_dma)
143*4882a593Smuzhiyun param.flags = PCITEST_FLAGS_USE_DMA;
144*4882a593Smuzhiyun ret = ioctl(fd, PCITEST_COPY, ¶m);
145*4882a593Smuzhiyun fprintf(stdout, "COPY (%7ld bytes):\t\t", test->size);
146*4882a593Smuzhiyun if (ret < 0)
147*4882a593Smuzhiyun fprintf(stdout, "TEST FAILED\n");
148*4882a593Smuzhiyun else
149*4882a593Smuzhiyun fprintf(stdout, "%s\n", result[ret]);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun fflush(stdout);
153*4882a593Smuzhiyun close(fd);
154*4882a593Smuzhiyun return (ret < 0) ? ret : 1 - ret; /* return 0 if test succeeded */
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
main(int argc,char ** argv)157*4882a593Smuzhiyun int main(int argc, char **argv)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun int c;
160*4882a593Smuzhiyun struct pci_test *test;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun test = calloc(1, sizeof(*test));
163*4882a593Smuzhiyun if (!test) {
164*4882a593Smuzhiyun perror("Fail to allocate memory for pci_test\n");
165*4882a593Smuzhiyun return -ENOMEM;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* since '0' is a valid BAR number, initialize it to -1 */
169*4882a593Smuzhiyun test->barnum = -1;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* set default size as 100KB */
172*4882a593Smuzhiyun test->size = 0x19000;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* set default endpoint device */
175*4882a593Smuzhiyun test->device = "/dev/pci-endpoint-test.0";
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun while ((c = getopt(argc, argv, "D:b:m:x:i:deIlhrwcs:")) != EOF)
178*4882a593Smuzhiyun switch (c) {
179*4882a593Smuzhiyun case 'D':
180*4882a593Smuzhiyun test->device = optarg;
181*4882a593Smuzhiyun continue;
182*4882a593Smuzhiyun case 'b':
183*4882a593Smuzhiyun test->barnum = atoi(optarg);
184*4882a593Smuzhiyun if (test->barnum < 0 || test->barnum > 5)
185*4882a593Smuzhiyun goto usage;
186*4882a593Smuzhiyun continue;
187*4882a593Smuzhiyun case 'l':
188*4882a593Smuzhiyun test->legacyirq = true;
189*4882a593Smuzhiyun continue;
190*4882a593Smuzhiyun case 'm':
191*4882a593Smuzhiyun test->msinum = atoi(optarg);
192*4882a593Smuzhiyun if (test->msinum < 1 || test->msinum > 32)
193*4882a593Smuzhiyun goto usage;
194*4882a593Smuzhiyun continue;
195*4882a593Smuzhiyun case 'x':
196*4882a593Smuzhiyun test->msixnum = atoi(optarg);
197*4882a593Smuzhiyun if (test->msixnum < 1 || test->msixnum > 2048)
198*4882a593Smuzhiyun goto usage;
199*4882a593Smuzhiyun continue;
200*4882a593Smuzhiyun case 'i':
201*4882a593Smuzhiyun test->irqtype = atoi(optarg);
202*4882a593Smuzhiyun if (test->irqtype < 0 || test->irqtype > 2)
203*4882a593Smuzhiyun goto usage;
204*4882a593Smuzhiyun test->set_irqtype = true;
205*4882a593Smuzhiyun continue;
206*4882a593Smuzhiyun case 'I':
207*4882a593Smuzhiyun test->get_irqtype = true;
208*4882a593Smuzhiyun continue;
209*4882a593Smuzhiyun case 'r':
210*4882a593Smuzhiyun test->read = true;
211*4882a593Smuzhiyun continue;
212*4882a593Smuzhiyun case 'w':
213*4882a593Smuzhiyun test->write = true;
214*4882a593Smuzhiyun continue;
215*4882a593Smuzhiyun case 'c':
216*4882a593Smuzhiyun test->copy = true;
217*4882a593Smuzhiyun continue;
218*4882a593Smuzhiyun case 'e':
219*4882a593Smuzhiyun test->clear_irq = true;
220*4882a593Smuzhiyun continue;
221*4882a593Smuzhiyun case 's':
222*4882a593Smuzhiyun test->size = strtoul(optarg, NULL, 0);
223*4882a593Smuzhiyun continue;
224*4882a593Smuzhiyun case 'd':
225*4882a593Smuzhiyun test->use_dma = true;
226*4882a593Smuzhiyun continue;
227*4882a593Smuzhiyun case 'h':
228*4882a593Smuzhiyun default:
229*4882a593Smuzhiyun usage:
230*4882a593Smuzhiyun fprintf(stderr,
231*4882a593Smuzhiyun "usage: %s [options]\n"
232*4882a593Smuzhiyun "Options:\n"
233*4882a593Smuzhiyun "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n"
234*4882a593Smuzhiyun "\t-b <bar num> BAR test (bar number between 0..5)\n"
235*4882a593Smuzhiyun "\t-m <msi num> MSI test (msi number between 1..32)\n"
236*4882a593Smuzhiyun "\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n"
237*4882a593Smuzhiyun "\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n"
238*4882a593Smuzhiyun "\t-e Clear IRQ\n"
239*4882a593Smuzhiyun "\t-I Get current IRQ type configured\n"
240*4882a593Smuzhiyun "\t-d Use DMA\n"
241*4882a593Smuzhiyun "\t-l Legacy IRQ test\n"
242*4882a593Smuzhiyun "\t-r Read buffer test\n"
243*4882a593Smuzhiyun "\t-w Write buffer test\n"
244*4882a593Smuzhiyun "\t-c Copy buffer test\n"
245*4882a593Smuzhiyun "\t-s <size> Size of buffer {default: 100KB}\n"
246*4882a593Smuzhiyun "\t-h Print this help message\n",
247*4882a593Smuzhiyun argv[0]);
248*4882a593Smuzhiyun return -EINVAL;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return run_test(test);
252*4882a593Smuzhiyun }
253