1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4 5.0 */ 27 28 #include <sys/types.h> 29 #include <sys/cmn_err.h> 30 #include <sys/conf.h> 31 #include <sys/ddi_impldefs.h> 32 #include <sys/autoconf.h> 33 #include <sys/systm.h> 34 #include <sys/modctl.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/ddi_subrdefs.h> 38 #include <sys/promif.h> 39 #include <sys/machsystm.h> 40 #include <sys/ddi_intr_impl.h> 41 #include <sys/hypervisor_api.h> 42 #include <sys/intr.h> 43 44 #define SUN4V_REG_SPEC2CFG_HDL(x) ((x >> 32) & ~(0xfull << 28)) 45 46 static kmutex_t vnex_id_lock; 47 /* 48 * Vnex name to pil map 49 */ 50 typedef struct vnex_regspec { 51 uint64_t physaddr; 52 uint64_t size; 53 } vnex_regspec_t; 54 55 struct vnex_pil_map { 56 caddr_t name; 57 uint32_t pil; 58 }; 59 60 /* vnex interrupt descriptor */ 61 typedef struct vnex_id { 62 dev_info_t *vid_dip; 63 uint32_t vid_ino; 64 uint64_t vid_ihdl; 65 uint_t (*vid_handler)(); 66 caddr_t vid_arg1; 67 caddr_t vid_arg2; 68 ddi_intr_handle_impl_t *vid_ddi_hdlp; 69 uint64_t vid_cfg_hdl; 70 struct vnex_id *vid_next; 71 } vnex_id_t; 72 73 /* vnex interrupt descriptor list */ 74 static vnex_id_t *vnex_id_list; 75 76 hrtime_t vnex_pending_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */ 77 78 /* 79 * vnex interrupt descriptor list manipulation functions 80 */ 81 82 static vnex_id_t *vnex_locate_id(dev_info_t *dip, uint32_t ino); 83 static vnex_id_t *vnex_alloc_id(dev_info_t *dip, uint32_t ino, 84 uint64_t dhdl); 85 static void vnex_add_id(vnex_id_t *vid_p); 86 static void vnex_rem_id(vnex_id_t *vid_p); 87 static void vnex_free_id(vnex_id_t *vid_p); 88 89 uint_t vnex_intr_wrapper(caddr_t arg); 90 91 static struct vnex_pil_map vnex_name_to_pil[] = { 92 {"console", PIL_12}, 93 {"fma", PIL_5}, 94 {"echo", PIL_3}, 95 {"loop", PIL_3}, 96 {"sunmc", PIL_3}, 97 {"sunvts", PIL_3}, 98 {"explorer", PIL_3}, 99 {"ncp", PIL_8} 100 }; 101 102 #define VNEX_MAX_DEVS (sizeof (vnex_name_to_pil) / \ 103 sizeof (struct vnex_pil_map)) 104 105 /* 106 * Config information 107 */ 108 static int vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip, 109 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 110 111 static int 112 vnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 113 114 static struct bus_ops vnex_bus_ops = { 115 BUSO_REV, 116 nullbusmap, 117 NULL, /* NO OP */ 118 NULL, /* NO OP */ 119 NULL, /* NO OP */ 120 i_ddi_map_fault, 121 ddi_no_dma_map, 122 ddi_no_dma_allochdl, 123 NULL, 124 NULL, 125 NULL, 126 NULL, 127 NULL, 128 NULL, 129 vnex_ctl, 130 ddi_bus_prop_op, 131 NULL, /* (*bus_get_eventcookie)(); */ 132 NULL, /* (*bus_add_eventcall)(); */ 133 NULL, /* (*bus_remove_eventcall)(); */ 134 NULL, /* (*bus_post_event)(); */ 135 NULL, /* (*bus_intr_ctl)(); */ 136 NULL, /* (*bus_config)(); */ 137 NULL, /* (*bus_unconfig)(); */ 138 NULL, /* (*bus_fm_init)(); */ 139 NULL, /* (*bus_fm_fini)(); */ 140 NULL, /* (*bus_fm_access_enter)(); */ 141 NULL, /* (*bus_fm_access_fini)(); */ 142 NULL, /* (*bus_power)(); */ 143 vnex_intr_ops /* (*bus_intr_op)(); */ 144 }; 145 146 static int vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 147 static int vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 148 149 static struct dev_ops pseudo_ops = { 150 DEVO_REV, /* devo_rev, */ 151 0, /* refcnt */ 152 ddi_no_info, /* info */ 153 nulldev, /* identify */ 154 nulldev, /* probe */ 155 vnex_attach, /* attach */ 156 vnex_detach, /* detach */ 157 nodev, /* reset */ 158 (struct cb_ops *)0, /* driver operations */ 159 &vnex_bus_ops, /* bus operations */ 160 nulldev /* power */ 161 }; 162 163 /* 164 * Module linkage information for the kernel. 165 */ 166 167 static struct modldrv modldrv = { 168 &mod_driverops, /* Type of module. This one is a pseudo driver */ 169 "sun4v virtual-devices nexus driver v%I%", 170 &pseudo_ops, /* driver ops */ 171 }; 172 173 static struct modlinkage modlinkage = { 174 MODREV_1, (void *)&modldrv, NULL 175 }; 176 177 int 178 _init(void) 179 { 180 return (mod_install(&modlinkage)); 181 } 182 183 int 184 _fini(void) 185 { 186 return (mod_remove(&modlinkage)); 187 } 188 189 int 190 _info(struct modinfo *modinfop) 191 { 192 return (mod_info(&modlinkage, modinfop)); 193 } 194 195 /*ARGSUSED*/ 196 void 197 vnex_intr_dist(void *arg) 198 { 199 vnex_id_t *vid_p; 200 uint32_t cpuid; 201 int intr_state; 202 hrtime_t start; 203 204 mutex_enter(&vnex_id_lock); 205 206 for (vid_p = vnex_id_list; vid_p != NULL; 207 vid_p = vid_p->vid_next) { 208 /* 209 * Don't do anything for disabled interrupts. 210 * vnex_enable_intr takes care of redistributing interrupts. 211 */ 212 if ((hvio_intr_getvalid(vid_p->vid_ihdl, 213 &intr_state) == H_EOK) && (intr_state == HV_INTR_NOTVALID)) 214 continue; 215 216 cpuid = intr_dist_cpuid(); 217 218 (void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID); 219 /* 220 * Make a best effort to wait for pending interrupts to finish. 221 * There is not much we can do if we timeout. 222 */ 223 start = gethrtime(); 224 while (!panicstr && 225 (hvio_intr_getstate(vid_p->vid_ihdl, &intr_state) == 226 H_EOK) && (intr_state == HV_INTR_DELIVERED_STATE)) { 227 if (gethrtime() - start > vnex_pending_timeout) { 228 cmn_err(CE_WARN, "vnex_intr_dist: %s%d " 229 "ino 0x%x pending: timedout\n", 230 ddi_driver_name(vid_p->vid_dip), 231 ddi_get_instance(vid_p->vid_dip), 232 vid_p->vid_ino); 233 break; 234 } 235 } 236 (void) hvio_intr_settarget(vid_p->vid_ihdl, cpuid); 237 (void) hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID); 238 } 239 mutex_exit(&vnex_id_lock); 240 } 241 242 static int 243 vnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 244 { 245 switch (cmd) { 246 case DDI_ATTACH: 247 /* 248 * Intitialize interrupt descriptor list 249 * and mutex. 250 */ 251 vnex_id_list = NULL; 252 mutex_init(&vnex_id_lock, NULL, MUTEX_DRIVER, NULL); 253 /* 254 * Add interrupt redistribution callback. 255 */ 256 intr_dist_add(vnex_intr_dist, dip); 257 return (DDI_SUCCESS); 258 259 case DDI_RESUME: 260 return (DDI_SUCCESS); 261 262 default: 263 return (DDI_FAILURE); 264 } 265 } 266 267 /*ARGSUSED*/ 268 static int 269 vnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 270 { 271 switch (cmd) { 272 case DDI_DETACH: 273 return (DDI_FAILURE); 274 275 case DDI_SUSPEND: 276 return (DDI_SUCCESS); 277 278 default: 279 return (DDI_FAILURE); 280 } 281 } 282 283 static int 284 vnex_ctl(dev_info_t *dip, dev_info_t *rdip, 285 ddi_ctl_enum_t ctlop, void *arg, void *result) 286 { 287 char name[12]; /* enough for a decimal integer */ 288 int reglen; 289 uint32_t *vnex_regspec; 290 291 switch (ctlop) { 292 case DDI_CTLOPS_REPORTDEV: 293 if (rdip == NULL) 294 return (DDI_FAILURE); 295 cmn_err(CE_CONT, "?virtual-device: %s%d\n", 296 ddi_driver_name(rdip), ddi_get_instance(rdip)); 297 return (DDI_SUCCESS); 298 299 case DDI_CTLOPS_INITCHILD: 300 { 301 dev_info_t *child = (dev_info_t *)arg; 302 303 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 304 "reg", (caddr_t)&vnex_regspec, ®len) != DDI_SUCCESS) 305 return (DDI_FAILURE); 306 307 (void) sprintf(name, "%x", *vnex_regspec); 308 ddi_set_name_addr(child, name); 309 ddi_set_parent_data(child, NULL); 310 kmem_free((caddr_t)vnex_regspec, reglen); 311 return (DDI_SUCCESS); 312 313 } 314 315 case DDI_CTLOPS_UNINITCHILD: 316 { 317 dev_info_t *child = (dev_info_t *)arg; 318 319 ddi_set_name_addr(child, NULL); 320 ddi_remove_minor_node(arg, NULL); 321 return (DDI_SUCCESS); 322 } 323 324 /* 325 * These ops correspond to functions that "shouldn't" be called 326 * by a pseudo driver. So we whinge when we're called. 327 */ 328 case DDI_CTLOPS_DMAPMAPC: 329 case DDI_CTLOPS_REPORTINT: 330 case DDI_CTLOPS_REGSIZE: 331 { 332 *((off_t *)result) = 0; 333 return (DDI_SUCCESS); 334 } 335 case DDI_CTLOPS_NREGS: 336 { 337 dev_info_t *child = (dev_info_t *)arg; 338 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 339 "reg", (caddr_t)&vnex_regspec, ®len) != DDI_SUCCESS) 340 return (DDI_FAILURE); 341 *((uint_t *)result) = reglen / sizeof (uint32_t); 342 kmem_free((caddr_t)vnex_regspec, reglen); 343 return (DDI_SUCCESS); 344 } 345 case DDI_CTLOPS_SIDDEV: 346 case DDI_CTLOPS_SLAVEONLY: 347 case DDI_CTLOPS_AFFINITY: 348 case DDI_CTLOPS_IOMIN: 349 case DDI_CTLOPS_POKE: 350 case DDI_CTLOPS_PEEK: 351 cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", 352 ddi_get_name(dip), ddi_get_instance(dip), 353 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip)); 354 return (DDI_FAILURE); 355 356 /* 357 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up 358 */ 359 default: 360 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 361 } 362 } 363 364 static int 365 vnex_get_pil(dev_info_t *rdip) 366 { 367 int i; 368 caddr_t name; 369 370 name = ddi_node_name(rdip); 371 for (i = 0; i < VNEX_MAX_DEVS; i++) { 372 if (strcmp(vnex_name_to_pil[i].name, 373 name) == 0) { 374 return (vnex_name_to_pil[i].pil); 375 } 376 } 377 /* 378 * if not found pil is 0 379 */ 380 return (0); 381 } 382 383 static int 384 vnex_enable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) 385 { 386 vnex_id_t *vid_p; 387 uint32_t cpuid; 388 389 vid_p = vnex_locate_id(rdip, hdlp->ih_vector); 390 391 ASSERT(vid_p != NULL); 392 393 cpuid = intr_dist_cpuid(); 394 395 if ((hvio_intr_settarget(vid_p->vid_ihdl, cpuid)) != H_EOK) { 396 return (DDI_FAILURE); 397 } 398 399 if (hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE) != H_EOK) { 400 return (DDI_FAILURE); 401 } 402 403 if ((hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_VALID)) != H_EOK) { 404 return (DDI_FAILURE); 405 } 406 407 return (DDI_SUCCESS); 408 } 409 410 static int 411 vnex_disable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) 412 { 413 vnex_id_t *vid_p; 414 415 vid_p = vnex_locate_id(rdip, hdlp->ih_vector); 416 417 ASSERT(vid_p != NULL); 418 419 if (hvio_intr_setvalid(vid_p->vid_ihdl, HV_INTR_NOTVALID) != H_EOK) { 420 return (DDI_FAILURE); 421 } 422 423 return (DDI_SUCCESS); 424 } 425 426 int 427 vnex_ino_to_inum(dev_info_t *dip, uint32_t ino) 428 { 429 vnex_id_t *vid_p; 430 ddi_intr_handle_impl_t *hdlp; 431 432 if ((vid_p = vnex_locate_id(dip, ino)) == NULL) 433 return (-1); 434 else if ((hdlp = vid_p->vid_ddi_hdlp) == NULL) 435 return (-1); 436 else 437 return (hdlp->ih_inum); 438 } 439 440 static int 441 vnex_add_intr(dev_info_t *dip, dev_info_t *rdip, 442 ddi_intr_handle_impl_t *hdlp) 443 { 444 int reglen, ret = DDI_SUCCESS; 445 vnex_id_t *vid_p; 446 uint64_t cfg; 447 uint32_t ino; 448 uint64_t ihdl; 449 vnex_regspec_t *reg_p; 450 451 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 452 DDI_PROP_DONTPASS, "reg", (caddr_t)®_p, 453 ®len) != DDI_SUCCESS) { 454 return (DDI_FAILURE); 455 } 456 457 /* 458 * get the sun4v config handle for this device 459 */ 460 461 cfg = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr); 462 kmem_free(reg_p, reglen); 463 ino = hdlp->ih_vector; 464 465 /* 466 * call hv to get vihdl 467 */ 468 if (hvio_intr_devino_to_sysino(cfg, ino, &ihdl) != H_EOK) 469 return (DDI_FAILURE); 470 471 hdlp->ih_vector = ihdl; 472 /* 473 * Allocate a interrupt descriptor (id) with the 474 * the interrupt handler and append it to 475 * the id list. 476 */ 477 478 vid_p = vnex_alloc_id(rdip, ino, cfg); 479 vid_p->vid_ihdl = ihdl; 480 vid_p->vid_handler = hdlp->ih_cb_func; 481 vid_p->vid_arg1 = hdlp->ih_cb_arg1; 482 vid_p->vid_arg2 = hdlp->ih_cb_arg2; 483 vid_p->vid_ddi_hdlp = hdlp; 484 485 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 486 (ddi_intr_handler_t *)vnex_intr_wrapper, (caddr_t)vid_p, NULL); 487 488 if (hdlp->ih_pri == 0) { 489 hdlp->ih_pri = vnex_get_pil(rdip); 490 } 491 492 ret = i_ddi_add_ivintr(hdlp); 493 if (ret != DDI_SUCCESS) { 494 return (ret); 495 } 496 497 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, vid_p->vid_handler, 498 vid_p->vid_arg1, vid_p->vid_arg2); 499 500 return (ret); 501 } 502 503 static int 504 vnex_remove_intr(dev_info_t *rdip, 505 ddi_intr_handle_impl_t *hdlp) 506 { 507 vnex_id_t *vid_p; 508 uint32_t ino; 509 int ret = DDI_SUCCESS; 510 511 ino = hdlp->ih_vector; 512 vid_p = vnex_locate_id(rdip, ino); 513 514 hdlp->ih_vector = vid_p->vid_ihdl; 515 i_ddi_rem_ivintr(hdlp); 516 517 vnex_free_id(vid_p); 518 519 return (ret); 520 } 521 522 static int 523 vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip, 524 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result) 525 { 526 int ret = DDI_SUCCESS; 527 528 switch (intr_op) { 529 case DDI_INTROP_GETCAP: 530 *(int *)result = DDI_INTR_FLAG_LEVEL; 531 break; 532 case DDI_INTROP_ALLOC: 533 *(int *)result = hdlp->ih_scratch1; 534 break; 535 case DDI_INTROP_GETPRI: 536 *(int *)result = hdlp->ih_pri ? 537 hdlp->ih_pri : vnex_get_pil(rdip); 538 break; 539 case DDI_INTROP_FREE: 540 break; 541 case DDI_INTROP_SETPRI: 542 break; 543 case DDI_INTROP_ADDISR: 544 ret = vnex_add_intr(dip, rdip, hdlp); 545 break; 546 case DDI_INTROP_REMISR: 547 ret = vnex_remove_intr(rdip, hdlp); 548 break; 549 case DDI_INTROP_ENABLE: 550 ret = vnex_enable_intr(rdip, hdlp); 551 break; 552 case DDI_INTROP_DISABLE: 553 ret = vnex_disable_intr(rdip, hdlp); 554 break; 555 case DDI_INTROP_NINTRS: 556 case DDI_INTROP_NAVAIL: 557 *(int *)result = i_ddi_get_nintrs(rdip); 558 break; 559 case DDI_INTROP_SUPPORTED_TYPES: 560 *(int *)result = i_ddi_get_nintrs(rdip) ? 561 DDI_INTR_TYPE_FIXED : 0; 562 break; 563 default: 564 ret = DDI_ENOTSUP; 565 break; 566 } 567 568 return (ret); 569 } 570 571 vnex_id_t * 572 vnex_alloc_id(dev_info_t *dip, uint32_t ino, uint64_t dhdl) 573 { 574 vnex_id_t *vid_p = kmem_alloc(sizeof (vnex_id_t), KM_SLEEP); 575 576 vid_p->vid_dip = dip; 577 vid_p->vid_ino = ino; 578 vid_p->vid_cfg_hdl = dhdl; 579 580 mutex_enter(&vnex_id_lock); 581 vnex_add_id(vid_p); 582 mutex_exit(&vnex_id_lock); 583 584 return (vid_p); 585 } 586 587 vnex_id_t * 588 vnex_locate_id(dev_info_t *dip, uint32_t ino) 589 { 590 vnex_id_t *vid_p; 591 592 mutex_enter(&vnex_id_lock); 593 vid_p = vnex_id_list; 594 595 while (vid_p != NULL) { 596 if (vid_p->vid_dip == dip && vid_p->vid_ino == ino) { 597 mutex_exit(&vnex_id_lock); 598 return (vid_p); 599 } 600 vid_p = vid_p->vid_next; 601 } 602 mutex_exit(&vnex_id_lock); 603 return (NULL); 604 } 605 606 static void 607 vnex_free_id(vnex_id_t *vid_p) 608 { 609 mutex_enter(&vnex_id_lock); 610 vnex_rem_id(vid_p); 611 mutex_exit(&vnex_id_lock); 612 613 kmem_free(vid_p, sizeof (*vid_p)); 614 } 615 616 static void 617 vnex_rem_id(vnex_id_t *vid_p) 618 { 619 vnex_id_t *prev_p = vnex_id_list; 620 621 if (vnex_id_list == NULL) 622 cmn_err(CE_PANIC, "vnex: interrupt list empty"); 623 624 if (vid_p == NULL) 625 cmn_err(CE_PANIC, "vnex: no element to remove"); 626 627 if (vnex_id_list == vid_p) { 628 vnex_id_list = vid_p->vid_next; 629 } else { 630 while (prev_p != NULL && prev_p->vid_next != vid_p) 631 prev_p = prev_p->vid_next; 632 633 if (prev_p == NULL) 634 cmn_err(CE_PANIC, "vnex: element %p not in list", 635 (void *) vid_p); 636 637 prev_p->vid_next = vid_p->vid_next; 638 } 639 } 640 641 static void 642 vnex_add_id(vnex_id_t *vid_p) 643 { 644 vid_p->vid_next = vnex_id_list; 645 vnex_id_list = vid_p; 646 } 647 648 uint_t 649 vnex_intr_wrapper(caddr_t arg) 650 { 651 vnex_id_t *vid_p = (vnex_id_t *)arg; 652 int res; 653 uint_t (*handler)(); 654 caddr_t handler_arg1; 655 caddr_t handler_arg2; 656 657 handler = vid_p->vid_handler; 658 handler_arg1 = vid_p->vid_arg1; 659 handler_arg2 = vid_p->vid_arg2; 660 661 res = (*handler)(handler_arg1, handler_arg2); 662 663 (void) hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE); 664 665 return (res); 666 } 667