xref: /netbsd-src/sys/arch/sparc64/dev/ldc.c (revision 1dc652ef5a0bffbd0917f95e0797bad8c6fc8efd)
1 /*	$NetBSD: ldc.c,v 1.8 2023/12/20 05:33:58 thorpej 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/param.h>
21 #include <sys/systm.h>
22 
23 #include <sys/bus.h>
24 #include <machine/hypervisor.h>
25 
26 #include <uvm/uvm_extern.h>
27 
28 #include <sparc64/dev/ldcvar.h>
29 
30 #ifdef LDC_DEBUG
31 #define DPRINTF(x)	printf x
32 #else
33 #define DPRINTF(x)
34 #endif
35 
36 void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
37 void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
38 void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
39 void	ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
40 
41 void	ldc_send_ack(struct ldc_conn *);
42 void	ldc_send_rtr(struct ldc_conn *);
43 void	ldc_send_rts(struct ldc_conn *);
44 void	ldc_send_rdx(struct ldc_conn *);
45 
46 void
ldc_rx_ctrl(struct ldc_conn * lc,struct ldc_pkt * lp)47 ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
48 {
49 	switch (lp->ctrl) {
50 	case LDC_VERS:
51 		ldc_rx_ctrl_vers(lc, lp);
52 		break;
53 
54 	case LDC_RTS:
55 		ldc_rx_ctrl_rts(lc, lp);
56 		break;
57 
58 	case LDC_RTR:
59 		ldc_rx_ctrl_rtr(lc, lp);
60 		break;
61 
62 	case LDC_RDX:
63 		ldc_rx_ctrl_rdx(lc, lp);
64 		break;
65 
66 	default:
67 		DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
68 		ldc_reset(lc);
69 		break;
70 	}
71 }
72 
73 void
ldc_rx_ctrl_vers(struct ldc_conn * lc,struct ldc_pkt * lp)74 ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
75 {
76 	switch (lp->stype) {
77 	case LDC_INFO:
78 		DPRINTF(("CTRL/INFO/VERS major %d minor %d\n", lp->major, lp->minor));
79 		if (lp->major == LDC_VERSION_MAJOR &&
80 		    lp->minor == LDC_VERSION_MINOR)
81 			ldc_send_ack(lc);
82 		else {
83 			/* XXX do nothing for now. */
84 			DPRINTF(("CTRL/INFO/VERS unsupported major/minor\n"));
85 		}
86 		break;
87 
88 	case LDC_ACK:
89 		DPRINTF(("CTRL/ACK/VERS\n"));
90 		if (lc->lc_state != LDC_SND_VERS) {
91 			DPRINTF(("Spurious CTRL/ACK/VERS: state %d major %d minor %d (ignored)\n",
92 					 lc->lc_state, lp->major, lp->minor));
93 		}
94 		else {
95 			ldc_send_rts(lc);
96 		}
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
ldc_rx_ctrl_rts(struct ldc_conn * lc,struct ldc_pkt * lp)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
ldc_rx_ctrl_rtr(struct ldc_conn * lc,struct ldc_pkt * lp)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
ldc_rx_ctrl_rdx(struct ldc_conn * lc,struct ldc_pkt * lp)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
ldc_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)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
ldc_send_vers(struct ldc_conn * lc)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 	DPRINTF(("ldc_send_vers() major %d minor %d\n", lp->major, lp->minor));
267 
268 	tx_tail += sizeof(*lp);
269 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
270 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
271 	if (err != H_EOK) {
272 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
273 		mutex_exit(&lc->lc_txq->lq_mtx);
274 		return;
275 	}
276 
277 	lc->lc_state = LDC_SND_VERS;
278 	DPRINTF(("ldc_send_vers() setting lc->lc_state to %d\n", lc->lc_state));
279 	mutex_exit(&lc->lc_txq->lq_mtx);
280 }
281 
282 void
ldc_send_ack(struct ldc_conn * lc)283 ldc_send_ack(struct ldc_conn *lc)
284 {
285 	struct ldc_pkt *lp;
286 	uint64_t tx_head, tx_tail, tx_state;
287 	int err;
288 
289 	mutex_enter(&lc->lc_txq->lq_mtx);
290 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
291 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
292 		mutex_exit(&lc->lc_txq->lq_mtx);
293 		return;
294 	}
295 
296 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
297 	bzero(lp, sizeof(struct ldc_pkt));
298 	lp->type = LDC_CTRL;
299 	lp->stype = LDC_ACK;
300 	lp->ctrl = LDC_VERS;
301 	lp->major = 1;
302 	lp->minor = 0;
303 
304 	tx_tail += sizeof(*lp);
305 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
306 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
307 	if (err != H_EOK) {
308 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
309 		mutex_exit(&lc->lc_txq->lq_mtx);
310 		return;
311 	}
312 
313 	lc->lc_state = LDC_RCV_VERS;
314 	DPRINTF(("ldc_send_ack() setting lc->lc_state to %d\n", lc->lc_state));
315 	mutex_exit(&lc->lc_txq->lq_mtx);
316 }
317 
318 void
ldc_send_rts(struct ldc_conn * lc)319 ldc_send_rts(struct ldc_conn *lc)
320 {
321 	struct ldc_pkt *lp;
322 	uint64_t tx_head, tx_tail, tx_state;
323 	int err;
324 
325 	mutex_enter(&lc->lc_txq->lq_mtx);
326 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
327 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
328 		mutex_exit(&lc->lc_txq->lq_mtx);
329 		return;
330 	}
331 
332 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
333 	bzero(lp, sizeof(struct ldc_pkt));
334 	lp->type = LDC_CTRL;
335 	lp->stype = LDC_INFO;
336 	lp->ctrl = LDC_RTS;
337 	lp->env = LDC_MODE_UNRELIABLE;
338 	lp->seqid = lc->lc_tx_seqid++;
339 
340 	tx_tail += sizeof(*lp);
341 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
342 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
343 	if (err != H_EOK) {
344 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
345 		mutex_exit(&lc->lc_txq->lq_mtx);
346 		return;
347 	}
348 
349 	lc->lc_state = LDC_SND_RTS;
350 	DPRINTF(("ldc_send_rts() setting lc->lc_state to %d\n", lc->lc_state));
351 	mutex_exit(&lc->lc_txq->lq_mtx);
352 }
353 
354 void
ldc_send_rtr(struct ldc_conn * lc)355 ldc_send_rtr(struct ldc_conn *lc)
356 {
357 	struct ldc_pkt *lp;
358 	uint64_t tx_head, tx_tail, tx_state;
359 	int err;
360 
361 	mutex_enter(&lc->lc_txq->lq_mtx);
362 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
363 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
364 		mutex_exit(&lc->lc_txq->lq_mtx);
365 		return;
366 	}
367 
368 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
369 	bzero(lp, sizeof(struct ldc_pkt));
370 	lp->type = LDC_CTRL;
371 	lp->stype = LDC_INFO;
372 	lp->ctrl = LDC_RTR;
373 	lp->env = LDC_MODE_UNRELIABLE;
374 	lp->seqid = lc->lc_tx_seqid++;
375 
376 	tx_tail += sizeof(*lp);
377 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
378 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
379 	if (err != H_EOK) {
380 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
381 		mutex_exit(&lc->lc_txq->lq_mtx);
382 		return;
383 	}
384 
385 	lc->lc_state = LDC_SND_RTR;
386 	DPRINTF(("ldc_send_rtr() setting lc->lc_state to %d\n", lc->lc_state));
387 	mutex_exit(&lc->lc_txq->lq_mtx);
388 }
389 
390 void
ldc_send_rdx(struct ldc_conn * lc)391 ldc_send_rdx(struct ldc_conn *lc)
392 {
393 	struct ldc_pkt *lp;
394 	uint64_t tx_head, tx_tail, tx_state;
395 	int err;
396 
397 	mutex_enter(&lc->lc_txq->lq_mtx);
398 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
399 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
400 		mutex_exit(&lc->lc_txq->lq_mtx);
401 		return;
402 	}
403 
404 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
405 	bzero(lp, sizeof(struct ldc_pkt));
406 	lp->type = LDC_CTRL;
407 	lp->stype = LDC_INFO;
408 	lp->ctrl = LDC_RDX;
409 	lp->env = LDC_MODE_UNRELIABLE;
410 	lp->seqid = lc->lc_tx_seqid++;
411 
412 	tx_tail += sizeof(*lp);
413 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
414 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
415 	if (err != H_EOK) {
416 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
417 		mutex_exit(&lc->lc_txq->lq_mtx);
418 		return;
419 	}
420 
421 	lc->lc_state = LDC_SND_RDX;
422 	DPRINTF(("ldc_send_rdx() setting lc->lc_state to %d\n", lc->lc_state));
423 	mutex_exit(&lc->lc_txq->lq_mtx);
424 }
425 
426 int
ldc_send_unreliable(struct ldc_conn * lc,void * msg,size_t len)427 ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
428 {
429 	struct ldc_pkt *lp;
430 	uint64_t tx_head, tx_tail, tx_state;
431 	uint64_t tx_avail;
432 	uint8_t *p = msg;
433 	int err;
434 
435 	mutex_enter(&lc->lc_txq->lq_mtx);
436 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
437 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
438 		mutex_exit(&lc->lc_txq->lq_mtx);
439 		return (EIO);
440 	}
441 
442 	tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
443 	    lc->lc_txq->lq_nentries - 1;
444 	tx_avail %= lc->lc_txq->lq_nentries;
445 	if (len > tx_avail * LDC_PKT_PAYLOAD) {
446 		mutex_exit(&lc->lc_txq->lq_mtx);
447 		return (EWOULDBLOCK);
448 	}
449 
450 	while (len > 0) {
451 		lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
452 		bzero(lp, sizeof(struct ldc_pkt));
453 		lp->type = LDC_DATA;
454 		lp->stype = LDC_INFO;
455 		lp->env = uimin(len, LDC_PKT_PAYLOAD);
456 		if (p == msg)
457 			lp->env |= LDC_FRAG_START;
458 		if (len <= LDC_PKT_PAYLOAD)
459 			lp->env |= LDC_FRAG_STOP;
460 		lp->seqid = lc->lc_tx_seqid++;
461 		bcopy(p, &lp->major, uimin(len, LDC_PKT_PAYLOAD));
462 
463 		tx_tail += sizeof(*lp);
464 		tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
465 		err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
466 		if (err != H_EOK) {
467 			printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
468 			mutex_exit(&lc->lc_txq->lq_mtx);
469 			return (EIO);
470 		}
471 		p += uimin(len, LDC_PKT_PAYLOAD);
472 		len -= uimin(len, LDC_PKT_PAYLOAD);
473 	}
474 
475 	mutex_exit(&lc->lc_txq->lq_mtx);
476 	return (0);
477 }
478 
479 void
ldc_reset(struct ldc_conn * lc)480 ldc_reset(struct ldc_conn *lc)
481 {
482 	int err;
483 	vaddr_t va;
484 	paddr_t pa;
485 
486 	DPRINTF(("Resetting connection\n"));
487 
488 	mutex_enter(&lc->lc_txq->lq_mtx);
489 
490 #if OPENBSD_BUSDMA
491 	err = hv_ldc_tx_qconf(lc->lc_id,
492 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
493 #else
494         va = lc->lc_txq->lq_va;
495 	pa = 0;
496 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
497 	  panic("pmap_extract failed %lx\n", va);
498 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
499 #endif
500 	if (err != H_EOK)
501 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
502 
503 #if OPENBSD_BUSDMA
504 	err = hv_ldc_rx_qconf(lc->lc_id,
505 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
506 #else
507         va = lc->lc_rxq->lq_va;
508 	pa = 0;
509 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
510 	  panic("pmap_extract failed %lx\n", va);
511 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
512 #endif
513 	if (err != H_EOK)
514 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
515 
516 	lc->lc_tx_seqid = 0;
517 	lc->lc_state = 0;
518 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
519 	mutex_exit(&lc->lc_txq->lq_mtx);
520 
521 	lc->lc_reset(lc);
522 }
523 #if OPENBSD_BUSDMA
524 struct ldc_queue *
ldc_queue_alloc(bus_dma_tag_t t,int nentries)525 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
526 #else
527 struct ldc_queue *
528 ldc_queue_alloc(int nentries)
529 #endif
530 {
531 	struct ldc_queue *lq;
532 	bus_size_t size;
533 	vaddr_t va = 0;
534 #if OPENBSD_BUSDMA
535 	int nsegs;
536 #endif
537 
538 	lq = kmem_zalloc(sizeof(struct ldc_queue), KM_SLEEP);
539 
540 	mutex_init(&lq->lq_mtx, MUTEX_DEFAULT, IPL_TTY);
541 
542 	size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
543 #if OPENBSD_BUSDMA
544 	if (bus_dmamap_create(t, size, 1, size, 0,
545 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
546 		return (NULL);
547 
548 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
549 	    &nsegs, BUS_DMA_NOWAIT) != 0)
550 		goto destroy;
551 
552 	if (bus_dmamem_map(t, &lq->lq_seg, 1, size, (void *)&va,
553 	    BUS_DMA_NOWAIT) != 0)
554 		goto free;
555 
556 	 if (bus_dmamap_load(t, lq->lq_map, (void*)va, size, NULL,
557 	    BUS_DMA_NOWAIT) != 0)
558 		goto unmap;
559 #else
560 	va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
561 #endif
562 	lq->lq_va = (vaddr_t)va;
563 	lq->lq_nentries = nentries;
564 	return (lq);
565 #if OPENBSD_BUSDMA
566 unmap:
567 	bus_dmamem_unmap(t, (void*)va, size);
568 free:
569 	bus_dmamem_free(t, &lq->lq_seg, 1);
570 destroy:
571 	bus_dmamap_destroy(t, lq->lq_map);
572 #endif
573 	return (NULL);
574 }
575 
576 void
577 #if OPENBSD_BUSDMA
ldc_queue_free(bus_dma_tag_t t,struct ldc_queue * lq)578 ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
579 #else
580 ldc_queue_free(struct ldc_queue *lq)
581 #endif
582 {
583 	bus_size_t size;
584 
585 	size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
586 
587 #if OPENBSD_BUSDMA
588 	bus_dmamap_unload(t, lq->lq_map);
589 	bus_dmamem_unmap(t, &lq->lq_va, size);
590 	bus_dmamem_free(t, &lq->lq_seg, 1);
591 	bus_dmamap_destroy(t, lq->lq_map);
592 #else
593 	kmem_free((void *)lq->lq_va, size);
594 #endif
595 	kmem_free(lq, size);
596 }
597 
598 #if OPENBSD_BUSDMA
599 struct ldc_map *
ldc_map_alloc(bus_dma_tag_t t,int nentries)600 ldc_map_alloc(bus_dma_tag_t t, int nentries)
601 #else
602 struct ldc_map *
603 ldc_map_alloc(int nentries)
604 #endif
605 {
606 	struct ldc_map *lm;
607 	bus_size_t size;
608 	vaddr_t va = 0;
609 
610 #if OPENBSD_BUSDMA
611 	int nsegs;
612 #endif
613 	lm = kmem_zalloc(sizeof(struct ldc_map), KM_SLEEP);
614 	size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
615 
616 #if OPENBSD_BUSDMA
617 	if (bus_dmamap_create(t, size, 1, size, 0,
618 			      BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0) {
619 		DPRINTF(("ldc_map_alloc() - bus_dmamap_create() failed\n"));
620 		return (NULL);
621 	}
622 
623 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
624 			     &nsegs, BUS_DMA_NOWAIT) != 0) {
625 		DPRINTF(("ldc_map_alloc() - bus_dmamem_alloc() failed\n"));
626 		goto destroy;
627 	}
628 
629 	if (bus_dmamem_map(t, &lm->lm_seg, 1, size, (void *)&va,
630 			   BUS_DMA_NOWAIT) != 0) {
631 		DPRINTF(("ldc_map_alloc() - bus_dmamem_map() failed\n"));
632 		goto free;
633 	}
634 	if (bus_dmamap_load(t, lm->lm_map, (void*)va, size, NULL,
635 			    BUS_DMA_NOWAIT) != 0) {
636 		DPRINTF(("ldc_map_alloc() - bus_dmamap_load() failed\n"));
637 		goto unmap;
638 	}
639 #else
640 	va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
641 #endif
642 	lm->lm_slot = (struct ldc_map_slot *)va;
643 	lm->lm_nentries = nentries;
644 	bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
645 	return (lm);
646 
647 #if OPENBSD_BUSDMA
648 unmap:
649 	bus_dmamem_unmap(t, (void*)va, size);
650 free:
651 	bus_dmamem_free(t, &lm->lm_seg, 1);
652 destroy:
653 	bus_dmamap_destroy(t, lm->lm_map);
654 #endif
655 	return (NULL);
656 }
657 
658 #if OPENBSD_BUSDMA
659 void
ldc_map_free(bus_dma_tag_t t,struct ldc_map * lm)660 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
661 #else
662 void
663 ldc_map_free(struct ldc_map *lm)
664 #endif
665 {
666 	bus_size_t size;
667 
668 	size = lm->lm_nentries * sizeof(struct ldc_map_slot);
669 	size = roundup(size, PAGE_SIZE);
670 
671 #if OPENBSD_BUSDMA
672 	bus_dmamap_unload(t, lm->lm_map);
673 	bus_dmamem_unmap(t, lm->lm_slot, size);
674 	bus_dmamem_free(t, &lm->lm_seg, 1);
675 	bus_dmamap_destroy(t, lm->lm_map);
676 #else
677 	kmem_free(lm->lm_slot, size);
678 #endif
679 	kmem_free(lm, size);
680 }
681