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
36void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
37void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
38void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
39void	ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
40
41void	ldc_send_ack(struct ldc_conn *);
42void	ldc_send_rtr(struct ldc_conn *);
43void	ldc_send_rts(struct ldc_conn *);
44void	ldc_send_rdx(struct ldc_conn *);
45
46void
47ldc_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
73void
74ldc_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
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	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
282void
283ldc_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
318void
319ldc_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
354void
355ldc_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
390void
391ldc_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
426int
427ldc_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
479void
480ldc_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
524struct ldc_queue *
525ldc_queue_alloc(bus_dma_tag_t t, int nentries)
526#else
527struct ldc_queue *
528ldc_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
566unmap:
567	bus_dmamem_unmap(t, (void*)va, size);
568free:
569	bus_dmamem_free(t, &lq->lq_seg, 1);
570destroy:
571	bus_dmamap_destroy(t, lq->lq_map);
572#endif
573	return (NULL);
574}
575
576void
577#if OPENBSD_BUSDMA
578ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
579#else
580ldc_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
599struct ldc_map *
600ldc_map_alloc(bus_dma_tag_t t, int nentries)
601#else
602struct ldc_map *
603ldc_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
648unmap:
649	bus_dmamem_unmap(t, (void*)va, size);
650free:
651	bus_dmamem_free(t, &lm->lm_seg, 1);
652destroy:
653	bus_dmamap_destroy(t, lm->lm_map);
654#endif
655	return (NULL);
656}
657
658#if OPENBSD_BUSDMA
659void
660ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
661#else
662void
663ldc_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