1 /* $OpenBSD: vldcp.c,v 1.22 2021/10/24 17:05:04 mpi Exp $ */ 2 /* 3 * Copyright (c) 2009, 2012 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/conf.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 #include <sys/poll.h> 23 #include <sys/proc.h> 24 #include <sys/systm.h> 25 26 #include <machine/autoconf.h> 27 #include <machine/hypervisor.h> 28 #include <machine/mdesc.h> 29 30 #include <uvm/uvm_extern.h> 31 32 #include <sparc64/dev/cbusvar.h> 33 #include <sparc64/dev/ldcvar.h> 34 35 #ifdef VLDCP_DEBUG 36 #define DPRINTF(x) printf x 37 #else 38 #define DPRINTF(x) 39 #endif 40 41 #include <sys/ioccom.h> 42 43 struct hv_io { 44 uint64_t hi_cookie; 45 void *hi_addr; 46 size_t hi_len; 47 }; 48 49 #define HVIOCREAD _IOW('h', 0, struct hv_io) 50 #define HVIOCWRITE _IOW('h', 1, struct hv_io) 51 52 #define VLDCP_TX_ENTRIES 128 53 #define VLDCP_RX_ENTRIES 128 54 55 struct vldcp_softc { 56 struct device sc_dv; 57 bus_space_tag_t sc_bustag; 58 bus_dma_tag_t sc_dmatag; 59 60 uint64_t sc_tx_ino; 61 uint64_t sc_rx_ino; 62 void *sc_tx_ih; 63 void *sc_rx_ih; 64 65 struct ldc_conn sc_lc; 66 67 struct selinfo sc_rsel; 68 struct selinfo sc_wsel; 69 }; 70 71 int vldcp_match(struct device *, void *, void *); 72 void vldcp_attach(struct device *, struct device *, void *); 73 void filt_vldcprdetach(struct knote *); 74 void filt_vldcpwdetach(struct knote *); 75 int filt_vldcpread(struct knote *, long); 76 int filt_vldcpwrite(struct knote *, long); 77 int vldcpkqfilter(dev_t, struct knote *); 78 79 const struct cfattach vldcp_ca = { 80 sizeof(struct vldcp_softc), vldcp_match, vldcp_attach 81 }; 82 83 struct cfdriver vldcp_cd = { 84 NULL, "vldcp", DV_DULL 85 }; 86 87 int vldcp_tx_intr(void *); 88 int vldcp_rx_intr(void *); 89 90 /* 91 * We attach to certain well-known channels. These are assigned fixed 92 * device minor device numbers through their index in the table below. 93 * So "hvctl" gets minor 0, "spds" gets minor 1, etc. etc. 94 * 95 * We also attach to the domain services channels. These are named 96 * "ldom-<guestname>" and get assigned a device minor starting at 97 * VLDC_LDOM_OFFSET. 98 */ 99 #define VLDC_NUM_SERVICES 64 100 #define VLDC_LDOM_OFFSET 32 101 int vldc_num_ldoms; 102 103 struct vldc_svc { 104 const char *vs_name; 105 struct vldcp_softc *vs_sc; 106 }; 107 108 struct vldc_svc vldc_svc[VLDC_NUM_SERVICES] = { 109 { "hvctl" }, 110 { "spds" }, 111 { NULL } 112 }; 113 114 int 115 vldcp_match(struct device *parent, void *match, void *aux) 116 { 117 struct cbus_attach_args *ca = aux; 118 struct vldc_svc *svc; 119 120 for (svc = vldc_svc; svc->vs_name != NULL; svc++) 121 if (strcmp(ca->ca_name, svc->vs_name) == 0) 122 return (1); 123 124 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 125 strcmp(ca->ca_name, "ldom-primary") != 0) 126 return (1); 127 128 return (0); 129 } 130 131 void 132 vldcp_attach(struct device *parent, struct device *self, void *aux) 133 { 134 struct vldcp_softc *sc = (struct vldcp_softc *)self; 135 struct cbus_attach_args *ca = aux; 136 struct vldc_svc *svc; 137 struct ldc_conn *lc; 138 139 sc->sc_bustag = ca->ca_bustag; 140 sc->sc_dmatag = ca->ca_dmatag; 141 sc->sc_tx_ino = ca->ca_tx_ino; 142 sc->sc_rx_ino = ca->ca_rx_ino; 143 144 printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino); 145 146 /* 147 * Un-configure queues before registering interrupt handlers, 148 * such that we dont get any stale LDC packets or events. 149 */ 150 hv_ldc_tx_qconf(ca->ca_id, 0, 0); 151 hv_ldc_rx_qconf(ca->ca_id, 0, 0); 152 153 sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino, 154 IPL_TTY, 0, vldcp_tx_intr, sc, sc->sc_dv.dv_xname); 155 sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino, 156 IPL_TTY, 0, vldcp_rx_intr, sc, sc->sc_dv.dv_xname); 157 if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) { 158 printf(", can't establish interrupt\n"); 159 return; 160 } 161 162 lc = &sc->sc_lc; 163 lc->lc_id = ca->ca_id; 164 lc->lc_sc = sc; 165 166 lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_TX_ENTRIES); 167 if (lc->lc_txq == NULL) { 168 printf(", can't allocate tx queue\n"); 169 return; 170 } 171 172 lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_RX_ENTRIES); 173 if (lc->lc_rxq == NULL) { 174 printf(", can't allocate rx queue\n"); 175 goto free_txqueue; 176 } 177 lc->lc_rx_state = LDC_CHANNEL_INIT; 178 179 for (svc = vldc_svc; svc->vs_name != NULL; svc++) { 180 if (strcmp(ca->ca_name, svc->vs_name) == 0) { 181 svc->vs_sc = sc; 182 break; 183 } 184 } 185 186 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 187 strcmp(ca->ca_name, "ldom-primary") != 0) { 188 int minor = VLDC_LDOM_OFFSET + vldc_num_ldoms++; 189 if (minor < nitems(vldc_svc)) 190 vldc_svc[minor].vs_sc = sc; 191 } 192 193 printf(" channel \"%s\"\n", ca->ca_name); 194 return; 195 196 #if 0 197 free_rxqueue: 198 ldc_queue_free(sc->sc_dmatag, lc->lc_rxq); 199 #endif 200 free_txqueue: 201 ldc_queue_free(sc->sc_dmatag, lc->lc_txq); 202 } 203 204 int 205 vldcp_tx_intr(void *arg) 206 { 207 struct vldcp_softc *sc = arg; 208 struct ldc_conn *lc = &sc->sc_lc; 209 uint64_t tx_head, tx_tail, tx_state; 210 int err; 211 212 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 213 if (err != H_EOK) { 214 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 215 return (0); 216 } 217 218 if (tx_state != lc->lc_tx_state) { 219 switch (tx_state) { 220 case LDC_CHANNEL_DOWN: 221 DPRINTF(("%s: Tx link down\n", __func__)); 222 break; 223 case LDC_CHANNEL_UP: 224 DPRINTF(("%s: Tx link up\n", __func__)); 225 break; 226 case LDC_CHANNEL_RESET: 227 DPRINTF(("%s: Tx link reset\n", __func__)); 228 break; 229 } 230 lc->lc_tx_state = tx_state; 231 } 232 233 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 234 selwakeup(&sc->sc_wsel); 235 wakeup(lc->lc_txq); 236 return (1); 237 } 238 239 int 240 vldcp_rx_intr(void *arg) 241 { 242 struct vldcp_softc *sc = arg; 243 struct ldc_conn *lc = &sc->sc_lc; 244 uint64_t rx_head, rx_tail, rx_state; 245 int err; 246 247 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 248 if (err != H_EOK) { 249 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 250 return (0); 251 } 252 253 if (rx_state != lc->lc_rx_state) { 254 switch (rx_state) { 255 case LDC_CHANNEL_DOWN: 256 DPRINTF(("%s: Rx link down\n", __func__)); 257 if (rx_head == rx_tail) 258 break; 259 /* Discard and ack pending I/O. */ 260 DPRINTF(("setting rx qhead to %llx\n", rx_tail)); 261 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail); 262 if (err == H_EOK) 263 break; 264 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 265 break; 266 case LDC_CHANNEL_UP: 267 DPRINTF(("%s: Rx link up\n", __func__)); 268 break; 269 case LDC_CHANNEL_RESET: 270 DPRINTF(("%s: Rx link reset\n", __func__)); 271 if (rx_head == rx_tail) 272 break; 273 /* Discard and ack pending I/O. */ 274 DPRINTF(("setting rx qhead to %llx\n", rx_tail)); 275 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail); 276 if (err == H_EOK) 277 break; 278 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 279 break; 280 } 281 lc->lc_rx_state = rx_state; 282 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 283 INTR_DISABLED); 284 selwakeup(&sc->sc_rsel); 285 wakeup(lc->lc_rxq); 286 return (1); 287 } 288 289 if (rx_head == rx_tail) 290 return (0); 291 292 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 293 selwakeup(&sc->sc_rsel); 294 wakeup(lc->lc_rxq); 295 return (1); 296 } 297 298 cdev_decl(vldcp); 299 struct vldcp_softc *vldcp_lookup(dev_t); 300 301 struct vldcp_softc * 302 vldcp_lookup(dev_t dev) 303 { 304 struct vldcp_softc *sc = NULL; 305 306 if (minor(dev) < nitems(vldc_svc)) 307 sc = vldc_svc[minor(dev)].vs_sc; 308 309 if (sc) 310 device_ref(&sc->sc_dv); 311 312 return (sc); 313 } 314 315 int 316 vldcpopen(dev_t dev, int flag, int mode, struct proc *p) 317 { 318 struct vldcp_softc *sc; 319 struct ldc_conn *lc; 320 uint64_t rx_head, rx_tail, rx_state; 321 int err; 322 323 sc = vldcp_lookup(dev); 324 if (sc == NULL) 325 return (ENXIO); 326 lc = &sc->sc_lc; 327 328 err = hv_ldc_tx_qconf(lc->lc_id, 329 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); 330 if (err != H_EOK) 331 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err); 332 333 err = hv_ldc_rx_qconf(lc->lc_id, 334 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); 335 if (err != H_EOK) 336 printf("%s: hv_ldc_rx_qconf %d\n", __func__, err); 337 338 /* Clear a pending channel reset. */ 339 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 340 if (err != H_EOK) 341 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 342 343 device_unref(&sc->sc_dv); 344 return (0); 345 } 346 347 int 348 vldcpclose(dev_t dev, int flag, int mode, struct proc *p) 349 { 350 struct vldcp_softc *sc; 351 352 sc = vldcp_lookup(dev); 353 if (sc == NULL) 354 return (ENXIO); 355 356 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 357 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 358 359 hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0); 360 hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0); 361 362 device_unref(&sc->sc_dv); 363 return (0); 364 } 365 366 int 367 vldcpread(dev_t dev, struct uio *uio, int ioflag) 368 { 369 struct vldcp_softc *sc; 370 struct ldc_conn *lc; 371 uint64_t rx_head, rx_tail, rx_state; 372 int err, ret; 373 int s; 374 375 sc = vldcp_lookup(dev); 376 if (sc == NULL) 377 return (ENXIO); 378 lc = &sc->sc_lc; 379 380 if (uio->uio_resid != 64) { 381 device_unref(&sc->sc_dv); 382 return (EINVAL); 383 } 384 385 s = spltty(); 386 retry: 387 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 388 if (err != H_EOK) { 389 splx(s); 390 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 391 device_unref(&sc->sc_dv); 392 return (EIO); 393 } 394 395 DPRINTF(("rx head %llx, rx tail %llx, state %lld\n", rx_head, rx_tail, rx_state)); 396 397 if (rx_state != LDC_CHANNEL_UP) { 398 splx(s); 399 device_unref(&sc->sc_dv); 400 return (EIO); 401 } 402 403 if (rx_head == rx_tail) { 404 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 405 INTR_ENABLED); 406 ret = tsleep_nsec(lc->lc_rxq, PWAIT | PCATCH, "hvrd", INFSLP); 407 if (ret) { 408 splx(s); 409 device_unref(&sc->sc_dv); 410 return (ret); 411 } 412 goto retry; 413 } 414 415 ret = uiomove(lc->lc_rxq->lq_va + rx_head, 64, uio); 416 417 rx_head += 64; 418 rx_head &= ((lc->lc_rxq->lq_nentries * 64) - 1); 419 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head); 420 if (err != H_EOK) 421 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 422 423 splx(s); 424 device_unref(&sc->sc_dv); 425 return (ret); 426 } 427 428 int 429 vldcpwrite(dev_t dev, struct uio *uio, int ioflag) 430 { 431 struct vldcp_softc *sc; 432 struct ldc_conn *lc; 433 uint64_t tx_head, tx_tail, tx_state; 434 uint64_t next_tx_tail; 435 int err, ret; 436 int s; 437 438 sc = vldcp_lookup(dev); 439 if (sc == NULL) 440 return (ENXIO); 441 lc = &sc->sc_lc; 442 443 if (uio->uio_resid != 64) { 444 device_unref(&sc->sc_dv); 445 return (EINVAL); 446 } 447 448 s = spltty(); 449 retry: 450 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 451 if (err != H_EOK) { 452 splx(s); 453 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 454 device_unref(&sc->sc_dv); 455 return (EIO); 456 } 457 458 if (tx_state != LDC_CHANNEL_UP) { 459 splx(s); 460 device_unref(&sc->sc_dv); 461 return (EIO); 462 } 463 464 DPRINTF(("tx head %llx, tx tail %llx\n", tx_head, tx_tail)); 465 466 next_tx_tail = tx_tail + 64; 467 next_tx_tail &= ((lc->lc_txq->lq_nentries * 64) - 1); 468 469 if (tx_head == next_tx_tail) { 470 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 471 INTR_ENABLED); 472 ret = tsleep_nsec(lc->lc_txq, PWAIT | PCATCH, "hvwr", INFSLP); 473 if (ret) { 474 splx(s); 475 device_unref(&sc->sc_dv); 476 return (ret); 477 } 478 goto retry; 479 } 480 splx(s); 481 482 ret = uiomove(lc->lc_txq->lq_va + tx_tail, 64, uio); 483 484 err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail); 485 if (err != H_EOK) { 486 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); 487 device_unref(&sc->sc_dv); 488 return (EIO); 489 } 490 491 device_unref(&sc->sc_dv); 492 return (ret); 493 } 494 495 int 496 vldcpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 497 { 498 struct vldcp_softc *sc; 499 struct ldc_conn *lc; 500 struct hv_io *hi = (struct hv_io *)data; 501 paddr_t pa, offset; 502 psize_t nbytes; 503 caddr_t buf; 504 size_t size; 505 int err; 506 507 sc = vldcp_lookup(dev); 508 if (sc == NULL) 509 return (ENXIO); 510 lc = &sc->sc_lc; 511 512 switch (cmd) { 513 case HVIOCREAD: 514 case HVIOCWRITE: 515 break; 516 default: 517 device_unref(&sc->sc_dv); 518 return (ENOTTY); 519 } 520 521 buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 522 523 switch(cmd) { 524 case HVIOCREAD: 525 size = hi->hi_len; 526 offset = 0; 527 while (size > 0) { 528 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 529 nbytes = min(PAGE_SIZE, size); 530 err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, 531 hi->hi_cookie + offset, pa, nbytes, &nbytes); 532 if (err != H_EOK) { 533 printf("hv_ldc_copy %d\n", err); 534 free(buf, M_DEVBUF, 0); 535 device_unref(&sc->sc_dv); 536 return (EINVAL); 537 } 538 err = copyout(buf, (caddr_t)hi->hi_addr + offset, nbytes); 539 if (err) { 540 free(buf, M_DEVBUF, 0); 541 device_unref(&sc->sc_dv); 542 return (err); 543 } 544 size -= nbytes; 545 offset += nbytes; 546 } 547 break; 548 case HVIOCWRITE: 549 size = hi->hi_len; 550 offset = 0; 551 while (size > 0) { 552 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 553 nbytes = min(PAGE_SIZE, size); 554 err = copyin((caddr_t)hi->hi_addr + offset, buf, nbytes); 555 if (err) { 556 free(buf, M_DEVBUF, 0); 557 device_unref(&sc->sc_dv); 558 return (err); 559 } 560 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 561 hi->hi_cookie + offset, pa, nbytes, &nbytes); 562 if (err != H_EOK) { 563 printf("hv_ldc_copy %d\n", err); 564 free(buf, M_DEVBUF, 0); 565 device_unref(&sc->sc_dv); 566 return (EINVAL); 567 } 568 size -= nbytes; 569 offset += nbytes; 570 } 571 break; 572 573 } 574 575 free(buf, M_DEVBUF, 0); 576 577 device_unref(&sc->sc_dv); 578 return (0); 579 } 580 581 int 582 vldcppoll(dev_t dev, int events, struct proc *p) 583 { 584 struct vldcp_softc *sc; 585 struct ldc_conn *lc; 586 uint64_t head, tail, state; 587 int revents = 0; 588 int s, err; 589 590 sc = vldcp_lookup(dev); 591 if (sc == NULL) 592 return (POLLERR); 593 lc = &sc->sc_lc; 594 595 s = spltty(); 596 if (events & (POLLIN | POLLRDNORM)) { 597 err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state); 598 599 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) 600 revents |= events & (POLLIN | POLLRDNORM); 601 } 602 if (events & (POLLOUT | POLLWRNORM)) { 603 err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state); 604 605 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) 606 revents |= events & (POLLOUT | POLLWRNORM); 607 } 608 if (revents == 0) { 609 if (events & (POLLIN | POLLRDNORM)) { 610 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 611 INTR_ENABLED); 612 selrecord(p, &sc->sc_rsel); 613 } 614 if (events & (POLLOUT | POLLWRNORM)) { 615 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 616 INTR_ENABLED); 617 selrecord(p, &sc->sc_wsel); 618 } 619 } 620 splx(s); 621 return revents; 622 } 623 624 void 625 filt_vldcprdetach(struct knote *kn) 626 { 627 struct vldcp_softc *sc = (void *)kn->kn_hook; 628 int s; 629 630 s = spltty(); 631 klist_remove_locked(&sc->sc_rsel.si_note, kn); 632 splx(s); 633 } 634 635 void 636 filt_vldcpwdetach(struct knote *kn) 637 { 638 struct vldcp_softc *sc = (void *)kn->kn_hook; 639 int s; 640 641 s = spltty(); 642 klist_remove_locked(&sc->sc_wsel.si_note, kn); 643 splx(s); 644 } 645 646 int 647 filt_vldcpread(struct knote *kn, long hint) 648 { 649 struct vldcp_softc *sc = (void *)kn->kn_hook; 650 struct ldc_conn *lc = &sc->sc_lc; 651 uint64_t head, tail, avail, state; 652 int s, err; 653 654 s = spltty(); 655 err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state); 656 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) { 657 avail = (tail - head) / sizeof(struct ldc_pkt) + 658 lc->lc_rxq->lq_nentries; 659 avail %= lc->lc_rxq->lq_nentries; 660 kn->kn_data = avail; 661 } else { 662 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 663 INTR_ENABLED); 664 } 665 splx(s); 666 667 return (kn->kn_data > 0); 668 } 669 670 int 671 filt_vldcwrite(struct knote *kn, long hint) 672 { 673 struct vldcp_softc *sc = (void *)kn->kn_hook; 674 struct ldc_conn *lc = &sc->sc_lc; 675 uint64_t head, tail, avail, state; 676 int s, err; 677 678 s = spltty(); 679 err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state); 680 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) { 681 avail = (head - tail) / sizeof(struct ldc_pkt) + 682 lc->lc_txq->lq_nentries - 1; 683 avail %= lc->lc_txq->lq_nentries; 684 kn->kn_data = avail; 685 } else { 686 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 687 INTR_ENABLED); 688 } 689 splx(s); 690 691 return (kn->kn_data > 0); 692 } 693 694 const struct filterops vldcpread_filtops = { 695 .f_flags = FILTEROP_ISFD, 696 .f_attach = NULL, 697 .f_detach = filt_vldcprdetach, 698 .f_event = filt_vldcpread, 699 }; 700 701 const struct filterops vldcpwrite_filtops = { 702 .f_flags = FILTEROP_ISFD, 703 .f_attach = NULL, 704 .f_detach = filt_vldcpwdetach, 705 .f_event = filt_vldcwrite, 706 }; 707 708 int 709 vldcpkqfilter(dev_t dev, struct knote *kn) 710 { 711 struct vldcp_softc *sc; 712 struct klist *klist; 713 int s; 714 715 sc = vldcp_lookup(dev); 716 if (sc == NULL) 717 return (ENXIO); 718 719 switch (kn->kn_filter) { 720 case EVFILT_READ: 721 klist = &sc->sc_rsel.si_note; 722 kn->kn_fop = &vldcpread_filtops; 723 break; 724 case EVFILT_WRITE: 725 klist = &sc->sc_wsel.si_note; 726 kn->kn_fop = &vldcpwrite_filtops; 727 break; 728 729 default: 730 return (EINVAL); 731 } 732 733 kn->kn_hook = sc; 734 735 s = spltty(); 736 klist_insert_locked(klist, kn); 737 splx(s); 738 739 return (0); 740 } 741