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