ldc.c revision 1.10 1 /* $NetBSD: ldc.c,v 1.10 2025/02/06 19:24:37 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/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 int ldc_send_ack(struct ldc_conn *);
42 int ldc_send_rtr(struct ldc_conn *);
43 int ldc_send_rts(struct ldc_conn *);
44 int ldc_send_rdx(struct ldc_conn *);
45
46 void
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
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
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
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
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
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 int
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 EIO;
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 = LDC_VERSION_MAJOR;
265 lp->minor = LDC_VERSION_MINOR;
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 EIO;
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 return 0;
281 }
282
283 int
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 printf("ldc_send_ack() err %d tx_state %lu\n", err, (long unsigned int)tx_state);
295 return EIO;
296 }
297
298 lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
299 bzero(lp, sizeof(struct ldc_pkt));
300 lp->type = LDC_CTRL;
301 lp->stype = LDC_ACK;
302 lp->ctrl = LDC_VERS;
303 lp->major = 1;
304 lp->minor = 0;
305
306 tx_tail += sizeof(*lp);
307 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
308 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
309 if (err != H_EOK) {
310 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
311 mutex_exit(&lc->lc_txq->lq_mtx);
312 return EIO;
313 }
314
315 lc->lc_state = LDC_RCV_VERS;
316 DPRINTF(("ldc_send_ack() setting lc->lc_state to %d\n", lc->lc_state));
317 mutex_exit(&lc->lc_txq->lq_mtx);
318 return 0;
319 }
320
321 int
322 ldc_send_rts(struct ldc_conn *lc)
323 {
324 struct ldc_pkt *lp;
325 uint64_t tx_head, tx_tail, tx_state;
326 int err;
327
328 mutex_enter(&lc->lc_txq->lq_mtx);
329 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
330 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
331 mutex_exit(&lc->lc_txq->lq_mtx);
332 printf("ldc_send_rts() err %d tx_state %lu\n", err, (long unsigned int)tx_state);
333 return EIO;
334 }
335
336 lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
337 bzero(lp, sizeof(struct ldc_pkt));
338 lp->type = LDC_CTRL;
339 lp->stype = LDC_INFO;
340 lp->ctrl = LDC_RTS;
341 lp->env = LDC_MODE_UNRELIABLE;
342 lp->seqid = lc->lc_tx_seqid++;
343
344 tx_tail += sizeof(*lp);
345 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
346 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
347 if (err != H_EOK) {
348 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
349 mutex_exit(&lc->lc_txq->lq_mtx);
350 return EIO;
351 }
352
353 lc->lc_state = LDC_SND_RTS;
354 DPRINTF(("ldc_send_rts() setting lc->lc_state to %d\n", lc->lc_state));
355 mutex_exit(&lc->lc_txq->lq_mtx);
356 return 0;
357 }
358
359 int
360 ldc_send_rtr(struct ldc_conn *lc)
361 {
362 struct ldc_pkt *lp;
363 uint64_t tx_head, tx_tail, tx_state;
364 int err;
365
366 mutex_enter(&lc->lc_txq->lq_mtx);
367 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
368 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
369 mutex_exit(&lc->lc_txq->lq_mtx);
370 printf("ldc_send_rtr() err %d state %lu\n", err, (long unsigned int)tx_state);
371 return EIO;
372 }
373
374 lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
375 bzero(lp, sizeof(struct ldc_pkt));
376 lp->type = LDC_CTRL;
377 lp->stype = LDC_INFO;
378 lp->ctrl = LDC_RTR;
379 lp->env = LDC_MODE_UNRELIABLE;
380 lp->seqid = lc->lc_tx_seqid++;
381
382 tx_tail += sizeof(*lp);
383 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
384 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
385 if (err != H_EOK) {
386 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
387 mutex_exit(&lc->lc_txq->lq_mtx);
388 return EIO;
389 }
390
391 lc->lc_state = LDC_SND_RTR;
392 DPRINTF(("ldc_send_rtr() setting lc->lc_state to %d\n", lc->lc_state));
393 mutex_exit(&lc->lc_txq->lq_mtx);
394 return 0;
395 }
396
397 int
398 ldc_send_rdx(struct ldc_conn *lc)
399 {
400 struct ldc_pkt *lp;
401 uint64_t tx_head, tx_tail, tx_state;
402 int err;
403
404 mutex_enter(&lc->lc_txq->lq_mtx);
405 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
406 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
407 mutex_exit(&lc->lc_txq->lq_mtx);
408 printf("ldc_send_rdx() err %d state %lu\n", err, (long unsigned int)tx_state);
409 return EIO;
410 }
411
412 lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
413 bzero(lp, sizeof(struct ldc_pkt));
414 lp->type = LDC_CTRL;
415 lp->stype = LDC_INFO;
416 lp->ctrl = LDC_RDX;
417 lp->env = LDC_MODE_UNRELIABLE;
418 lp->seqid = lc->lc_tx_seqid++;
419
420 tx_tail += sizeof(*lp);
421 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
422 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
423 if (err != H_EOK) {
424 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
425 mutex_exit(&lc->lc_txq->lq_mtx);
426 return EIO;
427 }
428
429 lc->lc_state = LDC_SND_RDX;
430 DPRINTF(("ldc_send_rdx() setting lc->lc_state to %d\n", lc->lc_state));
431 mutex_exit(&lc->lc_txq->lq_mtx);
432 return 0;
433 }
434
435 int
436 ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
437 {
438 struct ldc_pkt *lp;
439 uint64_t tx_head, tx_tail, tx_state;
440 uint64_t tx_avail;
441 uint8_t *p = msg;
442 int err;
443
444 mutex_enter(&lc->lc_txq->lq_mtx);
445 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
446 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
447 mutex_exit(&lc->lc_txq->lq_mtx);
448 printf("ldc_send_unrealiable() err %d state %lu\n", err, (long unsigned int)tx_state);
449 return (EIO);
450 }
451
452 tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
453 lc->lc_txq->lq_nentries - 1;
454 tx_avail %= lc->lc_txq->lq_nentries;
455 if (len > tx_avail * LDC_PKT_PAYLOAD) {
456 mutex_exit(&lc->lc_txq->lq_mtx);
457 return (EWOULDBLOCK);
458 }
459
460 while (len > 0) {
461 lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
462 bzero(lp, sizeof(struct ldc_pkt));
463 lp->type = LDC_DATA;
464 lp->stype = LDC_INFO;
465 lp->env = uimin(len, LDC_PKT_PAYLOAD);
466 if (p == msg)
467 lp->env |= LDC_FRAG_START;
468 if (len <= LDC_PKT_PAYLOAD)
469 lp->env |= LDC_FRAG_STOP;
470 lp->seqid = lc->lc_tx_seqid++;
471 bcopy(p, &lp->major, uimin(len, LDC_PKT_PAYLOAD));
472
473 tx_tail += sizeof(*lp);
474 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
475 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
476 if (err != H_EOK) {
477 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
478 mutex_exit(&lc->lc_txq->lq_mtx);
479 return (EIO);
480 }
481 p += uimin(len, LDC_PKT_PAYLOAD);
482 len -= uimin(len, LDC_PKT_PAYLOAD);
483 }
484
485 mutex_exit(&lc->lc_txq->lq_mtx);
486 return (0);
487 }
488
489 void
490 ldc_reset(struct ldc_conn *lc)
491 {
492 int err;
493 vaddr_t va;
494 paddr_t pa;
495
496 DPRINTF(("Resetting connection\n"));
497
498 mutex_enter(&lc->lc_txq->lq_mtx);
499
500 #if OPENBSD_BUSDMA
501 err = hv_ldc_tx_qconf(lc->lc_id,
502 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
503 #else
504 va = lc->lc_txq->lq_va;
505 pa = 0;
506 if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
507 panic("pmap_extract failed %lx\n", va);
508 err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
509 #endif
510 if (err != H_EOK)
511 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
512
513 #if OPENBSD_BUSDMA
514 err = hv_ldc_rx_qconf(lc->lc_id,
515 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
516 #else
517 va = lc->lc_rxq->lq_va;
518 pa = 0;
519 if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
520 panic("pmap_extract failed %lx\n", va);
521 err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
522 #endif
523 if (err != H_EOK)
524 printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
525
526 lc->lc_tx_seqid = 0;
527 lc->lc_state = 0;
528 lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
529 mutex_exit(&lc->lc_txq->lq_mtx);
530
531 lc->lc_reset(lc);
532 }
533 #if OPENBSD_BUSDMA
534 struct ldc_queue *
535 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
536 #else
537 struct ldc_queue *
538 ldc_queue_alloc(int nentries)
539 #endif
540 {
541 struct ldc_queue *lq;
542 bus_size_t size;
543 vaddr_t va = 0;
544 #if OPENBSD_BUSDMA
545 int nsegs;
546 #endif
547
548 lq = kmem_zalloc(sizeof(struct ldc_queue), KM_SLEEP);
549
550 mutex_init(&lq->lq_mtx, MUTEX_DEFAULT, IPL_TTY);
551
552 size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
553 #if OPENBSD_BUSDMA
554 if (bus_dmamap_create(t, size, 1, size, 0,
555 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
556 return (NULL);
557
558 if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
559 &nsegs, BUS_DMA_NOWAIT) != 0)
560 goto destroy;
561
562 if (bus_dmamem_map(t, &lq->lq_seg, 1, size, (void *)&va,
563 BUS_DMA_NOWAIT) != 0)
564 goto free;
565
566 if (bus_dmamap_load(t, lq->lq_map, (void*)va, size, NULL,
567 BUS_DMA_NOWAIT) != 0)
568 goto unmap;
569 #else
570 va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
571 #endif
572 lq->lq_va = (vaddr_t)va;
573 lq->lq_nentries = nentries;
574 return (lq);
575 #if OPENBSD_BUSDMA
576 unmap:
577 bus_dmamem_unmap(t, (void*)va, size);
578 free:
579 bus_dmamem_free(t, &lq->lq_seg, 1);
580 destroy:
581 bus_dmamap_destroy(t, lq->lq_map);
582 #endif
583 return (NULL);
584 }
585
586 void
587 #if OPENBSD_BUSDMA
588 ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
589 #else
590 ldc_queue_free(struct ldc_queue *lq)
591 #endif
592 {
593 bus_size_t size;
594
595 size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
596
597 #if OPENBSD_BUSDMA
598 bus_dmamap_unload(t, lq->lq_map);
599 bus_dmamem_unmap(t, &lq->lq_va, size);
600 bus_dmamem_free(t, &lq->lq_seg, 1);
601 bus_dmamap_destroy(t, lq->lq_map);
602 #else
603 kmem_free((void *)lq->lq_va, size);
604 #endif
605 kmem_free(lq, size);
606 }
607
608 #if OPENBSD_BUSDMA
609 struct ldc_map *
610 ldc_map_alloc(bus_dma_tag_t t, int nentries)
611 #else
612 struct ldc_map *
613 ldc_map_alloc(int nentries)
614 #endif
615 {
616 struct ldc_map *lm;
617 bus_size_t size;
618 vaddr_t va = 0;
619
620 #if OPENBSD_BUSDMA
621 int nsegs;
622 #endif
623 lm = kmem_zalloc(sizeof(struct ldc_map), KM_SLEEP);
624 size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
625
626 #if OPENBSD_BUSDMA
627 if (bus_dmamap_create(t, size, 1, size, 0,
628 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0) {
629 DPRINTF(("ldc_map_alloc() - bus_dmamap_create() failed\n"));
630 return (NULL);
631 }
632
633 if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
634 &nsegs, BUS_DMA_NOWAIT) != 0) {
635 DPRINTF(("ldc_map_alloc() - bus_dmamem_alloc() failed\n"));
636 goto destroy;
637 }
638
639 if (bus_dmamem_map(t, &lm->lm_seg, 1, size, (void *)&va,
640 BUS_DMA_NOWAIT) != 0) {
641 DPRINTF(("ldc_map_alloc() - bus_dmamem_map() failed\n"));
642 goto free;
643 }
644 if (bus_dmamap_load(t, lm->lm_map, (void*)va, size, NULL,
645 BUS_DMA_NOWAIT) != 0) {
646 DPRINTF(("ldc_map_alloc() - bus_dmamap_load() failed\n"));
647 goto unmap;
648 }
649 #else
650 va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
651 #endif
652 lm->lm_slot = (struct ldc_map_slot *)va;
653 lm->lm_nentries = nentries;
654 bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
655 return (lm);
656
657 #if OPENBSD_BUSDMA
658 unmap:
659 bus_dmamem_unmap(t, (void*)va, size);
660 free:
661 bus_dmamem_free(t, &lm->lm_seg, 1);
662 destroy:
663 bus_dmamap_destroy(t, lm->lm_map);
664 #endif
665 return (NULL);
666 }
667
668 #if OPENBSD_BUSDMA
669 void
670 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
671 #else
672 void
673 ldc_map_free(struct ldc_map *lm)
674 #endif
675 {
676 bus_size_t size;
677
678 size = lm->lm_nentries * sizeof(struct ldc_map_slot);
679 size = roundup(size, PAGE_SIZE);
680
681 #if OPENBSD_BUSDMA
682 bus_dmamap_unload(t, lm->lm_map);
683 bus_dmamem_unmap(t, lm->lm_slot, size);
684 bus_dmamem_free(t, &lm->lm_seg, 1);
685 bus_dmamap_destroy(t, lm->lm_map);
686 #else
687 kmem_free(lm->lm_slot, size);
688 #endif
689 kmem_free(lm, size);
690 }
691