ioatcontrol.c revision 302408
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: stable/11/tools/tools/ioat/ioatcontrol.c 300874 2016-05-27 21:12:25Z ngie $");
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
46static int prettyprint(struct ioat_test *);
47
48static void
49usage(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
68static void
69main_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
105int
106main(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
229static int
230prettyprint(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