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 36void ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *); 37void ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *); 38void ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *); 39void ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *); 40 41void ldc_send_ack(struct ldc_conn *); 42void ldc_send_rtr(struct ldc_conn *); 43void ldc_send_rts(struct ldc_conn *); 44void ldc_send_rdx(struct ldc_conn *); 45 46void 47ldc_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 73void 74ldc_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 111void 112ldc_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 143void 144ldc_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 176void 177ldc_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 208void 209ldc_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 245void 246ldc_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 282void 283ldc_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 318void 319ldc_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 354void 355ldc_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 390void 391ldc_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 426int 427ldc_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 479void 480ldc_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 524struct ldc_queue * 525ldc_queue_alloc(bus_dma_tag_t t, int nentries) 526#else 527struct ldc_queue * 528ldc_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 566unmap: 567 bus_dmamem_unmap(t, (void*)va, size); 568free: 569 bus_dmamem_free(t, &lq->lq_seg, 1); 570destroy: 571 bus_dmamap_destroy(t, lq->lq_map); 572#endif 573 return (NULL); 574} 575 576void 577#if OPENBSD_BUSDMA 578ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq) 579#else 580ldc_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 599struct ldc_map * 600ldc_map_alloc(bus_dma_tag_t t, int nentries) 601#else 602struct ldc_map * 603ldc_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 648unmap: 649 bus_dmamem_unmap(t, (void*)va, size); 650free: 651 bus_dmamem_free(t, &lm->lm_seg, 1); 652destroy: 653 bus_dmamap_destroy(t, lm->lm_map); 654#endif 655 return (NULL); 656} 657 658#if OPENBSD_BUSDMA 659void 660ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm) 661#else 662void 663ldc_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