xref: /freebsd/tools/tools/ioat/ioatcontrol.c (revision 315ee00f)
1 /*-
2  * Copyright (C) 2012 Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include <sys/ioctl.h>
29 #include <sys/queue.h>
30 
31 #include <fcntl.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sysexits.h>
38 #include <unistd.h>
39 
40 #include <libutil.h>
41 
42 #include "ioat_test.h"
43 
44 static int prettyprint(struct ioat_test *);
45 
46 static void
47 usage(void)
48 {
49 
50 	printf("Usage: %s [-c period] [-EefmVxXz] channel-number num-txns [<bufsize> "
51 	    "[<chain-len> [duration]]]\n", getprogname());
52 	printf("       %s -r [-c period] [-vVwz] channel-number address [<bufsize>]\n\n",
53 	    getprogname());
54 	printf("           -c period - Enable interrupt coalescing (us) (default: 0)\n");
55 	printf("           -E        - Test contiguous 8k copy.\n");
56 	printf("           -e        - Test non-contiguous 8k copy.\n");
57 	printf("           -f        - Test block fill.\n");
58 	printf("           -m        - Test memcpy instead of DMA.\n");
59 	printf("           -r        - Issue DMA to or from a specific address.\n");
60 	printf("           -V        - Enable verification\n");
61 	printf("           -v        - <address> is a kernel virtual address\n");
62 	printf("           -w        - Write to the specified address\n");
63 	printf("           -x        - Test DMA CRC.\n");
64 	printf("           -X        - Test DMA CRC copy.\n");
65 	printf("           -z        - Zero device stats before test\n");
66 	exit(EX_USAGE);
67 }
68 
69 static void
70 main_raw(struct ioat_test *t, int argc, char **argv)
71 {
72 	int fd;
73 
74 	/* Raw DMA defaults */
75 	t->testkind = IOAT_TEST_RAW_DMA;
76 	t->transactions = 1;
77 	t->chain_depth = 1;
78 	t->buffer_size = 4 * 1024;
79 
80 	t->raw_target = strtoull(argv[1], NULL, 0);
81 	if (t->raw_target == 0) {
82 		printf("Target shoudln't be NULL\n");
83 		exit(EX_USAGE);
84 	}
85 
86 	if (argc >= 3) {
87 		t->buffer_size = atoi(argv[2]);
88 		if (t->buffer_size == 0) {
89 			printf("Buffer size must be greater than zero\n");
90 			exit(EX_USAGE);
91 		}
92 	}
93 
94 	fd = open("/dev/ioat_test", O_RDWR);
95 	if (fd < 0) {
96 		printf("Cannot open /dev/ioat_test\n");
97 		exit(EX_UNAVAILABLE);
98 	}
99 
100 	(void)ioctl(fd, IOAT_DMATEST, t);
101 	close(fd);
102 
103 	exit(prettyprint(t));
104 }
105 
106 int
107 main(int argc, char **argv)
108 {
109 	struct ioat_test t;
110 	int fd, ch;
111 	bool fflag, rflag, Eflag, eflag, mflag, xflag, Xflag;
112 	unsigned modeflags;
113 
114 	memset(&t, 0, sizeof(t));
115 
116 	fflag = rflag = Eflag = eflag = mflag = xflag = Xflag = false;
117 	modeflags = 0;
118 
119 	while ((ch = getopt(argc, argv, "c:EefmrvVwxXz")) != -1) {
120 		switch (ch) {
121 		case 'c':
122 			t.coalesce_period = atoi(optarg);
123 			break;
124 		case 'E':
125 			Eflag = true;
126 			modeflags++;
127 			break;
128 		case 'e':
129 			eflag = true;
130 			modeflags++;
131 			break;
132 		case 'f':
133 			fflag = true;
134 			modeflags++;
135 			break;
136 		case 'm':
137 			mflag = true;
138 			modeflags++;
139 			break;
140 		case 'r':
141 			rflag = true;
142 			modeflags++;
143 			break;
144 		case 'v':
145 			t.raw_is_virtual = true;
146 			break;
147 		case 'V':
148 			t.verify = true;
149 			break;
150 		case 'w':
151 			t.raw_write = true;
152 			break;
153 		case 'x':
154 			xflag = true;
155 			modeflags++;
156 			break;
157 		case 'X':
158 			Xflag = true;
159 			modeflags++;
160 			break;
161 		case 'z':
162 			t.zero_stats = true;
163 			break;
164 		default:
165 			usage();
166 		}
167 	}
168 	argc -= optind;
169 	argv += optind;
170 
171 	if (argc < 2)
172 		usage();
173 
174 	if (modeflags > 1) {
175 		printf("Invalid: Cannot use >1 mode flag (-E, -e, -f, -m, -r, -x or -X)\n");
176 		usage();
177 	}
178 
179 	/* Defaults for optional args */
180 	t.buffer_size = 256 * 1024;
181 	t.chain_depth = 2;
182 	t.duration = 0;
183 	t.testkind = IOAT_TEST_DMA;
184 
185 	if (fflag)
186 		t.testkind = IOAT_TEST_FILL;
187 	else if (Eflag || eflag) {
188 		t.testkind = IOAT_TEST_DMA_8K;
189 		t.buffer_size = 8 * 1024;
190 	} else if (mflag)
191 		t.testkind = IOAT_TEST_MEMCPY;
192 	else if (xflag)
193 		t.testkind = IOAT_TEST_DMA_CRC;
194 	else if (Xflag)
195 		t.testkind = IOAT_TEST_DMA_CRC_COPY;
196 
197 	t.channel_index = atoi(argv[0]);
198 	if (t.channel_index > 8) {
199 		printf("Channel number must be between 0 and 7.\n");
200 		return (EX_USAGE);
201 	}
202 
203 	if (rflag) {
204 		main_raw(&t, argc, argv);
205 		return (EX_OK);
206 	}
207 
208 	t.transactions = atoi(argv[1]);
209 
210 	if (argc >= 3) {
211 		t.buffer_size = atoi(argv[2]);
212 		if (t.buffer_size == 0) {
213 			printf("Buffer size must be greater than zero\n");
214 			return (EX_USAGE);
215 		}
216 	}
217 
218 	if (argc >= 4) {
219 		t.chain_depth = atoi(argv[3]);
220 		if (t.chain_depth < 1) {
221 			printf("Chain length must be greater than zero\n");
222 			return (EX_USAGE);
223 		}
224 	}
225 
226 	if (argc >= 5) {
227 		t.duration = atoi(argv[4]);
228 		if (t.duration < 1) {
229 			printf("Duration must be greater than zero\n");
230 			return (EX_USAGE);
231 		}
232 	}
233 
234 	fd = open("/dev/ioat_test", O_RDWR);
235 	if (fd < 0) {
236 		printf("Cannot open /dev/ioat_test\n");
237 		return (EX_UNAVAILABLE);
238 	}
239 
240 	(void)ioctl(fd, IOAT_DMATEST, &t);
241 	close(fd);
242 
243 	return (prettyprint(&t));
244 }
245 
246 static int
247 prettyprint(struct ioat_test *t)
248 {
249 	char bps[10], bytesh[10];
250 	uintmax_t bytes;
251 
252 	if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0 ||
253 	    t->status[IOAT_TEST_NO_MEMORY] != 0 ||
254 	    t->status[IOAT_TEST_MISCOMPARE] != 0) {
255 		printf("Errors:\n");
256 		if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0)
257 			printf("\tNo DMA engine present: %u\n",
258 			    (unsigned)t->status[IOAT_TEST_NO_DMA_ENGINE]);
259 		if (t->status[IOAT_TEST_NO_MEMORY] != 0)
260 			printf("\tOut of memory: %u\n",
261 			    (unsigned)t->status[IOAT_TEST_NO_MEMORY]);
262 		if (t->status[IOAT_TEST_MISCOMPARE] != 0)
263 			printf("\tMiscompares: %u\n",
264 			    (unsigned)t->status[IOAT_TEST_MISCOMPARE]);
265 	}
266 
267 	printf("Processed %u txns\n", (unsigned)t->status[IOAT_TEST_OK] /
268 	    t->chain_depth);
269 	bytes = (uintmax_t)t->buffer_size * t->status[IOAT_TEST_OK];
270 
271 	humanize_number(bytesh, sizeof(bytesh), (int64_t)bytes, "B",
272 	    HN_AUTOSCALE, HN_DECIMAL);
273 	if (t->duration) {
274 		humanize_number(bps, sizeof(bps),
275 		    (int64_t)1000 * bytes / t->duration, "B/s", HN_AUTOSCALE,
276 		    HN_DECIMAL);
277 		printf("%ju (%s) copied in %u ms (%s)\n", bytes, bytesh,
278 		    (unsigned)t->duration, bps);
279 	} else
280 		printf("%ju (%s) copied\n", bytes, bytesh);
281 
282 	return (EX_OK);
283 }
284