1 /* $OpenBSD: vldcp.c,v 1.12 2015/02/10 22:04:00 miod 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 74 struct cfattach vldcp_ca = { 75 sizeof(struct vldcp_softc), vldcp_match, vldcp_attach 76 }; 77 78 struct cfdriver vldcp_cd = { 79 NULL, "vldcp", DV_DULL 80 }; 81 82 int vldcp_tx_intr(void *); 83 int vldcp_rx_intr(void *); 84 85 /* 86 * We attach to certain well-known channels. These are assigned fixed 87 * device minor device numbers through their index in the table below. 88 * So "hvctl" gets minor 0, "spds" gets minor 1, etc. etc. 89 * 90 * We also attach to the domain services channels. These are named 91 * "ldom-<guestname>" and get assigned a device minor starting at 92 * VLDC_LDOM_OFFSET. 93 */ 94 #define VLDC_NUM_SERVICES 64 95 #define VLDC_LDOM_OFFSET 32 96 int vldc_num_ldoms; 97 98 struct vldc_svc { 99 const char *vs_name; 100 struct vldcp_softc *vs_sc; 101 }; 102 103 struct vldc_svc vldc_svc[VLDC_NUM_SERVICES] = { 104 { "hvctl" }, 105 { "spds" }, 106 { NULL } 107 }; 108 109 int 110 vldcp_match(struct device *parent, void *match, void *aux) 111 { 112 struct cbus_attach_args *ca = aux; 113 struct vldc_svc *svc; 114 115 for (svc = vldc_svc; svc->vs_name != NULL; svc++) 116 if (strcmp(ca->ca_name, svc->vs_name) == 0) 117 return (1); 118 119 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 120 strcmp(ca->ca_name, "ldom-primary") != 0) 121 return (1); 122 123 return (0); 124 } 125 126 void 127 vldcp_attach(struct device *parent, struct device *self, void *aux) 128 { 129 struct vldcp_softc *sc = (struct vldcp_softc *)self; 130 struct cbus_attach_args *ca = aux; 131 struct vldc_svc *svc; 132 struct ldc_conn *lc; 133 134 sc->sc_bustag = ca->ca_bustag; 135 sc->sc_dmatag = ca->ca_dmatag; 136 sc->sc_tx_ino = ca->ca_tx_ino; 137 sc->sc_rx_ino = ca->ca_rx_ino; 138 139 printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino); 140 141 /* 142 * Un-configure queues before registering interrupt handlers, 143 * such that we dont get any stale LDC packets or events. 144 */ 145 hv_ldc_tx_qconf(ca->ca_id, 0, 0); 146 hv_ldc_rx_qconf(ca->ca_id, 0, 0); 147 148 sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino, 149 IPL_TTY, 0, vldcp_tx_intr, sc, sc->sc_dv.dv_xname); 150 sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino, 151 IPL_TTY, 0, vldcp_rx_intr, sc, sc->sc_dv.dv_xname); 152 if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) { 153 printf(", can't establish interrupt\n"); 154 return; 155 } 156 157 lc = &sc->sc_lc; 158 lc->lc_id = ca->ca_id; 159 lc->lc_sc = sc; 160 161 lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_TX_ENTRIES); 162 if (lc->lc_txq == NULL) { 163 printf(", can't allocate tx queue\n"); 164 return; 165 } 166 167 lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_RX_ENTRIES); 168 if (lc->lc_rxq == NULL) { 169 printf(", can't allocate rx queue\n"); 170 goto free_txqueue; 171 } 172 173 for (svc = vldc_svc; svc->vs_name != NULL; svc++) { 174 if (strcmp(ca->ca_name, svc->vs_name) == 0) { 175 svc->vs_sc = sc; 176 break; 177 } 178 } 179 180 if (strncmp(ca->ca_name, "ldom-", 5) == 0 && 181 strcmp(ca->ca_name, "ldom-primary") != 0) { 182 int minor = VLDC_LDOM_OFFSET + vldc_num_ldoms++; 183 if (minor < nitems(vldc_svc)) 184 vldc_svc[minor].vs_sc = sc; 185 } 186 187 printf(" channel \"%s\"\n", ca->ca_name); 188 return; 189 190 #if 0 191 free_rxqueue: 192 ldc_queue_free(sc->sc_dmatag, lc->lc_rxq); 193 #endif 194 free_txqueue: 195 ldc_queue_free(sc->sc_dmatag, lc->lc_txq); 196 } 197 198 int 199 vldcp_tx_intr(void *arg) 200 { 201 struct vldcp_softc *sc = arg; 202 struct ldc_conn *lc = &sc->sc_lc; 203 uint64_t tx_head, tx_tail, tx_state; 204 int err; 205 206 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 207 if (err != H_EOK) { 208 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 209 return (0); 210 } 211 212 if (tx_state != lc->lc_tx_state) { 213 switch (tx_state) { 214 case LDC_CHANNEL_DOWN: 215 DPRINTF(("Tx link down\n")); 216 break; 217 case LDC_CHANNEL_UP: 218 DPRINTF(("Tx link up\n")); 219 break; 220 case LDC_CHANNEL_RESET: 221 DPRINTF(("Tx link reset\n")); 222 break; 223 } 224 lc->lc_tx_state = tx_state; 225 } 226 227 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 228 selwakeup(&sc->sc_wsel); 229 wakeup(lc->lc_txq); 230 return (1); 231 } 232 233 int 234 vldcp_rx_intr(void *arg) 235 { 236 struct vldcp_softc *sc = arg; 237 struct ldc_conn *lc = &sc->sc_lc; 238 uint64_t rx_head, rx_tail, rx_state; 239 int err; 240 241 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 242 if (err != H_EOK) { 243 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 244 return (0); 245 } 246 247 if (rx_state != lc->lc_rx_state) { 248 switch (rx_state) { 249 case LDC_CHANNEL_DOWN: 250 DPRINTF(("Rx link down\n")); 251 break; 252 case LDC_CHANNEL_UP: 253 DPRINTF(("Rx link up\n")); 254 break; 255 case LDC_CHANNEL_RESET: 256 DPRINTF(("Rx link reset\n")); 257 break; 258 } 259 lc->lc_rx_state = rx_state; 260 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 261 INTR_DISABLED); 262 selwakeup(&sc->sc_rsel); 263 wakeup(lc->lc_rxq); 264 return (1); 265 } 266 267 if (rx_head == rx_tail) 268 return (0); 269 270 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 271 selwakeup(&sc->sc_rsel); 272 wakeup(lc->lc_rxq); 273 return (1); 274 } 275 276 cdev_decl(vldcp); 277 struct vldcp_softc *vldcp_lookup(dev_t); 278 279 struct vldcp_softc * 280 vldcp_lookup(dev_t dev) 281 { 282 struct vldcp_softc *sc = NULL; 283 284 if (minor(dev) < nitems(vldc_svc)) 285 sc = vldc_svc[minor(dev)].vs_sc; 286 287 if (sc) 288 device_ref(&sc->sc_dv); 289 290 return (sc); 291 } 292 293 int 294 vldcpopen(dev_t dev, int flag, int mode, struct proc *p) 295 { 296 struct vldcp_softc *sc; 297 struct ldc_conn *lc; 298 uint64_t rx_head, rx_tail, rx_state; 299 int err; 300 301 sc = vldcp_lookup(dev); 302 if (sc == NULL) 303 return (ENXIO); 304 lc = &sc->sc_lc; 305 306 err = hv_ldc_tx_qconf(lc->lc_id, 307 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); 308 if (err != H_EOK) 309 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err); 310 311 err = hv_ldc_rx_qconf(lc->lc_id, 312 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); 313 if (err != H_EOK) 314 printf("%s: hv_ldc_rx_qconf %d\n", __func__, err); 315 316 /* Clear a pending channel reset. */ 317 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 318 if (err != H_EOK) 319 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 320 321 device_unref(&sc->sc_dv); 322 return (0); 323 } 324 325 int 326 vldcpclose(dev_t dev, int flag, int mode, struct proc *p) 327 { 328 struct vldcp_softc *sc; 329 330 sc = vldcp_lookup(dev); 331 if (sc == NULL) 332 return (ENXIO); 333 334 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); 335 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); 336 337 hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0); 338 hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0); 339 340 device_unref(&sc->sc_dv); 341 return (0); 342 } 343 344 int 345 vldcpread(dev_t dev, struct uio *uio, int ioflag) 346 { 347 struct vldcp_softc *sc; 348 struct ldc_conn *lc; 349 uint64_t rx_head, rx_tail, rx_state; 350 int err, ret; 351 int s; 352 353 sc = vldcp_lookup(dev); 354 if (sc == NULL) 355 return (ENXIO); 356 lc = &sc->sc_lc; 357 358 if (uio->uio_resid != 64) { 359 device_unref(&sc->sc_dv); 360 return (EINVAL); 361 } 362 363 s = spltty(); 364 retry: 365 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 366 if (err != H_EOK) { 367 splx(s); 368 printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); 369 device_unref(&sc->sc_dv); 370 return (EIO); 371 } 372 373 if (rx_state != LDC_CHANNEL_UP) { 374 splx(s); 375 device_unref(&sc->sc_dv); 376 return (EIO); 377 } 378 379 DPRINTF(("rx head %llx, rx tail %llx\n", rx_head, rx_tail)); 380 381 if (rx_head == rx_tail) { 382 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 383 INTR_ENABLED); 384 ret = tsleep(lc->lc_rxq, PWAIT | PCATCH, "hvrd", 0); 385 if (ret) { 386 splx(s); 387 device_unref(&sc->sc_dv); 388 return (ret); 389 } 390 goto retry; 391 } 392 splx(s); 393 394 ret = uiomove(lc->lc_rxq->lq_va + rx_head, 64, uio); 395 396 rx_head += 64; 397 rx_head &= ((lc->lc_rxq->lq_nentries * 64) - 1); 398 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head); 399 if (err != H_EOK) 400 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 401 402 device_unref(&sc->sc_dv); 403 return (ret); 404 } 405 406 int 407 vldcpwrite(dev_t dev, struct uio *uio, int ioflag) 408 { 409 struct vldcp_softc *sc; 410 struct ldc_conn *lc; 411 uint64_t tx_head, tx_tail, tx_state; 412 uint64_t next_tx_tail; 413 int err, ret; 414 int s; 415 416 sc = vldcp_lookup(dev); 417 if (sc == NULL) 418 return (ENXIO); 419 lc = &sc->sc_lc; 420 421 if (uio->uio_resid != 64) { 422 device_unref(&sc->sc_dv); 423 return (EINVAL); 424 } 425 426 s = spltty(); 427 retry: 428 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 429 if (err != H_EOK) { 430 splx(s); 431 printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); 432 device_unref(&sc->sc_dv); 433 return (EIO); 434 } 435 436 if (tx_state != LDC_CHANNEL_UP) { 437 splx(s); 438 device_unref(&sc->sc_dv); 439 return (EIO); 440 } 441 442 DPRINTF(("tx head %llx, tx tail %llx\n", tx_head, tx_tail)); 443 444 next_tx_tail = tx_tail + 64; 445 next_tx_tail &= ((lc->lc_txq->lq_nentries * 64) - 1); 446 447 if (tx_head == next_tx_tail) { 448 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 449 INTR_ENABLED); 450 ret = tsleep(lc->lc_txq, PWAIT | PCATCH, "hvwr", 0); 451 if (ret) { 452 splx(s); 453 device_unref(&sc->sc_dv); 454 return (ret); 455 } 456 goto retry; 457 } 458 splx(s); 459 460 ret = uiomove(lc->lc_txq->lq_va + tx_tail, 64, uio); 461 462 err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail); 463 if (err != H_EOK) { 464 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); 465 device_unref(&sc->sc_dv); 466 return (EIO); 467 } 468 469 device_unref(&sc->sc_dv); 470 return (ret); 471 } 472 473 int 474 vldcpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 475 { 476 struct vldcp_softc *sc; 477 struct ldc_conn *lc; 478 struct hv_io *hi = (struct hv_io *)data; 479 paddr_t pa, offset; 480 psize_t nbytes; 481 caddr_t buf; 482 size_t size; 483 int err; 484 485 sc = vldcp_lookup(dev); 486 if (sc == NULL) 487 return (ENXIO); 488 lc = &sc->sc_lc; 489 490 switch (cmd) { 491 case HVIOCREAD: 492 case HVIOCWRITE: 493 break; 494 default: 495 device_unref(&sc->sc_dv); 496 return (ENOTTY); 497 } 498 499 buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 500 501 switch(cmd) { 502 case HVIOCREAD: 503 size = hi->hi_len; 504 offset = 0; 505 while (size > 0) { 506 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 507 nbytes = min(PAGE_SIZE, size); 508 err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, 509 hi->hi_cookie + offset, pa, nbytes, &nbytes); 510 if (err != H_EOK) { 511 printf("hv_ldc_copy %d\n", err); 512 free(buf, M_DEVBUF, 0); 513 device_unref(&sc->sc_dv); 514 return (EINVAL); 515 } 516 err = copyout(buf, (caddr_t)hi->hi_addr + offset, nbytes); 517 if (err) { 518 free(buf, M_DEVBUF, 0); 519 device_unref(&sc->sc_dv); 520 return (err); 521 } 522 size -= nbytes; 523 offset += nbytes; 524 } 525 break; 526 case HVIOCWRITE: 527 size = hi->hi_len; 528 offset = 0; 529 while (size > 0) { 530 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa); 531 nbytes = min(PAGE_SIZE, size); 532 err = copyin((caddr_t)hi->hi_addr + offset, buf, nbytes); 533 if (err) { 534 free(buf, M_DEVBUF, 0); 535 device_unref(&sc->sc_dv); 536 return (err); 537 } 538 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 539 hi->hi_cookie + offset, pa, nbytes, &nbytes); 540 if (err != H_EOK) { 541 printf("hv_ldc_copy %d\n", err); 542 free(buf, M_DEVBUF, 0); 543 device_unref(&sc->sc_dv); 544 return (EINVAL); 545 } 546 size -= nbytes; 547 offset += nbytes; 548 } 549 break; 550 551 } 552 553 free(buf, M_DEVBUF, 0); 554 555 device_unref(&sc->sc_dv); 556 return (0); 557 } 558 559 int 560 vldcppoll(dev_t dev, int events, struct proc *p) 561 { 562 struct vldcp_softc *sc; 563 struct ldc_conn *lc; 564 uint64_t head, tail, state; 565 int revents = 0; 566 int s, err; 567 568 sc = vldcp_lookup(dev); 569 if (sc == NULL) 570 return (ENXIO); 571 lc = &sc->sc_lc; 572 573 s = spltty(); 574 if (events & (POLLIN | POLLRDNORM)) { 575 err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state); 576 577 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) 578 revents |= events & (POLLIN | POLLRDNORM); 579 } 580 if (events & (POLLOUT | POLLWRNORM)) { 581 err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state); 582 583 if (err == 0 && state == LDC_CHANNEL_UP && head != tail) 584 revents |= events & (POLLOUT | POLLWRNORM); 585 } 586 if (revents == 0) { 587 if (events & (POLLIN | POLLRDNORM)) { 588 cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, 589 INTR_ENABLED); 590 selrecord(p, &sc->sc_rsel); 591 } 592 if (events & (POLLOUT | POLLWRNORM)) { 593 cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, 594 INTR_ENABLED); 595 selrecord(p, &sc->sc_wsel); 596 } 597 } 598 splx(s); 599 return revents; 600 } 601