#include <machine/resource.h>
#include <machine/stdarg.h>
#include <vm/vm.h>
+#include <vm/vm_param.h>
#include <vm/pmap.h>
#include "ioat.h"
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)
{
!= 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);
}
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;
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) {
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);
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);
}
enum ioat_test_kind {
IOAT_TEST_FILL = 0,
IOAT_TEST_DMA,
+ IOAT_TEST_RAW_DMA,
IOAT_NUM_TESTKINDS
};
/* 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;
.\"
.\" $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
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
.Fn ioat_copy
invocation.
The default is 256 KB.
+In raw mode, the default is 4 KB.
.Pp
The
.Ar chain-len
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();
}
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;
return (EX_USAGE);
}
+ if (rflag) {
+ main_raw(&t, argc, argv);
+ return (EX_OK);
+ }
+
t.transactions = atoi(argv[1]);
if (argc >= 3) {