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
usage(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
main_raw(struct ioat_test * t,int argc,char ** argv)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
main(int argc,char ** argv)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
prettyprint(struct ioat_test * t)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