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