ldc.c revision 1.3
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 37void ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *); 38void ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *); 39void ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *); 40void ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *); 41 42void ldc_send_ack(struct ldc_conn *); 43void ldc_send_rtr(struct ldc_conn *); 44void ldc_send_rts(struct ldc_conn *); 45void ldc_send_rdx(struct ldc_conn *); 46 47void 48ldc_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 74void 75ldc_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 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 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 280void 281ldc_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 315void 316ldc_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 350void 351ldc_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 385void 386ldc_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 420int 421ldc_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 473void 474ldc_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 518struct ldc_queue * 519ldc_queue_alloc(bus_dma_tag_t t, int nentries) 520#else 521struct ldc_queue * 522ldc_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 564unmap: 565 bus_dmamem_unmap(t, (void*)va, size); 566free: 567 bus_dmamem_free(t, &lq->lq_seg, 1); 568destroy: 569 bus_dmamap_destroy(t, lq->lq_map); 570#else 571free: 572 kmem_free(lq, sizeof(struct ldc_queue)); 573#endif 574 return (NULL); 575} 576 577void 578#if OPENBSD_BUSDMA 579ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq) 580#else 581ldc_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 600struct ldc_map * 601ldc_map_alloc(bus_dma_tag_t t, int nentries) 602#else 603struct ldc_map * 604ldc_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 654unmap: 655 bus_dmamem_unmap(t, (void*)va, size); 656free: 657 bus_dmamem_free(t, &lm->lm_seg, 1); 658destroy: 659 bus_dmamap_destroy(t, lm->lm_map); 660#else 661free: 662 kmem_free(lm, sizeof(struct ldc_map)); 663#endif 664 return (NULL); 665} 666 667#if OPENBSD_BUSDMA 668void 669ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm) 670#else 671void 672ldc_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