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