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
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 int
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 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
ldc_send_ack(struct ldc_conn * lc)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
ldc_send_rts(struct ldc_conn * lc)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
ldc_send_rtr(struct ldc_conn * lc)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
ldc_send_rdx(struct ldc_conn * lc)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
ldc_send_unreliable(struct ldc_conn * lc,void * msg,size_t len)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
ldc_reset(struct ldc_conn * lc)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 *
ldc_queue_alloc(bus_dma_tag_t t,int nentries)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
ldc_queue_free(bus_dma_tag_t t,struct ldc_queue * lq)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 *
ldc_map_alloc(bus_dma_tag_t t,int nentries)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
ldc_map_free(bus_dma_tag_t t,struct ldc_map * lm)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