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 2007 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/apic.h> 43 #include <sys/archsystm.h> 44 #include <sys/mach_intr.h> 45 #include <sys/hypervisor.h> 46 #include <sys/evtchn_impl.h> 47 #include <sys/modctl.h> 48 #include <sys/trap.h> 49 #include <sys/panic.h> 50 51 #include <xen/public/vcpu.h> 52 #include <xen/public/physdev.h> 53 54 55 /* 56 * Global Data 57 */ 58 59 int xen_psm_verbose = 0; 60 61 volatile uint32_t *apicadr = NULL; /* dummy, so common code will link */ 62 int apic_error = 0; 63 int apic_verbose = 0; 64 cpuset_t apic_cpumask; 65 int apic_forceload = 0; 66 uchar_t apic_vectortoipl[APIC_AVAIL_VECTOR / APIC_VECTOR_PER_IPL] = { 67 3, 4, 5, 5, 6, 6, 9, 10, 11, 12, 13, 14, 15, 15 68 }; 69 uchar_t apic_ipltopri[MAXIPL + 1]; 70 uchar_t apic_ipls[APIC_AVAIL_VECTOR]; 71 uint_t apic_picinit_called; 72 apic_cpus_info_t *apic_cpus; 73 int xen_psm_intr_policy = INTR_ROUND_ROBIN_WITH_AFFINITY; 74 /* use to make sure only one cpu handles the nmi */ 75 static lock_t xen_psm_nmi_lock; 76 int xen_psm_kmdb_on_nmi = 0; /* 0 - no, 1 - yes enter kmdb */ 77 int xen_psm_panic_on_nmi = 0; 78 int xen_psm_num_nmis = 0; 79 80 cpuset_t xen_psm_cpus_online; /* online cpus */ 81 int xen_psm_ncpus = 1; /* cpu count */ 82 int xen_psm_next_bind_cpu; /* next cpu to bind an interrupt to */ 83 84 /* 85 * XXPV we flag MSI as not supported, since the hypervisor currently doesn't 86 * support MSI at all. Change this initialization to zero when MSI is 87 * supported. 88 */ 89 int xen_support_msi = -1; 90 91 static int xen_clock_irq = INVALID_IRQ; 92 93 /* flag definitions for xen_psm_verbose */ 94 #define XEN_PSM_VERBOSE_IRQ_FLAG 0x00000001 95 #define XEN_PSM_VERBOSE_POWEROFF_FLAG 0x00000002 96 #define XEN_PSM_VERBOSE_POWEROFF_PAUSE_FLAG 0x00000004 97 98 #define XEN_PSM_VERBOSE_IRQ(fmt) \ 99 if (xen_psm_verbose & XEN_PSM_VERBOSE_IRQ_FLAG) \ 100 cmn_err fmt; 101 102 #define XEN_PSM_VERBOSE_POWEROFF(fmt) \ 103 if (xen_psm_verbose & XEN_PSM_VERBOSE_POWEROFF_FLAG) \ 104 prom_printf fmt; 105 106 /* 107 * Dummy apic array to point common routines at that want to do some apic 108 * manipulation. Xen doesn't allow guest apic access so we point at these 109 * memory locations to fake out those who want to do apic fiddling. 110 */ 111 uint32_t xen_psm_dummy_apic[APIC_IRR_REG + 1]; 112 113 static struct psm_info xen_psm_info; 114 static void xen_psm_setspl(int); 115 116 static int apic_alloc_vectors(dev_info_t *, int, int, int, int, int); 117 118 /* 119 * Local support routines 120 */ 121 122 /* 123 * Select vcpu to bind xen virtual device interrupt to. 124 */ 125 /*ARGSUSED*/ 126 int 127 xen_psm_bind_intr(int irq) 128 { 129 int bind_cpu, test_cpu; 130 apic_irq_t *irqptr; 131 132 if (xen_psm_intr_policy == INTR_LOWEST_PRIORITY) 133 return (IRQ_UNBOUND); 134 if (irq <= APIC_MAX_VECTOR) 135 irqptr = apic_irq_table[irq]; 136 else 137 irqptr = NULL; 138 if (irqptr && (irqptr->airq_cpu & IRQ_USER_BOUND)) { 139 bind_cpu = irqptr->airq_cpu; 140 test_cpu = bind_cpu & ~IRQ_USER_BOUND; 141 if (!CPU_IN_SET(xen_psm_cpus_online, test_cpu)) 142 bind_cpu = 0; 143 goto done; 144 } 145 if (xen_psm_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) { 146 do { 147 bind_cpu = xen_psm_next_bind_cpu++; 148 if (xen_psm_next_bind_cpu >= xen_psm_ncpus) 149 xen_psm_next_bind_cpu = 0; 150 } while (!CPU_IN_SET(xen_psm_cpus_online, bind_cpu)); 151 } else { 152 bind_cpu = 0; 153 } 154 done: 155 return (bind_cpu); 156 } 157 158 /* 159 * Autoconfiguration Routines 160 */ 161 162 static int 163 xen_psm_probe(void) 164 { 165 int ret = PSM_SUCCESS; 166 167 if (DOMAIN_IS_INITDOMAIN(xen_info)) 168 ret = apic_probe_common(xen_psm_info.p_mach_idstring); 169 return (ret); 170 } 171 172 static void 173 xen_psm_softinit(void) 174 { 175 /* LINTED logical expression always true: op "||" */ 176 ASSERT((1 << EVTCHN_SHIFT) == NBBY * sizeof (ulong_t)); 177 CPUSET_ATOMIC_ADD(xen_psm_cpus_online, 0); 178 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 179 apic_init_common(); 180 } 181 } 182 183 #define XEN_NSEC_PER_TICK 10 /* XXX - assume we have a 100 Mhz clock */ 184 185 /*ARGSUSED*/ 186 static int 187 xen_psm_clkinit(int hertz) 188 { 189 extern enum tod_fault_type tod_fault(enum tod_fault_type, int); 190 extern int dosynctodr; 191 192 /* 193 * domU cannot set the TOD hardware, fault the TOD clock now to 194 * indicate that and turn off attempts to sync TOD hardware 195 * with the hires timer. 196 */ 197 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 198 mutex_enter(&tod_lock); 199 (void) tod_fault(TOD_RDONLY, 0); 200 dosynctodr = 0; 201 mutex_exit(&tod_lock); 202 } 203 /* 204 * The hypervisor provides a timer based on the local APIC timer. 205 * The interface supports requests of nanosecond resolution. 206 * A common frequency of the apic clock is 100 Mhz which 207 * gives a resolution of 10 nsec per tick. What we would really like 208 * is a way to get the ns per tick value from xen. 209 * XXPV - This is an assumption that needs checking and may change 210 */ 211 return (XEN_NSEC_PER_TICK); 212 } 213 214 static void 215 xen_psm_hrtimeinit(void) 216 { 217 extern int gethrtime_hires; 218 gethrtime_hires = 1; 219 } 220 221 /* xen_psm NMI handler */ 222 /*ARGSUSED*/ 223 static void 224 xen_psm_nmi_intr(caddr_t arg, struct regs *rp) 225 { 226 xen_psm_num_nmis++; 227 228 if (!lock_try(&xen_psm_nmi_lock)) 229 return; 230 231 if (xen_psm_kmdb_on_nmi && psm_debugger()) { 232 debug_enter("NMI received: entering kmdb\n"); 233 } else if (xen_psm_panic_on_nmi) { 234 /* Keep panic from entering kmdb. */ 235 nopanicdebug = 1; 236 panic("NMI received\n"); 237 } else { 238 /* 239 * prom_printf is the best shot we have of something which is 240 * problem free from high level/NMI type of interrupts 241 */ 242 prom_printf("NMI received\n"); 243 } 244 245 lock_clear(&xen_psm_nmi_lock); 246 } 247 248 static void 249 xen_psm_picinit() 250 { 251 int cpu, irqno; 252 cpuset_t cpus; 253 254 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 255 /* set a flag so we know we have run xen_psm_picinit() */ 256 apic_picinit_called = 1; 257 LOCK_INIT_CLEAR(&apic_ioapic_lock); 258 259 /* XXPV - do we need to do this? */ 260 picsetup(); /* initialise the 8259 */ 261 262 /* enable apic mode if imcr present */ 263 /* XXPV - do we need to do this either? */ 264 if (apic_imcrp) { 265 outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT); 266 outb(APIC_IMCR_P2, (uchar_t)APIC_IMCR_APIC); 267 } 268 269 ioapic_init_intr(IOAPIC_NOMASK); 270 /* 271 * We never called xen_psm_addspl() when the SCI 272 * interrupt was added because that happened before the 273 * PSM module was loaded. Fix that up here by doing 274 * any missed operations (e.g. bind to CPU) 275 */ 276 if ((irqno = apic_sci_vect) > 0) { 277 if ((cpu = xen_psm_bind_intr(irqno)) == IRQ_UNBOUND) { 278 CPUSET_ZERO(cpus); 279 CPUSET_OR(cpus, xen_psm_cpus_online); 280 } else { 281 CPUSET_ONLY(cpus, cpu & ~IRQ_USER_BOUND); 282 } 283 ec_set_irq_affinity(irqno, cpus); 284 apic_irq_table[irqno]->airq_temp_cpu = 285 (uchar_t)(cpu & ~IRQ_USER_BOUND); 286 ec_enable_irq(irqno); 287 } 288 } 289 290 /* add nmi handler - least priority nmi handler */ 291 LOCK_INIT_CLEAR(&xen_psm_nmi_lock); 292 293 if (!psm_add_nmintr(0, (avfunc) xen_psm_nmi_intr, 294 "xVM_psm NMI handler", (caddr_t)NULL)) 295 cmn_err(CE_WARN, "xVM_psm: Unable to add nmi handler"); 296 } 297 298 299 /* 300 * generates an interprocessor interrupt to another CPU 301 */ 302 static void 303 xen_psm_send_ipi(int cpun, int ipl) 304 { 305 ulong_t flag = intr_clear(); 306 307 ec_send_ipi(ipl, cpun); 308 intr_restore(flag); 309 } 310 311 /*ARGSUSED*/ 312 static int 313 xen_psm_addspl(int irqno, int ipl, int min_ipl, int max_ipl) 314 { 315 int cpu, ret; 316 cpuset_t cpus; 317 318 /* 319 * We are called at splhi() so we can't call anything that might end 320 * up trying to context switch. 321 */ 322 if (irqno >= PIRQ_BASE && irqno < NR_PIRQS && 323 DOMAIN_IS_INITDOMAIN(xen_info)) { 324 /* 325 * Priority/affinity/enable for PIRQ's is set in ec_setup_pirq() 326 */ 327 ret = apic_addspl_common(irqno, ipl, min_ipl, max_ipl); 328 } else { 329 /* 330 * Set priority/affinity/enable for non PIRQs 331 */ 332 ret = ec_set_irq_priority(irqno, ipl); 333 ASSERT(ret == 0); 334 if ((cpu = xen_psm_bind_intr(irqno)) == IRQ_UNBOUND) { 335 CPUSET_ZERO(cpus); 336 CPUSET_OR(cpus, xen_psm_cpus_online); 337 } else { 338 CPUSET_ONLY(cpus, cpu & ~IRQ_USER_BOUND); 339 } 340 ec_set_irq_affinity(irqno, cpus); 341 ec_enable_irq(irqno); 342 } 343 return (ret); 344 } 345 346 /* 347 * Acquire ownership of this irq on this cpu 348 */ 349 void 350 xen_psm_acquire_irq(int irq) 351 { 352 ulong_t flags; 353 int cpuid; 354 355 /* 356 * If the irq is currently being serviced by another cpu 357 * we busy-wait for the other cpu to finish. Take any 358 * pending interrupts before retrying. 359 */ 360 do { 361 flags = intr_clear(); 362 cpuid = ec_block_irq(irq); 363 intr_restore(flags); 364 } while (cpuid != CPU->cpu_id); 365 } 366 367 /*ARGSUSED*/ 368 static int 369 xen_psm_delspl(int irqno, int ipl, int min_ipl, int max_ipl) 370 { 371 apic_irq_t *irqptr; 372 int err = PSM_SUCCESS; 373 374 if (irqno >= PIRQ_BASE && irqno < NR_PIRQS && 375 DOMAIN_IS_INITDOMAIN(xen_info)) { 376 irqptr = apic_irq_table[irqno]; 377 /* 378 * unbind if no more sharers of this irq/evtchn 379 */ 380 if (irqptr->airq_share == 1) { 381 xen_psm_acquire_irq(irqno); 382 ec_unbind_irq(irqno); 383 } 384 err = apic_delspl_common(irqno, ipl, min_ipl, max_ipl); 385 /* 386 * If still in use reset priority 387 */ 388 if (!err && irqptr->airq_share != 0) { 389 err = ec_set_irq_priority(irqno, max_ipl); 390 return (err); 391 } 392 } else { 393 xen_psm_acquire_irq(irqno); 394 ec_unbind_irq(irqno); 395 } 396 return (err); 397 } 398 399 static processorid_t 400 xen_psm_get_next_processorid(processorid_t id) 401 { 402 if (id == -1) 403 return (0); 404 405 for (id++; id < NCPU; id++) { 406 switch (-HYPERVISOR_vcpu_op(VCPUOP_is_up, id, NULL)) { 407 case 0: /* yeah, that one's there */ 408 return (id); 409 default: 410 case X_EINVAL: /* out of range */ 411 return (-1); 412 case X_ENOENT: /* not present in the domain */ 413 /* 414 * It's not clear that we -need- to keep looking 415 * at this point, if, e.g., we can guarantee 416 * the hypervisor always keeps a contiguous range 417 * of vcpus around this is equivalent to "out of range". 418 * 419 * But it would be sad to miss a vcpu we're 420 * supposed to be using .. 421 */ 422 break; 423 } 424 } 425 426 return (-1); 427 } 428 429 /* 430 * XXPV - undo the start cpu op change; return to ignoring this value 431 * - also tweak error handling in main startup loop 432 */ 433 /*ARGSUSED*/ 434 static int 435 xen_psm_cpu_start(processorid_t id, caddr_t arg) 436 { 437 int ret; 438 439 ASSERT(id > 0); 440 CPUSET_ATOMIC_ADD(xen_psm_cpus_online, id); 441 ec_bind_cpu_ipis(id); 442 (void) ec_bind_virq_to_irq(VIRQ_TIMER, id); 443 if ((ret = xen_vcpu_up(id)) == 0) 444 xen_psm_ncpus++; 445 else 446 ret = EINVAL; 447 return (ret); 448 } 449 450 /* 451 * Allocate an irq for inter cpu signaling 452 */ 453 /*ARGSUSED*/ 454 static int 455 xen_psm_get_ipivect(int ipl, int type) 456 { 457 return (ec_bind_ipi_to_irq(ipl, 0)); 458 } 459 460 /*ARGSUSED*/ 461 static int 462 xen_psm_get_clockirq(int ipl) 463 { 464 if (xen_clock_irq != INVALID_IRQ) 465 return (xen_clock_irq); 466 467 xen_clock_irq = ec_bind_virq_to_irq(VIRQ_TIMER, 0); 468 return (xen_clock_irq); 469 } 470 471 /*ARGSUSED*/ 472 static void 473 xen_psm_shutdown(int cmd, int fcn) 474 { 475 XEN_PSM_VERBOSE_POWEROFF(("xen_psm_shutdown(%d,%d);\n", cmd, fcn)); 476 477 switch (cmd) { 478 case A_SHUTDOWN: 479 switch (fcn) { 480 case AD_BOOT: 481 case AD_IBOOT: 482 (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); 483 break; 484 case AD_POWEROFF: 485 /* fall through if domU or if poweroff fails */ 486 if (DOMAIN_IS_INITDOMAIN(xen_info)) 487 if (apic_enable_acpi) 488 (void) acpi_poweroff(); 489 /* FALLTHRU */ 490 case AD_HALT: 491 default: 492 (void) HYPERVISOR_shutdown(SHUTDOWN_poweroff); 493 break; 494 } 495 break; 496 case A_REBOOT: 497 (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); 498 break; 499 default: 500 return; 501 } 502 } 503 504 505 static int 506 xen_psm_translate_irq(dev_info_t *dip, int irqno) 507 { 508 if (dip == NULL) { 509 XEN_PSM_VERBOSE_IRQ((CE_CONT, "!xen_psm: irqno = %d" 510 " dip = NULL\n", irqno)); 511 return (irqno); 512 } 513 return (irqno); 514 } 515 516 /* 517 * xen_psm_intr_enter() acks the event that triggered the interrupt and 518 * returns the new priority level, 519 */ 520 /*ARGSUSED*/ 521 static int 522 xen_psm_intr_enter(int ipl, int *vector) 523 { 524 int newipl; 525 uint_t intno; 526 cpu_t *cpu = CPU; 527 528 intno = (*vector); 529 530 ASSERT(intno < NR_IRQS); 531 ASSERT(cpu->cpu_m.mcpu_vcpu_info->evtchn_upcall_mask != 0); 532 533 ec_clear_irq(intno); 534 535 newipl = autovect[intno].avh_hi_pri; 536 if (newipl == 0) { 537 /* 538 * (newipl == 0) means we have no service routines for this 539 * vector. We will treat this as a spurious interrupt. 540 * We have cleared the pending bit already, clear the event 541 * mask and return a spurious interrupt. This case can happen 542 * when an interrupt delivery is racing with the removal of 543 * of the service routine for that interrupt. 544 */ 545 ec_unmask_irq(intno); 546 newipl = -1; /* flag spurious interrupt */ 547 } else if (newipl <= cpu->cpu_pri) { 548 /* 549 * (newipl <= cpu->cpu_pri) means that we must be trying to 550 * service a vector that was shared with a higher priority 551 * isr. The higher priority handler has been removed and 552 * we need to service this int. We can't return a lower 553 * priority than current cpu priority. Just synthesize a 554 * priority to return that should be acceptable. 555 */ 556 newipl = cpu->cpu_pri + 1; /* synthetic priority */ 557 } 558 return (newipl); 559 } 560 561 562 /* 563 * xen_psm_intr_exit() restores the old interrupt 564 * priority level after processing an interrupt. 565 * It is called with interrupts disabled, and does not enable interrupts. 566 */ 567 /* ARGSUSED */ 568 static void 569 xen_psm_intr_exit(int ipl, int vector) 570 { 571 ec_try_unmask_irq(vector); 572 xen_psm_setspl(ipl); 573 } 574 575 intr_exit_fn_t 576 psm_intr_exit_fn(void) 577 { 578 return (xen_psm_intr_exit); 579 } 580 581 /* 582 * Check if new ipl level allows delivery of previously unserviced events 583 */ 584 static void 585 xen_psm_setspl(int ipl) 586 { 587 struct cpu *cpu = CPU; 588 volatile vcpu_info_t *vci = cpu->cpu_m.mcpu_vcpu_info; 589 uint16_t pending; 590 591 ASSERT(vci->evtchn_upcall_mask != 0); 592 593 /* 594 * If new ipl level will enable any pending interrupts, setup so the 595 * upcoming sti will cause us to get an upcall. 596 */ 597 pending = cpu->cpu_m.mcpu_intr_pending & ~((1 << (ipl + 1)) - 1); 598 if (pending) { 599 int i; 600 ulong_t pending_sels = 0; 601 volatile ulong_t *selp; 602 struct xen_evt_data *cpe = cpu->cpu_m.mcpu_evt_pend; 603 604 for (i = bsrw_insn(pending); i > ipl; i--) 605 pending_sels |= cpe->pending_sel[i]; 606 ASSERT(pending_sels); 607 selp = (volatile ulong_t *)&vci->evtchn_pending_sel; 608 atomic_or_ulong(selp, pending_sels); 609 vci->evtchn_upcall_pending = 1; 610 } 611 } 612 613 /* 614 * This function provides external interface to the nexus for all 615 * functionality related to the new DDI interrupt framework. 616 * 617 * Input: 618 * dip - pointer to the dev_info structure of the requested device 619 * hdlp - pointer to the internal interrupt handle structure for the 620 * requested interrupt 621 * intr_op - opcode for this call 622 * result - pointer to the integer that will hold the result to be 623 * passed back if return value is PSM_SUCCESS 624 * 625 * Output: 626 * return value is either PSM_SUCCESS or PSM_FAILURE 627 */ 628 int 629 xen_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, 630 psm_intr_op_t intr_op, int *result) 631 { 632 int cap; 633 int err; 634 int new_priority; 635 apic_irq_t *irqp; 636 struct intrspec *ispec; 637 638 DDI_INTR_IMPLDBG((CE_CONT, "xen_intr_ops: dip: %p hdlp: %p " 639 "intr_op: %x\n", (void *)dip, (void *)hdlp, intr_op)); 640 641 switch (intr_op) { 642 case PSM_INTR_OP_CHECK_MSI: 643 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 644 *result = hdlp->ih_type & ~(DDI_INTR_TYPE_MSI | 645 DDI_INTR_TYPE_MSIX); 646 break; 647 } 648 /* 649 * Check MSI/X is supported or not at APIC level and 650 * masked off the MSI/X bits in hdlp->ih_type if not 651 * supported before return. If MSI/X is supported, 652 * leave the ih_type unchanged and return. 653 * 654 * hdlp->ih_type passed in from the nexus has all the 655 * interrupt types supported by the device. 656 */ 657 if (xen_support_msi == 0) { 658 /* 659 * if xen_support_msi is not set, call 660 * apic_check_msi_support() to check whether msi 661 * is supported first 662 */ 663 if (apic_check_msi_support() == PSM_SUCCESS) 664 xen_support_msi = 1; 665 else 666 xen_support_msi = -1; 667 } 668 if (xen_support_msi == 1) 669 *result = hdlp->ih_type; 670 else 671 *result = hdlp->ih_type & ~(DDI_INTR_TYPE_MSI | 672 DDI_INTR_TYPE_MSIX); 673 break; 674 case PSM_INTR_OP_ALLOC_VECTORS: 675 *result = apic_alloc_vectors(dip, hdlp->ih_inum, 676 hdlp->ih_scratch1, hdlp->ih_pri, hdlp->ih_type, 677 (int)(uintptr_t)hdlp->ih_scratch2); 678 break; 679 case PSM_INTR_OP_FREE_VECTORS: 680 apic_free_vectors(dip, hdlp->ih_inum, hdlp->ih_scratch1, 681 hdlp->ih_pri, hdlp->ih_type); 682 break; 683 case PSM_INTR_OP_NAVAIL_VECTORS: 684 /* 685 * XXPV - maybe we should make this be: 686 * min(APIC_VECTOR_PER_IPL, count of all avail vectors); 687 */ 688 if (DOMAIN_IS_INITDOMAIN(xen_info)) 689 *result = APIC_VECTOR_PER_IPL; 690 else 691 *result = 1; 692 break; 693 case PSM_INTR_OP_XLATE_VECTOR: 694 ispec = ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp; 695 if (ispec->intrspec_vec >= PIRQ_BASE && 696 ispec->intrspec_vec < NR_PIRQS && 697 DOMAIN_IS_INITDOMAIN(xen_info)) { 698 *result = apic_introp_xlate(dip, ispec, hdlp->ih_type); 699 } else { 700 *result = ispec->intrspec_vec; 701 } 702 break; 703 case PSM_INTR_OP_GET_PENDING: 704 /* XXPV - is this enough for dom0 or do we need to ref ioapic */ 705 *result = ec_pending_irq(hdlp->ih_vector); 706 break; 707 case PSM_INTR_OP_CLEAR_MASK: 708 /* XXPV - is this enough for dom0 or do we need to set ioapic */ 709 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 710 return (PSM_FAILURE); 711 ec_enable_irq(hdlp->ih_vector); 712 break; 713 case PSM_INTR_OP_SET_MASK: 714 /* XXPV - is this enough for dom0 or do we need to set ioapic */ 715 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 716 return (PSM_FAILURE); 717 ec_disable_irq(hdlp->ih_vector); 718 break; 719 case PSM_INTR_OP_GET_CAP: 720 cap = DDI_INTR_FLAG_PENDING | DDI_INTR_FLAG_EDGE; 721 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 722 cap |= DDI_INTR_FLAG_MASKABLE; 723 *result = cap; 724 break; 725 case PSM_INTR_OP_GET_SHARED: 726 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 727 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 728 return (PSM_FAILURE); 729 if ((irqp = apic_find_irq(dip, ispec, hdlp->ih_type)) 730 == NULL) 731 return (PSM_FAILURE); 732 *result = irqp->airq_share ? 1: 0; 733 } else { 734 return (PSM_FAILURE); 735 } 736 break; 737 case PSM_INTR_OP_SET_PRI: 738 new_priority = *(int *)result; 739 err = ec_set_irq_priority(hdlp->ih_vector, new_priority); 740 if (err != 0) 741 return (PSM_FAILURE); 742 break; 743 case PSM_INTR_OP_GET_INTR: 744 if (!DOMAIN_IS_INITDOMAIN(xen_info)) 745 return (PSM_FAILURE); 746 /* 747 * The interrupt handle given here has been allocated 748 * specifically for this command, and ih_private carries 749 * a pointer to a apic_get_intr_t. 750 */ 751 if (apic_get_vector_intr_info( 752 hdlp->ih_vector, hdlp->ih_private) != PSM_SUCCESS) 753 return (PSM_FAILURE); 754 break; 755 case PSM_INTR_OP_SET_CAP: 756 /* FALLTHRU */ 757 default: 758 return (PSM_FAILURE); 759 } 760 return (PSM_SUCCESS); 761 } 762 763 static void 764 xen_psm_rebind_irq(int irq) 765 { 766 cpuset_t ncpu; 767 processorid_t newcpu; 768 apic_irq_t *irqptr; 769 770 newcpu = xen_psm_bind_intr(irq); 771 if (newcpu == IRQ_UNBOUND) { 772 CPUSET_ZERO(ncpu); 773 CPUSET_OR(ncpu, xen_psm_cpus_online); 774 } else { 775 CPUSET_ONLY(ncpu, newcpu & ~IRQ_USER_BOUND); 776 } 777 ec_set_irq_affinity(irq, ncpu); 778 if (irq <= APIC_MAX_VECTOR) { 779 irqptr = apic_irq_table[irq]; 780 ASSERT(irqptr != NULL); 781 irqptr->airq_temp_cpu = (uchar_t)newcpu; 782 } 783 } 784 785 /* 786 * Disable all device interrupts for the given cpu. 787 * High priority interrupts are not disabled and will still be serviced. 788 */ 789 static int 790 xen_psm_disable_intr(processorid_t cpun) 791 { 792 int irq; 793 794 /* 795 * Can't offline VCPU 0 on this hypervisor. There's no reason 796 * anyone would want to given that the CPUs are virtual. Also note 797 * that the hypervisor requires suspend/resume to be on VCPU 0. 798 */ 799 if (cpun == 0) 800 return (PSM_FAILURE); 801 802 CPUSET_ATOMIC_DEL(xen_psm_cpus_online, cpun); 803 for (irq = 0; irq < NR_IRQS; irq++) { 804 if (!ec_irq_needs_rebind(irq, cpun)) 805 continue; 806 xen_psm_rebind_irq(irq); 807 } 808 return (PSM_SUCCESS); 809 } 810 811 static void 812 xen_psm_enable_intr(processorid_t cpun) 813 { 814 int irq; 815 816 if (cpun == 0) 817 return; 818 819 CPUSET_ATOMIC_ADD(xen_psm_cpus_online, cpun); 820 821 /* 822 * Rebalance device interrupts among online processors 823 */ 824 for (irq = 0; irq < NR_IRQS; irq++) { 825 if (!ec_irq_rebindable(irq)) 826 continue; 827 xen_psm_rebind_irq(irq); 828 } 829 } 830 831 static int 832 xen_psm_post_cpu_start() 833 { 834 processorid_t cpun; 835 836 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 837 cpun = psm_get_cpu_id(); 838 apic_cpus[cpun].aci_status = 839 APIC_CPU_ONLINE | APIC_CPU_INTR_ENABLE; 840 } 841 /* 842 * Re-distribute interrupts to include the newly added cpu. 843 */ 844 xen_psm_enable_intr(cpun); 845 return (PSM_SUCCESS); 846 } 847 848 /* 849 * This function will reprogram the timer. 850 * 851 * When in oneshot mode the argument is the absolute time in future at which to 852 * generate the interrupt. 853 * 854 * When in periodic mode, the argument is the interval at which the 855 * interrupts should be generated. There is no need to support the periodic 856 * mode timer change at this time. 857 * 858 * Note that we must be careful to convert from hrtime to Xen system time (see 859 * xpv_timestamp.c). 860 */ 861 static void 862 xen_psm_timer_reprogram(hrtime_t timer_req) 863 { 864 hrtime_t now, timer_new, time_delta, xen_time; 865 ulong_t flags; 866 867 flags = intr_clear(); 868 /* 869 * We should be called from high PIL context (CBE_HIGH_PIL), 870 * so kpreempt is disabled. 871 */ 872 873 now = xpv_gethrtime(); 874 xen_time = xpv_getsystime(); 875 if (timer_req <= now) { 876 /* 877 * requested to generate an interrupt in the past 878 * generate an interrupt as soon as possible 879 */ 880 time_delta = XEN_NSEC_PER_TICK; 881 } else 882 time_delta = timer_req - now; 883 884 timer_new = xen_time + time_delta; 885 if (HYPERVISOR_set_timer_op(timer_new) != 0) 886 panic("can't set hypervisor timer?"); 887 intr_restore(flags); 888 } 889 890 /* 891 * This function will enable timer interrupts. 892 */ 893 static void 894 xen_psm_timer_enable(void) 895 { 896 ec_unmask_irq(xen_clock_irq); 897 } 898 899 /* 900 * This function will disable timer interrupts on the current cpu. 901 */ 902 static void 903 xen_psm_timer_disable(void) 904 { 905 (void) ec_block_irq(xen_clock_irq); 906 /* 907 * If the clock irq is pending on this cpu then we need to 908 * clear the pending interrupt. 909 */ 910 ec_unpend_irq(xen_clock_irq); 911 } 912 913 /* 914 * 915 * The following functions are in the platform specific file so that they 916 * can be different functions depending on whether we are running on 917 * bare metal or a hypervisor. 918 */ 919 920 /* 921 * Allocate a free vector for irq at ipl. 922 */ 923 /* ARGSUSED */ 924 uchar_t 925 apic_allocate_vector(int ipl, int irq, int pri) 926 { 927 physdev_irq_t irq_op; 928 uchar_t vector; 929 930 irq_op.irq = irq; 931 932 if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) 933 panic("Hypervisor alloc vector failed"); 934 vector = irq_op.vector; 935 /* 936 * No need to worry about vector colliding with our reserved vectors 937 * e.g. T_FASTTRAP, xen can differentiate between hardware and software 938 * generated traps and handle them properly. 939 */ 940 apic_vector_to_irq[vector] = (uchar_t)irq; 941 return (vector); 942 } 943 944 /* Mark vector as not being used by any irq */ 945 void 946 apic_free_vector(uchar_t vector) 947 { 948 apic_vector_to_irq[vector] = APIC_RESV_IRQ; 949 } 950 951 /* 952 * This function allocate "count" vector(s) for the given "dip/pri/type" 953 */ 954 static int 955 apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type, 956 int behavior) 957 { 958 int rcount, i; 959 uchar_t vector, cpu; 960 int irqno; 961 major_t major; 962 apic_irq_t *irqptr; 963 964 /* only supports MSI at the moment, will add MSI-X support later */ 965 if (type != DDI_INTR_TYPE_MSI) 966 return (0); 967 968 DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: dip=0x%p type=%d " 969 "inum=0x%x pri=0x%x count=0x%x behavior=%d\n", 970 (void *)dip, type, inum, pri, count, behavior)); 971 972 if (count > 1) { 973 if (behavior == DDI_INTR_ALLOC_STRICT && 974 (apic_multi_msi_enable == 0 || count > apic_multi_msi_max)) 975 return (0); 976 977 if (apic_multi_msi_enable == 0) 978 count = 1; 979 else if (count > apic_multi_msi_max) 980 count = apic_multi_msi_max; 981 } 982 983 /* 984 * XXPV - metal version takes all vectors avail at given pri. 985 * Why do that? For now just allocate count vectors. 986 */ 987 rcount = count; 988 989 mutex_enter(&airq_mutex); 990 991 /* 992 * XXPV - currently the hypervisor does not support MSI at all. 993 * It doesn't return consecutive vectors. This code is a first 994 * cut for the (future) time that MSI is supported. 995 */ 996 major = (dip != NULL) ? ddi_name_to_major(ddi_get_name(dip)) : 0; 997 for (i = 0; i < rcount; i++) { 998 if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == 999 INVALID_IRQ) { 1000 mutex_exit(&airq_mutex); 1001 DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: " 1002 "apic_allocate_irq failed\n")); 1003 return (i); 1004 } 1005 apic_max_device_irq = max(irqno, apic_max_device_irq); 1006 apic_min_device_irq = min(irqno, apic_min_device_irq); 1007 irqptr = apic_irq_table[irqno]; 1008 vector = apic_allocate_vector(pri, irqno, 0); 1009 apic_vector_to_irq[vector] = (uchar_t)irqno; 1010 #ifdef DEBUG 1011 if (apic_vector_to_irq[vector] != APIC_RESV_IRQ) 1012 DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: " 1013 "apic_vector_to_irq is not APIC_RESV_IRQ\n")); 1014 #endif 1015 1016 irqptr->airq_vector = vector; 1017 irqptr->airq_ioapicindex = (uchar_t)inum; /* start */ 1018 irqptr->airq_intin_no = (uchar_t)rcount; 1019 irqptr->airq_ipl = pri; 1020 irqptr->airq_origirq = (uchar_t)(inum + i); 1021 irqptr->airq_share_id = 0; 1022 irqptr->airq_mps_intr_index = MSI_INDEX; 1023 irqptr->airq_dip = dip; 1024 irqptr->airq_major = major; 1025 if (i == 0) /* they all bound to the same cpu */ 1026 cpu = irqptr->airq_cpu = apic_bind_intr(dip, irqno, 1027 0xff, 0xff); 1028 else 1029 irqptr->airq_cpu = cpu; 1030 DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: irq=0x%x " 1031 "dip=0x%p vector=0x%x origirq=0x%x pri=0x%x\n", irqno, 1032 (void *)irqptr->airq_dip, irqptr->airq_vector, 1033 irqptr->airq_origirq, pri)); 1034 } 1035 mutex_exit(&airq_mutex); 1036 return (rcount); 1037 } 1038 1039 /* 1040 * The hypervisor doesn't permit access to local apics directly 1041 */ 1042 /* ARGSUSED */ 1043 uint32_t * 1044 mapin_apic(uint32_t addr, size_t len, int flags) 1045 { 1046 /* 1047 * Return a pointer to a memory area to fake out the 1048 * probe code that wants to read apic registers. 1049 * The dummy values will end up being ignored by xen 1050 * later on when they are used anyway. 1051 */ 1052 xen_psm_dummy_apic[APIC_VERS_REG] = APIC_INTEGRATED_VERS; 1053 return (xen_psm_dummy_apic); 1054 } 1055 1056 /* ARGSUSED */ 1057 uint32_t * 1058 mapin_ioapic(uint32_t addr, size_t len, int flags) 1059 { 1060 /* 1061 * Return non-null here to fake out configure code that calls this. 1062 * The i86xpv platform will not reference through the returned value.. 1063 */ 1064 return ((uint32_t *)0x1); 1065 } 1066 1067 /* ARGSUSED */ 1068 void 1069 mapout_apic(caddr_t addr, size_t len) 1070 { 1071 } 1072 1073 /* ARGSUSED */ 1074 void 1075 mapout_ioapic(caddr_t addr, size_t len) 1076 { 1077 } 1078 1079 uint32_t 1080 ioapic_read(int apic_ix, uint32_t reg) 1081 { 1082 physdev_apic_t apic; 1083 1084 apic.apic_physbase = (unsigned long)apic_physaddr[apic_ix]; 1085 apic.reg = reg; 1086 if (HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic)) 1087 panic("read ioapic %d reg %d failed", apic_ix, reg); 1088 return (apic.value); 1089 } 1090 1091 void 1092 ioapic_write(int apic_ix, uint32_t reg, uint32_t value) 1093 { 1094 physdev_apic_t apic; 1095 1096 apic.apic_physbase = (unsigned long)apic_physaddr[apic_ix]; 1097 apic.reg = reg; 1098 apic.value = value; 1099 if (HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic)) 1100 panic("write ioapic %d reg %d failed", apic_ix, reg); 1101 } 1102 1103 /* 1104 * Call rebind to do the actual programming. 1105 */ 1106 int 1107 apic_setup_io_intr(void *p, int irq, boolean_t deferred) 1108 { 1109 apic_irq_t *irqptr; 1110 struct ioapic_reprogram_data *drep = NULL; 1111 int rv, cpu; 1112 cpuset_t cpus; 1113 1114 /* 1115 * Set cpu based on xen idea of online cpu's not apic tables. 1116 * Note that xen ignores/sets to it's own preferred value the 1117 * target cpu field when programming ioapic anyway. 1118 */ 1119 if ((cpu = xen_psm_bind_intr(irq)) == IRQ_UNBOUND) { 1120 CPUSET_ZERO(cpus); 1121 CPUSET_OR(cpus, xen_psm_cpus_online); 1122 } else { 1123 CPUSET_ONLY(cpus, cpu & ~IRQ_USER_BOUND); 1124 } 1125 apic_irq_table[irq]->airq_cpu = cpu; 1126 if (deferred) { 1127 drep = (struct ioapic_reprogram_data *)p; 1128 ASSERT(drep != NULL); 1129 irqptr = drep->irqp; 1130 } else { 1131 irqptr = (apic_irq_t *)p; 1132 } 1133 ASSERT(irqptr != NULL); 1134 rv = apic_rebind(irqptr, cpu, drep); 1135 if (rv) { 1136 /* CPU is not up or interrupt is disabled. Fall back to 0 */ 1137 cpu = 0; 1138 rv = apic_rebind(irqptr, cpu, drep); 1139 } 1140 /* 1141 * If rebind successful bind the irq to an event channel 1142 */ 1143 if (rv == 0) { 1144 ec_setup_pirq(irq, irqptr->airq_ipl, &cpus); 1145 CPUSET_FIND(cpus, cpu); 1146 apic_irq_table[irq]->airq_temp_cpu = cpu & ~IRQ_USER_BOUND; 1147 } 1148 return (rv); 1149 } 1150 1151 /* 1152 * Allocate a new vector for the given irq 1153 */ 1154 /* ARGSUSED */ 1155 uchar_t 1156 apic_modify_vector(uchar_t vector, int irq) 1157 { 1158 return (apic_allocate_vector(0, irq, 0)); 1159 } 1160 1161 /* 1162 * The rest of the file is just generic psm module boilerplate 1163 */ 1164 1165 static struct psm_ops xen_psm_ops = { 1166 xen_psm_probe, /* psm_probe */ 1167 1168 xen_psm_softinit, /* psm_init */ 1169 xen_psm_picinit, /* psm_picinit */ 1170 xen_psm_intr_enter, /* psm_intr_enter */ 1171 xen_psm_intr_exit, /* psm_intr_exit */ 1172 xen_psm_setspl, /* psm_setspl */ 1173 xen_psm_addspl, /* psm_addspl */ 1174 xen_psm_delspl, /* psm_delspl */ 1175 xen_psm_disable_intr, /* psm_disable_intr */ 1176 xen_psm_enable_intr, /* psm_enable_intr */ 1177 (int (*)(int))NULL, /* psm_softlvl_to_irq */ 1178 (void (*)(int))NULL, /* psm_set_softintr */ 1179 (void (*)(processorid_t))NULL, /* psm_set_idlecpu */ 1180 (void (*)(processorid_t))NULL, /* psm_unset_idlecpu */ 1181 1182 xen_psm_clkinit, /* psm_clkinit */ 1183 xen_psm_get_clockirq, /* psm_get_clockirq */ 1184 xen_psm_hrtimeinit, /* psm_hrtimeinit */ 1185 xpv_gethrtime, /* psm_gethrtime */ 1186 1187 xen_psm_get_next_processorid, /* psm_get_next_processorid */ 1188 xen_psm_cpu_start, /* psm_cpu_start */ 1189 xen_psm_post_cpu_start, /* psm_post_cpu_start */ 1190 xen_psm_shutdown, /* psm_shutdown */ 1191 xen_psm_get_ipivect, /* psm_get_ipivect */ 1192 xen_psm_send_ipi, /* psm_send_ipi */ 1193 1194 xen_psm_translate_irq, /* psm_translate_irq */ 1195 1196 (void (*)(int, char *))NULL, /* psm_notify_error */ 1197 (void (*)(int msg))NULL, /* psm_notify_func */ 1198 xen_psm_timer_reprogram, /* psm_timer_reprogram */ 1199 xen_psm_timer_enable, /* psm_timer_enable */ 1200 xen_psm_timer_disable, /* psm_timer_disable */ 1201 (void (*)(void *arg))NULL, /* psm_post_cyclic_setup */ 1202 (void (*)(int, int))NULL, /* psm_preshutdown */ 1203 xen_intr_ops /* Advanced DDI Interrupt framework */ 1204 }; 1205 1206 static struct psm_info xen_psm_info = { 1207 PSM_INFO_VER01_5, /* version */ 1208 PSM_OWN_SYS_DEFAULT, /* ownership */ 1209 &xen_psm_ops, /* operation */ 1210 "xVM_psm", /* machine name */ 1211 "platform module %I%" /* machine descriptions */ 1212 }; 1213 1214 static void *xen_psm_hdlp; 1215 1216 int 1217 _init(void) 1218 { 1219 return (psm_mod_init(&xen_psm_hdlp, &xen_psm_info)); 1220 } 1221 1222 int 1223 _fini(void) 1224 { 1225 return (psm_mod_fini(&xen_psm_hdlp, &xen_psm_info)); 1226 } 1227 1228 int 1229 _info(struct modinfo *modinfop) 1230 { 1231 return (psm_mod_info(&xen_psm_hdlp, &xen_psm_info, modinfop)); 1232 } 1233