1 /* $OpenBSD: ldc.c,v 1.14 2016/10/13 18:40:47 tom Exp $ */
2 /*
3 * Copyright (c) 2009 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21
22 #include <machine/bus.h>
23 #include <machine/hypervisor.h>
24
25 #include <sparc64/dev/ldcvar.h>
26
27 #ifdef LDC_DEBUG
28 #define DPRINTF(x) printf x
29 #else
30 #define DPRINTF(x)
31 #endif
32
33 void ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
34 void ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
35 void ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
36 void ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
37
38 void ldc_send_ack(struct ldc_conn *);
39 void ldc_send_rtr(struct ldc_conn *);
40 void ldc_send_rts(struct ldc_conn *);
41 void ldc_send_rdx(struct ldc_conn *);
42
43 void
ldc_rx_ctrl(struct ldc_conn * lc,struct ldc_pkt * lp)44 ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
45 {
46 switch (lp->ctrl) {
47 case LDC_VERS:
48 ldc_rx_ctrl_vers(lc, lp);
49 break;
50
51 case LDC_RTS:
52 ldc_rx_ctrl_rts(lc, lp);
53 break;
54
55 case LDC_RTR:
56 ldc_rx_ctrl_rtr(lc, lp);
57 break;
58
59 case LDC_RDX:
60 ldc_rx_ctrl_rdx(lc, lp);
61 break;
62
63 default:
64 DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
65 ldc_reset(lc);
66 break;
67 }
68 }
69
70 void
ldc_rx_ctrl_vers(struct ldc_conn * lc,struct ldc_pkt * lp)71 ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
72 {
73 switch (lp->stype) {
74 case LDC_INFO:
75 DPRINTF(("CTRL/INFO/VERS\n"));
76 if (lp->major == LDC_VERSION_MAJOR &&
77 lp->minor == LDC_VERSION_MINOR)
78 ldc_send_ack(lc);
79 else
80 /* XXX do nothing for now. */
81 ;
82 break;
83
84 case LDC_ACK:
85 if (lc->lc_state != LDC_SND_VERS) {
86 DPRINTF(("Spurious CTRL/ACK/VERS: state %d\n",
87 lc->lc_state));
88 ldc_reset(lc);
89 return;
90 }
91 DPRINTF(("CTRL/ACK/VERS\n"));
92 ldc_send_rts(lc);
93 break;
94
95 case LDC_NACK:
96 DPRINTF(("CTRL/NACK/VERS\n"));
97 ldc_reset(lc);
98 break;
99
100 default:
101 DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
102 ldc_reset(lc);
103 break;
104 }
105 }
106
107 void
ldc_rx_ctrl_rts(struct ldc_conn * lc,struct ldc_pkt * lp)108 ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
109 {
110 switch (lp->stype) {
111 case LDC_INFO:
112 if (lc->lc_state != LDC_RCV_VERS) {
113 DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n",
114 lc->lc_state));
115 ldc_reset(lc);
116 return;
117 }
118 DPRINTF(("CTRL/INFO/RTS\n"));
119 ldc_send_rtr(lc);
120 break;
121
122 case LDC_ACK:
123 DPRINTF(("CTRL/ACK/RTS\n"));
124 ldc_reset(lc);
125 break;
126
127 case LDC_NACK:
128 DPRINTF(("CTRL/NACK/RTS\n"));
129 ldc_reset(lc);
130 break;
131
132 default:
133 DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
134 ldc_reset(lc);
135 break;
136 }
137 }
138
139 void
ldc_rx_ctrl_rtr(struct ldc_conn * lc,struct ldc_pkt * lp)140 ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
141 {
142 switch (lp->stype) {
143 case LDC_INFO:
144 if (lc->lc_state != LDC_SND_RTS) {
145 DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
146 lc->lc_state));
147 ldc_reset(lc);
148 return;
149 }
150 DPRINTF(("CTRL/INFO/RTR\n"));
151 ldc_send_rdx(lc);
152 lc->lc_start(lc);
153 break;
154
155 case LDC_ACK:
156 DPRINTF(("CTRL/ACK/RTR\n"));
157 ldc_reset(lc);
158 break;
159
160 case LDC_NACK:
161 DPRINTF(("CTRL/NACK/RTR\n"));
162 ldc_reset(lc);
163 break;
164
165 default:
166 DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
167 ldc_reset(lc);
168 break;
169 }
170 }
171
172 void
ldc_rx_ctrl_rdx(struct ldc_conn * lc,struct ldc_pkt * lp)173 ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp)
174 {
175 switch (lp->stype) {
176 case LDC_INFO:
177 if (lc->lc_state != LDC_SND_RTR) {
178 DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
179 lc->lc_state));
180 ldc_reset(lc);
181 return;
182 }
183 DPRINTF(("CTRL/INFO/RDX\n"));
184 lc->lc_start(lc);
185 break;
186
187 case LDC_ACK:
188 DPRINTF(("CTRL/ACK/RDX\n"));
189 ldc_reset(lc);
190 break;
191
192 case LDC_NACK:
193 DPRINTF(("CTRL/NACK/RDX\n"));
194 ldc_reset(lc);
195 break;
196
197 default:
198 DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype));
199 ldc_reset(lc);
200 break;
201 }
202 }
203
204 void
ldc_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)205 ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
206 {
207 size_t len;
208
209 if (lp->stype != LDC_INFO) {
210 DPRINTF(("DATA/0x%02x\n", lp->stype));
211 ldc_reset(lc);
212 return;
213 }
214
215 if (lc->lc_state != LDC_SND_RTR &&
216 lc->lc_state != LDC_SND_RDX) {
217 DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
218 ldc_reset(lc);
219 return;
220 }
221
222 if (lp->env & LDC_FRAG_START) {
223 lc->lc_len = (lp->env & LDC_LEN_MASK) + 8;
224 KASSERT(lc->lc_len <= sizeof(lc->lc_msg));
225 memcpy((uint8_t *)lc->lc_msg, lp, lc->lc_len);
226 } else {
227 len = (lp->env & LDC_LEN_MASK);
228 if (lc->lc_len + len > sizeof(lc->lc_msg)) {
229 DPRINTF(("Buffer overrun\n"));
230 ldc_reset(lc);
231 return;
232 }
233 memcpy(((uint8_t *)lc->lc_msg) + lc->lc_len, &lp->major, len);
234 lc->lc_len += len;
235 }
236
237 if (lp->env & LDC_FRAG_STOP)
238 lc->lc_rx_data(lc, (struct ldc_pkt *)lc->lc_msg);
239 }
240
241 void
ldc_send_vers(struct ldc_conn * lc)242 ldc_send_vers(struct ldc_conn *lc)
243 {
244 struct ldc_pkt *lp;
245 uint64_t tx_head, tx_tail, tx_state;
246 int err;
247
248 mtx_enter(&lc->lc_txq->lq_mtx);
249 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
250 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
251 mtx_leave(&lc->lc_txq->lq_mtx);
252 return;
253 }
254
255 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
256 bzero(lp, sizeof(struct ldc_pkt));
257 lp->type = LDC_CTRL;
258 lp->stype = LDC_INFO;
259 lp->ctrl = LDC_VERS;
260 lp->major = 1;
261 lp->minor = 0;
262
263 tx_tail += sizeof(*lp);
264 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
265 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
266 if (err != H_EOK) {
267 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
268 mtx_leave(&lc->lc_txq->lq_mtx);
269 return;
270 }
271
272 lc->lc_state = LDC_SND_VERS;
273 mtx_leave(&lc->lc_txq->lq_mtx);
274 }
275
276 void
ldc_send_ack(struct ldc_conn * lc)277 ldc_send_ack(struct ldc_conn *lc)
278 {
279 struct ldc_pkt *lp;
280 uint64_t tx_head, tx_tail, tx_state;
281 int err;
282
283 mtx_enter(&lc->lc_txq->lq_mtx);
284 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
285 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
286 mtx_leave(&lc->lc_txq->lq_mtx);
287 return;
288 }
289
290 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
291 bzero(lp, sizeof(struct ldc_pkt));
292 lp->type = LDC_CTRL;
293 lp->stype = LDC_ACK;
294 lp->ctrl = LDC_VERS;
295 lp->major = 1;
296 lp->minor = 0;
297
298 tx_tail += sizeof(*lp);
299 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
300 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
301 if (err != H_EOK) {
302 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
303 mtx_leave(&lc->lc_txq->lq_mtx);
304 return;
305 }
306
307 lc->lc_state = LDC_RCV_VERS;
308 mtx_leave(&lc->lc_txq->lq_mtx);
309 }
310
311 void
ldc_send_rts(struct ldc_conn * lc)312 ldc_send_rts(struct ldc_conn *lc)
313 {
314 struct ldc_pkt *lp;
315 uint64_t tx_head, tx_tail, tx_state;
316 int err;
317
318 mtx_enter(&lc->lc_txq->lq_mtx);
319 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
320 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
321 mtx_leave(&lc->lc_txq->lq_mtx);
322 return;
323 }
324
325 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
326 bzero(lp, sizeof(struct ldc_pkt));
327 lp->type = LDC_CTRL;
328 lp->stype = LDC_INFO;
329 lp->ctrl = LDC_RTS;
330 lp->env = LDC_MODE_UNRELIABLE;
331 lp->seqid = lc->lc_tx_seqid++;
332
333 tx_tail += sizeof(*lp);
334 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
335 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
336 if (err != H_EOK) {
337 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
338 mtx_leave(&lc->lc_txq->lq_mtx);
339 return;
340 }
341
342 lc->lc_state = LDC_SND_RTS;
343 mtx_leave(&lc->lc_txq->lq_mtx);
344 }
345
346 void
ldc_send_rtr(struct ldc_conn * lc)347 ldc_send_rtr(struct ldc_conn *lc)
348 {
349 struct ldc_pkt *lp;
350 uint64_t tx_head, tx_tail, tx_state;
351 int err;
352
353 mtx_enter(&lc->lc_txq->lq_mtx);
354 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
355 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
356 mtx_leave(&lc->lc_txq->lq_mtx);
357 return;
358 }
359
360 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
361 bzero(lp, sizeof(struct ldc_pkt));
362 lp->type = LDC_CTRL;
363 lp->stype = LDC_INFO;
364 lp->ctrl = LDC_RTR;
365 lp->env = LDC_MODE_UNRELIABLE;
366 lp->seqid = lc->lc_tx_seqid++;
367
368 tx_tail += sizeof(*lp);
369 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
370 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
371 if (err != H_EOK) {
372 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
373 mtx_leave(&lc->lc_txq->lq_mtx);
374 return;
375 }
376
377 lc->lc_state = LDC_SND_RTR;
378 mtx_leave(&lc->lc_txq->lq_mtx);
379 }
380
381 void
ldc_send_rdx(struct ldc_conn * lc)382 ldc_send_rdx(struct ldc_conn *lc)
383 {
384 struct ldc_pkt *lp;
385 uint64_t tx_head, tx_tail, tx_state;
386 int err;
387
388 mtx_enter(&lc->lc_txq->lq_mtx);
389 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
390 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
391 mtx_leave(&lc->lc_txq->lq_mtx);
392 return;
393 }
394
395 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
396 bzero(lp, sizeof(struct ldc_pkt));
397 lp->type = LDC_CTRL;
398 lp->stype = LDC_INFO;
399 lp->ctrl = LDC_RDX;
400 lp->env = LDC_MODE_UNRELIABLE;
401 lp->seqid = lc->lc_tx_seqid++;
402
403 tx_tail += sizeof(*lp);
404 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
405 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
406 if (err != H_EOK) {
407 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
408 mtx_leave(&lc->lc_txq->lq_mtx);
409 return;
410 }
411
412 lc->lc_state = LDC_SND_RDX;
413 mtx_leave(&lc->lc_txq->lq_mtx);
414 }
415
416 int
ldc_send_unreliable(struct ldc_conn * lc,void * msg,size_t len)417 ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
418 {
419 struct ldc_pkt *lp;
420 uint64_t tx_head, tx_tail, tx_state;
421 uint64_t tx_avail;
422 uint8_t *p = msg;
423 int err;
424
425 mtx_enter(&lc->lc_txq->lq_mtx);
426 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
427 if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
428 mtx_leave(&lc->lc_txq->lq_mtx);
429 return (EIO);
430 }
431
432 tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
433 lc->lc_txq->lq_nentries - 1;
434 tx_avail %= lc->lc_txq->lq_nentries;
435 if (len > tx_avail * LDC_PKT_PAYLOAD) {
436 mtx_leave(&lc->lc_txq->lq_mtx);
437 return (EWOULDBLOCK);
438 }
439
440 while (len > 0) {
441 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
442 bzero(lp, sizeof(struct ldc_pkt));
443 lp->type = LDC_DATA;
444 lp->stype = LDC_INFO;
445 lp->env = min(len, LDC_PKT_PAYLOAD);
446 if (p == msg)
447 lp->env |= LDC_FRAG_START;
448 if (len <= LDC_PKT_PAYLOAD)
449 lp->env |= LDC_FRAG_STOP;
450 lp->seqid = lc->lc_tx_seqid++;
451 bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD));
452
453 tx_tail += sizeof(*lp);
454 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
455 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
456 if (err != H_EOK) {
457 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
458 mtx_leave(&lc->lc_txq->lq_mtx);
459 return (EIO);
460 }
461 p += min(len, LDC_PKT_PAYLOAD);
462 len -= min(len, LDC_PKT_PAYLOAD);
463 }
464
465 mtx_leave(&lc->lc_txq->lq_mtx);
466 return (0);
467 }
468
469 void
ldc_reset(struct ldc_conn * lc)470 ldc_reset(struct ldc_conn *lc)
471 {
472 int err;
473
474 DPRINTF(("Resetting connection\n"));
475
476 mtx_enter(&lc->lc_txq->lq_mtx);
477 err = hv_ldc_tx_qconf(lc->lc_id,
478 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
479 if (err != H_EOK)
480 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
481
482 err = hv_ldc_rx_qconf(lc->lc_id,
483 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
484 if (err != H_EOK)
485 printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
486
487 lc->lc_tx_seqid = 0;
488 lc->lc_state = 0;
489 lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
490 mtx_leave(&lc->lc_txq->lq_mtx);
491
492 lc->lc_reset(lc);
493 }
494
495 struct ldc_queue *
ldc_queue_alloc(bus_dma_tag_t t,int nentries)496 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
497 {
498 struct ldc_queue *lq;
499 bus_size_t size;
500 caddr_t va;
501 int nsegs;
502
503 lq = malloc(sizeof(struct ldc_queue), M_DEVBUF, M_NOWAIT);
504 if (lq == NULL)
505 return NULL;
506
507 mtx_init(&lq->lq_mtx, IPL_TTY);
508
509 size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
510
511 if (bus_dmamap_create(t, size, 1, size, 0,
512 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
513 goto error;
514
515 if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
516 &nsegs, BUS_DMA_NOWAIT) != 0)
517 goto destroy;
518
519 if (bus_dmamem_map(t, &lq->lq_seg, 1, size, &va,
520 BUS_DMA_NOWAIT) != 0)
521 goto free;
522
523 if (bus_dmamap_load(t, lq->lq_map, va, size, NULL,
524 BUS_DMA_NOWAIT) != 0)
525 goto unmap;
526
527 lq->lq_va = va;
528 lq->lq_nentries = nentries;
529 return (lq);
530
531 unmap:
532 bus_dmamem_unmap(t, va, size);
533 free:
534 bus_dmamem_free(t, &lq->lq_seg, 1);
535 destroy:
536 bus_dmamap_destroy(t, lq->lq_map);
537 error:
538 free(lq, M_DEVBUF, sizeof(struct ldc_queue));
539
540 return (NULL);
541 }
542
543 void
ldc_queue_free(bus_dma_tag_t t,struct ldc_queue * lq)544 ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
545 {
546 bus_size_t size;
547
548 size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
549
550 bus_dmamap_unload(t, lq->lq_map);
551 bus_dmamem_unmap(t, lq->lq_va, size);
552 bus_dmamem_free(t, &lq->lq_seg, 1);
553 bus_dmamap_destroy(t, lq->lq_map);
554 free(lq, M_DEVBUF, 0);
555 }
556
557 struct ldc_map *
ldc_map_alloc(bus_dma_tag_t t,int nentries)558 ldc_map_alloc(bus_dma_tag_t t, int nentries)
559 {
560 struct ldc_map *lm;
561 bus_size_t size;
562 caddr_t va;
563 int nsegs;
564
565 lm = malloc(sizeof(struct ldc_map), M_DEVBUF, M_NOWAIT);
566 if (lm == NULL)
567 return NULL;
568
569 size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
570
571 if (bus_dmamap_create(t, size, 1, size, 0,
572 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0)
573 goto error;
574
575 if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
576 &nsegs, BUS_DMA_NOWAIT) != 0)
577 goto destroy;
578
579 if (bus_dmamem_map(t, &lm->lm_seg, 1, size, &va,
580 BUS_DMA_NOWAIT) != 0)
581 goto free;
582
583 if (bus_dmamap_load(t, lm->lm_map, va, size, NULL,
584 BUS_DMA_NOWAIT) != 0)
585 goto unmap;
586
587 lm->lm_slot = (struct ldc_map_slot *)va;
588 lm->lm_nentries = nentries;
589 bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
590 return (lm);
591
592 unmap:
593 bus_dmamem_unmap(t, va, size);
594 free:
595 bus_dmamem_free(t, &lm->lm_seg, 1);
596 destroy:
597 bus_dmamap_destroy(t, lm->lm_map);
598 error:
599 free(lm, M_DEVBUF, sizeof(struct ldc_map));
600
601 return (NULL);
602 }
603
604 void
ldc_map_free(bus_dma_tag_t t,struct ldc_map * lm)605 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
606 {
607 bus_size_t size;
608
609 size = lm->lm_nentries * sizeof(struct ldc_map_slot);
610 size = roundup(size, PAGE_SIZE);
611
612 bus_dmamap_unload(t, lm->lm_map);
613 bus_dmamem_unmap(t, (caddr_t)lm->lm_slot, size);
614 bus_dmamem_free(t, &lm->lm_seg, 1);
615 bus_dmamap_destroy(t, lm->lm_map);
616 free(lm, M_DEVBUF, 0);
617 }
618