]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
ioatcontrol(8): Add and document "raw" testing mode
authorcem <cem@FreeBSD.org>
Thu, 29 Oct 2015 04:16:16 +0000 (04:16 +0000)
committercem <cem@FreeBSD.org>
Thu, 29 Oct 2015 04:16:16 +0000 (04:16 +0000)
Allows DMA from/to arbitrary KVA or physical address.  /dev/ioat_test
must be enabled by root and is only R/W root, so this is approximately
as dangerous as /dev/mem and /dev/kmem.

Sponsored by: EMC / Isilon Storage Division

sys/dev/ioat/ioat_test.c
sys/dev/ioat/ioat_test.h
tools/tools/ioat/ioatcontrol.8
tools/tools/ioat/ioatcontrol.c

index 53d5e8a12b94ac1c46329088eb03b15616a37994..b4920d777ce793582de554d40dc9e7ca208382ab 100644 (file)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/stdarg.h>
 #include <vm/vm.h>
+#include <vm/vm_param.h>
 #include <vm/pmap.h>
 
 #include "ioat.h"
@@ -120,6 +121,18 @@ test_transaction *ioat_test_transaction_create(unsigned num_buffers,
        return (tx);
 }
 
+static void
+dump_hex(void *p, size_t chunks)
+{
+       size_t i, j;
+
+       for (i = 0; i < chunks; i++) {
+               for (j = 0; j < 8; j++)
+                       printf("%08x ", ((uint32_t *)p)[i * 8 + j]);
+               printf("\n");
+       }
+}
+
 static bool
 ioat_compare_ok(struct test_transaction *tx)
 {
@@ -140,9 +153,14 @@ ioat_compare_ok(struct test_transaction *tx)
                                    != 0)
                                        return (false);
                        }
-               } else if (test->testkind == IOAT_TEST_DMA)
+               } else if (test->testkind == IOAT_TEST_DMA) {
                        if (memcmp(src, dst, tx->length) != 0)
                                return (false);
+               } else if (test->testkind == IOAT_TEST_RAW_DMA) {
+                       if (test->raw_write)
+                               dst = test->raw_vtarget;
+                       dump_hex(dst, tx->length / 32);
+               }
        }
        return (true);
 }
@@ -242,6 +260,13 @@ ioat_test_submit_1_tx(struct ioat_test *test, bus_dmaengine_t dma)
                src = vtophys((vm_offset_t)tx->buf[2*i]);
                dest = vtophys((vm_offset_t)tx->buf[2*i+1]);
 
+               if (test->testkind == IOAT_TEST_RAW_DMA) {
+                       if (test->raw_write)
+                               dest = test->raw_target;
+                       else
+                               src = test->raw_target;
+               }
+
                if (i == tx->depth - 1) {
                        cb = ioat_dma_test_callback;
                        flags = DMA_INT_EN;
@@ -250,7 +275,8 @@ ioat_test_submit_1_tx(struct ioat_test *test, bus_dmaengine_t dma)
                        flags = 0;
                }
 
-               if (test->testkind == IOAT_TEST_DMA)
+               if (test->testkind == IOAT_TEST_DMA ||
+                   test->testkind == IOAT_TEST_RAW_DMA)
                        desc = ioat_copy(dma, dest, src, tx->length, cb, tx,
                            flags);
                else if (test->testkind == IOAT_TEST_FILL) {
@@ -328,6 +354,16 @@ ioat_dma_test(void *arg)
                goto out;
        }
 
+       if (test->testkind == IOAT_TEST_RAW_DMA) {
+               if (test->raw_is_virtual) {
+                       test->raw_vtarget = (void *)test->raw_target;
+                       test->raw_target = vtophys(test->raw_vtarget);
+               } else {
+                       test->raw_vtarget = pmap_mapdev(test->raw_target,
+                           test->buffer_size);
+               }
+       }
+
        index = g_thread_index++;
        TAILQ_INIT(&test->free_q);
        TAILQ_INIT(&test->pend_q);
@@ -373,6 +409,9 @@ ioat_dma_test(void *arg)
 
        ioat_test_release_memory(test);
 out:
+       if (test->testkind == IOAT_TEST_RAW_DMA && !test->raw_is_virtual)
+               pmap_unmapdev((vm_offset_t)test->raw_vtarget,
+                   test->buffer_size);
        ioat_put_dmaengine(dmaengine);
 }
 
index ecfef7d5cb19c15f95abf0e3108dcd887b1531d8..b6e6a15acb9ec4cae1e49b0f02b879bcc570520a 100644 (file)
@@ -41,6 +41,7 @@ enum ioat_res {
 enum ioat_test_kind {
        IOAT_TEST_FILL = 0,
        IOAT_TEST_DMA,
+       IOAT_TEST_RAW_DMA,
        IOAT_NUM_TESTKINDS
 };
 
@@ -66,6 +67,12 @@ struct ioat_test {
        /* If true, check for miscompares after a copy. */
        bool verify;
 
+       /* DMA directly to/from some memory address */
+       uint64_t raw_target;
+       void *raw_vtarget;
+       bool raw_write;
+       bool raw_is_virtual;
+
        /* Internal usage -- not test inputs */
        TAILQ_HEAD(, test_transaction) free_q;
        TAILQ_HEAD(, test_transaction) pend_q;
index 7e3234825edac60a9ba582f0dccd2d6e2850c1e7..2306d3876a36f3e75466170c43414bc371817509 100644 (file)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 26, 2015
+.Dd October 28, 2015
 .Dt IOATCONTROL 8
 .Os
 .Sh NAME
 .Ar [ bufsize
 .Ar [ chain-len
 .Ar [ duration ] ] ]
+.Nm
+.Fl r
+.Op Fl v
+.Op Fl V
+.Op Fl w
+.Ar channel_number
+.Ar address
+.Ar [ bufsize ]
 .Sh DESCRIPTION
 .Nm
 allows one to issue some number of test operations to the
@@ -55,6 +63,29 @@ tests copy)
 Verify copies/fills for accuracy
 .El
 .Pp
+Alternatively one can use
+.Nm
+.Fl r
+to issue DMA to or from a specific
+.Ar address .
+The arguments in "raw" mode are:
+.Bl -tag -width Ds
+.It Fl v
+.Ar address
+is a kernel virtual address (by default,
+.Ar address
+is assumed to be a physical address)
+.It Fl V
+Dump the resulting hex to syslog
+.It Fl w
+Write to the specified
+.Ar address
+(by default,
+.Nm
+.Fl r
+reads)
+.El
+.Pp
 .Nm
 operates in one of two modes; if the
 .Ar duration
@@ -77,6 +108,7 @@ argument determines the size of buffers to use for each
 .Fn ioat_copy
 invocation.
 The default is 256 KB.
+In raw mode, the default is 4 KB.
 .Pp
 The
 .Ar chain-len
index e55ce4f605d336b1911fb124709ebd4c54fb6edc..90255e7c7d25677c943fadbbd8530fdd063f43f5 100644 (file)
@@ -50,24 +50,72 @@ usage(void)
 
        printf("Usage: %s [-fV] <channel #> <txns> [<bufsize> "
            "[<chain-len> [duration]]]\n", getprogname());
+       printf("       %s -r [-vV] <channel #> <addr> [<bufsize>]\n",
+           getprogname());
        exit(EX_USAGE);
 }
 
+static void
+main_raw(struct ioat_test *t, int argc, char **argv)
+{
+       int fd;
+
+       /* Raw DMA defaults */
+       t->testkind = IOAT_TEST_RAW_DMA;
+       t->transactions = 1;
+       t->chain_depth = 1;
+       t->buffer_size = 4 * 1024;
+
+       t->raw_target = strtoull(argv[1], NULL, 0);
+       if (t->raw_target == 0) {
+               printf("Target shoudln't be NULL\n");
+               exit(EX_USAGE);
+       }
+
+       if (argc >= 3) {
+               t->buffer_size = atoi(argv[2]);
+               if (t->buffer_size == 0) {
+                       printf("Buffer size must be greater than zero\n");
+                       exit(EX_USAGE);
+               }
+       }
+
+       fd = open("/dev/ioat_test", O_RDWR);
+       if (fd < 0) {
+               printf("Cannot open /dev/ioat_test\n");
+               exit(EX_UNAVAILABLE);
+       }
+
+       (void)ioctl(fd, IOAT_DMATEST, t);
+       close(fd);
+
+       exit(prettyprint(t));
+}
+
 int
 main(int argc, char **argv)
 {
        struct ioat_test t;
        int fd, ch;
-       bool fflag;
+       bool fflag, rflag;
 
-       while ((ch = getopt(argc, argv, "fV")) != -1) {
+       while ((ch = getopt(argc, argv, "rfvVw")) != -1) {
                switch (ch) {
                case 'f':
                        fflag = true;
                        break;
+               case 'r':
+                       rflag = true;
+                       break;
+               case 'v':
+                       t.raw_is_virtual = true;
+                       break;
                case 'V':
                        t.verify = true;
                        break;
+               case 'w':
+                       t.raw_write = true;
+                       break;
                default:
                        usage();
                }
@@ -78,6 +126,11 @@ main(int argc, char **argv)
        if (argc < 2)
                usage();
 
+       if (rflag && fflag) {
+               printf("Invalid: -r and -f\n");
+               usage();
+       }
+
        /* Defaults for optional args */
        t.buffer_size = 256 * 1024;
        t.chain_depth = 2;
@@ -93,6 +146,11 @@ main(int argc, char **argv)
                return (EX_USAGE);
        }
 
+       if (rflag) {
+               main_raw(&t, argc, argv);
+               return (EX_OK);
+       }
+
        t.transactions = atoi(argv[1]);
 
        if (argc >= 3) {