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