ioat_test.c revision 287117
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__FBSDID("$FreeBSD: head/sys/dev/ioat/ioat_test.c 287117 2015-08-24 19:32:03Z cem $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/ioccom.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/mutex.h>
40#include <sys/rman.h>
41#include <sys/sysctl.h>
42#include <dev/pci/pcireg.h>
43#include <dev/pci/pcivar.h>
44#include <machine/bus.h>
45#include <machine/resource.h>
46#include <vm/vm.h>
47#include <vm/pmap.h>
48
49#include "ioat.h"
50#include "ioat_hw.h"
51#include "ioat_internal.h"
52#include "ioat_test.h"
53
54MALLOC_DEFINE(M_IOAT_TEST, "ioat_test", "ioat test allocations");
55
56#define	IOAT_TEST_SIZE	0x40000
57#define	IOAT_MAX_BUFS	8
58
59struct test_transaction {
60	uint8_t			num_buffers;
61	void			*buf[IOAT_MAX_BUFS];
62	uint32_t		length;
63	struct ioat_test	*test;
64};
65
66static int g_thread_index = 1;
67static struct cdev *g_ioat_cdev = NULL;
68
69static void
70ioat_test_transaction_destroy(struct test_transaction *tx)
71{
72	int i;
73
74	for (i = 0; i < IOAT_MAX_BUFS; i++) {
75		if (tx->buf[i] != NULL) {
76			contigfree(tx->buf[i], IOAT_TEST_SIZE, M_IOAT_TEST);
77			tx->buf[i] = NULL;
78		}
79	}
80
81	free(tx, M_IOAT_TEST);
82}
83
84static struct
85test_transaction *ioat_test_transaction_create(uint8_t num_buffers,
86    uint32_t buffer_size)
87{
88	struct test_transaction *tx;
89	int i;
90
91	tx = malloc(sizeof(struct test_transaction), M_IOAT_TEST, M_NOWAIT | M_ZERO);
92	if (tx == NULL)
93		return (NULL);
94
95	tx->num_buffers = num_buffers;
96	tx->length = buffer_size;
97
98	for (i = 0; i < num_buffers; i++) {
99		tx->buf[i] = contigmalloc(buffer_size, M_IOAT_TEST, M_NOWAIT,
100		    0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
101
102		if (tx->buf[i] == NULL) {
103			ioat_test_transaction_destroy(tx);
104			return (NULL);
105		}
106	}
107	return (tx);
108}
109
110static void
111ioat_dma_test_callback(void *arg)
112{
113	struct test_transaction *tx;
114	struct ioat_test *test;
115
116	tx = arg;
117	test = tx->test;
118
119	if (memcmp(tx->buf[0], tx->buf[1], tx->length) != 0) {
120		ioat_log_message(0, "miscompare found\n");
121		test->status = IOAT_TEST_MISCOMPARE;
122	}
123	atomic_add_32(&test->num_completions, 1);
124	ioat_test_transaction_destroy(tx);
125	if (test->num_completions == test->num_loops)
126		wakeup(test);
127}
128
129static void
130ioat_dma_test(void *arg)
131{
132	struct test_transaction *tx;
133	struct ioat_test *test;
134	bus_dmaengine_t dmaengine;
135	uint32_t loops;
136	int index, i;
137
138	test = arg;
139	loops = test->num_loops;
140
141	test->status = IOAT_TEST_OK;
142	test->num_completions = 0;
143
144	index = g_thread_index++;
145	dmaengine = ioat_get_dmaengine(test->channel_index);
146
147	if (dmaengine == NULL) {
148		ioat_log_message(0, "Couldn't acquire dmaengine\n");
149		test->status = IOAT_TEST_NO_DMA_ENGINE;
150		return;
151	}
152
153	ioat_log_message(0, "Thread %d: num_loops remaining: 0x%07x\n", index,
154	    test->num_loops);
155
156	for (loops = 0; loops < test->num_loops; loops++) {
157		bus_addr_t src, dest;
158
159		if (loops % 0x10000 == 0) {
160			ioat_log_message(0, "Thread %d: "
161			    "num_loops remaining: 0x%07x\n", index,
162			    test->num_loops - loops);
163		}
164
165		tx = ioat_test_transaction_create(2, IOAT_TEST_SIZE);
166		if (tx == NULL) {
167			ioat_log_message(0, "tx == NULL - memory exhausted\n");
168			atomic_add_32(&test->num_completions, 1);
169			test->status = IOAT_TEST_NO_MEMORY;
170			continue;
171		}
172
173		tx->test = test;
174		wmb();
175
176		/* fill in source buffer */
177		for (i = 0; i < (IOAT_TEST_SIZE / sizeof(uint32_t)); i++) {
178			uint32_t val = i + (loops << 16) + (index << 28);
179			((uint32_t *)tx->buf[0])[i] = ~val;
180			((uint32_t *)tx->buf[1])[i] = val;
181		}
182
183		src = pmap_kextract((vm_offset_t)tx->buf[0]);
184		dest = pmap_kextract((vm_offset_t)tx->buf[1]);
185
186		ioat_acquire(dmaengine);
187		ioat_copy(dmaengine, src, dest, IOAT_TEST_SIZE,
188		    ioat_dma_test_callback, tx, DMA_INT_EN);
189		ioat_release(dmaengine);
190	}
191
192	while (test->num_completions < test->num_loops)
193		tsleep(test, 0, "compl", 5 * hz);
194
195}
196
197static int
198ioat_test_open(struct cdev *dev, int flags, int fmt, struct thread *td)
199{
200
201	return (0);
202}
203
204static int
205ioat_test_close(struct cdev *dev, int flags, int fmt, struct thread *td)
206{
207
208	return (0);
209}
210
211static int
212ioat_test_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, int flag,
213    struct thread *td)
214{
215
216	switch (cmd) {
217	case IOAT_DMATEST:
218		ioat_dma_test(arg);
219		break;
220	default:
221		return (EINVAL);
222	}
223	return (0);
224}
225
226static struct cdevsw ioat_cdevsw = {
227	.d_version =	D_VERSION,
228	.d_flags =	0,
229	.d_open =	ioat_test_open,
230	.d_close =	ioat_test_close,
231	.d_ioctl =	ioat_test_ioctl,
232	.d_name =	"ioat_test",
233};
234
235static int
236sysctl_enable_ioat_test(SYSCTL_HANDLER_ARGS)
237{
238	int error, enabled;
239
240	enabled = (g_ioat_cdev != NULL);
241	error = sysctl_handle_int(oidp, &enabled, 0, req);
242	if (error != 0 || req->newptr == NULL)
243		return (error);
244
245	if (enabled != 0 && g_ioat_cdev == NULL) {
246		g_ioat_cdev = make_dev(&ioat_cdevsw, 0, UID_ROOT, GID_WHEEL,
247		    0600, "ioat_test");
248	} else if (enabled == 0 && g_ioat_cdev != NULL) {
249		destroy_dev(g_ioat_cdev);
250		g_ioat_cdev = NULL;
251	}
252	return (0);
253}
254SYSCTL_PROC(_hw_ioat, OID_AUTO, enable_ioat_test, CTLTYPE_INT | CTLFLAG_RW,
255    0, 0, sysctl_enable_ioat_test, "I",
256    "Non-zero: Enable the /dev/ioat_test device");
257