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