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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 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