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