xref: /netbsd-src/sys/arch/sparc64/dev/ldc.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: ldc.c,v 1.3 2017/03/03 21:09:25 palle Exp $	*/
2 /*	$OpenBSD: ldc.c,v 1.12 2015/03/21 18:02:58 kettenis Exp $	*/
3 /*
4  * Copyright (c) 2009 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/kmem.h>
20 #include <sys/malloc.h>
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 
24 #include <sys/bus.h>
25 #include <machine/hypervisor.h>
26 
27 #include <uvm/uvm_extern.h>
28 
29 #include <sparc64/dev/ldcvar.h>
30 
31 #ifdef LDC_DEBUG
32 #define DPRINTF(x)	printf x
33 #else
34 #define DPRINTF(x)
35 #endif
36 
37 void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
38 void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
39 void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
40 void	ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
41 
42 void	ldc_send_ack(struct ldc_conn *);
43 void	ldc_send_rtr(struct ldc_conn *);
44 void	ldc_send_rts(struct ldc_conn *);
45 void	ldc_send_rdx(struct ldc_conn *);
46 
47 void
48 ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
49 {
50 	switch (lp->ctrl) {
51 	case LDC_VERS:
52 		ldc_rx_ctrl_vers(lc, lp);
53 		break;
54 
55 	case LDC_RTS:
56 		ldc_rx_ctrl_rts(lc, lp);
57 		break;
58 
59 	case LDC_RTR:
60 		ldc_rx_ctrl_rtr(lc, lp);
61 		break;
62 
63 	case LDC_RDX:
64 		ldc_rx_ctrl_rdx(lc, lp);
65 		break;
66 
67 	default:
68 		DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
69 		ldc_reset(lc);
70 		break;
71 	}
72 }
73 
74 void
75 ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
76 {
77 	switch (lp->stype) {
78 	case LDC_INFO:
79 		DPRINTF(("CTRL/INFO/VERS\n"));
80 		if (lp->major == LDC_VERSION_MAJOR &&
81 		    lp->minor == LDC_VERSION_MINOR)
82 			ldc_send_ack(lc);
83 		else {
84 			/* XXX do nothing for now. */
85 		}
86 		break;
87 
88 	case LDC_ACK:
89 		if (lc->lc_state != LDC_SND_VERS) {
90 			DPRINTF(("Spurious CTRL/ACK/VERS: state %d\n",
91 			    lc->lc_state));
92 			ldc_reset(lc);
93 			return;
94 		}
95 		DPRINTF(("CTRL/ACK/VERS\n"));
96 		ldc_send_rts(lc);
97 		break;
98 
99 	case LDC_NACK:
100 		DPRINTF(("CTRL/NACK/VERS\n"));
101 		ldc_reset(lc);
102 		break;
103 
104 	default:
105 		DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
106 		ldc_reset(lc);
107 		break;
108 	}
109 }
110 
111 void
112 ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
113 {
114 	switch (lp->stype) {
115 	case LDC_INFO:
116 		if (lc->lc_state != LDC_RCV_VERS) {
117 			DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n",
118 			    lc->lc_state));
119 			ldc_reset(lc);
120 			return;
121 		}
122 		DPRINTF(("CTRL/INFO/RTS\n"));
123 		ldc_send_rtr(lc);
124 		break;
125 
126 	case LDC_ACK:
127 		DPRINTF(("CTRL/ACK/RTS\n"));
128 		ldc_reset(lc);
129 		break;
130 
131 	case LDC_NACK:
132 		DPRINTF(("CTRL/NACK/RTS\n"));
133 		ldc_reset(lc);
134 		break;
135 
136 	default:
137 		DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
138 		ldc_reset(lc);
139 		break;
140 	}
141 }
142 
143 void
144 ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
145 {
146 	switch (lp->stype) {
147 	case LDC_INFO:
148 		if (lc->lc_state != LDC_SND_RTS) {
149 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
150 			    lc->lc_state));
151 			ldc_reset(lc);
152 			return;
153 		}
154 		DPRINTF(("CTRL/INFO/RTR\n"));
155 		ldc_send_rdx(lc);
156 		lc->lc_start(lc);
157 		break;
158 
159 	case LDC_ACK:
160 		DPRINTF(("CTRL/ACK/RTR\n"));
161 		ldc_reset(lc);
162 		break;
163 
164 	case LDC_NACK:
165 		DPRINTF(("CTRL/NACK/RTR\n"));
166 		ldc_reset(lc);
167 		break;
168 
169 	default:
170 		DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
171 		ldc_reset(lc);
172 		break;
173 	}
174 }
175 
176 void
177 ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp)
178 {
179 	switch (lp->stype) {
180 	case LDC_INFO:
181 		if (lc->lc_state != LDC_SND_RTR) {
182 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
183 			    lc->lc_state));
184 			ldc_reset(lc);
185 			return;
186 		}
187 		DPRINTF(("CTRL/INFO/RDX\n"));
188 		lc->lc_start(lc);
189 		break;
190 
191 	case LDC_ACK:
192 		DPRINTF(("CTRL/ACK/RDX\n"));
193 		ldc_reset(lc);
194 		break;
195 
196 	case LDC_NACK:
197 		DPRINTF(("CTRL/NACK/RDX\n"));
198 		ldc_reset(lc);
199 		break;
200 
201 	default:
202 		DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype));
203 		ldc_reset(lc);
204 		break;
205 	}
206 }
207 
208 void
209 ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
210 {
211 	size_t len;
212 
213 	if (lp->stype != LDC_INFO) {
214 		DPRINTF(("DATA/0x%02x\n", lp->stype));
215 		ldc_reset(lc);
216 		return;
217 	}
218 
219 	if (lc->lc_state != LDC_SND_RTR &&
220 	    lc->lc_state != LDC_SND_RDX) {
221 		DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
222 		ldc_reset(lc);
223 		return;
224 	}
225 
226 	if (lp->env & LDC_FRAG_START) {
227 		lc->lc_len = (lp->env & LDC_LEN_MASK) + 8;
228 		KASSERT(lc->lc_len <= sizeof(lc->lc_msg));
229 		memcpy((uint8_t *)lc->lc_msg, lp, lc->lc_len);
230 	} else {
231 		len = (lp->env & LDC_LEN_MASK);
232 		if (lc->lc_len + len > sizeof(lc->lc_msg)) {
233 			DPRINTF(("Buffer overrun\n"));
234 			ldc_reset(lc);
235 			return;
236 		}
237 		memcpy(((uint8_t *)lc->lc_msg) + lc->lc_len, &lp->major, len);
238 		lc->lc_len += len;
239 	}
240 
241 	if (lp->env & LDC_FRAG_STOP)
242 		lc->lc_rx_data(lc, (struct ldc_pkt *)lc->lc_msg);
243 }
244 
245 void
246 ldc_send_vers(struct ldc_conn *lc)
247 {
248 	struct ldc_pkt *lp;
249 	uint64_t tx_head, tx_tail, tx_state;
250 	int err;
251 
252 	mutex_enter(&lc->lc_txq->lq_mtx);
253 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
254 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
255 		mutex_exit(&lc->lc_txq->lq_mtx);
256 		return;
257 	}
258 
259 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
260 	bzero(lp, sizeof(struct ldc_pkt));
261 	lp->type = LDC_CTRL;
262 	lp->stype = LDC_INFO;
263 	lp->ctrl = LDC_VERS;
264 	lp->major = 1;
265 	lp->minor = 0;
266 
267 	tx_tail += sizeof(*lp);
268 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
269 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
270 	if (err != H_EOK) {
271 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
272 		mutex_exit(&lc->lc_txq->lq_mtx);
273 		return;
274 	}
275 
276 	lc->lc_state = LDC_SND_VERS;
277 	mutex_exit(&lc->lc_txq->lq_mtx);
278 }
279 
280 void
281 ldc_send_ack(struct ldc_conn *lc)
282 {
283 	struct ldc_pkt *lp;
284 	uint64_t tx_head, tx_tail, tx_state;
285 	int err;
286 
287 	mutex_enter(&lc->lc_txq->lq_mtx);
288 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
289 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
290 		mutex_exit(&lc->lc_txq->lq_mtx);
291 		return;
292 	}
293 
294 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
295 	bzero(lp, sizeof(struct ldc_pkt));
296 	lp->type = LDC_CTRL;
297 	lp->stype = LDC_ACK;
298 	lp->ctrl = LDC_VERS;
299 	lp->major = 1;
300 	lp->minor = 0;
301 
302 	tx_tail += sizeof(*lp);
303 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
304 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
305 	if (err != H_EOK) {
306 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
307 		mutex_exit(&lc->lc_txq->lq_mtx);
308 		return;
309 	}
310 
311 	lc->lc_state = LDC_RCV_VERS;
312 	mutex_exit(&lc->lc_txq->lq_mtx);
313 }
314 
315 void
316 ldc_send_rts(struct ldc_conn *lc)
317 {
318 	struct ldc_pkt *lp;
319 	uint64_t tx_head, tx_tail, tx_state;
320 	int err;
321 
322 	mutex_enter(&lc->lc_txq->lq_mtx);
323 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
324 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
325 		mutex_exit(&lc->lc_txq->lq_mtx);
326 		return;
327 	}
328 
329 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
330 	bzero(lp, sizeof(struct ldc_pkt));
331 	lp->type = LDC_CTRL;
332 	lp->stype = LDC_INFO;
333 	lp->ctrl = LDC_RTS;
334 	lp->env = LDC_MODE_UNRELIABLE;
335 	lp->seqid = lc->lc_tx_seqid++;
336 
337 	tx_tail += sizeof(*lp);
338 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
339 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
340 	if (err != H_EOK) {
341 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
342 		mutex_exit(&lc->lc_txq->lq_mtx);
343 		return;
344 	}
345 
346 	lc->lc_state = LDC_SND_RTS;
347 	mutex_exit(&lc->lc_txq->lq_mtx);
348 }
349 
350 void
351 ldc_send_rtr(struct ldc_conn *lc)
352 {
353 	struct ldc_pkt *lp;
354 	uint64_t tx_head, tx_tail, tx_state;
355 	int err;
356 
357 	mutex_enter(&lc->lc_txq->lq_mtx);
358 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
359 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
360 		mutex_exit(&lc->lc_txq->lq_mtx);
361 		return;
362 	}
363 
364 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
365 	bzero(lp, sizeof(struct ldc_pkt));
366 	lp->type = LDC_CTRL;
367 	lp->stype = LDC_INFO;
368 	lp->ctrl = LDC_RTR;
369 	lp->env = LDC_MODE_UNRELIABLE;
370 	lp->seqid = lc->lc_tx_seqid++;
371 
372 	tx_tail += sizeof(*lp);
373 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
374 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
375 	if (err != H_EOK) {
376 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
377 		mutex_exit(&lc->lc_txq->lq_mtx);
378 		return;
379 	}
380 
381 	lc->lc_state = LDC_SND_RTR;
382 	mutex_exit(&lc->lc_txq->lq_mtx);
383 }
384 
385 void
386 ldc_send_rdx(struct ldc_conn *lc)
387 {
388 	struct ldc_pkt *lp;
389 	uint64_t tx_head, tx_tail, tx_state;
390 	int err;
391 
392 	mutex_enter(&lc->lc_txq->lq_mtx);
393 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
394 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
395 		mutex_exit(&lc->lc_txq->lq_mtx);
396 		return;
397 	}
398 
399 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
400 	bzero(lp, sizeof(struct ldc_pkt));
401 	lp->type = LDC_CTRL;
402 	lp->stype = LDC_INFO;
403 	lp->ctrl = LDC_RDX;
404 	lp->env = LDC_MODE_UNRELIABLE;
405 	lp->seqid = lc->lc_tx_seqid++;
406 
407 	tx_tail += sizeof(*lp);
408 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
409 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
410 	if (err != H_EOK) {
411 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
412 		mutex_exit(&lc->lc_txq->lq_mtx);
413 		return;
414 	}
415 
416 	lc->lc_state = LDC_SND_RDX;
417 	mutex_exit(&lc->lc_txq->lq_mtx);
418 }
419 
420 int
421 ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
422 {
423 	struct ldc_pkt *lp;
424 	uint64_t tx_head, tx_tail, tx_state;
425 	uint64_t tx_avail;
426 	uint8_t *p = msg;
427 	int err;
428 
429 	mutex_enter(&lc->lc_txq->lq_mtx);
430 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
431 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
432 		mutex_exit(&lc->lc_txq->lq_mtx);
433 		return (EIO);
434 	}
435 
436 	tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
437 	    lc->lc_txq->lq_nentries - 1;
438 	tx_avail %= lc->lc_txq->lq_nentries;
439 	if (len > tx_avail * LDC_PKT_PAYLOAD) {
440 		mutex_exit(&lc->lc_txq->lq_mtx);
441 		return (EWOULDBLOCK);
442 	}
443 
444 	while (len > 0) {
445 		lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
446 		bzero(lp, sizeof(struct ldc_pkt));
447 		lp->type = LDC_DATA;
448 		lp->stype = LDC_INFO;
449 		lp->env = min(len, LDC_PKT_PAYLOAD);
450 		if (p == msg)
451 			lp->env |= LDC_FRAG_START;
452 		if (len <= LDC_PKT_PAYLOAD)
453 			lp->env |= LDC_FRAG_STOP;
454 		lp->seqid = lc->lc_tx_seqid++;
455 		bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD));
456 
457 		tx_tail += sizeof(*lp);
458 		tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
459 		err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
460 		if (err != H_EOK) {
461 			printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
462 			mutex_exit(&lc->lc_txq->lq_mtx);
463 			return (EIO);
464 		}
465 		p += min(len, LDC_PKT_PAYLOAD);
466 		len -= min(len, LDC_PKT_PAYLOAD);
467 	}
468 
469 	mutex_exit(&lc->lc_txq->lq_mtx);
470 	return (0);
471 }
472 
473 void
474 ldc_reset(struct ldc_conn *lc)
475 {
476 	int err;
477 	vaddr_t va;
478 	paddr_t pa;
479 
480 	DPRINTF(("Resetting connection\n"));
481 
482 	mutex_enter(&lc->lc_txq->lq_mtx);
483 
484 #if OPENBSD_BUSDMA
485 	err = hv_ldc_tx_qconf(lc->lc_id,
486 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
487 #else
488         va = lc->lc_txq->lq_va;
489 	pa = 0;
490 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
491 	  panic("pmap_extract failed %lx\n", va);
492 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
493 #endif
494 	if (err != H_EOK)
495 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
496 
497 #if OPENBSD_BUSDMA
498 	err = hv_ldc_rx_qconf(lc->lc_id,
499 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
500 #else
501         va = lc->lc_rxq->lq_va;
502 	pa = 0;
503 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
504 	  panic("pmap_extract failed %lx\n", va);
505 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
506 #endif
507 	if (err != H_EOK)
508 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
509 
510 	lc->lc_tx_seqid = 0;
511 	lc->lc_state = 0;
512 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
513 	mutex_exit(&lc->lc_txq->lq_mtx);
514 
515 	lc->lc_reset(lc);
516 }
517 #if OPENBSD_BUSDMA
518 struct ldc_queue *
519 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
520 #else
521 struct ldc_queue *
522 ldc_queue_alloc(int nentries)
523 #endif
524 {
525 	struct ldc_queue *lq;
526 	bus_size_t size;
527 	vaddr_t va = 0;
528 #if OPENBSD_BUSDMA
529 	int nsegs;
530 #endif
531 
532 	lq = kmem_zalloc(sizeof(struct ldc_queue), KM_NOSLEEP);
533 	if (lq == NULL)
534 		return NULL;
535 
536 	mutex_init(&lq->lq_mtx, MUTEX_DEFAULT, IPL_TTY);
537 
538 	size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
539 #if OPENBSD_BUSDMA
540 	if (bus_dmamap_create(t, size, 1, size, 0,
541 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
542 		return (NULL);
543 
544 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
545 	    &nsegs, BUS_DMA_NOWAIT) != 0)
546 		goto destroy;
547 
548 	if (bus_dmamem_map(t, &lq->lq_seg, 1, size, (void *)&va,
549 	    BUS_DMA_NOWAIT) != 0)
550 		goto free;
551 
552 	 if (bus_dmamap_load(t, lq->lq_map, (void*)va, size, NULL,
553 	    BUS_DMA_NOWAIT) != 0)
554 		goto unmap;
555 #else
556 	 va = (vaddr_t)kmem_zalloc(size, KM_NOSLEEP);
557 	 if (va == 0)
558 		goto free;
559 #endif
560 	lq->lq_va = (vaddr_t)va;
561 	lq->lq_nentries = nentries;
562 	return (lq);
563 #if OPENBSD_BUSDMA
564 unmap:
565 	bus_dmamem_unmap(t, (void*)va, size);
566 free:
567 	bus_dmamem_free(t, &lq->lq_seg, 1);
568 destroy:
569 	bus_dmamap_destroy(t, lq->lq_map);
570 #else
571 free:
572 	kmem_free(lq, sizeof(struct ldc_queue));
573 #endif
574 	return (NULL);
575 }
576 
577 void
578 #if OPENBSD_BUSDMA
579 ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
580 #else
581 ldc_queue_free(struct ldc_queue *lq)
582 #endif
583 {
584 	bus_size_t size;
585 
586 	size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
587 
588 #if OPENBSD_BUSDMA
589 	bus_dmamap_unload(t, lq->lq_map);
590 	bus_dmamem_unmap(t, &lq->lq_va, size);
591 	bus_dmamem_free(t, &lq->lq_seg, 1);
592 	bus_dmamap_destroy(t, lq->lq_map);
593 #else
594 	kmem_free((void *)lq->lq_va, size);
595 #endif
596 	kmem_free(lq, size);
597 }
598 
599 #if OPENBSD_BUSDMA
600 struct ldc_map *
601 ldc_map_alloc(bus_dma_tag_t t, int nentries)
602 #else
603 struct ldc_map *
604 ldc_map_alloc(int nentries)
605 #endif
606 {
607 	struct ldc_map *lm;
608 	bus_size_t size;
609 	vaddr_t va = 0;
610 
611 #if OPENBSD_BUSDMA
612 	int nsegs;
613 #endif
614 	lm = kmem_zalloc(sizeof(struct ldc_map), KM_NOSLEEP);
615 	if (lm == NULL)
616 		return NULL;
617 
618 	size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
619 
620 #if OPENBSD_BUSDMA
621 	if (bus_dmamap_create(t, size, 1, size, 0,
622 			      BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0) {
623 		DPRINTF(("ldc_map_alloc() - bus_dmamap_create() failed\n"));
624 		return (NULL);
625 	}
626 
627 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
628 			     &nsegs, BUS_DMA_NOWAIT) != 0) {
629 		DPRINTF(("ldc_map_alloc() - bus_dmamem_alloc() failed\n"));
630 		goto destroy;
631 	}
632 
633 	if (bus_dmamem_map(t, &lm->lm_seg, 1, size, (void *)&va,
634 			   BUS_DMA_NOWAIT) != 0) {
635 		DPRINTF(("ldc_map_alloc() - bus_dmamem_map() failed\n"));
636 		goto free;
637 	}
638 	if (bus_dmamap_load(t, lm->lm_map, (void*)va, size, NULL,
639 			    BUS_DMA_NOWAIT) != 0) {
640 		DPRINTF(("ldc_map_alloc() - bus_dmamap_load() failed\n"));
641 		goto unmap;
642 	}
643 #else
644 	va = (vaddr_t)kmem_zalloc(size, KM_NOSLEEP);
645 	if (va == 0)
646 		goto free;
647 #endif
648 	lm->lm_slot = (struct ldc_map_slot *)va;
649 	lm->lm_nentries = nentries;
650 	bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
651 	return (lm);
652 
653 #if OPENBSD_BUSDMA
654 unmap:
655 	bus_dmamem_unmap(t, (void*)va, size);
656 free:
657 	bus_dmamem_free(t, &lm->lm_seg, 1);
658 destroy:
659 	bus_dmamap_destroy(t, lm->lm_map);
660 #else
661 free:
662 	kmem_free(lm, sizeof(struct ldc_map));
663 #endif
664 	return (NULL);
665 }
666 
667 #if OPENBSD_BUSDMA
668 void
669 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
670 #else
671 void
672 ldc_map_free(struct ldc_map *lm)
673 #endif
674 {
675 	bus_size_t size;
676 
677 	size = lm->lm_nentries * sizeof(struct ldc_map_slot);
678 	size = roundup(size, PAGE_SIZE);
679 
680 #if OPENBSD_BUSDMA
681 	bus_dmamap_unload(t, lm->lm_map);
682 	bus_dmamem_unmap(t, lm->lm_slot, size);
683 	bus_dmamem_free(t, &lm->lm_seg, 1);
684 	bus_dmamap_destroy(t, lm->lm_map);
685 #else
686 	kmem_free(lm->lm_slot, size);
687 #endif
688 	kmem_free(lm, size);
689 }
690