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