xref: /freebsd/sys/dev/ioat/ioat_test.c (revision bd81e07d2761cf1c13063eb49a5c0cb4a6951318)
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$");
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 
54 MALLOC_DEFINE(M_IOAT_TEST, "ioat_test", "ioat test allocations");
55 
56 #define	IOAT_TEST_SIZE	0x40000
57 #define	IOAT_MAX_BUFS	8
58 
59 struct test_transaction {
60 	uint8_t			num_buffers;
61 	void			*buf[IOAT_MAX_BUFS];
62 	uint32_t		length;
63 	struct ioat_test	*test;
64 };
65 
66 static int g_thread_index = 1;
67 static struct cdev *g_ioat_cdev = NULL;
68 
69 static void
70 ioat_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 
84 static struct
85 test_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 
110 static void
111 ioat_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 
129 static void
130 ioat_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 
197 static int
198 ioat_test_open(struct cdev *dev, int flags, int fmt, struct thread *td)
199 {
200 
201 	return (0);
202 }
203 
204 static int
205 ioat_test_close(struct cdev *dev, int flags, int fmt, struct thread *td)
206 {
207 
208 	return (0);
209 }
210 
211 static int
212 ioat_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 
226 static 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 
235 static int
236 sysctl_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 }
254 SYSCTL_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