Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ioat/ioat_test.c
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include "ioat.h" | #include "ioat.h" | ||||
#include "ioat_test.h" | #include "ioat_test.h" | ||||
#include "ioat_logger.h" | #include "ioat_logger.h" | ||||
#include "ioat_sysctl.h" | |||||
MALLOC_DEFINE(M_IOAT_TEST, "ioat_test", "ioat test allocations"); | MALLOC_DEFINE(M_IOAT_TEST, "ioat_test", "ioat test allocations"); | ||||
static struct cdev *ioat_cdev = NULL; | |||||
#define IOAT_TEST_SIZE 0x40000 | #define IOAT_TEST_SIZE 0x40000 | ||||
#define IOAT_MAX_BUFS 8 | #define IOAT_MAX_BUFS 8 | ||||
static int g_thread_index = 1; | |||||
static struct cdev *g_ioat_cdev = NULL; | |||||
static int g_enable_ioat_test; | |||||
SYSCTL_INT(_hw_ioat, OID_AUTO, enable_ioat_test, CTLFLAG_RDTUN, | |||||
&g_enable_ioat_test, 0, "Non-zero: Enable the /dev/ioat_test device"); | |||||
jimharris: The same comment applies here as the force_legacy_interrupts SYSCTL above. I think this needs… | |||||
cemAuthorUnsubmitted Not Done Inline ActionsIt is a tunable — it's just readable as a sysctl (RDTUN). We could also split the /dev/ioat_test device out into a separate kld, but I figure it wasn't worth bothering. I don't imagine it adds much in the way of bloat to the size of the .ko. (I don't like editing the Makefile to enable/disable the test device.) cem: It is a tunable — it's just readable as a sysctl (RDTUN).
We could also split the… | |||||
jimharrisUnsubmitted Done Inline ActionsSorry - I forgot oat_test was not a separate kld on my original branch. I think what you have here is fine. One alternative would be to change enable_ioat_test to a SYSCTL_PROC, so that the cdev can be created/deleted dynamically (and the sysctl could even be invoked within the ioatcontrol utility). jimharris: Sorry - I forgot oat_test was not a separate kld on my original branch. I think what you have… | |||||
cemAuthorUnsubmitted Not Done Inline ActionsHah, sure. cem: Hah, sure. | |||||
struct test_transaction { | struct test_transaction { | ||||
uint8_t num_buffers; | uint8_t num_buffers; | ||||
void *buf[IOAT_MAX_BUFS]; | void *buf[IOAT_MAX_BUFS]; | ||||
uint32_t length; | uint32_t length; | ||||
struct ioat_test *test; | struct ioat_test *test; | ||||
}; | }; | ||||
static void | static void | ||||
ioat_test_transaction_destroy(struct test_transaction *tx) | ioat_test_transaction_destroy(struct test_transaction *tx) | ||||
{ | { | ||||
int i; | int i; | ||||
for (i = 0; i < IOAT_MAX_BUFS; i++) { | for (i = 0; i < IOAT_MAX_BUFS; i++) { | ||||
if (tx->buf[i] != NULL) { | if (tx->buf[i] != NULL) { | ||||
contigfree(tx->buf[i], IOAT_TEST_SIZE, M_IOAT_TEST); | contigfree(tx->buf[i], IOAT_TEST_SIZE, M_IOAT_TEST); | ||||
tx->buf[i] = NULL; | tx->buf[i] = NULL; | ||||
} | } | ||||
} | } | ||||
free(tx, M_IOAT_TEST); | free(tx, M_IOAT_TEST); | ||||
} | } | ||||
static struct | static struct | ||||
test_transaction *ioat_test_transaction_create(uint8_t num_buffers, | test_transaction *ioat_test_transaction_create(uint8_t num_buffers, | ||||
uint32_t buffer_size) | uint32_t buffer_size) | ||||
{ | { | ||||
struct test_transaction *tx; | struct test_transaction *tx; | ||||
int i; | int i; | ||||
tx = malloc(sizeof(struct test_transaction), M_IOAT_TEST, M_NOWAIT | M_ZERO); | tx = malloc(sizeof(struct test_transaction), M_IOAT_TEST, M_NOWAIT | M_ZERO); | ||||
if (tx == NULL) | if (tx == NULL) | ||||
return (NULL); | return (NULL); | ||||
tx->num_buffers = num_buffers; | tx->num_buffers = num_buffers; | ||||
tx->length = buffer_size; | tx->length = buffer_size; | ||||
for (i = 0; i < num_buffers; i++) { | for (i = 0; i < num_buffers; i++) { | ||||
tx->buf[i] = contigmalloc(buffer_size, M_IOAT_TEST, M_NOWAIT, | tx->buf[i] = contigmalloc(buffer_size, M_IOAT_TEST, M_NOWAIT, | ||||
0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); | 0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); | ||||
if (tx->buf[i] == NULL) { | if (tx->buf[i] == NULL) { | ||||
ioat_test_transaction_destroy(tx); | ioat_test_transaction_destroy(tx); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
} | } | ||||
return (tx); | return (tx); | ||||
} | } | ||||
static void | static void | ||||
ioat_dma_test_callback(void *arg) | ioat_dma_test_callback(void *arg) | ||||
{ | { | ||||
struct test_transaction *tx = arg; | struct test_transaction *tx; | ||||
struct ioat_test *test = tx->test; | struct ioat_test *test; | ||||
tx = arg; | |||||
test = tx->test; | |||||
if (memcmp(tx->buf[0], tx->buf[1], tx->length) != 0) { | if (memcmp(tx->buf[0], tx->buf[1], tx->length) != 0) { | ||||
ioat_log_message(0, "miscompare found\n"); | ioat_log_message(0, "miscompare found\n"); | ||||
test->status = IOAT_TEST_MISCOMPARE; | test->status = IOAT_TEST_MISCOMPARE; | ||||
} | } | ||||
atomic_add_32(&test->num_completions, 1); | atomic_add_32(&test->num_completions, 1); | ||||
ioat_test_transaction_destroy(tx); | ioat_test_transaction_destroy(tx); | ||||
if (test->num_completions == test->num_loops) | if (test->num_completions == test->num_loops) | ||||
wakeup(test); | wakeup(test); | ||||
} | } | ||||
int g_thread_index = 1; | |||||
static void | static void | ||||
ioat_dma_test(void *arg) | ioat_dma_test(void *arg) | ||||
{ | { | ||||
struct ioat_test *test = arg; | |||||
struct test_transaction *tx; | struct test_transaction *tx; | ||||
struct ioat_test *test; | |||||
bus_dmaengine_t dmaengine; | bus_dmaengine_t dmaengine; | ||||
uint32_t loops; | |||||
int index, i; | int index, i; | ||||
uint32_t loops = test->num_loops; | |||||
test = arg; | |||||
loops = test->num_loops; | |||||
test->status = IOAT_TEST_OK; | test->status = IOAT_TEST_OK; | ||||
test->num_completions = 0; | test->num_completions = 0; | ||||
index = g_thread_index++; | index = g_thread_index++; | ||||
dmaengine = ioat_get_dmaengine(test->channel_index); | dmaengine = ioat_get_dmaengine(test->channel_index); | ||||
if (dmaengine == NULL) { | if (dmaengine == NULL) { | ||||
ioat_log_message(0, "Couldn't acquire dmaengine\n"); | ioat_log_message(0, "Couldn't acquire dmaengine\n"); | ||||
test->status = IOAT_TEST_NO_DMA_ENGINE; | test->status = IOAT_TEST_NO_DMA_ENGINE; | ||||
return; | return; | ||||
} | } | ||||
ioat_log_message(0, "Thread %d: num_loops remaining: 0x%07x\n", index, | ioat_log_message(0, "Thread %d: num_loops remaining: 0x%07x\n", index, | ||||
loops); | test->num_loops); | ||||
while (loops-- > 0) { | for (loops = 0; loops < test->num_loops; loops++) { | ||||
bus_addr_t src, dest; | bus_addr_t src, dest; | ||||
if (loops % 0x10000 == 0) { | if (loops % 0x10000 == 0) { | ||||
ioat_log_message(0, "Thread %d: " | ioat_log_message(0, "Thread %d: " | ||||
"num_loops remaining: 0x%07x\n", index, loops); | "num_loops remaining: 0x%07x\n", index, | ||||
test->num_loops - loops); | |||||
} | } | ||||
tx = ioat_test_transaction_create(2, IOAT_TEST_SIZE); | tx = ioat_test_transaction_create(2, IOAT_TEST_SIZE); | ||||
if (tx == NULL) { | if (tx == NULL) { | ||||
ioat_log_message(0, "tx == NULL - memory exhausted\n"); | ioat_log_message(0, "tx == NULL - memory exhausted\n"); | ||||
atomic_add_32(&test->num_completions, 1); | atomic_add_32(&test->num_completions, 1); | ||||
test->status = IOAT_TEST_NO_MEMORY; | test->status = IOAT_TEST_NO_MEMORY; | ||||
continue; | continue; | ||||
} | } | ||||
tx->test = test; | tx->test = test; | ||||
Show All 10 Lines | for (loops = 0; loops < test->num_loops; loops++) { | ||||
dest = pmap_kextract((vm_offset_t)tx->buf[1]); | dest = pmap_kextract((vm_offset_t)tx->buf[1]); | ||||
ioat_acquire(dmaengine); | ioat_acquire(dmaengine); | ||||
ioat_copy(dmaengine, src, dest, IOAT_TEST_SIZE, | ioat_copy(dmaengine, src, dest, IOAT_TEST_SIZE, | ||||
ioat_dma_test_callback, tx, DMA_INT_EN); | ioat_dma_test_callback, tx, DMA_INT_EN); | ||||
ioat_release(dmaengine); | ioat_release(dmaengine); | ||||
} | } | ||||
while(test->num_completions < test->num_loops) | while (test->num_completions < test->num_loops) | ||||
tsleep(test, 0, "compl", 5*hz); | tsleep(test, 0, "compl", 5 * hz); | ||||
} | } | ||||
static int | static int | ||||
ioat_test_open(struct cdev *dev, int flags, int fmt, struct thread *td) | ioat_test_open(struct cdev *dev, int flags, int fmt, struct thread *td) | ||||
{ | { | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
ioat_test_close(struct cdev *dev, int flags, int fmt, struct thread *td) | ioat_test_close(struct cdev *dev, int flags, int fmt, struct thread *td) | ||||
{ | { | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
ioat_test_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, int flag, | ioat_test_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, int flag, | ||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
switch (cmd) { | switch (cmd) { | ||||
case IOAT_DMATEST: | case IOAT_DMATEST: | ||||
ioat_dma_test(arg); | ioat_dma_test(arg); | ||||
break; | break; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static struct cdevsw ioat_cdevsw = { | static struct cdevsw ioat_cdevsw = { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_flags = 0, | .d_flags = 0, | ||||
.d_open = ioat_test_open, | .d_open = ioat_test_open, | ||||
.d_close = ioat_test_close, | .d_close = ioat_test_close, | ||||
.d_ioctl = ioat_test_ioctl, | .d_ioctl = ioat_test_ioctl, | ||||
.d_name = "ioat_test", | .d_name = "ioat_test", | ||||
}; | }; | ||||
static void | static void | ||||
ioat_test_init(void *arg) | ioat_test_init(void *arg) | ||||
{ | { | ||||
ioat_cdev = make_dev(&ioat_cdevsw, 0, UID_ROOT, GID_OPERATOR, | |||||
if (g_enable_ioat_test) | |||||
g_ioat_cdev = make_dev(&ioat_cdevsw, 0, UID_ROOT, GID_WHEEL, | |||||
0600, "ioat_test"); | 0600, "ioat_test"); | ||||
} | } | ||||
static void | static void | ||||
ioat_test_uninit(void *arg) | ioat_test_uninit(void *arg) | ||||
{ | { | ||||
if (ioat_cdev != NULL) { | |||||
destroy_dev(ioat_cdev); | if (g_ioat_cdev != NULL) { | ||||
ioat_cdev = NULL; | destroy_dev(g_ioat_cdev); | ||||
g_ioat_cdev = NULL; | |||||
} | } | ||||
} | } | ||||
SYSINIT(ioat_test_load, SI_SUB_DRIVERS, SI_ORDER_FIRST, ioat_test_init, NULL); | SYSINIT(ioat_test_load, SI_SUB_DRIVERS, SI_ORDER_FIRST, ioat_test_init, NULL); | ||||
SYSUNINIT(ioat_test_unload, SI_SUB_DRIVERS, SI_ORDER_FIRST, ioat_test_uninit, NULL); | SYSUNINIT(ioat_test_unload, SI_SUB_DRIVERS, SI_ORDER_FIRST, ioat_test_uninit, NULL); | ||||
The same comment applies here as the force_legacy_interrupts SYSCTL above. I think this needs to be a tunable. (But then I would argue if someone does not want the /dev/ioat_test device enabled, they should just not load the test driver.)