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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2018 Joyent, Inc. 26 */ 27 28 #define PSMI_1_7 29 30 #include <sys/mutex.h> 31 #include <sys/types.h> 32 #include <sys/time.h> 33 #include <sys/clock.h> 34 #include <sys/machlock.h> 35 #include <sys/smp_impldefs.h> 36 #include <sys/uadmin.h> 37 #include <sys/promif.h> 38 #include <sys/psm.h> 39 #include <sys/psm_common.h> 40 #include <sys/atomic.h> 41 #include <sys/archsystm.h> 42 #include <sys/mach_intr.h> 43 #include <sys/hypervisor.h> 44 #include <sys/evtchn_impl.h> 45 #include <sys/modctl.h> 46 #include <sys/trap.h> 47 #include <sys/panic.h> 48 49 #include <xen/public/vcpu.h> 50 #include <xen/public/physdev.h> 51 52 53 /* 54 * Global Data 55 */ 56 int xen_uppc_use_acpi = 1; /* Use ACPI by default */ 57 int xen_uppc_enable_acpi = 0; 58 59 static int xen_clock_irq = -1; 60 61 /* 62 * For interrupt link devices, if xen_uppc_unconditional_srs is set, an irq 63 * resource will be assigned (via _SRS). If it is not set, use the current 64 * irq setting (via _CRS), but only if that irq is in the set of possible 65 * irqs (returned by _PRS) for the device. 66 */ 67 int xen_uppc_unconditional_srs = 1; 68 69 /* 70 * For interrupt link devices, if xen_uppc_prefer_crs is set when we are 71 * assigning an IRQ resource to a device, prefer the current IRQ setting 72 * over other possible irq settings under same conditions. 73 */ 74 int xen_uppc_prefer_crs = 1; 75 76 int xen_uppc_verbose = 0; 77 78 /* flag definitions for xen_uppc_verbose */ 79 #define XEN_UPPC_VERBOSE_IRQ_FLAG 0x00000001 80 #define XEN_UPPC_VERBOSE_POWEROFF_FLAG 0x00000002 81 #define XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG 0x00000004 82 83 #define XEN_UPPC_VERBOSE_IRQ(fmt) \ 84 if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG) \ 85 cmn_err fmt; 86 87 #define XEN_UPPC_VERBOSE_POWEROFF(fmt) \ 88 if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG) \ 89 prom_printf fmt; 90 91 uchar_t xen_uppc_reserved_irqlist[MAX_ISA_IRQ + 1]; 92 93 static uint16_t xen_uppc_irq_shared_table[MAX_ISA_IRQ + 1]; 94 95 /* 96 * Contains SCI irqno from FADT after initialization 97 */ 98 static int xen_uppc_sci = -1; 99 100 static struct psm_info xen_uppc_info; 101 102 /* 103 * Local support routines 104 */ 105 106 static int 107 xen_uppc_init_acpi(void) 108 { 109 int verboseflags = 0; 110 int sci; 111 iflag_t sci_flags; 112 113 /* 114 * Process SCI configuration here; this may return 115 * an error if acpi-user-options has specified 116 * legacy mode (use ACPI without ACPI mode or SCI) 117 */ 118 if (acpica_get_sci(&sci, &sci_flags) != AE_OK) 119 sci = -1; 120 121 /* 122 * Initialize sub-system - if error is returns, ACPI is not 123 * used. 124 */ 125 if (acpica_init() != AE_OK) 126 return (0); 127 128 /* 129 * uppc implies system is in PIC mode; set edge/level 130 * via ELCR based on return value from get_sci; this 131 * will default to level/low if no override present, 132 * as recommended by Intel ACPI CA team. 133 */ 134 if (sci >= 0) { 135 ASSERT((sci_flags.intr_el == INTR_EL_LEVEL) || 136 (sci_flags.intr_el == INTR_EL_EDGE)); 137 138 psm_set_elcr(sci, sci_flags.intr_el == INTR_EL_LEVEL); 139 } 140 141 /* 142 * Remember SCI for later use 143 */ 144 xen_uppc_sci = sci; 145 146 if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG) 147 verboseflags |= PSM_VERBOSE_IRQ_FLAG; 148 149 if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG) 150 verboseflags |= PSM_VERBOSE_POWEROFF_FLAG; 151 152 if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG) 153 verboseflags |= PSM_VERBOSE_POWEROFF_PAUSE_FLAG; 154 155 if (acpi_psm_init(xen_uppc_info.p_mach_idstring, verboseflags) == 156 ACPI_PSM_FAILURE) { 157 return (0); 158 } 159 160 return (1); 161 } 162 163 /* 164 * Autoconfiguration Routines 165 */ 166 167 static int 168 xen_uppc_probe(void) 169 { 170 171 return (PSM_SUCCESS); 172 } 173 174 static void 175 xen_uppc_softinit(void) 176 { 177 int i; 178 179 /* LINTED logical expression always true: op "||" */ 180 ASSERT((1 << EVTCHN_SHIFT) == NBBY * sizeof (ulong_t)); 181 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 182 if (xen_uppc_use_acpi && xen_uppc_init_acpi()) { 183 build_reserved_irqlist((uchar_t *) 184 xen_uppc_reserved_irqlist); 185 for (i = 0; i <= MAX_ISA_IRQ; i++) 186 xen_uppc_irq_shared_table[i] = 0; 187 xen_uppc_enable_acpi = 1; 188 } 189 } 190 } 191 192 193 #define XEN_NSEC_PER_TICK 10 /* XXX - assume we have a 100 Mhz clock */ 194 195 /*ARGSUSED*/ 196 static int 197 xen_uppc_clkinit(int hertz) 198 { 199 extern enum tod_fault_type tod_fault(enum tod_fault_type, int); 200 extern int dosynctodr; 201 202 /* 203 * domU cannot set the TOD hardware, fault the TOD clock now to 204 * indicate that and turn off attempts to sync TOD hardware 205 * with the hires timer. 206 */ 207 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 208 mutex_enter(&tod_lock); 209 (void) tod_fault(TOD_RDONLY, 0); 210 dosynctodr = 0; 211 mutex_exit(&tod_lock); 212 } 213 /* 214 * The hypervisor provides a timer based on the local APIC timer. 215 * The interface supports requests of nanosecond resolution. 216 * A common frequency of the apic clock is 100 Mhz which 217 * gives a resolution of 10 nsec per tick. What we would really like 218 * is a way to get the ns per tick value from xen. 219 * XXPV - This is an assumption that needs checking and may change 220 */ 221 return (XEN_NSEC_PER_TICK); 222 } 223 224 static void 225 xen_uppc_picinit() 226 { 227 int irqno; 228 229 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 230 #if 0 231 /* hypervisor initializes the 8259, don't mess with it */ 232 picsetup(); /* initialise the 8259 */ 233 #endif 234 /* 235 * We never called xen_uppc_addspl() when the SCI 236 * interrupt was added because that happened before the 237 * PSM module was loaded. Fix that up here by doing 238 * any missed operations (e.g. bind to CPU) 239 */ 240 if ((irqno = xen_uppc_sci) >= 0) { 241 ec_enable_irq(irqno); 242 } 243 } 244 } 245 246 247 /*ARGSUSED*/ 248 static int 249 xen_uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl) 250 { 251 int ret = PSM_SUCCESS; 252 cpuset_t cpus; 253 254 if (irqno >= 0 && irqno <= MAX_ISA_IRQ) 255 atomic_inc_16(&xen_uppc_irq_shared_table[irqno]); 256 257 /* 258 * We are called at splhi() so we can't call anything that might end 259 * up trying to context switch. 260 */ 261 if (irqno >= PIRQ_BASE && irqno < NR_PIRQS && 262 DOMAIN_IS_INITDOMAIN(xen_info)) { 263 CPUSET_ZERO(cpus); 264 CPUSET_ADD(cpus, 0); 265 ec_setup_pirq(irqno, ipl, &cpus); 266 } else { 267 /* 268 * Set priority/affinity/enable for non PIRQs 269 */ 270 ret = ec_set_irq_priority(irqno, ipl); 271 ASSERT(ret == 0); 272 CPUSET_ZERO(cpus); 273 CPUSET_ADD(cpus, 0); 274 ec_set_irq_affinity(irqno, cpus); 275 ec_enable_irq(irqno); 276 } 277 278 return (ret); 279 } 280 281 /*ARGSUSED*/ 282 static int 283 xen_uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl) 284 { 285 int err = PSM_SUCCESS; 286 287 if (irqno >= 0 && irqno <= MAX_ISA_IRQ) 288 atomic_dec_16(&xen_uppc_irq_shared_table[irqno]); 289 290 if (irqno >= PIRQ_BASE && irqno < NR_PIRQS && 291 DOMAIN_IS_INITDOMAIN(xen_info)) { 292 if (max_ipl == PSM_INVALID_IPL) { 293 /* 294 * unbind if no more sharers of this irq/evtchn 295 */ 296 (void) ec_block_irq(irqno); 297 ec_unbind_irq(irqno); 298 } else { 299 /* 300 * If still in use reset priority 301 */ 302 err = ec_set_irq_priority(irqno, max_ipl); 303 } 304 } else { 305 (void) ec_block_irq(irqno); 306 ec_unbind_irq(irqno); 307 } 308 return (err); 309 } 310 311 static processorid_t 312 xen_uppc_get_next_processorid(processorid_t id) 313 { 314 if (id == -1) 315 return (0); 316 return (-1); 317 } 318 319 /*ARGSUSED*/ 320 static int 321 xen_uppc_get_clockirq(int ipl) 322 { 323 if (xen_clock_irq != -1) 324 return (xen_clock_irq); 325 326 xen_clock_irq = ec_bind_virq_to_irq(VIRQ_TIMER, 0); 327 return (xen_clock_irq); 328 } 329 330 /*ARGSUSED*/ 331 static void 332 xen_uppc_shutdown(int cmd, int fcn) 333 { 334 XEN_UPPC_VERBOSE_POWEROFF(("xen_uppc_shutdown(%d,%d);\n", cmd, fcn)); 335 336 switch (cmd) { 337 case A_SHUTDOWN: 338 switch (fcn) { 339 case AD_BOOT: 340 case AD_IBOOT: 341 (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); 342 break; 343 case AD_POWEROFF: 344 /* fall through if domU or if poweroff fails */ 345 if (DOMAIN_IS_INITDOMAIN(xen_info)) 346 if (xen_uppc_enable_acpi) 347 (void) acpi_poweroff(); 348 /* FALLTHRU */ 349 case AD_HALT: 350 default: 351 (void) HYPERVISOR_shutdown(SHUTDOWN_poweroff); 352 break; 353 } 354 break; 355 case A_REBOOT: 356 (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); 357 break; 358 default: 359 return; 360 } 361 } 362 363 364 /* 365 * This function will reprogram the timer. 366 * 367 * When in oneshot mode the argument is the absolute time in future at which to 368 * generate the interrupt. 369 * 370 * When in periodic mode, the argument is the interval at which the 371 * interrupts should be generated. There is no need to support the periodic 372 * mode timer change at this time. 373 * 374 * Note that we must be careful to convert from hrtime to Xen system time (see 375 * xpv_timestamp.c). 376 */ 377 static void 378 xen_uppc_timer_reprogram(hrtime_t timer_req) 379 { 380 hrtime_t now, timer_new, time_delta, xen_time; 381 ulong_t flags; 382 383 flags = intr_clear(); 384 /* 385 * We should be called from high PIL context (CBE_HIGH_PIL), 386 * so kpreempt is disabled. 387 */ 388 389 now = xpv_gethrtime(); 390 xen_time = xpv_getsystime(); 391 if (timer_req <= now) { 392 /* 393 * requested to generate an interrupt in the past 394 * generate an interrupt as soon as possible 395 */ 396 time_delta = XEN_NSEC_PER_TICK; 397 } else 398 time_delta = timer_req - now; 399 400 timer_new = xen_time + time_delta; 401 if (HYPERVISOR_set_timer_op(timer_new) != 0) 402 panic("can't set hypervisor timer?"); 403 intr_restore(flags); 404 } 405 406 /* 407 * This function will enable timer interrupts. 408 */ 409 static void 410 xen_uppc_timer_enable(void) 411 { 412 ec_unmask_irq(xen_clock_irq); 413 } 414 415 /* 416 * This function will disable timer interrupts on the current cpu. 417 */ 418 static void 419 xen_uppc_timer_disable(void) 420 { 421 (void) ec_block_irq(xen_clock_irq); 422 /* 423 * If the clock irq is pending on this cpu then we need to 424 * clear the pending interrupt. 425 */ 426 ec_unpend_irq(xen_clock_irq); 427 } 428 429 430 /* 431 * Configures the irq for the interrupt link device identified by 432 * acpipsmlnkp. 433 * 434 * Gets the current and the list of possible irq settings for the 435 * device. If xen_uppc_unconditional_srs is not set, and the current 436 * resource setting is in the list of possible irq settings, 437 * current irq resource setting is passed to the caller. 438 * 439 * Otherwise, picks an irq number from the list of possible irq 440 * settings, and sets the irq of the device to this value. 441 * If prefer_crs is set, among a set of irq numbers in the list that have 442 * the least number of devices sharing the interrupt, we pick current irq 443 * resource setting if it is a member of this set. 444 * 445 * Passes the irq number in the value pointed to by pci_irqp, and 446 * polarity and sensitivity in the structure pointed to by dipintrflagp 447 * to the caller. 448 * 449 * Note that if setting the irq resource failed, but successfuly obtained 450 * the current irq resource settings, passes the current irq resources 451 * and considers it a success. 452 * 453 * Returns: 454 * ACPI_PSM_SUCCESS on success. 455 * 456 * ACPI_PSM_FAILURE if an error occured during the configuration or 457 * if a suitable irq was not found for this device, or if setting the 458 * irq resource and obtaining the current resource fails. 459 * 460 */ 461 static int 462 xen_uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip, 463 int *pci_irqp, iflag_t *dipintr_flagp) 464 { 465 int i, min_share, foundnow, done = 0; 466 int32_t irq; 467 int32_t share_irq = -1; 468 int32_t chosen_irq = -1; 469 int cur_irq = -1; 470 acpi_irqlist_t *irqlistp; 471 acpi_irqlist_t *irqlistent; 472 473 if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp)) 474 == ACPI_PSM_FAILURE) { 475 XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Unable to determine " 476 "or assign IRQ for device %s, instance #%d: The system was " 477 "unable to get the list of potential IRQs from ACPI.", 478 ddi_get_name(dip), ddi_get_instance(dip))); 479 480 return (ACPI_PSM_FAILURE); 481 } 482 483 if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq, 484 dipintr_flagp) == ACPI_PSM_SUCCESS) && 485 (!xen_uppc_unconditional_srs) && 486 (cur_irq > 0)) { 487 488 if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL) 489 == ACPI_PSM_SUCCESS) { 490 491 acpi_free_irqlist(irqlistp); 492 ASSERT(pci_irqp != NULL); 493 *pci_irqp = cur_irq; 494 return (ACPI_PSM_SUCCESS); 495 } 496 XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Could not find the " 497 "current irq %d for device %s, instance #%d in ACPI's " 498 "list of possible irqs for this device. Picking one from " 499 " the latter list.", cur_irq, ddi_get_name(dip), 500 ddi_get_instance(dip))); 501 502 } 503 504 irqlistent = irqlistp; 505 min_share = 255; 506 507 while (irqlistent != NULL) { 508 509 for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) { 510 511 irq = irqlistp->irqs[i]; 512 513 if ((irq > MAX_ISA_IRQ) || 514 (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) || 515 (irq == 0)) 516 continue; 517 518 if (xen_uppc_reserved_irqlist[irq]) 519 continue; 520 521 if (xen_uppc_irq_shared_table[irq] == 0) { 522 chosen_irq = irq; 523 foundnow = 1; 524 if (!(xen_uppc_prefer_crs) || 525 (irq == cur_irq)) { 526 done = 1; 527 break; 528 } 529 } 530 531 if ((xen_uppc_irq_shared_table[irq] < min_share) || 532 ((xen_uppc_irq_shared_table[irq] == min_share) && 533 (cur_irq == irq) && (xen_uppc_prefer_crs))) { 534 min_share = xen_uppc_irq_shared_table[irq]; 535 share_irq = irq; 536 foundnow = 1; 537 } 538 } 539 540 /* If we found an IRQ in the inner loop, save the details */ 541 if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) { 542 /* 543 * Copy the acpi_prs_private_t and flags from this 544 * irq list entry, since we found an irq from this 545 * entry. 546 */ 547 acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv; 548 *dipintr_flagp = irqlistent->intr_flags; 549 } 550 551 if (done) 552 break; 553 554 /* Load the next entry in the irqlist */ 555 irqlistent = irqlistent->next; 556 } 557 558 acpi_free_irqlist(irqlistp); 559 560 if (chosen_irq != -1) 561 irq = chosen_irq; 562 else if (share_irq != -1) 563 irq = share_irq; 564 else { 565 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Could not find a " 566 "suitable irq from the list of possible irqs for device " 567 "%s, instance #%d in ACPI's list of possible\n", 568 ddi_get_name(dip), ddi_get_instance(dip))); 569 570 return (ACPI_PSM_FAILURE); 571 } 572 573 574 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Setting irq %d " 575 "for device %s instance #%d\n", irq, ddi_get_name(dip), 576 ddi_get_instance(dip))); 577 578 if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) { 579 /* 580 * setting irq was successful, check to make sure CRS 581 * reflects that. If CRS does not agree with what we 582 * set, return the irq that was set. 583 */ 584 585 if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq, 586 dipintr_flagp) == ACPI_PSM_SUCCESS) { 587 588 if (cur_irq != irq) 589 XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: " 590 "IRQ resource set (irqno %d) for device %s " 591 "instance #%d, differs from current " 592 "setting irqno %d", 593 irq, ddi_get_name(dip), 594 ddi_get_instance(dip), cur_irq)); 595 } 596 /* 597 * return the irq that was set, and not what CRS reports, 598 * since CRS has been seen to be bogus on some systems 599 */ 600 cur_irq = irq; 601 } else { 602 XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: set resource irq %d " 603 "failed for device %s instance #%d", 604 irq, ddi_get_name(dip), ddi_get_instance(dip))); 605 if (cur_irq == -1) 606 return (ACPI_PSM_FAILURE); 607 } 608 609 ASSERT(pci_irqp != NULL); 610 *pci_irqp = cur_irq; 611 return (ACPI_PSM_SUCCESS); 612 } 613 614 615 static int 616 xen_uppc_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid, 617 int ipin, int *pci_irqp, iflag_t *intr_flagp) 618 { 619 int status; 620 acpi_psm_lnk_t acpipsmlnk; 621 622 if ((status = acpi_get_irq_cache_ent(busid, devid, ipin, pci_irqp, 623 intr_flagp)) == ACPI_PSM_SUCCESS) { 624 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Found irqno %d " 625 "from cache for device %s, instance #%d\n", *pci_irqp, 626 ddi_get_name(dip), ddi_get_instance(dip))); 627 return (status); 628 } 629 630 bzero(&acpipsmlnk, sizeof (acpi_psm_lnk_t)); 631 632 if ((status = acpi_translate_pci_irq(dip, ipin, pci_irqp, 633 intr_flagp, &acpipsmlnk)) == ACPI_PSM_FAILURE) { 634 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: " 635 " acpi_translate_pci_irq failed for device %s, instance" 636 " #%d\n", ddi_get_name(dip), ddi_get_instance(dip))); 637 638 return (status); 639 } 640 641 if (status == ACPI_PSM_PARTIAL && acpipsmlnk.lnkobj != NULL) { 642 status = xen_uppc_acpi_irq_configure(&acpipsmlnk, dip, pci_irqp, 643 intr_flagp); 644 if (status != ACPI_PSM_SUCCESS) { 645 status = acpi_get_current_irq_resource(&acpipsmlnk, 646 pci_irqp, intr_flagp); 647 } 648 } 649 650 if (status == ACPI_PSM_SUCCESS) { 651 acpi_new_irq_cache_ent(busid, devid, ipin, *pci_irqp, 652 intr_flagp, &acpipsmlnk); 653 psm_set_elcr(*pci_irqp, 1); /* set IRQ to PCI mode */ 654 655 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] " 656 "new irq %d for device %s, instance #%d\n", 657 *pci_irqp, ddi_get_name(dip), ddi_get_instance(dip))); 658 } 659 660 return (status); 661 } 662 663 664 /*ARGSUSED*/ 665 static int 666 xen_uppc_translate_irq(dev_info_t *dip, int irqno) 667 { 668 char dev_type[16]; 669 int dev_len, pci_irq, devid, busid; 670 ddi_acc_handle_t cfg_handle; 671 uchar_t ipin, iline; 672 iflag_t intr_flag; 673 674 if (dip == NULL) { 675 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno = %d" 676 " dip = NULL\n", irqno)); 677 return (irqno); 678 } 679 680 if (!xen_uppc_enable_acpi) { 681 return (irqno); 682 } 683 684 dev_len = sizeof (dev_type); 685 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip), 686 DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, 687 &dev_len) != DDI_PROP_SUCCESS) { 688 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno %d" 689 " device %s instance %d no device_type\n", irqno, 690 ddi_get_name(dip), ddi_get_instance(dip))); 691 return (irqno); 692 } 693 694 if ((strcmp(dev_type, "pci") == 0) || 695 (strcmp(dev_type, "pciex") == 0)) { 696 697 /* pci device */ 698 if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0) 699 return (irqno); 700 701 if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS) 702 return (irqno); 703 704 ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA; 705 iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE); 706 if (xen_uppc_acpi_translate_pci_irq(dip, busid, devid, 707 ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) { 708 709 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] " 710 "new irq %d old irq %d device %s, instance %d\n", 711 pci_irq, irqno, ddi_get_name(dip), 712 ddi_get_instance(dip))); 713 714 /* 715 * Make sure pci_irq is within range. 716 * Otherwise, fall through and return irqno. 717 */ 718 if (pci_irq <= MAX_ISA_IRQ) { 719 if (iline != pci_irq) { 720 /* 721 * Update the device's ILINE byte, 722 * in case uppc_acpi_translate_pci_irq 723 * has choosen a different pci_irq 724 * than the BIOS has configured. 725 * Some chipsets use the value in 726 * ILINE to control interrupt routing, 727 * in conflict with the PCI spec. 728 */ 729 pci_config_put8(cfg_handle, 730 PCI_CONF_ILINE, pci_irq); 731 } 732 pci_config_teardown(&cfg_handle); 733 return (pci_irq); 734 } 735 } 736 pci_config_teardown(&cfg_handle); 737 738 /* FALLTHRU to common case - returning irqno */ 739 } else { 740 /* non-PCI; assumes ISA-style edge-triggered */ 741 psm_set_elcr(irqno, 0); /* set IRQ to ISA mode */ 742 743 XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: non-pci," 744 "irqno %d device %s instance %d\n", irqno, 745 ddi_get_name(dip), ddi_get_instance(dip))); 746 } 747 748 return (irqno); 749 } 750 751 /* 752 * xen_uppc_intr_enter() acks the event that triggered the interrupt and 753 * returns the new priority level, 754 */ 755 /*ARGSUSED*/ 756 static int 757 xen_uppc_intr_enter(int ipl, int *vector) 758 { 759 int newipl; 760 uint_t intno; 761 cpu_t *cpu = CPU; 762 763 intno = (*vector); 764 765 ASSERT(intno < NR_IRQS); 766 ASSERT(cpu->cpu_m.mcpu_vcpu_info->evtchn_upcall_mask != 0); 767 768 ec_clear_irq(intno); 769 770 newipl = autovect[intno].avh_hi_pri; 771 if (newipl == 0) { 772 /* 773 * (newipl == 0) means we have no service routines for this 774 * vector. We will treat this as a spurious interrupt. 775 * We have cleared the pending bit already, clear the event 776 * mask and return a spurious interrupt. This case can happen 777 * when an interrupt delivery is racing with the removal of 778 * of the service routine for that interrupt. 779 */ 780 ec_unmask_irq(intno); 781 newipl = -1; /* flag spurious interrupt */ 782 } else if (newipl <= cpu->cpu_pri) { 783 /* 784 * (newipl <= cpu->cpu_pri) means that we must be trying to 785 * service a vector that was shared with a higher priority 786 * isr. The higher priority handler has been removed and 787 * we need to service this int. We can't return a lower 788 * priority than current cpu priority. Just synthesize a 789 * priority to return that should be acceptable. 790 */ 791 newipl = cpu->cpu_pri + 1; /* synthetic priority */ 792 } 793 return (newipl); 794 } 795 796 797 static void xen_uppc_setspl(int); 798 799 /* 800 * xen_uppc_intr_exit() restores the old interrupt 801 * priority level after processing an interrupt. 802 * It is called with interrupts disabled, and does not enable interrupts. 803 */ 804 /* ARGSUSED */ 805 static void 806 xen_uppc_intr_exit(int ipl, int vector) 807 { 808 ec_try_unmask_irq(vector); 809 xen_uppc_setspl(ipl); 810 } 811 812 intr_exit_fn_t 813 psm_intr_exit_fn(void) 814 { 815 return (xen_uppc_intr_exit); 816 } 817 818 /* 819 * Check if new ipl level allows delivery of previously unserviced events 820 */ 821 static void 822 xen_uppc_setspl(int ipl) 823 { 824 struct cpu *cpu = CPU; 825 volatile vcpu_info_t *vci = cpu->cpu_m.mcpu_vcpu_info; 826 uint16_t pending; 827 828 ASSERT(vci->evtchn_upcall_mask != 0); 829 830 /* 831 * If new ipl level will enable any pending interrupts, setup so the 832 * upcoming sti will cause us to get an upcall. 833 */ 834 pending = cpu->cpu_m.mcpu_intr_pending & ~((1 << (ipl + 1)) - 1); 835 if (pending) { 836 int i; 837 ulong_t pending_sels = 0; 838 volatile ulong_t *selp; 839 struct xen_evt_data *cpe = cpu->cpu_m.mcpu_evt_pend; 840 841 for (i = bsrw_insn(pending); i > ipl; i--) 842 pending_sels |= cpe->pending_sel[i]; 843 ASSERT(pending_sels); 844 selp = (volatile ulong_t *)&vci->evtchn_pending_sel; 845 atomic_or_ulong(selp, pending_sels); 846 vci->evtchn_upcall_pending = 1; 847 } 848 } 849 850 /* 851 * The rest of the file is just generic psm module boilerplate 852 */ 853 854 static struct psm_ops xen_uppc_ops = { 855 xen_uppc_probe, /* psm_probe */ 856 857 xen_uppc_softinit, /* psm_init */ 858 xen_uppc_picinit, /* psm_picinit */ 859 xen_uppc_intr_enter, /* psm_intr_enter */ 860 xen_uppc_intr_exit, /* psm_intr_exit */ 861 xen_uppc_setspl, /* psm_setspl */ 862 xen_uppc_addspl, /* psm_addspl */ 863 xen_uppc_delspl, /* psm_delspl */ 864 (int (*)(processorid_t))NULL, /* psm_disable_intr */ 865 (void (*)(processorid_t))NULL, /* psm_enable_intr */ 866 (int (*)(int))NULL, /* psm_softlvl_to_irq */ 867 (void (*)(int))NULL, /* psm_set_softintr */ 868 (void (*)(processorid_t))NULL, /* psm_set_idlecpu */ 869 (void (*)(processorid_t))NULL, /* psm_unset_idlecpu */ 870 871 xen_uppc_clkinit, /* psm_clkinit */ 872 xen_uppc_get_clockirq, /* psm_get_clockirq */ 873 (void (*)(void))NULL, /* psm_hrtimeinit */ 874 xpv_gethrtime, /* psm_gethrtime */ 875 876 xen_uppc_get_next_processorid, /* psm_get_next_processorid */ 877 (int (*)(processorid_t, caddr_t))NULL, /* psm_cpu_start */ 878 (int (*)(void))NULL, /* psm_post_cpu_start */ 879 xen_uppc_shutdown, /* psm_shutdown */ 880 (int (*)(int, int))NULL, /* psm_get_ipivect */ 881 (void (*)(processorid_t, int))NULL, /* psm_send_ipi */ 882 883 xen_uppc_translate_irq, /* psm_translate_irq */ 884 885 (void (*)(int, char *))NULL, /* psm_notify_error */ 886 (void (*)(int msg))NULL, /* psm_notify_func */ 887 xen_uppc_timer_reprogram, /* psm_timer_reprogram */ 888 xen_uppc_timer_enable, /* psm_timer_enable */ 889 xen_uppc_timer_disable, /* psm_timer_disable */ 890 (void (*)(void *arg))NULL, /* psm_post_cyclic_setup */ 891 (void (*)(int, int))NULL, /* psm_preshutdown */ 892 893 (int (*)(dev_info_t *, ddi_intr_handle_impl_t *, 894 psm_intr_op_t, int *))NULL, /* psm_intr_ops */ 895 (int (*)(psm_state_request_t *))NULL, /* psm_state */ 896 (int (*)(psm_cpu_request_t *))NULL, /* psm_cpu_ops */ 897 898 (int (*)(void))NULL, /* psm_get_pir_ipivect */ 899 (void (*)(processorid_t))NULL, /* psm_send_pir_ipi */ 900 (void (*)(processorid_t, boolean_t))NULL /* psm_cmci_setup */ 901 }; 902 903 static struct psm_info xen_uppc_info = { 904 PSM_INFO_VER01_5, /* version */ 905 PSM_OWN_SYS_DEFAULT, /* ownership */ 906 &xen_uppc_ops, /* operation */ 907 "xVM_uppc", /* machine name */ 908 "UniProcessor PC" /* machine descriptions */ 909 }; 910 911 static void *xen_uppc_hdlp; 912 913 int 914 _init(void) 915 { 916 return (psm_mod_init(&xen_uppc_hdlp, &xen_uppc_info)); 917 } 918 919 int 920 _fini(void) 921 { 922 return (psm_mod_fini(&xen_uppc_hdlp, &xen_uppc_info)); 923 } 924 925 int 926 _info(struct modinfo *modinfop) 927 { 928 return (psm_mod_info(&xen_uppc_hdlp, &xen_uppc_info, modinfop)); 929 } 930