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