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