xref: /freebsd/tools/tools/ioat/ioatcontrol.c (revision 0957b409)
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 __FBSDID("$FreeBSD$");
29 
30 #include <sys/ioctl.h>
31 #include <sys/queue.h>
32 
33 #include <fcntl.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sysexits.h>
40 #include <unistd.h>
41 
42 #include <libutil.h>
43 
44 #include "ioat_test.h"
45 
46 static int prettyprint(struct ioat_test *);
47 
48 static void
49 usage(void)
50 {
51 
52 	printf("Usage: %s [-c period] [-EfmVz] channel-number num-txns [<bufsize> "
53 	    "[<chain-len> [duration]]]\n", getprogname());
54 	printf("       %s -r [-c period] [-vVwz] channel-number address [<bufsize>]\n\n",
55 	    getprogname());
56 	printf("           -c period - Enable interrupt coalescing (us) (default: 0)\n");
57 	printf("           -E        - Test non-contiguous 8k copy.\n");
58 	printf("           -f        - Test block fill (default: DMA copy).\n");
59 	printf("           -m        - Test memcpy instead of DMA.\n");
60 	printf("           -r        - Issue DMA to or from a specific address.\n");
61 	printf("           -V        - Enable verification\n");
62 	printf("           -v        - <address> is a kernel virtual address\n");
63 	printf("           -w        - Write to the specified address\n");
64 	printf("           -z        - Zero device stats before test\n");
65 	exit(EX_USAGE);
66 }
67 
68 static void
69 main_raw(struct ioat_test *t, int argc, char **argv)
70 {
71 	int fd;
72 
73 	/* Raw DMA defaults */
74 	t->testkind = IOAT_TEST_RAW_DMA;
75 	t->transactions = 1;
76 	t->chain_depth = 1;
77 	t->buffer_size = 4 * 1024;
78 
79 	t->raw_target = strtoull(argv[1], NULL, 0);
80 	if (t->raw_target == 0) {
81 		printf("Target shoudln't be NULL\n");
82 		exit(EX_USAGE);
83 	}
84 
85 	if (argc >= 3) {
86 		t->buffer_size = atoi(argv[2]);
87 		if (t->buffer_size == 0) {
88 			printf("Buffer size must be greater than zero\n");
89 			exit(EX_USAGE);
90 		}
91 	}
92 
93 	fd = open("/dev/ioat_test", O_RDWR);
94 	if (fd < 0) {
95 		printf("Cannot open /dev/ioat_test\n");
96 		exit(EX_UNAVAILABLE);
97 	}
98 
99 	(void)ioctl(fd, IOAT_DMATEST, t);
100 	close(fd);
101 
102 	exit(prettyprint(t));
103 }
104 
105 int
106 main(int argc, char **argv)
107 {
108 	struct ioat_test t;
109 	int fd, ch;
110 	bool fflag, rflag, Eflag, mflag;
111 	unsigned modeflags;
112 
113 	memset(&t, 0, sizeof(t));
114 
115 	fflag = rflag = Eflag = mflag = false;
116 	modeflags = 0;
117 
118 	while ((ch = getopt(argc, argv, "c:EfmrvVwz")) != -1) {
119 		switch (ch) {
120 		case 'c':
121 			t.coalesce_period = atoi(optarg);
122 			break;
123 		case 'E':
124 			Eflag = true;
125 			modeflags++;
126 			break;
127 		case 'f':
128 			fflag = true;
129 			modeflags++;
130 			break;
131 		case 'm':
132 			mflag = true;
133 			modeflags++;
134 			break;
135 		case 'r':
136 			rflag = true;
137 			modeflags++;
138 			break;
139 		case 'v':
140 			t.raw_is_virtual = true;
141 			break;
142 		case 'V':
143 			t.verify = true;
144 			break;
145 		case 'w':
146 			t.raw_write = true;
147 			break;
148 		case 'z':
149 			t.zero_stats = true;
150 			break;
151 		default:
152 			usage();
153 		}
154 	}
155 	argc -= optind;
156 	argv += optind;
157 
158 	if (argc < 2)
159 		usage();
160 
161 	if (modeflags > 1) {
162 		printf("Invalid: Cannot use >1 mode flag (-E, -f, -m, or -r)\n");
163 		usage();
164 	}
165 
166 	/* Defaults for optional args */
167 	t.buffer_size = 256 * 1024;
168 	t.chain_depth = 2;
169 	t.duration = 0;
170 	t.testkind = IOAT_TEST_DMA;
171 
172 	if (fflag)
173 		t.testkind = IOAT_TEST_FILL;
174 	else if (Eflag) {
175 		t.testkind = IOAT_TEST_DMA_8K;
176 		t.buffer_size = 8 * 1024;
177 	} else if (mflag)
178 		t.testkind = IOAT_TEST_MEMCPY;
179 
180 	t.channel_index = atoi(argv[0]);
181 	if (t.channel_index > 8) {
182 		printf("Channel number must be between 0 and 7.\n");
183 		return (EX_USAGE);
184 	}
185 
186 	if (rflag) {
187 		main_raw(&t, argc, argv);
188 		return (EX_OK);
189 	}
190 
191 	t.transactions = atoi(argv[1]);
192 
193 	if (argc >= 3) {
194 		t.buffer_size = atoi(argv[2]);
195 		if (t.buffer_size == 0) {
196 			printf("Buffer size must be greater than zero\n");
197 			return (EX_USAGE);
198 		}
199 	}
200 
201 	if (argc >= 4) {
202 		t.chain_depth = atoi(argv[3]);
203 		if (t.chain_depth < 1) {
204 			printf("Chain length must be greater than zero\n");
205 			return (EX_USAGE);
206 		}
207 	}
208 
209 	if (argc >= 5) {
210 		t.duration = atoi(argv[4]);
211 		if (t.duration < 1) {
212 			printf("Duration must be greater than zero\n");
213 			return (EX_USAGE);
214 		}
215 	}
216 
217 	fd = open("/dev/ioat_test", O_RDWR);
218 	if (fd < 0) {
219 		printf("Cannot open /dev/ioat_test\n");
220 		return (EX_UNAVAILABLE);
221 	}
222 
223 	(void)ioctl(fd, IOAT_DMATEST, &t);
224 	close(fd);
225 
226 	return (prettyprint(&t));
227 }
228 
229 static int
230 prettyprint(struct ioat_test *t)
231 {
232 	char bps[10], bytesh[10];
233 	uintmax_t bytes;
234 
235 	if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0 ||
236 	    t->status[IOAT_TEST_NO_MEMORY] != 0 ||
237 	    t->status[IOAT_TEST_MISCOMPARE] != 0) {
238 		printf("Errors:\n");
239 		if (t->status[IOAT_TEST_NO_DMA_ENGINE] != 0)
240 			printf("\tNo DMA engine present: %u\n",
241 			    (unsigned)t->status[IOAT_TEST_NO_DMA_ENGINE]);
242 		if (t->status[IOAT_TEST_NO_MEMORY] != 0)
243 			printf("\tOut of memory: %u\n",
244 			    (unsigned)t->status[IOAT_TEST_NO_MEMORY]);
245 		if (t->status[IOAT_TEST_MISCOMPARE] != 0)
246 			printf("\tMiscompares: %u\n",
247 			    (unsigned)t->status[IOAT_TEST_MISCOMPARE]);
248 	}
249 
250 	printf("Processed %u txns\n", (unsigned)t->status[IOAT_TEST_OK] /
251 	    t->chain_depth);
252 	bytes = (uintmax_t)t->buffer_size * t->status[IOAT_TEST_OK];
253 
254 	humanize_number(bytesh, sizeof(bytesh), (int64_t)bytes, "B",
255 	    HN_AUTOSCALE, HN_DECIMAL);
256 	if (t->duration) {
257 		humanize_number(bps, sizeof(bps),
258 		    (int64_t)1000 * bytes / t->duration, "B/s", HN_AUTOSCALE,
259 		    HN_DECIMAL);
260 		printf("%ju (%s) copied in %u ms (%s)\n", bytes, bytesh,
261 		    (unsigned)t->duration, bps);
262 	} else
263 		printf("%ju (%s) copied\n", bytes, bytesh);
264 
265 	return (EX_OK);
266 }
267