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