1e974f91cSConrad Meyer /*- 2e974f91cSConrad Meyer * Copyright (C) 2012 Intel Corporation 3e974f91cSConrad Meyer * All rights reserved. 4e974f91cSConrad Meyer * 5e974f91cSConrad Meyer * Redistribution and use in source and binary forms, with or without 6e974f91cSConrad Meyer * modification, are permitted provided that the following conditions 7e974f91cSConrad Meyer * are met: 8e974f91cSConrad Meyer * 1. Redistributions of source code must retain the above copyright 9e974f91cSConrad Meyer * notice, this list of conditions and the following disclaimer. 10e974f91cSConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright 11e974f91cSConrad Meyer * notice, this list of conditions and the following disclaimer in the 12e974f91cSConrad Meyer * documentation and/or other materials provided with the distribution. 13e974f91cSConrad Meyer * 14e974f91cSConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15e974f91cSConrad Meyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e974f91cSConrad Meyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e974f91cSConrad Meyer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18e974f91cSConrad Meyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e974f91cSConrad Meyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e974f91cSConrad Meyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e974f91cSConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e974f91cSConrad Meyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e974f91cSConrad Meyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e974f91cSConrad Meyer * SUCH DAMAGE. 25e974f91cSConrad Meyer */ 26e974f91cSConrad Meyer 27e974f91cSConrad Meyer #include <sys/param.h> 28e974f91cSConrad Meyer #include <sys/systm.h> 29e974f91cSConrad Meyer #include <sys/bus.h> 30e974f91cSConrad Meyer #include <sys/conf.h> 31e974f91cSConrad Meyer #include <sys/ioccom.h> 32e974f91cSConrad Meyer #include <sys/kernel.h> 33e974f91cSConrad Meyer #include <sys/lock.h> 34e974f91cSConrad Meyer #include <sys/malloc.h> 35e974f91cSConrad Meyer #include <sys/module.h> 36e974f91cSConrad Meyer #include <sys/mutex.h> 37e974f91cSConrad Meyer #include <sys/rman.h> 38e974f91cSConrad Meyer #include <sys/sysctl.h> 39e974f91cSConrad Meyer #include <dev/pci/pcireg.h> 40e974f91cSConrad Meyer #include <dev/pci/pcivar.h> 41e974f91cSConrad Meyer #include <machine/bus.h> 42e974f91cSConrad Meyer #include <machine/resource.h> 431c25420eSConrad Meyer #include <machine/stdarg.h> 44e974f91cSConrad Meyer #include <vm/vm.h> 45e9497f9bSConrad Meyer #include <vm/vm_param.h> 46e974f91cSConrad Meyer #include <vm/pmap.h> 47e974f91cSConrad Meyer 48e974f91cSConrad Meyer #include "ioat.h" 49e974f91cSConrad Meyer #include "ioat_hw.h" 50e974f91cSConrad Meyer #include "ioat_internal.h" 51e974f91cSConrad Meyer #include "ioat_test.h" 52e974f91cSConrad Meyer 537c69db50SConrad Meyer #ifndef time_after 547c69db50SConrad Meyer #define time_after(a,b) ((long)(b) - (long)(a) < 0) 557c69db50SConrad Meyer #endif 567c69db50SConrad Meyer 57e974f91cSConrad Meyer MALLOC_DEFINE(M_IOAT_TEST, "ioat_test", "ioat test allocations"); 58e974f91cSConrad Meyer 597c69db50SConrad Meyer #define IOAT_MAX_BUFS 256 60e974f91cSConrad Meyer 61e974f91cSConrad Meyer struct test_transaction { 62e974f91cSConrad Meyer void *buf[IOAT_MAX_BUFS]; 63e974f91cSConrad Meyer uint32_t length; 647c69db50SConrad Meyer uint32_t depth; 65a8d9ee9cSTycho Nightingale uint32_t crc[IOAT_MAX_BUFS]; 66e974f91cSConrad Meyer struct ioat_test *test; 677c69db50SConrad Meyer TAILQ_ENTRY(test_transaction) entry; 68e974f91cSConrad Meyer }; 69e974f91cSConrad Meyer 707c69db50SConrad Meyer #define IT_LOCK() mtx_lock(&ioat_test_lk) 717c69db50SConrad Meyer #define IT_UNLOCK() mtx_unlock(&ioat_test_lk) 727c69db50SConrad Meyer #define IT_ASSERT() mtx_assert(&ioat_test_lk, MA_OWNED) 737c69db50SConrad Meyer static struct mtx ioat_test_lk; 747c69db50SConrad Meyer MTX_SYSINIT(ioat_test_lk, &ioat_test_lk, "test coordination mtx", MTX_DEF); 757c69db50SConrad Meyer 76e974f91cSConrad Meyer static int g_thread_index = 1; 77e974f91cSConrad Meyer static struct cdev *g_ioat_cdev = NULL; 78e974f91cSConrad Meyer 79592fe72dSConrad Meyer #define ioat_test_log(v, ...) _ioat_test_log((v), "ioat_test: " __VA_ARGS__) 801a140621SAndriy Gapon static void _ioat_test_log(int verbosity, const char *fmt, ...); 811c25420eSConrad Meyer 82e974f91cSConrad Meyer static void 83e974f91cSConrad Meyer ioat_test_transaction_destroy(struct test_transaction *tx) 84e974f91cSConrad Meyer { 85e974f91cSConrad Meyer int i; 86e974f91cSConrad Meyer 87e974f91cSConrad Meyer for (i = 0; i < IOAT_MAX_BUFS; i++) { 88e974f91cSConrad Meyer if (tx->buf[i] != NULL) { 896a301ac8SConrad Meyer free(tx->buf[i], M_IOAT_TEST); 90e974f91cSConrad Meyer tx->buf[i] = NULL; 91e974f91cSConrad Meyer } 92e974f91cSConrad Meyer } 93e974f91cSConrad Meyer 94e974f91cSConrad Meyer free(tx, M_IOAT_TEST); 95e974f91cSConrad Meyer } 96e974f91cSConrad Meyer 97e974f91cSConrad Meyer static struct 986a301ac8SConrad Meyer test_transaction *ioat_test_transaction_create(struct ioat_test *test, 996a301ac8SConrad Meyer unsigned num_buffers) 100e974f91cSConrad Meyer { 101e974f91cSConrad Meyer struct test_transaction *tx; 1027c69db50SConrad Meyer unsigned i; 103e974f91cSConrad Meyer 1047c69db50SConrad Meyer tx = malloc(sizeof(*tx), M_IOAT_TEST, M_NOWAIT | M_ZERO); 105e974f91cSConrad Meyer if (tx == NULL) 106e974f91cSConrad Meyer return (NULL); 107e974f91cSConrad Meyer 1086a301ac8SConrad Meyer tx->length = test->buffer_size; 109e974f91cSConrad Meyer 110e974f91cSConrad Meyer for (i = 0; i < num_buffers; i++) { 1116a301ac8SConrad Meyer if (test->testkind == IOAT_TEST_DMA_8K) 1126a301ac8SConrad Meyer tx->buf[i] = malloc(test->buffer_size, M_IOAT_TEST, 1136a301ac8SConrad Meyer M_NOWAIT); 1146a301ac8SConrad Meyer else 1156a301ac8SConrad Meyer tx->buf[i] = contigmalloc(test->buffer_size, 1166a301ac8SConrad Meyer M_IOAT_TEST, M_NOWAIT, 0, BUS_SPACE_MAXADDR, 1176a301ac8SConrad Meyer PAGE_SIZE, 0); 118e974f91cSConrad Meyer 119e974f91cSConrad Meyer if (tx->buf[i] == NULL) { 120e974f91cSConrad Meyer ioat_test_transaction_destroy(tx); 121e974f91cSConrad Meyer return (NULL); 122e974f91cSConrad Meyer } 123e974f91cSConrad Meyer } 124e974f91cSConrad Meyer return (tx); 125e974f91cSConrad Meyer } 126e974f91cSConrad Meyer 127e9497f9bSConrad Meyer static void 128e9497f9bSConrad Meyer dump_hex(void *p, size_t chunks) 129e9497f9bSConrad Meyer { 130e9497f9bSConrad Meyer size_t i, j; 131e9497f9bSConrad Meyer 132e9497f9bSConrad Meyer for (i = 0; i < chunks; i++) { 133e9497f9bSConrad Meyer for (j = 0; j < 8; j++) 134e9497f9bSConrad Meyer printf("%08x ", ((uint32_t *)p)[i * 8 + j]); 135e9497f9bSConrad Meyer printf("\n"); 136e9497f9bSConrad Meyer } 137e9497f9bSConrad Meyer } 138e9497f9bSConrad Meyer 1397c69db50SConrad Meyer static bool 1407c69db50SConrad Meyer ioat_compare_ok(struct test_transaction *tx) 1417c69db50SConrad Meyer { 1422a4fd6b1SConrad Meyer struct ioat_test *test; 1432a4fd6b1SConrad Meyer char *dst, *src; 1442a4fd6b1SConrad Meyer uint32_t i, j; 1452a4fd6b1SConrad Meyer 1462a4fd6b1SConrad Meyer test = tx->test; 1477c69db50SConrad Meyer 1487c69db50SConrad Meyer for (i = 0; i < tx->depth; i++) { 1492a4fd6b1SConrad Meyer dst = tx->buf[2 * i + 1]; 1502a4fd6b1SConrad Meyer src = tx->buf[2 * i]; 1512a4fd6b1SConrad Meyer 1522a4fd6b1SConrad Meyer if (test->testkind == IOAT_TEST_FILL) { 1532a4fd6b1SConrad Meyer for (j = 0; j < tx->length; j += sizeof(uint64_t)) { 1542a4fd6b1SConrad Meyer if (memcmp(src, &dst[j], 1552a4fd6b1SConrad Meyer MIN(sizeof(uint64_t), tx->length - j)) 1562a4fd6b1SConrad Meyer != 0) 1572a4fd6b1SConrad Meyer return (false); 1582a4fd6b1SConrad Meyer } 159e9497f9bSConrad Meyer } else if (test->testkind == IOAT_TEST_DMA) { 1602a4fd6b1SConrad Meyer if (memcmp(src, dst, tx->length) != 0) 1617c69db50SConrad Meyer return (false); 162e9497f9bSConrad Meyer } else if (test->testkind == IOAT_TEST_RAW_DMA) { 163e9497f9bSConrad Meyer if (test->raw_write) 164e9497f9bSConrad Meyer dst = test->raw_vtarget; 165e9497f9bSConrad Meyer dump_hex(dst, tx->length / 32); 166e9497f9bSConrad Meyer } 1677c69db50SConrad Meyer } 1687c69db50SConrad Meyer return (true); 1697c69db50SConrad Meyer } 1707c69db50SConrad Meyer 171e974f91cSConrad Meyer static void 172faefad9cSConrad Meyer ioat_dma_test_callback(void *arg, int error) 173e974f91cSConrad Meyer { 174e974f91cSConrad Meyer struct test_transaction *tx; 175e974f91cSConrad Meyer struct ioat_test *test; 176e974f91cSConrad Meyer 177faefad9cSConrad Meyer if (error != 0) 178faefad9cSConrad Meyer ioat_test_log(0, "%s: Got error: %d\n", __func__, error); 179faefad9cSConrad Meyer 180e974f91cSConrad Meyer tx = arg; 181e974f91cSConrad Meyer test = tx->test; 182e974f91cSConrad Meyer 1837c69db50SConrad Meyer if (test->verify && !ioat_compare_ok(tx)) { 1841c25420eSConrad Meyer ioat_test_log(0, "miscompare found\n"); 1857c69db50SConrad Meyer atomic_add_32(&test->status[IOAT_TEST_MISCOMPARE], tx->depth); 1867c69db50SConrad Meyer } else if (!test->too_late) 1877c69db50SConrad Meyer atomic_add_32(&test->status[IOAT_TEST_OK], tx->depth); 1887c69db50SConrad Meyer 1897c69db50SConrad Meyer IT_LOCK(); 1907c69db50SConrad Meyer TAILQ_REMOVE(&test->pend_q, tx, entry); 1917c69db50SConrad Meyer TAILQ_INSERT_TAIL(&test->free_q, tx, entry); 1927c69db50SConrad Meyer wakeup(&test->free_q); 1937c69db50SConrad Meyer IT_UNLOCK(); 194e974f91cSConrad Meyer } 1957c69db50SConrad Meyer 1967c69db50SConrad Meyer static int 1977c69db50SConrad Meyer ioat_test_prealloc_memory(struct ioat_test *test, int index) 1987c69db50SConrad Meyer { 1997c69db50SConrad Meyer uint32_t i, j, k; 2007c69db50SConrad Meyer struct test_transaction *tx; 2017c69db50SConrad Meyer 2027c69db50SConrad Meyer for (i = 0; i < test->transactions; i++) { 2036a301ac8SConrad Meyer tx = ioat_test_transaction_create(test, test->chain_depth * 2); 2047c69db50SConrad Meyer if (tx == NULL) { 2051c25420eSConrad Meyer ioat_test_log(0, "tx == NULL - memory exhausted\n"); 2067c69db50SConrad Meyer test->status[IOAT_TEST_NO_MEMORY]++; 2077c69db50SConrad Meyer return (ENOMEM); 2087c69db50SConrad Meyer } 2097c69db50SConrad Meyer 2107c69db50SConrad Meyer TAILQ_INSERT_HEAD(&test->free_q, tx, entry); 2117c69db50SConrad Meyer 2127c69db50SConrad Meyer tx->test = test; 2137c69db50SConrad Meyer tx->depth = test->chain_depth; 2147c69db50SConrad Meyer 2157c69db50SConrad Meyer /* fill in source buffers */ 2167c69db50SConrad Meyer for (j = 0; j < (tx->length / sizeof(uint32_t)); j++) { 2177c69db50SConrad Meyer uint32_t val = j + (index << 28); 2187c69db50SConrad Meyer 2197c69db50SConrad Meyer for (k = 0; k < test->chain_depth; k++) { 2207c69db50SConrad Meyer ((uint32_t *)tx->buf[2*k])[j] = ~val; 2217c69db50SConrad Meyer ((uint32_t *)tx->buf[2*k+1])[j] = val; 2227c69db50SConrad Meyer } 2237c69db50SConrad Meyer } 2247c69db50SConrad Meyer } 2257c69db50SConrad Meyer return (0); 2267c69db50SConrad Meyer } 2277c69db50SConrad Meyer 2287c69db50SConrad Meyer static void 2297c69db50SConrad Meyer ioat_test_release_memory(struct ioat_test *test) 2307c69db50SConrad Meyer { 2317c69db50SConrad Meyer struct test_transaction *tx, *s; 2327c69db50SConrad Meyer 2337c69db50SConrad Meyer TAILQ_FOREACH_SAFE(tx, &test->free_q, entry, s) 234e974f91cSConrad Meyer ioat_test_transaction_destroy(tx); 2357c69db50SConrad Meyer TAILQ_INIT(&test->free_q); 2367c69db50SConrad Meyer 2377c69db50SConrad Meyer TAILQ_FOREACH_SAFE(tx, &test->pend_q, entry, s) 2387c69db50SConrad Meyer ioat_test_transaction_destroy(tx); 2397c69db50SConrad Meyer TAILQ_INIT(&test->pend_q); 2407c69db50SConrad Meyer } 2417c69db50SConrad Meyer 2427c69db50SConrad Meyer static void 2437c69db50SConrad Meyer ioat_test_submit_1_tx(struct ioat_test *test, bus_dmaengine_t dma) 2447c69db50SConrad Meyer { 2457c69db50SConrad Meyer struct test_transaction *tx; 2467c69db50SConrad Meyer struct bus_dmadesc *desc; 2477c69db50SConrad Meyer bus_dmaengine_callback_t cb; 2487c69db50SConrad Meyer bus_addr_t src, dest; 2492a4fd6b1SConrad Meyer uint64_t fillpattern; 2507c69db50SConrad Meyer uint32_t i, flags; 2517c69db50SConrad Meyer 2522a4fd6b1SConrad Meyer desc = NULL; 2532a4fd6b1SConrad Meyer 2547c69db50SConrad Meyer IT_LOCK(); 2557c69db50SConrad Meyer while (TAILQ_EMPTY(&test->free_q)) 2567c69db50SConrad Meyer msleep(&test->free_q, &ioat_test_lk, 0, "test_submit", 0); 2577c69db50SConrad Meyer 2587c69db50SConrad Meyer tx = TAILQ_FIRST(&test->free_q); 2597c69db50SConrad Meyer TAILQ_REMOVE(&test->free_q, tx, entry); 2607c69db50SConrad Meyer TAILQ_INSERT_HEAD(&test->pend_q, tx, entry); 2617c69db50SConrad Meyer IT_UNLOCK(); 2627c69db50SConrad Meyer 2636a301ac8SConrad Meyer if (test->testkind != IOAT_TEST_MEMCPY) 2647c69db50SConrad Meyer ioat_acquire(dma); 2657c69db50SConrad Meyer for (i = 0; i < tx->depth; i++) { 2666a301ac8SConrad Meyer if (test->testkind == IOAT_TEST_MEMCPY) { 2676a301ac8SConrad Meyer memcpy(tx->buf[2 * i + 1], tx->buf[2 * i], tx->length); 2686a301ac8SConrad Meyer if (i == tx->depth - 1) 2696a301ac8SConrad Meyer ioat_dma_test_callback(tx, 0); 2706a301ac8SConrad Meyer continue; 2716a301ac8SConrad Meyer } 2726a301ac8SConrad Meyer 2737c69db50SConrad Meyer src = vtophys((vm_offset_t)tx->buf[2*i]); 2747c69db50SConrad Meyer dest = vtophys((vm_offset_t)tx->buf[2*i+1]); 2757c69db50SConrad Meyer 276e9497f9bSConrad Meyer if (test->testkind == IOAT_TEST_RAW_DMA) { 277e9497f9bSConrad Meyer if (test->raw_write) 278e9497f9bSConrad Meyer dest = test->raw_target; 279e9497f9bSConrad Meyer else 280e9497f9bSConrad Meyer src = test->raw_target; 281e9497f9bSConrad Meyer } 282e9497f9bSConrad Meyer 2837c69db50SConrad Meyer if (i == tx->depth - 1) { 2847c69db50SConrad Meyer cb = ioat_dma_test_callback; 2857c69db50SConrad Meyer flags = DMA_INT_EN; 2867c69db50SConrad Meyer } else { 2877c69db50SConrad Meyer cb = NULL; 2887c69db50SConrad Meyer flags = 0; 2897c69db50SConrad Meyer } 2907c69db50SConrad Meyer 291e9497f9bSConrad Meyer if (test->testkind == IOAT_TEST_DMA || 292e9497f9bSConrad Meyer test->testkind == IOAT_TEST_RAW_DMA) 2932a4fd6b1SConrad Meyer desc = ioat_copy(dma, dest, src, tx->length, cb, tx, 2942a4fd6b1SConrad Meyer flags); 2952a4fd6b1SConrad Meyer else if (test->testkind == IOAT_TEST_FILL) { 2962a4fd6b1SConrad Meyer fillpattern = *(uint64_t *)tx->buf[2*i]; 2972a4fd6b1SConrad Meyer desc = ioat_blockfill(dma, dest, fillpattern, 2982a4fd6b1SConrad Meyer tx->length, cb, tx, flags); 2996a301ac8SConrad Meyer } else if (test->testkind == IOAT_TEST_DMA_8K) { 3006a301ac8SConrad Meyer bus_addr_t src2, dst2; 3016a301ac8SConrad Meyer 3026a301ac8SConrad Meyer src2 = vtophys((vm_offset_t)tx->buf[2*i] + PAGE_SIZE); 3036a301ac8SConrad Meyer dst2 = vtophys((vm_offset_t)tx->buf[2*i+1] + PAGE_SIZE); 3046a301ac8SConrad Meyer 3056a301ac8SConrad Meyer desc = ioat_copy_8k_aligned(dma, dest, dst2, src, src2, 3066a301ac8SConrad Meyer cb, tx, flags); 307a8d9ee9cSTycho Nightingale } else if (test->testkind == IOAT_TEST_DMA_8K_PB) { 308a8d9ee9cSTycho Nightingale bus_addr_t src2, dst2; 309a8d9ee9cSTycho Nightingale 310a8d9ee9cSTycho Nightingale src2 = vtophys((vm_offset_t)tx->buf[2*i+1] + PAGE_SIZE); 311a8d9ee9cSTycho Nightingale dst2 = vtophys((vm_offset_t)tx->buf[2*i] + PAGE_SIZE); 312a8d9ee9cSTycho Nightingale 313a8d9ee9cSTycho Nightingale desc = ioat_copy_8k_aligned(dma, dest, dst2, src, src2, 314a8d9ee9cSTycho Nightingale cb, tx, flags); 315a8d9ee9cSTycho Nightingale } else if (test->testkind == IOAT_TEST_DMA_CRC) { 316a8d9ee9cSTycho Nightingale bus_addr_t crc; 317a8d9ee9cSTycho Nightingale 318a8d9ee9cSTycho Nightingale tx->crc[i] = 0; 319a8d9ee9cSTycho Nightingale crc = vtophys((vm_offset_t)&tx->crc[i]); 320a8d9ee9cSTycho Nightingale desc = ioat_crc(dma, src, tx->length, 321a8d9ee9cSTycho Nightingale NULL, crc, cb, tx, flags | DMA_CRC_STORE); 322a8d9ee9cSTycho Nightingale } else if (test->testkind == IOAT_TEST_DMA_CRC_COPY) { 323a8d9ee9cSTycho Nightingale bus_addr_t crc; 324a8d9ee9cSTycho Nightingale 325a8d9ee9cSTycho Nightingale tx->crc[i] = 0; 326a8d9ee9cSTycho Nightingale crc = vtophys((vm_offset_t)&tx->crc[i]); 327a8d9ee9cSTycho Nightingale desc = ioat_copy_crc(dma, dest, src, tx->length, 328a8d9ee9cSTycho Nightingale NULL, crc, cb, tx, flags | DMA_CRC_STORE); 3292a4fd6b1SConrad Meyer } 3307c69db50SConrad Meyer if (desc == NULL) 3311ffae6e8SConrad Meyer break; 3327c69db50SConrad Meyer } 3336a301ac8SConrad Meyer if (test->testkind == IOAT_TEST_MEMCPY) 3346a301ac8SConrad Meyer return; 3357c69db50SConrad Meyer ioat_release(dma); 3361ffae6e8SConrad Meyer 3371ffae6e8SConrad Meyer /* 3381ffae6e8SConrad Meyer * We couldn't issue an IO -- either the device is being detached or 3391ffae6e8SConrad Meyer * the HW reset. Essentially spin until the device comes back up or 3401ffae6e8SConrad Meyer * our timer expires. 3411ffae6e8SConrad Meyer */ 3421ffae6e8SConrad Meyer if (desc == NULL && tx->depth > 0) { 3431ffae6e8SConrad Meyer atomic_add_32(&test->status[IOAT_TEST_NO_DMA_ENGINE], tx->depth); 3441ffae6e8SConrad Meyer IT_LOCK(); 3451ffae6e8SConrad Meyer TAILQ_REMOVE(&test->pend_q, tx, entry); 3461ffae6e8SConrad Meyer TAILQ_INSERT_HEAD(&test->free_q, tx, entry); 3471ffae6e8SConrad Meyer IT_UNLOCK(); 3481ffae6e8SConrad Meyer } 349e974f91cSConrad Meyer } 350e974f91cSConrad Meyer 351e974f91cSConrad Meyer static void 352e974f91cSConrad Meyer ioat_dma_test(void *arg) 353e974f91cSConrad Meyer { 354d37872daSConrad Meyer struct ioat_softc *ioat; 355e974f91cSConrad Meyer struct ioat_test *test; 356e974f91cSConrad Meyer bus_dmaengine_t dmaengine; 357e974f91cSConrad Meyer uint32_t loops; 358d37872daSConrad Meyer int index, rc, start, end, error; 359e974f91cSConrad Meyer 360e974f91cSConrad Meyer test = arg; 3617c69db50SConrad Meyer memset(__DEVOLATILE(void *, test->status), 0, sizeof(test->status)); 362e974f91cSConrad Meyer 363a8d9ee9cSTycho Nightingale if ((test->testkind == IOAT_TEST_DMA_8K || 364a8d9ee9cSTycho Nightingale test->testkind == IOAT_TEST_DMA_8K_PB) && 3656a301ac8SConrad Meyer test->buffer_size != 2 * PAGE_SIZE) { 3666a301ac8SConrad Meyer ioat_test_log(0, "Asked for 8k test and buffer size isn't 8k\n"); 3676a301ac8SConrad Meyer test->status[IOAT_TEST_INVALID_INPUT]++; 3686a301ac8SConrad Meyer return; 3696a301ac8SConrad Meyer } 3706a301ac8SConrad Meyer 3717c69db50SConrad Meyer if (test->buffer_size > 1024 * 1024) { 3721c25420eSConrad Meyer ioat_test_log(0, "Buffer size too large >1MB\n"); 3737c69db50SConrad Meyer test->status[IOAT_TEST_NO_MEMORY]++; 374e974f91cSConrad Meyer return; 375e974f91cSConrad Meyer } 376e974f91cSConrad Meyer 3777c69db50SConrad Meyer if (test->chain_depth * 2 > IOAT_MAX_BUFS) { 3781c25420eSConrad Meyer ioat_test_log(0, "Depth too large (> %u)\n", 3797c69db50SConrad Meyer (unsigned)IOAT_MAX_BUFS / 2); 3807c69db50SConrad Meyer test->status[IOAT_TEST_NO_MEMORY]++; 3817c69db50SConrad Meyer return; 382e974f91cSConrad Meyer } 383e974f91cSConrad Meyer 3847c69db50SConrad Meyer if (btoc((uint64_t)test->buffer_size * test->chain_depth * 3857c69db50SConrad Meyer test->transactions) > (physmem / 4)) { 3861c25420eSConrad Meyer ioat_test_log(0, "Sanity check failed -- test would " 3877c69db50SConrad Meyer "use more than 1/4 of phys mem.\n"); 3887c69db50SConrad Meyer test->status[IOAT_TEST_NO_MEMORY]++; 3897c69db50SConrad Meyer return; 390e974f91cSConrad Meyer } 391e974f91cSConrad Meyer 3927c69db50SConrad Meyer if ((uint64_t)test->transactions * test->chain_depth > (1<<16)) { 3931c25420eSConrad Meyer ioat_test_log(0, "Sanity check failed -- test would " 3947c69db50SConrad Meyer "use more than available IOAT ring space.\n"); 3957c69db50SConrad Meyer test->status[IOAT_TEST_NO_MEMORY]++; 3967c69db50SConrad Meyer return; 3977c69db50SConrad Meyer } 3987c69db50SConrad Meyer 3992a4fd6b1SConrad Meyer if (test->testkind >= IOAT_NUM_TESTKINDS) { 4002a4fd6b1SConrad Meyer ioat_test_log(0, "Invalid kind %u\n", 4012a4fd6b1SConrad Meyer (unsigned)test->testkind); 4022a4fd6b1SConrad Meyer test->status[IOAT_TEST_INVALID_INPUT]++; 4032a4fd6b1SConrad Meyer return; 4042a4fd6b1SConrad Meyer } 4052a4fd6b1SConrad Meyer 4060ff814e8SConrad Meyer dmaengine = ioat_get_dmaengine(test->channel_index, M_NOWAIT); 4077c69db50SConrad Meyer if (dmaengine == NULL) { 4081c25420eSConrad Meyer ioat_test_log(0, "Couldn't acquire dmaengine\n"); 4097c69db50SConrad Meyer test->status[IOAT_TEST_NO_DMA_ENGINE]++; 4107c69db50SConrad Meyer return; 4117c69db50SConrad Meyer } 412d37872daSConrad Meyer ioat = to_ioat_softc(dmaengine); 4137c69db50SConrad Meyer 4141693d27bSConrad Meyer if (test->testkind == IOAT_TEST_FILL && 415d37872daSConrad Meyer (ioat->capabilities & IOAT_DMACAP_BFILL) == 0) 4161693d27bSConrad Meyer { 4171693d27bSConrad Meyer ioat_test_log(0, 4181693d27bSConrad Meyer "Hardware doesn't support block fill, aborting test\n"); 4191693d27bSConrad Meyer test->status[IOAT_TEST_INVALID_INPUT]++; 4201693d27bSConrad Meyer goto out; 4211693d27bSConrad Meyer } 4221693d27bSConrad Meyer 423d37872daSConrad Meyer if (test->coalesce_period > ioat->intrdelay_max) { 424d37872daSConrad Meyer ioat_test_log(0, 425d37872daSConrad Meyer "Hardware doesn't support intrdelay of %u us.\n", 426d37872daSConrad Meyer (unsigned)test->coalesce_period); 427d37872daSConrad Meyer test->status[IOAT_TEST_INVALID_INPUT]++; 428d37872daSConrad Meyer goto out; 429d37872daSConrad Meyer } 430d37872daSConrad Meyer error = ioat_set_interrupt_coalesce(dmaengine, test->coalesce_period); 431d37872daSConrad Meyer if (error == ENODEV && test->coalesce_period == 0) 432d37872daSConrad Meyer error = 0; 433d37872daSConrad Meyer if (error != 0) { 434d37872daSConrad Meyer ioat_test_log(0, "ioat_set_interrupt_coalesce: %d\n", error); 435d37872daSConrad Meyer test->status[IOAT_TEST_INVALID_INPUT]++; 436d37872daSConrad Meyer goto out; 437d37872daSConrad Meyer } 438d37872daSConrad Meyer 439d37872daSConrad Meyer if (test->zero_stats) 440d37872daSConrad Meyer memset(&ioat->stats, 0, sizeof(ioat->stats)); 441d37872daSConrad Meyer 442e9497f9bSConrad Meyer if (test->testkind == IOAT_TEST_RAW_DMA) { 443e9497f9bSConrad Meyer if (test->raw_is_virtual) { 444e9497f9bSConrad Meyer test->raw_vtarget = (void *)test->raw_target; 445e9497f9bSConrad Meyer test->raw_target = vtophys(test->raw_vtarget); 446e9497f9bSConrad Meyer } else { 447e9497f9bSConrad Meyer test->raw_vtarget = pmap_mapdev(test->raw_target, 448e9497f9bSConrad Meyer test->buffer_size); 449e9497f9bSConrad Meyer } 450e9497f9bSConrad Meyer } 451e9497f9bSConrad Meyer 4527c69db50SConrad Meyer index = g_thread_index++; 4537c69db50SConrad Meyer TAILQ_INIT(&test->free_q); 4547c69db50SConrad Meyer TAILQ_INIT(&test->pend_q); 4557c69db50SConrad Meyer 4567c69db50SConrad Meyer if (test->duration == 0) 4571c25420eSConrad Meyer ioat_test_log(1, "Thread %d: num_loops remaining: 0x%08x\n", 4587c69db50SConrad Meyer index, test->transactions); 4597c69db50SConrad Meyer else 4601c25420eSConrad Meyer ioat_test_log(1, "Thread %d: starting\n", index); 4617c69db50SConrad Meyer 4627c69db50SConrad Meyer rc = ioat_test_prealloc_memory(test, index); 4637c69db50SConrad Meyer if (rc != 0) { 4641c25420eSConrad Meyer ioat_test_log(0, "prealloc_memory: %d\n", rc); 465466b3540SConrad Meyer goto out; 4667c69db50SConrad Meyer } 467e974f91cSConrad Meyer wmb(); 468e974f91cSConrad Meyer 4697c69db50SConrad Meyer test->too_late = false; 4707c69db50SConrad Meyer start = ticks; 4717c69db50SConrad Meyer end = start + (((sbintime_t)test->duration * hz) / 1000); 4727c69db50SConrad Meyer 4737c69db50SConrad Meyer for (loops = 0;; loops++) { 4747c69db50SConrad Meyer if (test->duration == 0 && loops >= test->transactions) 4757c69db50SConrad Meyer break; 4767c69db50SConrad Meyer else if (test->duration != 0 && time_after(ticks, end)) { 4777c69db50SConrad Meyer test->too_late = true; 4787c69db50SConrad Meyer break; 479e974f91cSConrad Meyer } 480e974f91cSConrad Meyer 4817c69db50SConrad Meyer ioat_test_submit_1_tx(test, dmaengine); 482e974f91cSConrad Meyer } 483e974f91cSConrad Meyer 4841c25420eSConrad Meyer ioat_test_log(1, "Test Elapsed: %d ticks (overrun %d), %d sec.\n", 4857c69db50SConrad Meyer ticks - start, ticks - end, (ticks - start) / hz); 486e974f91cSConrad Meyer 4877c69db50SConrad Meyer IT_LOCK(); 4887c69db50SConrad Meyer while (!TAILQ_EMPTY(&test->pend_q)) 4897c69db50SConrad Meyer msleep(&test->free_q, &ioat_test_lk, 0, "ioattestcompl", hz); 4907c69db50SConrad Meyer IT_UNLOCK(); 4917c69db50SConrad Meyer 4921c25420eSConrad Meyer ioat_test_log(1, "Test Elapsed2: %d ticks (overrun %d), %d sec.\n", 4937c69db50SConrad Meyer ticks - start, ticks - end, (ticks - start) / hz); 4947c69db50SConrad Meyer 4957c69db50SConrad Meyer ioat_test_release_memory(test); 496466b3540SConrad Meyer out: 497e9497f9bSConrad Meyer if (test->testkind == IOAT_TEST_RAW_DMA && !test->raw_is_virtual) 498*7ae99f80SJohn Baldwin pmap_unmapdev(test->raw_vtarget, test->buffer_size); 499466b3540SConrad Meyer ioat_put_dmaengine(dmaengine); 500e974f91cSConrad Meyer } 501e974f91cSConrad Meyer 502e974f91cSConrad Meyer static int 503e974f91cSConrad Meyer ioat_test_open(struct cdev *dev, int flags, int fmt, struct thread *td) 504e974f91cSConrad Meyer { 505e974f91cSConrad Meyer 506e974f91cSConrad Meyer return (0); 507e974f91cSConrad Meyer } 508e974f91cSConrad Meyer 509e974f91cSConrad Meyer static int 510e974f91cSConrad Meyer ioat_test_close(struct cdev *dev, int flags, int fmt, struct thread *td) 511e974f91cSConrad Meyer { 512e974f91cSConrad Meyer 513e974f91cSConrad Meyer return (0); 514e974f91cSConrad Meyer } 515e974f91cSConrad Meyer 516e974f91cSConrad Meyer static int 517e974f91cSConrad Meyer ioat_test_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, int flag, 518e974f91cSConrad Meyer struct thread *td) 519e974f91cSConrad Meyer { 520e974f91cSConrad Meyer 521e974f91cSConrad Meyer switch (cmd) { 522e974f91cSConrad Meyer case IOAT_DMATEST: 523e974f91cSConrad Meyer ioat_dma_test(arg); 524e974f91cSConrad Meyer break; 525e974f91cSConrad Meyer default: 526e974f91cSConrad Meyer return (EINVAL); 527e974f91cSConrad Meyer } 528e974f91cSConrad Meyer return (0); 529e974f91cSConrad Meyer } 530e974f91cSConrad Meyer 531e974f91cSConrad Meyer static struct cdevsw ioat_cdevsw = { 532e974f91cSConrad Meyer .d_version = D_VERSION, 533e974f91cSConrad Meyer .d_flags = 0, 534e974f91cSConrad Meyer .d_open = ioat_test_open, 535e974f91cSConrad Meyer .d_close = ioat_test_close, 536e974f91cSConrad Meyer .d_ioctl = ioat_test_ioctl, 537e974f91cSConrad Meyer .d_name = "ioat_test", 538e974f91cSConrad Meyer }; 539e974f91cSConrad Meyer 540e974f91cSConrad Meyer static int 5417afbb263SConrad Meyer enable_ioat_test(bool enable) 5427afbb263SConrad Meyer { 54371bf3900SAlexander Motin struct make_dev_args devargs; 54471bf3900SAlexander Motin int error = 0; 5457afbb263SConrad Meyer 5467afbb263SConrad Meyer if (enable && g_ioat_cdev == NULL) { 54771bf3900SAlexander Motin make_dev_args_init(&devargs); 54871bf3900SAlexander Motin devargs.mda_devsw = &ioat_cdevsw; 54971bf3900SAlexander Motin devargs.mda_uid = UID_ROOT; 55071bf3900SAlexander Motin devargs.mda_gid = GID_WHEEL; 55171bf3900SAlexander Motin devargs.mda_mode = 0600; 55271bf3900SAlexander Motin error = make_dev_s(&devargs, &g_ioat_cdev, "ioat_test"); 5537afbb263SConrad Meyer } else if (!enable && g_ioat_cdev != NULL) { 5547afbb263SConrad Meyer destroy_dev(g_ioat_cdev); 5557afbb263SConrad Meyer g_ioat_cdev = NULL; 5567afbb263SConrad Meyer } 55771bf3900SAlexander Motin return (error); 5587afbb263SConrad Meyer } 5597afbb263SConrad Meyer 5607afbb263SConrad Meyer static int 561e974f91cSConrad Meyer sysctl_enable_ioat_test(SYSCTL_HANDLER_ARGS) 562e974f91cSConrad Meyer { 563e974f91cSConrad Meyer int error, enabled; 564e974f91cSConrad Meyer 565e974f91cSConrad Meyer enabled = (g_ioat_cdev != NULL); 566e974f91cSConrad Meyer error = sysctl_handle_int(oidp, &enabled, 0, req); 567e974f91cSConrad Meyer if (error != 0 || req->newptr == NULL) 568e974f91cSConrad Meyer return (error); 569e974f91cSConrad Meyer 57071bf3900SAlexander Motin return (enable_ioat_test(enabled)); 571e974f91cSConrad Meyer } 5727029da5cSPawel Biernacki SYSCTL_PROC(_hw_ioat, OID_AUTO, enable_ioat_test, 57371bf3900SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0, 5747029da5cSPawel Biernacki sysctl_enable_ioat_test, "I", 575e974f91cSConrad Meyer "Non-zero: Enable the /dev/ioat_test device"); 5767afbb263SConrad Meyer 5777afbb263SConrad Meyer void 5787afbb263SConrad Meyer ioat_test_attach(void) 5797afbb263SConrad Meyer { 5807afbb263SConrad Meyer char *val; 5817afbb263SConrad Meyer 5827afbb263SConrad Meyer val = kern_getenv("hw.ioat.enable_ioat_test"); 58371bf3900SAlexander Motin if (val != NULL && strcmp(val, "0") != 0) 5847afbb263SConrad Meyer enable_ioat_test(true); 5857afbb263SConrad Meyer freeenv(val); 5867afbb263SConrad Meyer } 5877afbb263SConrad Meyer 5887afbb263SConrad Meyer void 5897afbb263SConrad Meyer ioat_test_detach(void) 5907afbb263SConrad Meyer { 5917afbb263SConrad Meyer 5927afbb263SConrad Meyer enable_ioat_test(false); 5937afbb263SConrad Meyer } 5941c25420eSConrad Meyer 5951a140621SAndriy Gapon static void 5961c25420eSConrad Meyer _ioat_test_log(int verbosity, const char *fmt, ...) 5971c25420eSConrad Meyer { 5981c25420eSConrad Meyer va_list argp; 5991c25420eSConrad Meyer 6001c25420eSConrad Meyer if (verbosity > g_ioat_debug_level) 6011c25420eSConrad Meyer return; 6021c25420eSConrad Meyer 6031c25420eSConrad Meyer va_start(argp, fmt); 6041c25420eSConrad Meyer vprintf(fmt, argp); 6051c25420eSConrad Meyer va_end(argp); 6061c25420eSConrad Meyer } 607