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