ldc.c revision 1.3
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
37void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
38void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
39void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
40void	ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
41
42void	ldc_send_ack(struct ldc_conn *);
43void	ldc_send_rtr(struct ldc_conn *);
44void	ldc_send_rts(struct ldc_conn *);
45void	ldc_send_rdx(struct ldc_conn *);
46
47void
48ldc_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
74void
75ldc_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
111void
112ldc_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
143void
144ldc_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
176void
177ldc_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
208void
209ldc_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
245void
246ldc_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
280void
281ldc_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
315void
316ldc_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
350void
351ldc_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
385void
386ldc_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
420int
421ldc_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
473void
474ldc_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
518struct ldc_queue *
519ldc_queue_alloc(bus_dma_tag_t t, int nentries)
520#else
521struct ldc_queue *
522ldc_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
564unmap:
565	bus_dmamem_unmap(t, (void*)va, size);
566free:
567	bus_dmamem_free(t, &lq->lq_seg, 1);
568destroy:
569	bus_dmamap_destroy(t, lq->lq_map);
570#else
571free:
572	kmem_free(lq, sizeof(struct ldc_queue));
573#endif
574	return (NULL);
575}
576
577void
578#if OPENBSD_BUSDMA
579ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
580#else
581ldc_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
600struct ldc_map *
601ldc_map_alloc(bus_dma_tag_t t, int nentries)
602#else
603struct ldc_map *
604ldc_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
654unmap:
655	bus_dmamem_unmap(t, (void*)va, size);
656free:
657	bus_dmamem_free(t, &lm->lm_seg, 1);
658destroy:
659	bus_dmamap_destroy(t, lm->lm_map);
660#else
661free:
662	kmem_free(lm, sizeof(struct ldc_map));
663#endif
664	return (NULL);
665}
666
667#if OPENBSD_BUSDMA
668void
669ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
670#else
671void
672ldc_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