xref: /netbsd-src/sys/arch/sparc64/dev/ldc.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: ldc.c,v 1.7 2021/04/05 12:19:22 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 major %d minor %d\n", lp->major, lp->minor));
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 			DPRINTF(("CTRL/INFO/VERS unsupported major/minor\n"));
86 		}
87 		break;
88 
89 	case LDC_ACK:
90 		DPRINTF(("CTRL/ACK/VERS\n"));
91 		if (lc->lc_state != LDC_SND_VERS) {
92 			DPRINTF(("Spurious CTRL/ACK/VERS: state %d major %d minor %d (ignored)\n",
93 					 lc->lc_state, lp->major, lp->minor));
94 		}
95 		else {
96 			ldc_send_rts(lc);
97 		}
98 		break;
99 
100 	case LDC_NACK:
101 		DPRINTF(("CTRL/NACK/VERS\n"));
102 		ldc_reset(lc);
103 		break;
104 
105 	default:
106 		DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
107 		ldc_reset(lc);
108 		break;
109 	}
110 }
111 
112 void
113 ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
114 {
115 	switch (lp->stype) {
116 	case LDC_INFO:
117 		if (lc->lc_state != LDC_RCV_VERS) {
118 			DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n",
119 			    lc->lc_state));
120 			ldc_reset(lc);
121 			return;
122 		}
123 		DPRINTF(("CTRL/INFO/RTS\n"));
124 		ldc_send_rtr(lc);
125 		break;
126 
127 	case LDC_ACK:
128 		DPRINTF(("CTRL/ACK/RTS\n"));
129 		ldc_reset(lc);
130 		break;
131 
132 	case LDC_NACK:
133 		DPRINTF(("CTRL/NACK/RTS\n"));
134 		ldc_reset(lc);
135 		break;
136 
137 	default:
138 		DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
139 		ldc_reset(lc);
140 		break;
141 	}
142 }
143 
144 void
145 ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
146 {
147 	switch (lp->stype) {
148 	case LDC_INFO:
149 		if (lc->lc_state != LDC_SND_RTS) {
150 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
151 			    lc->lc_state));
152 			ldc_reset(lc);
153 			return;
154 		}
155 		DPRINTF(("CTRL/INFO/RTR\n"));
156 		ldc_send_rdx(lc);
157 		lc->lc_start(lc);
158 		break;
159 
160 	case LDC_ACK:
161 		DPRINTF(("CTRL/ACK/RTR\n"));
162 		ldc_reset(lc);
163 		break;
164 
165 	case LDC_NACK:
166 		DPRINTF(("CTRL/NACK/RTR\n"));
167 		ldc_reset(lc);
168 		break;
169 
170 	default:
171 		DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
172 		ldc_reset(lc);
173 		break;
174 	}
175 }
176 
177 void
178 ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp)
179 {
180 	switch (lp->stype) {
181 	case LDC_INFO:
182 		if (lc->lc_state != LDC_SND_RTR) {
183 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
184 			    lc->lc_state));
185 			ldc_reset(lc);
186 			return;
187 		}
188 		DPRINTF(("CTRL/INFO/RDX\n"));
189 		lc->lc_start(lc);
190 		break;
191 
192 	case LDC_ACK:
193 		DPRINTF(("CTRL/ACK/RDX\n"));
194 		ldc_reset(lc);
195 		break;
196 
197 	case LDC_NACK:
198 		DPRINTF(("CTRL/NACK/RDX\n"));
199 		ldc_reset(lc);
200 		break;
201 
202 	default:
203 		DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype));
204 		ldc_reset(lc);
205 		break;
206 	}
207 }
208 
209 void
210 ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
211 {
212 	size_t len;
213 
214 	if (lp->stype != LDC_INFO) {
215 		DPRINTF(("DATA/0x%02x\n", lp->stype));
216 		ldc_reset(lc);
217 		return;
218 	}
219 
220 	if (lc->lc_state != LDC_SND_RTR &&
221 	    lc->lc_state != LDC_SND_RDX) {
222 		DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
223 		ldc_reset(lc);
224 		return;
225 	}
226 
227 	if (lp->env & LDC_FRAG_START) {
228 		lc->lc_len = (lp->env & LDC_LEN_MASK) + 8;
229 		KASSERT(lc->lc_len <= sizeof(lc->lc_msg));
230 		memcpy((uint8_t *)lc->lc_msg, lp, lc->lc_len);
231 	} else {
232 		len = (lp->env & LDC_LEN_MASK);
233 		if (lc->lc_len + len > sizeof(lc->lc_msg)) {
234 			DPRINTF(("Buffer overrun\n"));
235 			ldc_reset(lc);
236 			return;
237 		}
238 		memcpy(((uint8_t *)lc->lc_msg) + lc->lc_len, &lp->major, len);
239 		lc->lc_len += len;
240 	}
241 
242 	if (lp->env & LDC_FRAG_STOP)
243 		lc->lc_rx_data(lc, (struct ldc_pkt *)lc->lc_msg);
244 }
245 
246 void
247 ldc_send_vers(struct ldc_conn *lc)
248 {
249 	struct ldc_pkt *lp;
250 	uint64_t tx_head, tx_tail, tx_state;
251 	int err;
252 
253 	mutex_enter(&lc->lc_txq->lq_mtx);
254 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
255 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
256 		mutex_exit(&lc->lc_txq->lq_mtx);
257 		return;
258 	}
259 
260 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
261 	bzero(lp, sizeof(struct ldc_pkt));
262 	lp->type = LDC_CTRL;
263 	lp->stype = LDC_INFO;
264 	lp->ctrl = LDC_VERS;
265 	lp->major = 1;
266 	lp->minor = 0;
267 	DPRINTF(("ldc_send_vers() major %d minor %d\n", lp->major, lp->minor));
268 
269 	tx_tail += sizeof(*lp);
270 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
271 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
272 	if (err != H_EOK) {
273 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
274 		mutex_exit(&lc->lc_txq->lq_mtx);
275 		return;
276 	}
277 
278 	lc->lc_state = LDC_SND_VERS;
279 	DPRINTF(("ldc_send_vers() setting lc->lc_state to %d\n", lc->lc_state));
280 	mutex_exit(&lc->lc_txq->lq_mtx);
281 }
282 
283 void
284 ldc_send_ack(struct ldc_conn *lc)
285 {
286 	struct ldc_pkt *lp;
287 	uint64_t tx_head, tx_tail, tx_state;
288 	int err;
289 
290 	mutex_enter(&lc->lc_txq->lq_mtx);
291 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
292 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
293 		mutex_exit(&lc->lc_txq->lq_mtx);
294 		return;
295 	}
296 
297 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
298 	bzero(lp, sizeof(struct ldc_pkt));
299 	lp->type = LDC_CTRL;
300 	lp->stype = LDC_ACK;
301 	lp->ctrl = LDC_VERS;
302 	lp->major = 1;
303 	lp->minor = 0;
304 
305 	tx_tail += sizeof(*lp);
306 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
307 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
308 	if (err != H_EOK) {
309 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
310 		mutex_exit(&lc->lc_txq->lq_mtx);
311 		return;
312 	}
313 
314 	lc->lc_state = LDC_RCV_VERS;
315 	DPRINTF(("ldc_send_ack() setting lc->lc_state to %d\n", lc->lc_state));
316 	mutex_exit(&lc->lc_txq->lq_mtx);
317 }
318 
319 void
320 ldc_send_rts(struct ldc_conn *lc)
321 {
322 	struct ldc_pkt *lp;
323 	uint64_t tx_head, tx_tail, tx_state;
324 	int err;
325 
326 	mutex_enter(&lc->lc_txq->lq_mtx);
327 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
328 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
329 		mutex_exit(&lc->lc_txq->lq_mtx);
330 		return;
331 	}
332 
333 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
334 	bzero(lp, sizeof(struct ldc_pkt));
335 	lp->type = LDC_CTRL;
336 	lp->stype = LDC_INFO;
337 	lp->ctrl = LDC_RTS;
338 	lp->env = LDC_MODE_UNRELIABLE;
339 	lp->seqid = lc->lc_tx_seqid++;
340 
341 	tx_tail += sizeof(*lp);
342 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
343 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
344 	if (err != H_EOK) {
345 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
346 		mutex_exit(&lc->lc_txq->lq_mtx);
347 		return;
348 	}
349 
350 	lc->lc_state = LDC_SND_RTS;
351 	DPRINTF(("ldc_send_rts() setting lc->lc_state to %d\n", lc->lc_state));
352 	mutex_exit(&lc->lc_txq->lq_mtx);
353 }
354 
355 void
356 ldc_send_rtr(struct ldc_conn *lc)
357 {
358 	struct ldc_pkt *lp;
359 	uint64_t tx_head, tx_tail, tx_state;
360 	int err;
361 
362 	mutex_enter(&lc->lc_txq->lq_mtx);
363 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
364 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
365 		mutex_exit(&lc->lc_txq->lq_mtx);
366 		return;
367 	}
368 
369 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
370 	bzero(lp, sizeof(struct ldc_pkt));
371 	lp->type = LDC_CTRL;
372 	lp->stype = LDC_INFO;
373 	lp->ctrl = LDC_RTR;
374 	lp->env = LDC_MODE_UNRELIABLE;
375 	lp->seqid = lc->lc_tx_seqid++;
376 
377 	tx_tail += sizeof(*lp);
378 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
379 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
380 	if (err != H_EOK) {
381 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
382 		mutex_exit(&lc->lc_txq->lq_mtx);
383 		return;
384 	}
385 
386 	lc->lc_state = LDC_SND_RTR;
387 	DPRINTF(("ldc_send_rtr() setting lc->lc_state to %d\n", lc->lc_state));
388 	mutex_exit(&lc->lc_txq->lq_mtx);
389 }
390 
391 void
392 ldc_send_rdx(struct ldc_conn *lc)
393 {
394 	struct ldc_pkt *lp;
395 	uint64_t tx_head, tx_tail, tx_state;
396 	int err;
397 
398 	mutex_enter(&lc->lc_txq->lq_mtx);
399 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
400 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
401 		mutex_exit(&lc->lc_txq->lq_mtx);
402 		return;
403 	}
404 
405 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
406 	bzero(lp, sizeof(struct ldc_pkt));
407 	lp->type = LDC_CTRL;
408 	lp->stype = LDC_INFO;
409 	lp->ctrl = LDC_RDX;
410 	lp->env = LDC_MODE_UNRELIABLE;
411 	lp->seqid = lc->lc_tx_seqid++;
412 
413 	tx_tail += sizeof(*lp);
414 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
415 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
416 	if (err != H_EOK) {
417 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
418 		mutex_exit(&lc->lc_txq->lq_mtx);
419 		return;
420 	}
421 
422 	lc->lc_state = LDC_SND_RDX;
423 	DPRINTF(("ldc_send_rdx() setting lc->lc_state to %d\n", lc->lc_state));
424 	mutex_exit(&lc->lc_txq->lq_mtx);
425 }
426 
427 int
428 ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
429 {
430 	struct ldc_pkt *lp;
431 	uint64_t tx_head, tx_tail, tx_state;
432 	uint64_t tx_avail;
433 	uint8_t *p = msg;
434 	int err;
435 
436 	mutex_enter(&lc->lc_txq->lq_mtx);
437 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
438 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
439 		mutex_exit(&lc->lc_txq->lq_mtx);
440 		return (EIO);
441 	}
442 
443 	tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
444 	    lc->lc_txq->lq_nentries - 1;
445 	tx_avail %= lc->lc_txq->lq_nentries;
446 	if (len > tx_avail * LDC_PKT_PAYLOAD) {
447 		mutex_exit(&lc->lc_txq->lq_mtx);
448 		return (EWOULDBLOCK);
449 	}
450 
451 	while (len > 0) {
452 		lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
453 		bzero(lp, sizeof(struct ldc_pkt));
454 		lp->type = LDC_DATA;
455 		lp->stype = LDC_INFO;
456 		lp->env = uimin(len, LDC_PKT_PAYLOAD);
457 		if (p == msg)
458 			lp->env |= LDC_FRAG_START;
459 		if (len <= LDC_PKT_PAYLOAD)
460 			lp->env |= LDC_FRAG_STOP;
461 		lp->seqid = lc->lc_tx_seqid++;
462 		bcopy(p, &lp->major, uimin(len, LDC_PKT_PAYLOAD));
463 
464 		tx_tail += sizeof(*lp);
465 		tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
466 		err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
467 		if (err != H_EOK) {
468 			printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
469 			mutex_exit(&lc->lc_txq->lq_mtx);
470 			return (EIO);
471 		}
472 		p += uimin(len, LDC_PKT_PAYLOAD);
473 		len -= uimin(len, LDC_PKT_PAYLOAD);
474 	}
475 
476 	mutex_exit(&lc->lc_txq->lq_mtx);
477 	return (0);
478 }
479 
480 void
481 ldc_reset(struct ldc_conn *lc)
482 {
483 	int err;
484 	vaddr_t va;
485 	paddr_t pa;
486 
487 	DPRINTF(("Resetting connection\n"));
488 
489 	mutex_enter(&lc->lc_txq->lq_mtx);
490 
491 #if OPENBSD_BUSDMA
492 	err = hv_ldc_tx_qconf(lc->lc_id,
493 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
494 #else
495         va = lc->lc_txq->lq_va;
496 	pa = 0;
497 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
498 	  panic("pmap_extract failed %lx\n", va);
499 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
500 #endif
501 	if (err != H_EOK)
502 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
503 
504 #if OPENBSD_BUSDMA
505 	err = hv_ldc_rx_qconf(lc->lc_id,
506 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
507 #else
508         va = lc->lc_rxq->lq_va;
509 	pa = 0;
510 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
511 	  panic("pmap_extract failed %lx\n", va);
512 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
513 #endif
514 	if (err != H_EOK)
515 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
516 
517 	lc->lc_tx_seqid = 0;
518 	lc->lc_state = 0;
519 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
520 	mutex_exit(&lc->lc_txq->lq_mtx);
521 
522 	lc->lc_reset(lc);
523 }
524 #if OPENBSD_BUSDMA
525 struct ldc_queue *
526 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
527 #else
528 struct ldc_queue *
529 ldc_queue_alloc(int nentries)
530 #endif
531 {
532 	struct ldc_queue *lq;
533 	bus_size_t size;
534 	vaddr_t va = 0;
535 #if OPENBSD_BUSDMA
536 	int nsegs;
537 #endif
538 
539 	lq = kmem_zalloc(sizeof(struct ldc_queue), KM_SLEEP);
540 
541 	mutex_init(&lq->lq_mtx, MUTEX_DEFAULT, IPL_TTY);
542 
543 	size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
544 #if OPENBSD_BUSDMA
545 	if (bus_dmamap_create(t, size, 1, size, 0,
546 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
547 		return (NULL);
548 
549 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
550 	    &nsegs, BUS_DMA_NOWAIT) != 0)
551 		goto destroy;
552 
553 	if (bus_dmamem_map(t, &lq->lq_seg, 1, size, (void *)&va,
554 	    BUS_DMA_NOWAIT) != 0)
555 		goto free;
556 
557 	 if (bus_dmamap_load(t, lq->lq_map, (void*)va, size, NULL,
558 	    BUS_DMA_NOWAIT) != 0)
559 		goto unmap;
560 #else
561 	va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
562 #endif
563 	lq->lq_va = (vaddr_t)va;
564 	lq->lq_nentries = nentries;
565 	return (lq);
566 #if OPENBSD_BUSDMA
567 unmap:
568 	bus_dmamem_unmap(t, (void*)va, size);
569 free:
570 	bus_dmamem_free(t, &lq->lq_seg, 1);
571 destroy:
572 	bus_dmamap_destroy(t, lq->lq_map);
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_SLEEP);
615 	size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
616 
617 #if OPENBSD_BUSDMA
618 	if (bus_dmamap_create(t, size, 1, size, 0,
619 			      BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0) {
620 		DPRINTF(("ldc_map_alloc() - bus_dmamap_create() failed\n"));
621 		return (NULL);
622 	}
623 
624 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
625 			     &nsegs, BUS_DMA_NOWAIT) != 0) {
626 		DPRINTF(("ldc_map_alloc() - bus_dmamem_alloc() failed\n"));
627 		goto destroy;
628 	}
629 
630 	if (bus_dmamem_map(t, &lm->lm_seg, 1, size, (void *)&va,
631 			   BUS_DMA_NOWAIT) != 0) {
632 		DPRINTF(("ldc_map_alloc() - bus_dmamem_map() failed\n"));
633 		goto free;
634 	}
635 	if (bus_dmamap_load(t, lm->lm_map, (void*)va, size, NULL,
636 			    BUS_DMA_NOWAIT) != 0) {
637 		DPRINTF(("ldc_map_alloc() - bus_dmamap_load() failed\n"));
638 		goto unmap;
639 	}
640 #else
641 	va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
642 #endif
643 	lm->lm_slot = (struct ldc_map_slot *)va;
644 	lm->lm_nentries = nentries;
645 	bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
646 	return (lm);
647 
648 #if OPENBSD_BUSDMA
649 unmap:
650 	bus_dmamem_unmap(t, (void*)va, size);
651 free:
652 	bus_dmamem_free(t, &lm->lm_seg, 1);
653 destroy:
654 	bus_dmamap_destroy(t, lm->lm_map);
655 #endif
656 	return (NULL);
657 }
658 
659 #if OPENBSD_BUSDMA
660 void
661 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
662 #else
663 void
664 ldc_map_free(struct ldc_map *lm)
665 #endif
666 {
667 	bus_size_t size;
668 
669 	size = lm->lm_nentries * sizeof(struct ldc_map_slot);
670 	size = roundup(size, PAGE_SIZE);
671 
672 #if OPENBSD_BUSDMA
673 	bus_dmamap_unload(t, lm->lm_map);
674 	bus_dmamem_unmap(t, lm->lm_slot, size);
675 	bus_dmamem_free(t, &lm->lm_seg, 1);
676 	bus_dmamap_destroy(t, lm->lm_map);
677 #else
678 	kmem_free(lm->lm_slot, size);
679 #endif
680 	kmem_free(lm, size);
681 }
682