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 2006 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/promif.h> 40 #include <sys/machsystm.h> 41 #include <sys/ddi_intr_impl.h> 42 #include <sys/hypervisor_api.h> 43 #include <sys/intr.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 }; 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 static int 427 vnex_add_intr(dev_info_t *dip, dev_info_t *rdip, 428 ddi_intr_handle_impl_t *hdlp) 429 { 430 int reglen, ret = DDI_SUCCESS; 431 vnex_id_t *vid_p; 432 uint64_t cfg; 433 uint32_t ino; 434 uint64_t ihdl; 435 vnex_regspec_t *reg_p; 436 437 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 438 DDI_PROP_DONTPASS, "reg", (caddr_t)®_p, 439 ®len) != DDI_SUCCESS) { 440 return (DDI_FAILURE); 441 } 442 443 /* 444 * get the sun4v config handle for this device 445 */ 446 447 cfg = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr); 448 kmem_free(reg_p, reglen); 449 ino = hdlp->ih_vector; 450 451 /* 452 * call hv to get vihdl 453 */ 454 if (hvio_intr_devino_to_sysino(cfg, ino, &ihdl) != H_EOK) 455 return (DDI_FAILURE); 456 457 hdlp->ih_vector = ihdl; 458 /* 459 * Allocate a interrupt descriptor (id) with the 460 * the interrupt handler and append it to 461 * the id list. 462 */ 463 464 vid_p = vnex_alloc_id(rdip, ino, cfg); 465 vid_p->vid_ihdl = ihdl; 466 vid_p->vid_handler = hdlp->ih_cb_func; 467 vid_p->vid_arg1 = hdlp->ih_cb_arg1; 468 vid_p->vid_arg2 = hdlp->ih_cb_arg2; 469 vid_p->vid_ddi_hdlp = hdlp; 470 471 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, 472 (ddi_intr_handler_t *)vnex_intr_wrapper, (caddr_t)vid_p, NULL); 473 474 if (hdlp->ih_pri == 0) { 475 hdlp->ih_pri = vnex_get_pil(rdip); 476 } 477 478 ret = i_ddi_add_ivintr(hdlp); 479 if (ret != DDI_SUCCESS) { 480 return (ret); 481 } 482 483 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, vid_p->vid_handler, 484 vid_p->vid_arg1, vid_p->vid_arg2); 485 486 return (ret); 487 } 488 489 static int 490 vnex_remove_intr(dev_info_t *rdip, 491 ddi_intr_handle_impl_t *hdlp) 492 { 493 vnex_id_t *vid_p; 494 uint32_t ino; 495 int ret = DDI_SUCCESS; 496 497 ino = hdlp->ih_vector; 498 vid_p = vnex_locate_id(rdip, ino); 499 500 hdlp->ih_vector = vid_p->vid_ihdl; 501 i_ddi_rem_ivintr(hdlp); 502 503 vnex_free_id(vid_p); 504 505 return (ret); 506 } 507 508 static int 509 vnex_intr_ops(dev_info_t *dip, dev_info_t *rdip, 510 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result) 511 { 512 int ret = DDI_SUCCESS; 513 514 switch (intr_op) { 515 case DDI_INTROP_GETCAP: 516 *(int *)result = DDI_INTR_FLAG_LEVEL; 517 break; 518 case DDI_INTROP_ALLOC: 519 *(int *)result = hdlp->ih_scratch1; 520 break; 521 case DDI_INTROP_GETPRI: 522 *(int *)result = hdlp->ih_pri ? 523 hdlp->ih_pri : vnex_get_pil(rdip); 524 break; 525 case DDI_INTROP_FREE: 526 break; 527 case DDI_INTROP_SETPRI: 528 break; 529 case DDI_INTROP_ADDISR: 530 ret = vnex_add_intr(dip, rdip, hdlp); 531 break; 532 case DDI_INTROP_REMISR: 533 ret = vnex_remove_intr(rdip, hdlp); 534 break; 535 case DDI_INTROP_ENABLE: 536 ret = vnex_enable_intr(rdip, hdlp); 537 break; 538 case DDI_INTROP_DISABLE: 539 ret = vnex_disable_intr(rdip, hdlp); 540 break; 541 case DDI_INTROP_NINTRS: 542 case DDI_INTROP_NAVAIL: 543 *(int *)result = i_ddi_get_nintrs(rdip); 544 break; 545 case DDI_INTROP_SUPPORTED_TYPES: 546 *(int *)result = i_ddi_get_nintrs(rdip) ? 547 DDI_INTR_TYPE_FIXED : 0; 548 break; 549 default: 550 ret = DDI_ENOTSUP; 551 break; 552 } 553 554 return (ret); 555 } 556 557 vnex_id_t * 558 vnex_alloc_id(dev_info_t *dip, uint32_t ino, uint64_t dhdl) 559 { 560 vnex_id_t *vid_p = kmem_alloc(sizeof (vnex_id_t), KM_SLEEP); 561 562 vid_p->vid_dip = dip; 563 vid_p->vid_ino = ino; 564 vid_p->vid_cfg_hdl = dhdl; 565 566 mutex_enter(&vnex_id_lock); 567 vnex_add_id(vid_p); 568 mutex_exit(&vnex_id_lock); 569 570 return (vid_p); 571 } 572 573 vnex_id_t * 574 vnex_locate_id(dev_info_t *dip, uint32_t ino) 575 { 576 vnex_id_t *vid_p; 577 578 mutex_enter(&vnex_id_lock); 579 vid_p = vnex_id_list; 580 581 while (vid_p != NULL) { 582 if (vid_p->vid_dip == dip && vid_p->vid_ino == ino) { 583 mutex_exit(&vnex_id_lock); 584 return (vid_p); 585 } 586 vid_p = vid_p->vid_next; 587 } 588 mutex_exit(&vnex_id_lock); 589 return (NULL); 590 } 591 592 static void 593 vnex_free_id(vnex_id_t *vid_p) 594 { 595 mutex_enter(&vnex_id_lock); 596 vnex_rem_id(vid_p); 597 mutex_exit(&vnex_id_lock); 598 599 kmem_free(vid_p, sizeof (*vid_p)); 600 } 601 602 static void 603 vnex_rem_id(vnex_id_t *vid_p) 604 { 605 vnex_id_t *prev_p = vnex_id_list; 606 607 if (vnex_id_list == NULL) 608 cmn_err(CE_PANIC, "vnex: interrupt list empty"); 609 610 if (vid_p == NULL) 611 cmn_err(CE_PANIC, "vnex: no element to remove"); 612 613 if (vnex_id_list == vid_p) { 614 vnex_id_list = vid_p->vid_next; 615 } else { 616 while (prev_p != NULL && prev_p->vid_next != vid_p) 617 prev_p = prev_p->vid_next; 618 619 if (prev_p == NULL) 620 cmn_err(CE_PANIC, "vnex: element %p not in list", 621 (void *) vid_p); 622 623 prev_p->vid_next = vid_p->vid_next; 624 } 625 } 626 627 static void 628 vnex_add_id(vnex_id_t *vid_p) 629 { 630 vid_p->vid_next = vnex_id_list; 631 vnex_id_list = vid_p; 632 } 633 634 uint_t 635 vnex_intr_wrapper(caddr_t arg) 636 { 637 vnex_id_t *vid_p = (vnex_id_t *)arg; 638 int res; 639 uint_t (*handler)(); 640 caddr_t handler_arg1; 641 caddr_t handler_arg2; 642 643 handler = vid_p->vid_handler; 644 handler_arg1 = vid_p->vid_arg1; 645 handler_arg2 = vid_p->vid_arg2; 646 647 res = (*handler)(handler_arg1, handler_arg2); 648 649 (void) hvio_intr_setstate(vid_p->vid_ihdl, HV_INTR_IDLE_STATE); 650 651 return (res); 652 } 653