ldc.c revision 1.7 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