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