17ff178cdSJimmy Vetayases /* 27ff178cdSJimmy Vetayases * CDDL HEADER START 37ff178cdSJimmy Vetayases * 47ff178cdSJimmy Vetayases * The contents of this file are subject to the terms of the 57ff178cdSJimmy Vetayases * Common Development and Distribution License (the "License"). 67ff178cdSJimmy Vetayases * You may not use this file except in compliance with the License. 77ff178cdSJimmy Vetayases * 87ff178cdSJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97ff178cdSJimmy Vetayases * or http://www.opensolaris.org/os/licensing. 107ff178cdSJimmy Vetayases * See the License for the specific language governing permissions 117ff178cdSJimmy Vetayases * and limitations under the License. 127ff178cdSJimmy Vetayases * 137ff178cdSJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each 147ff178cdSJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157ff178cdSJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the 167ff178cdSJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying 177ff178cdSJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner] 187ff178cdSJimmy Vetayases * 197ff178cdSJimmy Vetayases * CDDL HEADER END 207ff178cdSJimmy Vetayases */ 217ff178cdSJimmy Vetayases 227ff178cdSJimmy Vetayases /* 237ff178cdSJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 247ff178cdSJimmy Vetayases */ 25a288e5a9SJoshua M. Clulow /* 26a288e5a9SJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27a288e5a9SJoshua M. Clulow */ 287ff178cdSJimmy Vetayases 297ff178cdSJimmy Vetayases /* 307ff178cdSJimmy Vetayases * PSMI 1.1 extensions are supported only in 2.6 and later versions. 317ff178cdSJimmy Vetayases * PSMI 1.2 extensions are supported only in 2.7 and later versions. 327ff178cdSJimmy Vetayases * PSMI 1.3 and 1.4 extensions are supported in Solaris 10. 337ff178cdSJimmy Vetayases * PSMI 1.5 extensions are supported in Solaris Nevada. 347ff178cdSJimmy Vetayases * PSMI 1.6 extensions are supported in Solaris Nevada. 357ff178cdSJimmy Vetayases * PSMI 1.7 extensions are supported in Solaris Nevada. 367ff178cdSJimmy Vetayases */ 377ff178cdSJimmy Vetayases #define PSMI_1_7 387ff178cdSJimmy Vetayases 397ff178cdSJimmy Vetayases #include <sys/processor.h> 407ff178cdSJimmy Vetayases #include <sys/time.h> 417ff178cdSJimmy Vetayases #include <sys/psm.h> 427ff178cdSJimmy Vetayases #include <sys/smp_impldefs.h> 437ff178cdSJimmy Vetayases #include <sys/cram.h> 447ff178cdSJimmy Vetayases #include <sys/acpi/acpi.h> 457ff178cdSJimmy Vetayases #include <sys/acpica.h> 467ff178cdSJimmy Vetayases #include <sys/psm_common.h> 477ff178cdSJimmy Vetayases #include <sys/apic.h> 487ff178cdSJimmy Vetayases #include <sys/pit.h> 497ff178cdSJimmy Vetayases #include <sys/ddi.h> 507ff178cdSJimmy Vetayases #include <sys/sunddi.h> 517ff178cdSJimmy Vetayases #include <sys/ddi_impldefs.h> 527ff178cdSJimmy Vetayases #include <sys/pci.h> 537ff178cdSJimmy Vetayases #include <sys/promif.h> 547ff178cdSJimmy Vetayases #include <sys/x86_archext.h> 557ff178cdSJimmy Vetayases #include <sys/cpc_impl.h> 567ff178cdSJimmy Vetayases #include <sys/uadmin.h> 577ff178cdSJimmy Vetayases #include <sys/panic.h> 587ff178cdSJimmy Vetayases #include <sys/debug.h> 597ff178cdSJimmy Vetayases #include <sys/archsystm.h> 607ff178cdSJimmy Vetayases #include <sys/trap.h> 617ff178cdSJimmy Vetayases #include <sys/machsystm.h> 627ff178cdSJimmy Vetayases #include <sys/sysmacros.h> 637ff178cdSJimmy Vetayases #include <sys/cpuvar.h> 647ff178cdSJimmy Vetayases #include <sys/rm_platter.h> 657ff178cdSJimmy Vetayases #include <sys/privregs.h> 667ff178cdSJimmy Vetayases #include <sys/note.h> 677ff178cdSJimmy Vetayases #include <sys/pci_intr_lib.h> 687ff178cdSJimmy Vetayases #include <sys/spl.h> 697ff178cdSJimmy Vetayases #include <sys/clock.h> 707ff178cdSJimmy Vetayases #include <sys/dditypes.h> 717ff178cdSJimmy Vetayases #include <sys/sunddi.h> 727ff178cdSJimmy Vetayases #include <sys/x_call.h> 737ff178cdSJimmy Vetayases #include <sys/reboot.h> 747ff178cdSJimmy Vetayases #include <sys/hpet.h> 757ff178cdSJimmy Vetayases #include <sys/apic_common.h> 7641afdfa7SKrishnendu Sadhukhan - Sun Microsystems #include <sys/apic_timer.h> 777ff178cdSJimmy Vetayases 787ff178cdSJimmy Vetayases static void apic_record_ioapic_rdt(void *intrmap_private, 797ff178cdSJimmy Vetayases ioapic_rdt_t *irdt); 807ff178cdSJimmy Vetayases static void apic_record_msi(void *intrmap_private, msi_regs_t *mregs); 817ff178cdSJimmy Vetayases 827ff178cdSJimmy Vetayases /* 837ff178cdSJimmy Vetayases * Common routines between pcplusmp & apix (taken from apic.c). 847ff178cdSJimmy Vetayases */ 857ff178cdSJimmy Vetayases 867ff178cdSJimmy Vetayases int apic_clkinit(int); 877ff178cdSJimmy Vetayases hrtime_t apic_gethrtime(void); 887ff178cdSJimmy Vetayases void apic_send_ipi(int, int); 897ff178cdSJimmy Vetayases void apic_set_idlecpu(processorid_t); 907ff178cdSJimmy Vetayases void apic_unset_idlecpu(processorid_t); 917ff178cdSJimmy Vetayases void apic_shutdown(int, int); 927ff178cdSJimmy Vetayases void apic_preshutdown(int, int); 937ff178cdSJimmy Vetayases processorid_t apic_get_next_processorid(processorid_t); 947ff178cdSJimmy Vetayases 957ff178cdSJimmy Vetayases hrtime_t apic_gettime(); 967ff178cdSJimmy Vetayases 977ff178cdSJimmy Vetayases enum apic_ioapic_method_type apix_mul_ioapic_method = APIC_MUL_IOAPIC_PCPLUSMP; 987ff178cdSJimmy Vetayases 997ff178cdSJimmy Vetayases /* Now the ones for Dynamic Interrupt distribution */ 1007ff178cdSJimmy Vetayases int apic_enable_dynamic_migration = 0; 1017ff178cdSJimmy Vetayases 1027ff178cdSJimmy Vetayases /* maximum loop count when sending Start IPIs. */ 1037ff178cdSJimmy Vetayases int apic_sipi_max_loop_count = 0x1000; 1047ff178cdSJimmy Vetayases 1057ff178cdSJimmy Vetayases /* 1067ff178cdSJimmy Vetayases * These variables are frequently accessed in apic_intr_enter(), 1077ff178cdSJimmy Vetayases * apic_intr_exit and apic_setspl, so group them together 1087ff178cdSJimmy Vetayases */ 1097ff178cdSJimmy Vetayases volatile uint32_t *apicadr = NULL; /* virtual addr of local APIC */ 1107ff178cdSJimmy Vetayases int apic_setspl_delay = 1; /* apic_setspl - delay enable */ 1117ff178cdSJimmy Vetayases int apic_clkvect; 1127ff178cdSJimmy Vetayases 1137ff178cdSJimmy Vetayases /* vector at which error interrupts come in */ 1147ff178cdSJimmy Vetayases int apic_errvect; 1157ff178cdSJimmy Vetayases int apic_enable_error_intr = 1; 1167ff178cdSJimmy Vetayases int apic_error_display_delay = 100; 1177ff178cdSJimmy Vetayases 1187ff178cdSJimmy Vetayases /* vector at which performance counter overflow interrupts come in */ 1197ff178cdSJimmy Vetayases int apic_cpcovf_vect; 1207ff178cdSJimmy Vetayases int apic_enable_cpcovf_intr = 1; 1217ff178cdSJimmy Vetayases 1227ff178cdSJimmy Vetayases /* vector at which CMCI interrupts come in */ 1237ff178cdSJimmy Vetayases int apic_cmci_vect; 1247ff178cdSJimmy Vetayases extern int cmi_enable_cmci; 1257ff178cdSJimmy Vetayases extern void cmi_cmci_trap(void); 1267ff178cdSJimmy Vetayases 1277ff178cdSJimmy Vetayases kmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */ 1287ff178cdSJimmy Vetayases int cmci_cpu_setup_registered; 1297ff178cdSJimmy Vetayases 1307ff178cdSJimmy Vetayases /* number of CPUs in power-on transition state */ 1317ff178cdSJimmy Vetayases static int apic_poweron_cnt = 0; 1327ff178cdSJimmy Vetayases lock_t apic_mode_switch_lock; 1337ff178cdSJimmy Vetayases 1347ff178cdSJimmy Vetayases /* 1357ff178cdSJimmy Vetayases * Patchable global variables. 1367ff178cdSJimmy Vetayases */ 1377ff178cdSJimmy Vetayases int apic_forceload = 0; 1387ff178cdSJimmy Vetayases 1397ff178cdSJimmy Vetayases int apic_coarse_hrtime = 1; /* 0 - use accurate slow gethrtime() */ 1407ff178cdSJimmy Vetayases 1417ff178cdSJimmy Vetayases int apic_flat_model = 0; /* 0 - clustered. 1 - flat */ 1427ff178cdSJimmy Vetayases int apic_panic_on_nmi = 0; 1437ff178cdSJimmy Vetayases int apic_panic_on_apic_error = 0; 1447ff178cdSJimmy Vetayases 1457ff178cdSJimmy Vetayases int apic_verbose = 0; /* 0x1ff */ 1467ff178cdSJimmy Vetayases 1477ff178cdSJimmy Vetayases #ifdef DEBUG 1487ff178cdSJimmy Vetayases int apic_debug = 0; 1497ff178cdSJimmy Vetayases int apic_restrict_vector = 0; 1507ff178cdSJimmy Vetayases 1517ff178cdSJimmy Vetayases int apic_debug_msgbuf[APIC_DEBUG_MSGBUFSIZE]; 1527ff178cdSJimmy Vetayases int apic_debug_msgbufindex = 0; 1537ff178cdSJimmy Vetayases 1547ff178cdSJimmy Vetayases #endif /* DEBUG */ 1557ff178cdSJimmy Vetayases 1567ff178cdSJimmy Vetayases uint_t apic_nticks = 0; 1577ff178cdSJimmy Vetayases uint_t apic_skipped_redistribute = 0; 1587ff178cdSJimmy Vetayases 1597ff178cdSJimmy Vetayases uint_t last_count_read = 0; 1607ff178cdSJimmy Vetayases lock_t apic_gethrtime_lock; 1617ff178cdSJimmy Vetayases volatile int apic_hrtime_stamp = 0; 1627ff178cdSJimmy Vetayases volatile hrtime_t apic_nsec_since_boot = 0; 1637ff178cdSJimmy Vetayases 1647ff178cdSJimmy Vetayases static hrtime_t apic_last_hrtime = 0; 1657ff178cdSJimmy Vetayases int apic_hrtime_error = 0; 1667ff178cdSJimmy Vetayases int apic_remote_hrterr = 0; 1677ff178cdSJimmy Vetayases int apic_num_nmis = 0; 1687ff178cdSJimmy Vetayases int apic_apic_error = 0; 1697ff178cdSJimmy Vetayases int apic_num_apic_errors = 0; 1707ff178cdSJimmy Vetayases int apic_num_cksum_errors = 0; 1717ff178cdSJimmy Vetayases 1727ff178cdSJimmy Vetayases int apic_error = 0; 1737ff178cdSJimmy Vetayases 1747ff178cdSJimmy Vetayases static int apic_cmos_ssb_set = 0; 1757ff178cdSJimmy Vetayases 1767ff178cdSJimmy Vetayases /* use to make sure only one cpu handles the nmi */ 1777ff178cdSJimmy Vetayases lock_t apic_nmi_lock; 1787ff178cdSJimmy Vetayases /* use to make sure only one cpu handles the error interrupt */ 1797ff178cdSJimmy Vetayases lock_t apic_error_lock; 1807ff178cdSJimmy Vetayases 1817ff178cdSJimmy Vetayases static struct { 1827ff178cdSJimmy Vetayases uchar_t cntl; 1837ff178cdSJimmy Vetayases uchar_t data; 1847ff178cdSJimmy Vetayases } aspen_bmc[] = { 1857ff178cdSJimmy Vetayases { CC_SMS_WR_START, 0x18 }, /* NetFn/LUN */ 1867ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */ 1877ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0x84 }, /* DataByte 1: SMS/OS no log */ 1887ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0x2 }, /* DataByte 2: Power Down */ 1897ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 3: no pre-timeout */ 1907ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 4: timer expir. */ 1917ff178cdSJimmy Vetayases { CC_SMS_WR_NEXT, 0xa }, /* DataByte 5: init countdown */ 1927ff178cdSJimmy Vetayases { CC_SMS_WR_END, 0x0 }, /* DataByte 6: init countdown */ 1937ff178cdSJimmy Vetayases 1947ff178cdSJimmy Vetayases { CC_SMS_WR_START, 0x18 }, /* NetFn/LUN */ 1957ff178cdSJimmy Vetayases { CC_SMS_WR_END, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */ 1967ff178cdSJimmy Vetayases }; 1977ff178cdSJimmy Vetayases 1987ff178cdSJimmy Vetayases static struct { 1997ff178cdSJimmy Vetayases int port; 2007ff178cdSJimmy Vetayases uchar_t data; 2017ff178cdSJimmy Vetayases } sitka_bmc[] = { 2027ff178cdSJimmy Vetayases { SMS_COMMAND_REGISTER, SMS_WRITE_START }, 2037ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */ 2047ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */ 2057ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x84 }, /* DataByte 1: SMS/OS no log */ 2067ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x2 }, /* DataByte 2: Power Down */ 2077ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 3: no pre-timeout */ 2087ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 4: timer expir. */ 2097ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0xa }, /* DataByte 5: init countdown */ 2107ff178cdSJimmy Vetayases { SMS_COMMAND_REGISTER, SMS_WRITE_END }, 2117ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 6: init countdown */ 2127ff178cdSJimmy Vetayases 2137ff178cdSJimmy Vetayases { SMS_COMMAND_REGISTER, SMS_WRITE_START }, 2147ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */ 2157ff178cdSJimmy Vetayases { SMS_COMMAND_REGISTER, SMS_WRITE_END }, 2167ff178cdSJimmy Vetayases { SMS_DATA_REGISTER, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */ 2177ff178cdSJimmy Vetayases }; 2187ff178cdSJimmy Vetayases 2197ff178cdSJimmy Vetayases /* Patchable global variables. */ 2207ff178cdSJimmy Vetayases int apic_kmdb_on_nmi = 0; /* 0 - no, 1 - yes enter kmdb */ 2217ff178cdSJimmy Vetayases uint32_t apic_divide_reg_init = 0; /* 0 - divide by 2 */ 2227ff178cdSJimmy Vetayases 2237ff178cdSJimmy Vetayases /* default apic ops without interrupt remapping */ 2247ff178cdSJimmy Vetayases static apic_intrmap_ops_t apic_nointrmap_ops = { 2257ff178cdSJimmy Vetayases (int (*)(int))return_instr, 2267ff178cdSJimmy Vetayases (void (*)(int))return_instr, 2277ff178cdSJimmy Vetayases (void (*)(void **, dev_info_t *, uint16_t, int, uchar_t))return_instr, 2287ff178cdSJimmy Vetayases (void (*)(void *, void *, uint16_t, int))return_instr, 2297ff178cdSJimmy Vetayases (void (*)(void **))return_instr, 2307ff178cdSJimmy Vetayases apic_record_ioapic_rdt, 2317ff178cdSJimmy Vetayases apic_record_msi, 2327ff178cdSJimmy Vetayases }; 2337ff178cdSJimmy Vetayases 2347ff178cdSJimmy Vetayases apic_intrmap_ops_t *apic_vt_ops = &apic_nointrmap_ops; 2357ff178cdSJimmy Vetayases apic_cpus_info_t *apic_cpus = NULL; 2367ff178cdSJimmy Vetayases cpuset_t apic_cpumask; 2377ff178cdSJimmy Vetayases uint_t apic_picinit_called; 2387ff178cdSJimmy Vetayases 2397ff178cdSJimmy Vetayases /* Flag to indicate that we need to shut down all processors */ 2407ff178cdSJimmy Vetayases static uint_t apic_shutdown_processors; 2417ff178cdSJimmy Vetayases 2427ff178cdSJimmy Vetayases /* 2437ff178cdSJimmy Vetayases * Probe the ioapic method for apix module. Called in apic_probe_common() 2447ff178cdSJimmy Vetayases */ 2457ff178cdSJimmy Vetayases int 2467ff178cdSJimmy Vetayases apic_ioapic_method_probe() 2477ff178cdSJimmy Vetayases { 2487ff178cdSJimmy Vetayases if (apix_enable == 0) 2497ff178cdSJimmy Vetayases return (PSM_SUCCESS); 2507ff178cdSJimmy Vetayases 2517ff178cdSJimmy Vetayases /* 2527ff178cdSJimmy Vetayases * Set IOAPIC EOI handling method. The priority from low to high is: 2537ff178cdSJimmy Vetayases * 1. IOxAPIC: with EOI register 2547ff178cdSJimmy Vetayases * 2. IOMMU interrupt mapping 2557ff178cdSJimmy Vetayases * 3. Mask-Before-EOI method for systems without boot 2567ff178cdSJimmy Vetayases * interrupt routing, such as systems with only one IOAPIC; 2577ff178cdSJimmy Vetayases * NVIDIA CK8-04/MCP55 systems; systems with bridge solution 2587ff178cdSJimmy Vetayases * which disables the boot interrupt routing already. 2597ff178cdSJimmy Vetayases * 4. Directed EOI 2607ff178cdSJimmy Vetayases */ 2617ff178cdSJimmy Vetayases if (apic_io_ver[0] >= 0x20) 2627ff178cdSJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_IOXAPIC; 2637ff178cdSJimmy Vetayases if ((apic_io_max == 1) || (apic_nvidia_io_max == apic_io_max)) 2647ff178cdSJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_MASK; 2657ff178cdSJimmy Vetayases if (apic_directed_EOI_supported()) 2667ff178cdSJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_DEOI; 2677ff178cdSJimmy Vetayases 2687ff178cdSJimmy Vetayases /* fall back to pcplusmp */ 2697ff178cdSJimmy Vetayases if (apix_mul_ioapic_method == APIC_MUL_IOAPIC_PCPLUSMP) { 2707ff178cdSJimmy Vetayases /* make sure apix is after pcplusmp in /etc/mach */ 2717ff178cdSJimmy Vetayases apix_enable = 0; /* go ahead with pcplusmp install next */ 2727ff178cdSJimmy Vetayases return (PSM_FAILURE); 2737ff178cdSJimmy Vetayases } 2747ff178cdSJimmy Vetayases 2757ff178cdSJimmy Vetayases return (PSM_SUCCESS); 2767ff178cdSJimmy Vetayases } 2777ff178cdSJimmy Vetayases 2787ff178cdSJimmy Vetayases /* 2797ff178cdSJimmy Vetayases * handler for APIC Error interrupt. Just print a warning and continue 2807ff178cdSJimmy Vetayases */ 2817ff178cdSJimmy Vetayases int 2827ff178cdSJimmy Vetayases apic_error_intr() 2837ff178cdSJimmy Vetayases { 2847ff178cdSJimmy Vetayases uint_t error0, error1, error; 2857ff178cdSJimmy Vetayases uint_t i; 2867ff178cdSJimmy Vetayases 2877ff178cdSJimmy Vetayases /* 2887ff178cdSJimmy Vetayases * We need to write before read as per 7.4.17 of system prog manual. 2897ff178cdSJimmy Vetayases * We do both and or the results to be safe 2907ff178cdSJimmy Vetayases */ 2917ff178cdSJimmy Vetayases error0 = apic_reg_ops->apic_read(APIC_ERROR_STATUS); 2927ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 2937ff178cdSJimmy Vetayases error1 = apic_reg_ops->apic_read(APIC_ERROR_STATUS); 2947ff178cdSJimmy Vetayases error = error0 | error1; 2957ff178cdSJimmy Vetayases 2967ff178cdSJimmy Vetayases /* 2977ff178cdSJimmy Vetayases * Clear the APIC error status (do this on all cpus that enter here) 2987ff178cdSJimmy Vetayases * (two writes are required due to the semantics of accessing the 2997ff178cdSJimmy Vetayases * error status register.) 3007ff178cdSJimmy Vetayases */ 3017ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 3027ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 3037ff178cdSJimmy Vetayases 3047ff178cdSJimmy Vetayases /* 3057ff178cdSJimmy Vetayases * Prevent more than 1 CPU from handling error interrupt causing 3067ff178cdSJimmy Vetayases * double printing (interleave of characters from multiple 3077ff178cdSJimmy Vetayases * CPU's when using prom_printf) 3087ff178cdSJimmy Vetayases */ 3097ff178cdSJimmy Vetayases if (lock_try(&apic_error_lock) == 0) 3107ff178cdSJimmy Vetayases return (error ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 3117ff178cdSJimmy Vetayases if (error) { 3127ff178cdSJimmy Vetayases #if DEBUG 3137ff178cdSJimmy Vetayases if (apic_debug) 3147ff178cdSJimmy Vetayases debug_enter("pcplusmp: APIC Error interrupt received"); 3157ff178cdSJimmy Vetayases #endif /* DEBUG */ 3167ff178cdSJimmy Vetayases if (apic_panic_on_apic_error) 3177ff178cdSJimmy Vetayases cmn_err(CE_PANIC, 3187ff178cdSJimmy Vetayases "APIC Error interrupt on CPU %d. Status = %x", 3197ff178cdSJimmy Vetayases psm_get_cpu_id(), error); 3207ff178cdSJimmy Vetayases else { 3217ff178cdSJimmy Vetayases if ((error & ~APIC_CS_ERRORS) == 0) { 3227ff178cdSJimmy Vetayases /* cksum error only */ 3237ff178cdSJimmy Vetayases apic_error |= APIC_ERR_APIC_ERROR; 3247ff178cdSJimmy Vetayases apic_apic_error |= error; 3257ff178cdSJimmy Vetayases apic_num_apic_errors++; 3267ff178cdSJimmy Vetayases apic_num_cksum_errors++; 3277ff178cdSJimmy Vetayases } else { 3287ff178cdSJimmy Vetayases /* 3297ff178cdSJimmy Vetayases * prom_printf is the best shot we have of 3307ff178cdSJimmy Vetayases * something which is problem free from 3317ff178cdSJimmy Vetayases * high level/NMI type of interrupts 3327ff178cdSJimmy Vetayases */ 3337ff178cdSJimmy Vetayases prom_printf("APIC Error interrupt on CPU %d. " 3347ff178cdSJimmy Vetayases "Status 0 = %x, Status 1 = %x\n", 3357ff178cdSJimmy Vetayases psm_get_cpu_id(), error0, error1); 3367ff178cdSJimmy Vetayases apic_error |= APIC_ERR_APIC_ERROR; 3377ff178cdSJimmy Vetayases apic_apic_error |= error; 3387ff178cdSJimmy Vetayases apic_num_apic_errors++; 3397ff178cdSJimmy Vetayases for (i = 0; i < apic_error_display_delay; i++) { 3407ff178cdSJimmy Vetayases tenmicrosec(); 3417ff178cdSJimmy Vetayases } 3427ff178cdSJimmy Vetayases /* 3437ff178cdSJimmy Vetayases * provide more delay next time limited to 3447ff178cdSJimmy Vetayases * roughly 1 clock tick time 3457ff178cdSJimmy Vetayases */ 3467ff178cdSJimmy Vetayases if (apic_error_display_delay < 500) 3477ff178cdSJimmy Vetayases apic_error_display_delay *= 2; 3487ff178cdSJimmy Vetayases } 3497ff178cdSJimmy Vetayases } 3507ff178cdSJimmy Vetayases lock_clear(&apic_error_lock); 3517ff178cdSJimmy Vetayases return (DDI_INTR_CLAIMED); 3527ff178cdSJimmy Vetayases } else { 3537ff178cdSJimmy Vetayases lock_clear(&apic_error_lock); 3547ff178cdSJimmy Vetayases return (DDI_INTR_UNCLAIMED); 3557ff178cdSJimmy Vetayases } 3567ff178cdSJimmy Vetayases } 3577ff178cdSJimmy Vetayases 3587ff178cdSJimmy Vetayases /* 3597ff178cdSJimmy Vetayases * Turn off the mask bit in the performance counter Local Vector Table entry. 3607ff178cdSJimmy Vetayases */ 3617ff178cdSJimmy Vetayases void 3627ff178cdSJimmy Vetayases apic_cpcovf_mask_clear(void) 3637ff178cdSJimmy Vetayases { 3647ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_PCINT_VECT, 3657ff178cdSJimmy Vetayases (apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK)); 3667ff178cdSJimmy Vetayases } 3677ff178cdSJimmy Vetayases 3687ff178cdSJimmy Vetayases /*ARGSUSED*/ 3697ff178cdSJimmy Vetayases static int 3707ff178cdSJimmy Vetayases apic_cmci_enable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 3717ff178cdSJimmy Vetayases { 3727ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect); 3737ff178cdSJimmy Vetayases return (0); 3747ff178cdSJimmy Vetayases } 3757ff178cdSJimmy Vetayases 3767ff178cdSJimmy Vetayases /*ARGSUSED*/ 3777ff178cdSJimmy Vetayases static int 3787ff178cdSJimmy Vetayases apic_cmci_disable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 3797ff178cdSJimmy Vetayases { 3807ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK); 3817ff178cdSJimmy Vetayases return (0); 3827ff178cdSJimmy Vetayases } 3837ff178cdSJimmy Vetayases 3847ff178cdSJimmy Vetayases /*ARGSUSED*/ 3857ff178cdSJimmy Vetayases int 3867ff178cdSJimmy Vetayases cmci_cpu_setup(cpu_setup_t what, int cpuid, void *arg) 3877ff178cdSJimmy Vetayases { 3887ff178cdSJimmy Vetayases cpuset_t cpu_set; 3897ff178cdSJimmy Vetayases 3907ff178cdSJimmy Vetayases CPUSET_ONLY(cpu_set, cpuid); 3917ff178cdSJimmy Vetayases 3927ff178cdSJimmy Vetayases switch (what) { 3937ff178cdSJimmy Vetayases case CPU_ON: 3947ff178cdSJimmy Vetayases xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set), 3957ff178cdSJimmy Vetayases (xc_func_t)apic_cmci_enable); 3967ff178cdSJimmy Vetayases break; 3977ff178cdSJimmy Vetayases 3987ff178cdSJimmy Vetayases case CPU_OFF: 3997ff178cdSJimmy Vetayases xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set), 4007ff178cdSJimmy Vetayases (xc_func_t)apic_cmci_disable); 4017ff178cdSJimmy Vetayases break; 4027ff178cdSJimmy Vetayases 4037ff178cdSJimmy Vetayases default: 4047ff178cdSJimmy Vetayases break; 4057ff178cdSJimmy Vetayases } 4067ff178cdSJimmy Vetayases 4077ff178cdSJimmy Vetayases return (0); 4087ff178cdSJimmy Vetayases } 4097ff178cdSJimmy Vetayases 4107ff178cdSJimmy Vetayases static void 4117ff178cdSJimmy Vetayases apic_disable_local_apic(void) 4127ff178cdSJimmy Vetayases { 4137ff178cdSJimmy Vetayases apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL); 4147ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK); 4157ff178cdSJimmy Vetayases 4167ff178cdSJimmy Vetayases /* local intr reg 0 */ 4177ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK); 4187ff178cdSJimmy Vetayases 4197ff178cdSJimmy Vetayases /* disable NMI */ 4207ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_VECT1, AV_MASK); 4217ff178cdSJimmy Vetayases 4227ff178cdSJimmy Vetayases /* and error interrupt */ 4237ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_ERR_VECT, AV_MASK); 4247ff178cdSJimmy Vetayases 4257ff178cdSJimmy Vetayases /* and perf counter intr */ 4267ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_PCINT_VECT, AV_MASK); 4277ff178cdSJimmy Vetayases 4287ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_SPUR_INT_REG, APIC_SPUR_INTR); 4297ff178cdSJimmy Vetayases } 4307ff178cdSJimmy Vetayases 4317ff178cdSJimmy Vetayases static void 4327ff178cdSJimmy Vetayases apic_cpu_send_SIPI(processorid_t cpun, boolean_t start) 4337ff178cdSJimmy Vetayases { 4347ff178cdSJimmy Vetayases int loop_count; 4357ff178cdSJimmy Vetayases uint32_t vector; 4367ff178cdSJimmy Vetayases uint_t apicid; 4377ff178cdSJimmy Vetayases ulong_t iflag; 4387ff178cdSJimmy Vetayases 4397ff178cdSJimmy Vetayases apicid = apic_cpus[cpun].aci_local_id; 4407ff178cdSJimmy Vetayases 4417ff178cdSJimmy Vetayases /* 4427ff178cdSJimmy Vetayases * Interrupts on current CPU will be disabled during the 4437ff178cdSJimmy Vetayases * steps in order to avoid unwanted side effects from 4447ff178cdSJimmy Vetayases * executing interrupt handlers on a problematic BIOS. 4457ff178cdSJimmy Vetayases */ 4467ff178cdSJimmy Vetayases iflag = intr_clear(); 4477ff178cdSJimmy Vetayases 4487ff178cdSJimmy Vetayases if (start) { 4497ff178cdSJimmy Vetayases outb(CMOS_ADDR, SSB); 4507ff178cdSJimmy Vetayases outb(CMOS_DATA, BIOS_SHUTDOWN); 4517ff178cdSJimmy Vetayases } 4527ff178cdSJimmy Vetayases 4537ff178cdSJimmy Vetayases /* 4547ff178cdSJimmy Vetayases * According to X2APIC specification in section '2.3.5.1' of 4557ff178cdSJimmy Vetayases * Interrupt Command Register Semantics, the semantics of 4567ff178cdSJimmy Vetayases * programming the Interrupt Command Register to dispatch an interrupt 4577ff178cdSJimmy Vetayases * is simplified. A single MSR write to the 64-bit ICR is required 4587ff178cdSJimmy Vetayases * for dispatching an interrupt. Specifically, with the 64-bit MSR 4597ff178cdSJimmy Vetayases * interface to ICR, system software is not required to check the 4607ff178cdSJimmy Vetayases * status of the delivery status bit prior to writing to the ICR 4617ff178cdSJimmy Vetayases * to send an IPI. With the removal of the Delivery Status bit, 4627ff178cdSJimmy Vetayases * system software no longer has a reason to read the ICR. It remains 4637ff178cdSJimmy Vetayases * readable only to aid in debugging. 4647ff178cdSJimmy Vetayases */ 4657ff178cdSJimmy Vetayases #ifdef DEBUG 4667ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 4677ff178cdSJimmy Vetayases #else 4687ff178cdSJimmy Vetayases if (apic_mode == LOCAL_APIC) { 4697ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 4707ff178cdSJimmy Vetayases } 4717ff178cdSJimmy Vetayases #endif /* DEBUG */ 4727ff178cdSJimmy Vetayases 4737ff178cdSJimmy Vetayases /* for integrated - make sure there is one INIT IPI in buffer */ 4747ff178cdSJimmy Vetayases /* for external - it will wake up the cpu */ 4757ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, AV_ASSERT | AV_RESET); 4767ff178cdSJimmy Vetayases 4777ff178cdSJimmy Vetayases /* If only 1 CPU is installed, PENDING bit will not go low */ 4787ff178cdSJimmy Vetayases for (loop_count = apic_sipi_max_loop_count; loop_count; loop_count--) { 4797ff178cdSJimmy Vetayases if (apic_mode == LOCAL_APIC && 4807ff178cdSJimmy Vetayases apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING) 4817ff178cdSJimmy Vetayases apic_ret(); 4827ff178cdSJimmy Vetayases else 4837ff178cdSJimmy Vetayases break; 4847ff178cdSJimmy Vetayases } 4857ff178cdSJimmy Vetayases 4867ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, AV_DEASSERT | AV_RESET); 4877ff178cdSJimmy Vetayases drv_usecwait(20000); /* 20 milli sec */ 4887ff178cdSJimmy Vetayases 4897ff178cdSJimmy Vetayases if (apic_cpus[cpun].aci_local_ver >= APIC_INTEGRATED_VERS) { 4907ff178cdSJimmy Vetayases /* integrated apic */ 4917ff178cdSJimmy Vetayases 4927ff178cdSJimmy Vetayases vector = (rm_platter_pa >> MMU_PAGESHIFT) & 4937ff178cdSJimmy Vetayases (APIC_VECTOR_MASK | APIC_IPL_MASK); 4947ff178cdSJimmy Vetayases 4957ff178cdSJimmy Vetayases /* to offset the INIT IPI queue up in the buffer */ 4967ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP); 4977ff178cdSJimmy Vetayases drv_usecwait(200); /* 20 micro sec */ 4987ff178cdSJimmy Vetayases 4997ff178cdSJimmy Vetayases /* 5007ff178cdSJimmy Vetayases * send the second SIPI (Startup IPI) as recommended by Intel 5017ff178cdSJimmy Vetayases * software development manual. 5027ff178cdSJimmy Vetayases */ 5037ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP); 5047ff178cdSJimmy Vetayases drv_usecwait(200); /* 20 micro sec */ 5057ff178cdSJimmy Vetayases } 5067ff178cdSJimmy Vetayases 5077ff178cdSJimmy Vetayases intr_restore(iflag); 5087ff178cdSJimmy Vetayases } 5097ff178cdSJimmy Vetayases 5107ff178cdSJimmy Vetayases /*ARGSUSED1*/ 5117ff178cdSJimmy Vetayases int 5127ff178cdSJimmy Vetayases apic_cpu_start(processorid_t cpun, caddr_t arg) 5137ff178cdSJimmy Vetayases { 5147ff178cdSJimmy Vetayases ASSERT(MUTEX_HELD(&cpu_lock)); 5157ff178cdSJimmy Vetayases 5167ff178cdSJimmy Vetayases if (!apic_cpu_in_range(cpun)) { 5177ff178cdSJimmy Vetayases return (EINVAL); 5187ff178cdSJimmy Vetayases } 5197ff178cdSJimmy Vetayases 5207ff178cdSJimmy Vetayases /* 5217ff178cdSJimmy Vetayases * Switch to apic_common_send_ipi for safety during starting other CPUs. 5227ff178cdSJimmy Vetayases */ 5237ff178cdSJimmy Vetayases if (apic_mode == LOCAL_X2APIC) { 5247ff178cdSJimmy Vetayases apic_switch_ipi_callback(B_TRUE); 5257ff178cdSJimmy Vetayases } 5267ff178cdSJimmy Vetayases 5277ff178cdSJimmy Vetayases apic_cmos_ssb_set = 1; 5287ff178cdSJimmy Vetayases apic_cpu_send_SIPI(cpun, B_TRUE); 5297ff178cdSJimmy Vetayases 5307ff178cdSJimmy Vetayases return (0); 5317ff178cdSJimmy Vetayases } 5327ff178cdSJimmy Vetayases 5337ff178cdSJimmy Vetayases /* 5347ff178cdSJimmy Vetayases * Put CPU into halted state with interrupts disabled. 5357ff178cdSJimmy Vetayases */ 5367ff178cdSJimmy Vetayases /*ARGSUSED1*/ 5377ff178cdSJimmy Vetayases int 5387ff178cdSJimmy Vetayases apic_cpu_stop(processorid_t cpun, caddr_t arg) 5397ff178cdSJimmy Vetayases { 5407ff178cdSJimmy Vetayases int rc; 5417ff178cdSJimmy Vetayases cpu_t *cp; 5427ff178cdSJimmy Vetayases extern cpuset_t cpu_ready_set; 5437ff178cdSJimmy Vetayases extern void cpu_idle_intercept_cpu(cpu_t *cp); 5447ff178cdSJimmy Vetayases 5457ff178cdSJimmy Vetayases ASSERT(MUTEX_HELD(&cpu_lock)); 5467ff178cdSJimmy Vetayases 5477ff178cdSJimmy Vetayases if (!apic_cpu_in_range(cpun)) { 5487ff178cdSJimmy Vetayases return (EINVAL); 5497ff178cdSJimmy Vetayases } 5507ff178cdSJimmy Vetayases if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) { 5517ff178cdSJimmy Vetayases return (ENOTSUP); 5527ff178cdSJimmy Vetayases } 5537ff178cdSJimmy Vetayases 5547ff178cdSJimmy Vetayases cp = cpu_get(cpun); 5557ff178cdSJimmy Vetayases ASSERT(cp != NULL); 5567ff178cdSJimmy Vetayases ASSERT((cp->cpu_flags & CPU_OFFLINE) != 0); 5577ff178cdSJimmy Vetayases ASSERT((cp->cpu_flags & CPU_QUIESCED) != 0); 5587ff178cdSJimmy Vetayases ASSERT((cp->cpu_flags & CPU_ENABLE) == 0); 5597ff178cdSJimmy Vetayases 5607ff178cdSJimmy Vetayases /* Clear CPU_READY flag to disable cross calls. */ 5617ff178cdSJimmy Vetayases cp->cpu_flags &= ~CPU_READY; 5627ff178cdSJimmy Vetayases CPUSET_ATOMIC_DEL(cpu_ready_set, cpun); 5637ff178cdSJimmy Vetayases rc = xc_flush_cpu(cp); 5647ff178cdSJimmy Vetayases if (rc != 0) { 5657ff178cdSJimmy Vetayases CPUSET_ATOMIC_ADD(cpu_ready_set, cpun); 5667ff178cdSJimmy Vetayases cp->cpu_flags |= CPU_READY; 5677ff178cdSJimmy Vetayases return (rc); 5687ff178cdSJimmy Vetayases } 5697ff178cdSJimmy Vetayases 5707ff178cdSJimmy Vetayases /* Intercept target CPU at a safe point before powering it off. */ 5717ff178cdSJimmy Vetayases cpu_idle_intercept_cpu(cp); 5727ff178cdSJimmy Vetayases 5737ff178cdSJimmy Vetayases apic_cpu_send_SIPI(cpun, B_FALSE); 5747ff178cdSJimmy Vetayases cp->cpu_flags &= ~CPU_RUNNING; 5757ff178cdSJimmy Vetayases 5767ff178cdSJimmy Vetayases return (0); 5777ff178cdSJimmy Vetayases } 5787ff178cdSJimmy Vetayases 5797ff178cdSJimmy Vetayases int 5807ff178cdSJimmy Vetayases apic_cpu_ops(psm_cpu_request_t *reqp) 5817ff178cdSJimmy Vetayases { 5827ff178cdSJimmy Vetayases if (reqp == NULL) { 5837ff178cdSJimmy Vetayases return (EINVAL); 5847ff178cdSJimmy Vetayases } 5857ff178cdSJimmy Vetayases 5867ff178cdSJimmy Vetayases switch (reqp->pcr_cmd) { 5877ff178cdSJimmy Vetayases case PSM_CPU_ADD: 5887ff178cdSJimmy Vetayases return (apic_cpu_add(reqp)); 5897ff178cdSJimmy Vetayases 5907ff178cdSJimmy Vetayases case PSM_CPU_REMOVE: 5917ff178cdSJimmy Vetayases return (apic_cpu_remove(reqp)); 5927ff178cdSJimmy Vetayases 5937ff178cdSJimmy Vetayases case PSM_CPU_STOP: 5947ff178cdSJimmy Vetayases return (apic_cpu_stop(reqp->req.cpu_stop.cpuid, 5957ff178cdSJimmy Vetayases reqp->req.cpu_stop.ctx)); 5967ff178cdSJimmy Vetayases 5977ff178cdSJimmy Vetayases default: 5987ff178cdSJimmy Vetayases return (ENOTSUP); 5997ff178cdSJimmy Vetayases } 6007ff178cdSJimmy Vetayases } 6017ff178cdSJimmy Vetayases 6027ff178cdSJimmy Vetayases #ifdef DEBUG 6037ff178cdSJimmy Vetayases int apic_break_on_cpu = 9; 6047ff178cdSJimmy Vetayases int apic_stretch_interrupts = 0; 6057ff178cdSJimmy Vetayases int apic_stretch_ISR = 1 << 3; /* IPL of 3 matches nothing now */ 6067ff178cdSJimmy Vetayases #endif /* DEBUG */ 6077ff178cdSJimmy Vetayases 6087ff178cdSJimmy Vetayases /* 6097ff178cdSJimmy Vetayases * generates an interprocessor interrupt to another CPU. Any changes made to 6107ff178cdSJimmy Vetayases * this routine must be accompanied by similar changes to 6117ff178cdSJimmy Vetayases * apic_common_send_ipi(). 6127ff178cdSJimmy Vetayases */ 6137ff178cdSJimmy Vetayases void 6147ff178cdSJimmy Vetayases apic_send_ipi(int cpun, int ipl) 6157ff178cdSJimmy Vetayases { 6167ff178cdSJimmy Vetayases int vector; 6177ff178cdSJimmy Vetayases ulong_t flag; 6187ff178cdSJimmy Vetayases 6197ff178cdSJimmy Vetayases vector = apic_resv_vector[ipl]; 6207ff178cdSJimmy Vetayases 6217ff178cdSJimmy Vetayases ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR)); 6227ff178cdSJimmy Vetayases 6237ff178cdSJimmy Vetayases flag = intr_clear(); 6247ff178cdSJimmy Vetayases 6257ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 6267ff178cdSJimmy Vetayases 6277ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apic_cpus[cpun].aci_local_id, 6287ff178cdSJimmy Vetayases vector); 6297ff178cdSJimmy Vetayases 6307ff178cdSJimmy Vetayases intr_restore(flag); 6317ff178cdSJimmy Vetayases } 6327ff178cdSJimmy Vetayases 6337ff178cdSJimmy Vetayases 6347ff178cdSJimmy Vetayases /*ARGSUSED*/ 6357ff178cdSJimmy Vetayases void 6367ff178cdSJimmy Vetayases apic_set_idlecpu(processorid_t cpun) 6377ff178cdSJimmy Vetayases { 6387ff178cdSJimmy Vetayases } 6397ff178cdSJimmy Vetayases 6407ff178cdSJimmy Vetayases /*ARGSUSED*/ 6417ff178cdSJimmy Vetayases void 6427ff178cdSJimmy Vetayases apic_unset_idlecpu(processorid_t cpun) 6437ff178cdSJimmy Vetayases { 6447ff178cdSJimmy Vetayases } 6457ff178cdSJimmy Vetayases 6467ff178cdSJimmy Vetayases 6477ff178cdSJimmy Vetayases void 6487ff178cdSJimmy Vetayases apic_ret() 6497ff178cdSJimmy Vetayases { 6507ff178cdSJimmy Vetayases } 6517ff178cdSJimmy Vetayases 6527ff178cdSJimmy Vetayases /* 6537ff178cdSJimmy Vetayases * If apic_coarse_time == 1, then apic_gettime() is used instead of 6547ff178cdSJimmy Vetayases * apic_gethrtime(). This is used for performance instead of accuracy. 6557ff178cdSJimmy Vetayases */ 6567ff178cdSJimmy Vetayases 6577ff178cdSJimmy Vetayases hrtime_t 6587ff178cdSJimmy Vetayases apic_gettime() 6597ff178cdSJimmy Vetayases { 6607ff178cdSJimmy Vetayases int old_hrtime_stamp; 6617ff178cdSJimmy Vetayases hrtime_t temp; 6627ff178cdSJimmy Vetayases 6637ff178cdSJimmy Vetayases /* 6647ff178cdSJimmy Vetayases * In one-shot mode, we do not keep time, so if anyone 6657ff178cdSJimmy Vetayases * calls psm_gettime() directly, we vector over to 6667ff178cdSJimmy Vetayases * gethrtime(). 6677ff178cdSJimmy Vetayases * one-shot mode MUST NOT be enabled if this psm is the source of 6687ff178cdSJimmy Vetayases * hrtime. 6697ff178cdSJimmy Vetayases */ 6707ff178cdSJimmy Vetayases 6717ff178cdSJimmy Vetayases if (apic_oneshot) 6727ff178cdSJimmy Vetayases return (gethrtime()); 6737ff178cdSJimmy Vetayases 6747ff178cdSJimmy Vetayases 6757ff178cdSJimmy Vetayases gettime_again: 6767ff178cdSJimmy Vetayases while ((old_hrtime_stamp = apic_hrtime_stamp) & 1) 6777ff178cdSJimmy Vetayases apic_ret(); 6787ff178cdSJimmy Vetayases 6797ff178cdSJimmy Vetayases temp = apic_nsec_since_boot; 6807ff178cdSJimmy Vetayases 6817ff178cdSJimmy Vetayases if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */ 6827ff178cdSJimmy Vetayases goto gettime_again; 6837ff178cdSJimmy Vetayases } 6847ff178cdSJimmy Vetayases return (temp); 6857ff178cdSJimmy Vetayases } 6867ff178cdSJimmy Vetayases 6877ff178cdSJimmy Vetayases /* 6887ff178cdSJimmy Vetayases * Here we return the number of nanoseconds since booting. Note every 6897ff178cdSJimmy Vetayases * clock interrupt increments apic_nsec_since_boot by the appropriate 6907ff178cdSJimmy Vetayases * amount. 6917ff178cdSJimmy Vetayases */ 6927ff178cdSJimmy Vetayases hrtime_t 6937ff178cdSJimmy Vetayases apic_gethrtime(void) 6947ff178cdSJimmy Vetayases { 6957ff178cdSJimmy Vetayases int curr_timeval, countval, elapsed_ticks; 6967ff178cdSJimmy Vetayases int old_hrtime_stamp, status; 6977ff178cdSJimmy Vetayases hrtime_t temp; 6987ff178cdSJimmy Vetayases uint32_t cpun; 6997ff178cdSJimmy Vetayases ulong_t oflags; 7007ff178cdSJimmy Vetayases 7017ff178cdSJimmy Vetayases /* 7027ff178cdSJimmy Vetayases * In one-shot mode, we do not keep time, so if anyone 7037ff178cdSJimmy Vetayases * calls psm_gethrtime() directly, we vector over to 7047ff178cdSJimmy Vetayases * gethrtime(). 7057ff178cdSJimmy Vetayases * one-shot mode MUST NOT be enabled if this psm is the source of 7067ff178cdSJimmy Vetayases * hrtime. 7077ff178cdSJimmy Vetayases */ 7087ff178cdSJimmy Vetayases 7097ff178cdSJimmy Vetayases if (apic_oneshot) 7107ff178cdSJimmy Vetayases return (gethrtime()); 7117ff178cdSJimmy Vetayases 7127ff178cdSJimmy Vetayases oflags = intr_clear(); /* prevent migration */ 7137ff178cdSJimmy Vetayases 7147ff178cdSJimmy Vetayases cpun = apic_reg_ops->apic_read(APIC_LID_REG); 7157ff178cdSJimmy Vetayases if (apic_mode == LOCAL_APIC) 7167ff178cdSJimmy Vetayases cpun >>= APIC_ID_BIT_OFFSET; 7177ff178cdSJimmy Vetayases 7187ff178cdSJimmy Vetayases lock_set(&apic_gethrtime_lock); 7197ff178cdSJimmy Vetayases 7207ff178cdSJimmy Vetayases gethrtime_again: 7217ff178cdSJimmy Vetayases while ((old_hrtime_stamp = apic_hrtime_stamp) & 1) 7227ff178cdSJimmy Vetayases apic_ret(); 7237ff178cdSJimmy Vetayases 7247ff178cdSJimmy Vetayases /* 7257ff178cdSJimmy Vetayases * Check to see which CPU we are on. Note the time is kept on 7267ff178cdSJimmy Vetayases * the local APIC of CPU 0. If on CPU 0, simply read the current 7277ff178cdSJimmy Vetayases * counter. If on another CPU, issue a remote read command to CPU 0. 7287ff178cdSJimmy Vetayases */ 7297ff178cdSJimmy Vetayases if (cpun == apic_cpus[0].aci_local_id) { 7307ff178cdSJimmy Vetayases countval = apic_reg_ops->apic_read(APIC_CURR_COUNT); 7317ff178cdSJimmy Vetayases } else { 7327ff178cdSJimmy Vetayases #ifdef DEBUG 7337ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 7347ff178cdSJimmy Vetayases #else 7357ff178cdSJimmy Vetayases if (apic_mode == LOCAL_APIC) 7367ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 7377ff178cdSJimmy Vetayases #endif /* DEBUG */ 7387ff178cdSJimmy Vetayases 7397ff178cdSJimmy Vetayases apic_reg_ops->apic_write_int_cmd( 7407ff178cdSJimmy Vetayases apic_cpus[0].aci_local_id, APIC_CURR_ADD | AV_REMOTE); 7417ff178cdSJimmy Vetayases 7427ff178cdSJimmy Vetayases while ((status = apic_reg_ops->apic_read(APIC_INT_CMD1)) 7437ff178cdSJimmy Vetayases & AV_READ_PENDING) { 7447ff178cdSJimmy Vetayases apic_ret(); 7457ff178cdSJimmy Vetayases } 7467ff178cdSJimmy Vetayases 7477ff178cdSJimmy Vetayases if (status & AV_REMOTE_STATUS) /* 1 = valid */ 7487ff178cdSJimmy Vetayases countval = apic_reg_ops->apic_read(APIC_REMOTE_READ); 7497ff178cdSJimmy Vetayases else { /* 0 = invalid */ 7507ff178cdSJimmy Vetayases apic_remote_hrterr++; 7517ff178cdSJimmy Vetayases /* 7527ff178cdSJimmy Vetayases * return last hrtime right now, will need more 7537ff178cdSJimmy Vetayases * testing if change to retry 7547ff178cdSJimmy Vetayases */ 7557ff178cdSJimmy Vetayases temp = apic_last_hrtime; 7567ff178cdSJimmy Vetayases 7577ff178cdSJimmy Vetayases lock_clear(&apic_gethrtime_lock); 7587ff178cdSJimmy Vetayases 7597ff178cdSJimmy Vetayases intr_restore(oflags); 7607ff178cdSJimmy Vetayases 7617ff178cdSJimmy Vetayases return (temp); 7627ff178cdSJimmy Vetayases } 7637ff178cdSJimmy Vetayases } 7647ff178cdSJimmy Vetayases if (countval > last_count_read) 7657ff178cdSJimmy Vetayases countval = 0; 7667ff178cdSJimmy Vetayases else 7677ff178cdSJimmy Vetayases last_count_read = countval; 7687ff178cdSJimmy Vetayases 7697ff178cdSJimmy Vetayases elapsed_ticks = apic_hertz_count - countval; 7707ff178cdSJimmy Vetayases 7717ff178cdSJimmy Vetayases curr_timeval = APIC_TICKS_TO_NSECS(elapsed_ticks); 7727ff178cdSJimmy Vetayases temp = apic_nsec_since_boot + curr_timeval; 7737ff178cdSJimmy Vetayases 7747ff178cdSJimmy Vetayases if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */ 7757ff178cdSJimmy Vetayases /* we might have clobbered last_count_read. Restore it */ 7767ff178cdSJimmy Vetayases last_count_read = apic_hertz_count; 7777ff178cdSJimmy Vetayases goto gethrtime_again; 7787ff178cdSJimmy Vetayases } 7797ff178cdSJimmy Vetayases 7807ff178cdSJimmy Vetayases if (temp < apic_last_hrtime) { 7817ff178cdSJimmy Vetayases /* return last hrtime if error occurs */ 7827ff178cdSJimmy Vetayases apic_hrtime_error++; 7837ff178cdSJimmy Vetayases temp = apic_last_hrtime; 7847ff178cdSJimmy Vetayases } 7857ff178cdSJimmy Vetayases else 7867ff178cdSJimmy Vetayases apic_last_hrtime = temp; 7877ff178cdSJimmy Vetayases 7887ff178cdSJimmy Vetayases lock_clear(&apic_gethrtime_lock); 7897ff178cdSJimmy Vetayases intr_restore(oflags); 7907ff178cdSJimmy Vetayases 7917ff178cdSJimmy Vetayases return (temp); 7927ff178cdSJimmy Vetayases } 7937ff178cdSJimmy Vetayases 7947ff178cdSJimmy Vetayases /* apic NMI handler */ 7957ff178cdSJimmy Vetayases /*ARGSUSED*/ 7967ff178cdSJimmy Vetayases void 7977ff178cdSJimmy Vetayases apic_nmi_intr(caddr_t arg, struct regs *rp) 7987ff178cdSJimmy Vetayases { 7997ff178cdSJimmy Vetayases if (apic_shutdown_processors) { 8007ff178cdSJimmy Vetayases apic_disable_local_apic(); 8017ff178cdSJimmy Vetayases return; 8027ff178cdSJimmy Vetayases } 8037ff178cdSJimmy Vetayases 8047ff178cdSJimmy Vetayases apic_error |= APIC_ERR_NMI; 8057ff178cdSJimmy Vetayases 8067ff178cdSJimmy Vetayases if (!lock_try(&apic_nmi_lock)) 8077ff178cdSJimmy Vetayases return; 8087ff178cdSJimmy Vetayases apic_num_nmis++; 8097ff178cdSJimmy Vetayases 8107ff178cdSJimmy Vetayases if (apic_kmdb_on_nmi && psm_debugger()) { 8117ff178cdSJimmy Vetayases debug_enter("NMI received: entering kmdb\n"); 8127ff178cdSJimmy Vetayases } else if (apic_panic_on_nmi) { 8137ff178cdSJimmy Vetayases /* Keep panic from entering kmdb. */ 8147ff178cdSJimmy Vetayases nopanicdebug = 1; 8157ff178cdSJimmy Vetayases panic("NMI received\n"); 8167ff178cdSJimmy Vetayases } else { 8177ff178cdSJimmy Vetayases /* 8187ff178cdSJimmy Vetayases * prom_printf is the best shot we have of something which is 8197ff178cdSJimmy Vetayases * problem free from high level/NMI type of interrupts 8207ff178cdSJimmy Vetayases */ 8217ff178cdSJimmy Vetayases prom_printf("NMI received\n"); 8227ff178cdSJimmy Vetayases } 8237ff178cdSJimmy Vetayases 8247ff178cdSJimmy Vetayases lock_clear(&apic_nmi_lock); 8257ff178cdSJimmy Vetayases } 8267ff178cdSJimmy Vetayases 8277ff178cdSJimmy Vetayases processorid_t 8287ff178cdSJimmy Vetayases apic_get_next_processorid(processorid_t cpu_id) 8297ff178cdSJimmy Vetayases { 8307ff178cdSJimmy Vetayases 8317ff178cdSJimmy Vetayases int i; 8327ff178cdSJimmy Vetayases 8337ff178cdSJimmy Vetayases if (cpu_id == -1) 8347ff178cdSJimmy Vetayases return ((processorid_t)0); 8357ff178cdSJimmy Vetayases 8367ff178cdSJimmy Vetayases for (i = cpu_id + 1; i < NCPU; i++) { 8377ff178cdSJimmy Vetayases if (apic_cpu_in_range(i)) 8387ff178cdSJimmy Vetayases return (i); 8397ff178cdSJimmy Vetayases } 8407ff178cdSJimmy Vetayases 8417ff178cdSJimmy Vetayases return ((processorid_t)-1); 8427ff178cdSJimmy Vetayases } 8437ff178cdSJimmy Vetayases 8447ff178cdSJimmy Vetayases int 8457ff178cdSJimmy Vetayases apic_cpu_add(psm_cpu_request_t *reqp) 8467ff178cdSJimmy Vetayases { 8477ff178cdSJimmy Vetayases int i, rv = 0; 8487ff178cdSJimmy Vetayases ulong_t iflag; 8497ff178cdSJimmy Vetayases boolean_t first = B_TRUE; 8507ff178cdSJimmy Vetayases uchar_t localver; 8517ff178cdSJimmy Vetayases uint32_t localid, procid; 8527ff178cdSJimmy Vetayases processorid_t cpuid = (processorid_t)-1; 8537ff178cdSJimmy Vetayases mach_cpu_add_arg_t *ap; 8547ff178cdSJimmy Vetayases 8557ff178cdSJimmy Vetayases ASSERT(reqp != NULL); 8567ff178cdSJimmy Vetayases reqp->req.cpu_add.cpuid = (processorid_t)-1; 8577ff178cdSJimmy Vetayases 8587ff178cdSJimmy Vetayases /* Check whether CPU hotplug is supported. */ 8597ff178cdSJimmy Vetayases if (!plat_dr_support_cpu() || apic_max_nproc == -1) { 8607ff178cdSJimmy Vetayases return (ENOTSUP); 8617ff178cdSJimmy Vetayases } 8627ff178cdSJimmy Vetayases 8637ff178cdSJimmy Vetayases ap = (mach_cpu_add_arg_t *)reqp->req.cpu_add.argp; 8647ff178cdSJimmy Vetayases switch (ap->type) { 8657ff178cdSJimmy Vetayases case MACH_CPU_ARG_LOCAL_APIC: 8667ff178cdSJimmy Vetayases localid = ap->arg.apic.apic_id; 8677ff178cdSJimmy Vetayases procid = ap->arg.apic.proc_id; 8687ff178cdSJimmy Vetayases if (localid >= 255 || procid > 255) { 8697ff178cdSJimmy Vetayases cmn_err(CE_WARN, 8707ff178cdSJimmy Vetayases "!apic: apicid(%u) or procid(%u) is invalid.", 8717ff178cdSJimmy Vetayases localid, procid); 8727ff178cdSJimmy Vetayases return (EINVAL); 8737ff178cdSJimmy Vetayases } 8747ff178cdSJimmy Vetayases break; 8757ff178cdSJimmy Vetayases 8767ff178cdSJimmy Vetayases case MACH_CPU_ARG_LOCAL_X2APIC: 8777ff178cdSJimmy Vetayases localid = ap->arg.apic.apic_id; 8787ff178cdSJimmy Vetayases procid = ap->arg.apic.proc_id; 8797ff178cdSJimmy Vetayases if (localid >= UINT32_MAX) { 8807ff178cdSJimmy Vetayases cmn_err(CE_WARN, 8817ff178cdSJimmy Vetayases "!apic: x2apicid(%u) is invalid.", localid); 8827ff178cdSJimmy Vetayases return (EINVAL); 8837ff178cdSJimmy Vetayases } else if (localid >= 255 && apic_mode == LOCAL_APIC) { 8847ff178cdSJimmy Vetayases cmn_err(CE_WARN, "!apic: system is in APIC mode, " 8857ff178cdSJimmy Vetayases "can't support x2APIC processor."); 8867ff178cdSJimmy Vetayases return (ENOTSUP); 8877ff178cdSJimmy Vetayases } 8887ff178cdSJimmy Vetayases break; 8897ff178cdSJimmy Vetayases 8907ff178cdSJimmy Vetayases default: 8917ff178cdSJimmy Vetayases cmn_err(CE_WARN, 8927ff178cdSJimmy Vetayases "!apic: unknown argument type %d to apic_cpu_add().", 8937ff178cdSJimmy Vetayases ap->type); 8947ff178cdSJimmy Vetayases return (EINVAL); 8957ff178cdSJimmy Vetayases } 8967ff178cdSJimmy Vetayases 8977ff178cdSJimmy Vetayases /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */ 8987ff178cdSJimmy Vetayases iflag = intr_clear(); 8997ff178cdSJimmy Vetayases lock_set(&apic_ioapic_lock); 9007ff178cdSJimmy Vetayases 9017ff178cdSJimmy Vetayases /* Check whether local APIC id already exists. */ 9027ff178cdSJimmy Vetayases for (i = 0; i < apic_nproc; i++) { 9037ff178cdSJimmy Vetayases if (!CPU_IN_SET(apic_cpumask, i)) 9047ff178cdSJimmy Vetayases continue; 9057ff178cdSJimmy Vetayases if (apic_cpus[i].aci_local_id == localid) { 9067ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 9077ff178cdSJimmy Vetayases intr_restore(iflag); 9087ff178cdSJimmy Vetayases cmn_err(CE_WARN, 9097ff178cdSJimmy Vetayases "!apic: local apic id %u already exists.", 9107ff178cdSJimmy Vetayases localid); 9117ff178cdSJimmy Vetayases return (EEXIST); 9127ff178cdSJimmy Vetayases } else if (apic_cpus[i].aci_processor_id == procid) { 9137ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 9147ff178cdSJimmy Vetayases intr_restore(iflag); 9157ff178cdSJimmy Vetayases cmn_err(CE_WARN, 9167ff178cdSJimmy Vetayases "!apic: processor id %u already exists.", 9177ff178cdSJimmy Vetayases (int)procid); 9187ff178cdSJimmy Vetayases return (EEXIST); 9197ff178cdSJimmy Vetayases } 9207ff178cdSJimmy Vetayases 9217ff178cdSJimmy Vetayases /* 9227ff178cdSJimmy Vetayases * There's no local APIC version number available in MADT table, 9237ff178cdSJimmy Vetayases * so assume that all CPUs are homogeneous and use local APIC 9247ff178cdSJimmy Vetayases * version number of the first existing CPU. 9257ff178cdSJimmy Vetayases */ 9267ff178cdSJimmy Vetayases if (first) { 9277ff178cdSJimmy Vetayases first = B_FALSE; 9287ff178cdSJimmy Vetayases localver = apic_cpus[i].aci_local_ver; 9297ff178cdSJimmy Vetayases } 9307ff178cdSJimmy Vetayases } 9317ff178cdSJimmy Vetayases ASSERT(first == B_FALSE); 9327ff178cdSJimmy Vetayases 9337ff178cdSJimmy Vetayases /* 9347ff178cdSJimmy Vetayases * Try to assign the same cpuid if APIC id exists in the dirty cache. 9357ff178cdSJimmy Vetayases */ 9367ff178cdSJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) { 9377ff178cdSJimmy Vetayases if (CPU_IN_SET(apic_cpumask, i)) { 9387ff178cdSJimmy Vetayases ASSERT((apic_cpus[i].aci_status & APIC_CPU_FREE) == 0); 9397ff178cdSJimmy Vetayases continue; 9407ff178cdSJimmy Vetayases } 9417ff178cdSJimmy Vetayases ASSERT(apic_cpus[i].aci_status & APIC_CPU_FREE); 9427ff178cdSJimmy Vetayases if ((apic_cpus[i].aci_status & APIC_CPU_DIRTY) && 9437ff178cdSJimmy Vetayases apic_cpus[i].aci_local_id == localid && 9447ff178cdSJimmy Vetayases apic_cpus[i].aci_processor_id == procid) { 9457ff178cdSJimmy Vetayases cpuid = i; 9467ff178cdSJimmy Vetayases break; 9477ff178cdSJimmy Vetayases } 9487ff178cdSJimmy Vetayases } 9497ff178cdSJimmy Vetayases 9507ff178cdSJimmy Vetayases /* Avoid the dirty cache and allocate fresh slot if possible. */ 9517ff178cdSJimmy Vetayases if (cpuid == (processorid_t)-1) { 9527ff178cdSJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) { 9537ff178cdSJimmy Vetayases if ((apic_cpus[i].aci_status & APIC_CPU_FREE) && 9547ff178cdSJimmy Vetayases (apic_cpus[i].aci_status & APIC_CPU_DIRTY) == 0) { 9557ff178cdSJimmy Vetayases cpuid = i; 9567ff178cdSJimmy Vetayases break; 9577ff178cdSJimmy Vetayases } 9587ff178cdSJimmy Vetayases } 9597ff178cdSJimmy Vetayases } 9607ff178cdSJimmy Vetayases 9617ff178cdSJimmy Vetayases /* Try to find any free slot as last resort. */ 9627ff178cdSJimmy Vetayases if (cpuid == (processorid_t)-1) { 9637ff178cdSJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) { 9647ff178cdSJimmy Vetayases if (apic_cpus[i].aci_status & APIC_CPU_FREE) { 9657ff178cdSJimmy Vetayases cpuid = i; 9667ff178cdSJimmy Vetayases break; 9677ff178cdSJimmy Vetayases } 9687ff178cdSJimmy Vetayases } 9697ff178cdSJimmy Vetayases } 9707ff178cdSJimmy Vetayases 9717ff178cdSJimmy Vetayases if (cpuid == (processorid_t)-1) { 9727ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 9737ff178cdSJimmy Vetayases intr_restore(iflag); 9747ff178cdSJimmy Vetayases cmn_err(CE_NOTE, 9757ff178cdSJimmy Vetayases "!apic: failed to allocate cpu id for processor %u.", 9767ff178cdSJimmy Vetayases procid); 9777ff178cdSJimmy Vetayases rv = EAGAIN; 9787ff178cdSJimmy Vetayases } else if (ACPI_FAILURE(acpica_map_cpu(cpuid, procid))) { 9797ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 9807ff178cdSJimmy Vetayases intr_restore(iflag); 9817ff178cdSJimmy Vetayases cmn_err(CE_NOTE, 9827ff178cdSJimmy Vetayases "!apic: failed to build mapping for processor %u.", 9837ff178cdSJimmy Vetayases procid); 9847ff178cdSJimmy Vetayases rv = EBUSY; 9857ff178cdSJimmy Vetayases } else { 9867ff178cdSJimmy Vetayases ASSERT(cpuid >= 0 && cpuid < NCPU); 9877ff178cdSJimmy Vetayases ASSERT(cpuid < apic_max_nproc && cpuid < max_ncpus); 9887ff178cdSJimmy Vetayases bzero(&apic_cpus[cpuid], sizeof (apic_cpus[0])); 9897ff178cdSJimmy Vetayases apic_cpus[cpuid].aci_processor_id = procid; 9907ff178cdSJimmy Vetayases apic_cpus[cpuid].aci_local_id = localid; 9917ff178cdSJimmy Vetayases apic_cpus[cpuid].aci_local_ver = localver; 9927ff178cdSJimmy Vetayases CPUSET_ATOMIC_ADD(apic_cpumask, cpuid); 9937ff178cdSJimmy Vetayases if (cpuid >= apic_nproc) { 9947ff178cdSJimmy Vetayases apic_nproc = cpuid + 1; 9957ff178cdSJimmy Vetayases } 9967ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 9977ff178cdSJimmy Vetayases intr_restore(iflag); 9987ff178cdSJimmy Vetayases reqp->req.cpu_add.cpuid = cpuid; 9997ff178cdSJimmy Vetayases } 10007ff178cdSJimmy Vetayases 10017ff178cdSJimmy Vetayases return (rv); 10027ff178cdSJimmy Vetayases } 10037ff178cdSJimmy Vetayases 10047ff178cdSJimmy Vetayases int 10057ff178cdSJimmy Vetayases apic_cpu_remove(psm_cpu_request_t *reqp) 10067ff178cdSJimmy Vetayases { 10077ff178cdSJimmy Vetayases int i; 10087ff178cdSJimmy Vetayases ulong_t iflag; 10097ff178cdSJimmy Vetayases processorid_t cpuid; 10107ff178cdSJimmy Vetayases 10117ff178cdSJimmy Vetayases /* Check whether CPU hotplug is supported. */ 10127ff178cdSJimmy Vetayases if (!plat_dr_support_cpu() || apic_max_nproc == -1) { 10137ff178cdSJimmy Vetayases return (ENOTSUP); 10147ff178cdSJimmy Vetayases } 10157ff178cdSJimmy Vetayases 10167ff178cdSJimmy Vetayases cpuid = reqp->req.cpu_remove.cpuid; 10177ff178cdSJimmy Vetayases 10187ff178cdSJimmy Vetayases /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */ 10197ff178cdSJimmy Vetayases iflag = intr_clear(); 10207ff178cdSJimmy Vetayases lock_set(&apic_ioapic_lock); 10217ff178cdSJimmy Vetayases 10227ff178cdSJimmy Vetayases if (!apic_cpu_in_range(cpuid)) { 10237ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 10247ff178cdSJimmy Vetayases intr_restore(iflag); 10257ff178cdSJimmy Vetayases cmn_err(CE_WARN, 10267ff178cdSJimmy Vetayases "!apic: cpuid %d doesn't exist in apic_cpus array.", 10277ff178cdSJimmy Vetayases cpuid); 10287ff178cdSJimmy Vetayases return (ENODEV); 10297ff178cdSJimmy Vetayases } 10307ff178cdSJimmy Vetayases ASSERT((apic_cpus[cpuid].aci_status & APIC_CPU_FREE) == 0); 10317ff178cdSJimmy Vetayases 10327ff178cdSJimmy Vetayases if (ACPI_FAILURE(acpica_unmap_cpu(cpuid))) { 10337ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 10347ff178cdSJimmy Vetayases intr_restore(iflag); 10357ff178cdSJimmy Vetayases return (ENOENT); 10367ff178cdSJimmy Vetayases } 10377ff178cdSJimmy Vetayases 10387ff178cdSJimmy Vetayases if (cpuid == apic_nproc - 1) { 10397ff178cdSJimmy Vetayases /* 10407ff178cdSJimmy Vetayases * We are removing the highest numbered cpuid so we need to 10417ff178cdSJimmy Vetayases * find the next highest cpuid as the new value for apic_nproc. 10427ff178cdSJimmy Vetayases */ 10437ff178cdSJimmy Vetayases for (i = apic_nproc; i > 0; i--) { 10447ff178cdSJimmy Vetayases if (CPU_IN_SET(apic_cpumask, i - 1)) { 10457ff178cdSJimmy Vetayases apic_nproc = i; 10467ff178cdSJimmy Vetayases break; 10477ff178cdSJimmy Vetayases } 10487ff178cdSJimmy Vetayases } 10497ff178cdSJimmy Vetayases /* at least one CPU left */ 10507ff178cdSJimmy Vetayases ASSERT(i > 0); 10517ff178cdSJimmy Vetayases } 10527ff178cdSJimmy Vetayases CPUSET_ATOMIC_DEL(apic_cpumask, cpuid); 10537ff178cdSJimmy Vetayases /* mark slot as free and keep it in the dirty cache */ 10547ff178cdSJimmy Vetayases apic_cpus[cpuid].aci_status = APIC_CPU_FREE | APIC_CPU_DIRTY; 10557ff178cdSJimmy Vetayases 10567ff178cdSJimmy Vetayases lock_clear(&apic_ioapic_lock); 10577ff178cdSJimmy Vetayases intr_restore(iflag); 10587ff178cdSJimmy Vetayases 10597ff178cdSJimmy Vetayases return (0); 10607ff178cdSJimmy Vetayases } 10617ff178cdSJimmy Vetayases 10627ff178cdSJimmy Vetayases /* 10637ff178cdSJimmy Vetayases * Return the number of APIC clock ticks elapsed for 8245 to decrement 10647ff178cdSJimmy Vetayases * (APIC_TIME_COUNT + pit_ticks_adj) ticks. 10657ff178cdSJimmy Vetayases */ 106641afdfa7SKrishnendu Sadhukhan - Sun Microsystems uint_t 10677ff178cdSJimmy Vetayases apic_calibrate(volatile uint32_t *addr, uint16_t *pit_ticks_adj) 10687ff178cdSJimmy Vetayases { 10697ff178cdSJimmy Vetayases uint8_t pit_tick_lo; 10707ff178cdSJimmy Vetayases uint16_t pit_tick, target_pit_tick; 10717ff178cdSJimmy Vetayases uint32_t start_apic_tick, end_apic_tick; 10727ff178cdSJimmy Vetayases ulong_t iflag; 10737ff178cdSJimmy Vetayases uint32_t reg; 10747ff178cdSJimmy Vetayases 10757ff178cdSJimmy Vetayases reg = addr + APIC_CURR_COUNT - apicadr; 10767ff178cdSJimmy Vetayases 10777ff178cdSJimmy Vetayases iflag = intr_clear(); 10787ff178cdSJimmy Vetayases 10797ff178cdSJimmy Vetayases do { 10807ff178cdSJimmy Vetayases pit_tick_lo = inb(PITCTR0_PORT); 10817ff178cdSJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 10827ff178cdSJimmy Vetayases } while (pit_tick < APIC_TIME_MIN || 10837ff178cdSJimmy Vetayases pit_tick_lo <= APIC_LB_MIN || pit_tick_lo >= APIC_LB_MAX); 10847ff178cdSJimmy Vetayases 10857ff178cdSJimmy Vetayases /* 10867ff178cdSJimmy Vetayases * Wait for the 8254 to decrement by 5 ticks to ensure 10877ff178cdSJimmy Vetayases * we didn't start in the middle of a tick. 10887ff178cdSJimmy Vetayases * Compare with 0x10 for the wrap around case. 10897ff178cdSJimmy Vetayases */ 10907ff178cdSJimmy Vetayases target_pit_tick = pit_tick - 5; 10917ff178cdSJimmy Vetayases do { 10927ff178cdSJimmy Vetayases pit_tick_lo = inb(PITCTR0_PORT); 10937ff178cdSJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 10947ff178cdSJimmy Vetayases } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10); 10957ff178cdSJimmy Vetayases 10967ff178cdSJimmy Vetayases start_apic_tick = apic_reg_ops->apic_read(reg); 10977ff178cdSJimmy Vetayases 10987ff178cdSJimmy Vetayases /* 10997ff178cdSJimmy Vetayases * Wait for the 8254 to decrement by 11007ff178cdSJimmy Vetayases * (APIC_TIME_COUNT + pit_ticks_adj) ticks 11017ff178cdSJimmy Vetayases */ 11027ff178cdSJimmy Vetayases target_pit_tick = pit_tick - APIC_TIME_COUNT; 11037ff178cdSJimmy Vetayases do { 11047ff178cdSJimmy Vetayases pit_tick_lo = inb(PITCTR0_PORT); 11057ff178cdSJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 11067ff178cdSJimmy Vetayases } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10); 11077ff178cdSJimmy Vetayases 11087ff178cdSJimmy Vetayases end_apic_tick = apic_reg_ops->apic_read(reg); 11097ff178cdSJimmy Vetayases 11107ff178cdSJimmy Vetayases *pit_ticks_adj = target_pit_tick - pit_tick; 11117ff178cdSJimmy Vetayases 11127ff178cdSJimmy Vetayases intr_restore(iflag); 11137ff178cdSJimmy Vetayases 11147ff178cdSJimmy Vetayases return (start_apic_tick - end_apic_tick); 11157ff178cdSJimmy Vetayases } 11167ff178cdSJimmy Vetayases 11177ff178cdSJimmy Vetayases /* 11187ff178cdSJimmy Vetayases * Initialise the APIC timer on the local APIC of CPU 0 to the desired 11197ff178cdSJimmy Vetayases * frequency. Note at this stage in the boot sequence, the boot processor 11207ff178cdSJimmy Vetayases * is the only active processor. 11217ff178cdSJimmy Vetayases * hertz value of 0 indicates a one-shot mode request. In this case 11227ff178cdSJimmy Vetayases * the function returns the resolution (in nanoseconds) for the hardware 11237ff178cdSJimmy Vetayases * timer interrupt. If one-shot mode capability is not available, 11247ff178cdSJimmy Vetayases * the return value will be 0. apic_enable_oneshot is a global switch 11257ff178cdSJimmy Vetayases * for disabling the functionality. 11267ff178cdSJimmy Vetayases * A non-zero positive value for hertz indicates a periodic mode request. 11277ff178cdSJimmy Vetayases * In this case the hardware will be programmed to generate clock interrupts 11287ff178cdSJimmy Vetayases * at hertz frequency and returns the resolution of interrupts in 11297ff178cdSJimmy Vetayases * nanosecond. 11307ff178cdSJimmy Vetayases */ 11317ff178cdSJimmy Vetayases 11327ff178cdSJimmy Vetayases int 11337ff178cdSJimmy Vetayases apic_clkinit(int hertz) 11347ff178cdSJimmy Vetayases { 11357ff178cdSJimmy Vetayases int ret; 11367ff178cdSJimmy Vetayases 11377ff178cdSJimmy Vetayases apic_int_busy_mark = (apic_int_busy_mark * 11387ff178cdSJimmy Vetayases apic_sample_factor_redistribution) / 100; 11397ff178cdSJimmy Vetayases apic_int_free_mark = (apic_int_free_mark * 11407ff178cdSJimmy Vetayases apic_sample_factor_redistribution) / 100; 11417ff178cdSJimmy Vetayases apic_diff_for_redistribution = (apic_diff_for_redistribution * 11427ff178cdSJimmy Vetayases apic_sample_factor_redistribution) / 100; 11437ff178cdSJimmy Vetayases 114441afdfa7SKrishnendu Sadhukhan - Sun Microsystems ret = apic_timer_init(hertz); 11457ff178cdSJimmy Vetayases return (ret); 11467ff178cdSJimmy Vetayases 11477ff178cdSJimmy Vetayases } 11487ff178cdSJimmy Vetayases 11497ff178cdSJimmy Vetayases /* 11507ff178cdSJimmy Vetayases * apic_preshutdown: 11517ff178cdSJimmy Vetayases * Called early in shutdown whilst we can still access filesystems to do 11527ff178cdSJimmy Vetayases * things like loading modules which will be required to complete shutdown 11537ff178cdSJimmy Vetayases * after filesystems are all unmounted. 11547ff178cdSJimmy Vetayases */ 11557ff178cdSJimmy Vetayases void 11567ff178cdSJimmy Vetayases apic_preshutdown(int cmd, int fcn) 11577ff178cdSJimmy Vetayases { 11587ff178cdSJimmy Vetayases APIC_VERBOSE_POWEROFF(("apic_preshutdown(%d,%d); m=%d a=%d\n", 11597ff178cdSJimmy Vetayases cmd, fcn, apic_poweroff_method, apic_enable_acpi)); 11607ff178cdSJimmy Vetayases } 11617ff178cdSJimmy Vetayases 11627ff178cdSJimmy Vetayases void 11637ff178cdSJimmy Vetayases apic_shutdown(int cmd, int fcn) 11647ff178cdSJimmy Vetayases { 11657ff178cdSJimmy Vetayases int restarts, attempts; 11667ff178cdSJimmy Vetayases int i; 11677ff178cdSJimmy Vetayases uchar_t byte; 11687ff178cdSJimmy Vetayases ulong_t iflag; 11697ff178cdSJimmy Vetayases 11707ff178cdSJimmy Vetayases hpet_acpi_fini(); 11717ff178cdSJimmy Vetayases 11727ff178cdSJimmy Vetayases /* Send NMI to all CPUs except self to do per processor shutdown */ 11737ff178cdSJimmy Vetayases iflag = intr_clear(); 11747ff178cdSJimmy Vetayases #ifdef DEBUG 11757ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 11767ff178cdSJimmy Vetayases #else 11777ff178cdSJimmy Vetayases if (apic_mode == LOCAL_APIC) 11787ff178cdSJimmy Vetayases APIC_AV_PENDING_SET(); 11797ff178cdSJimmy Vetayases #endif /* DEBUG */ 11807ff178cdSJimmy Vetayases apic_shutdown_processors = 1; 11817ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_CMD1, 11827ff178cdSJimmy Vetayases AV_NMI | AV_LEVEL | AV_SH_ALL_EXCSELF); 11837ff178cdSJimmy Vetayases 11847ff178cdSJimmy Vetayases /* restore cmos shutdown byte before reboot */ 11857ff178cdSJimmy Vetayases if (apic_cmos_ssb_set) { 11867ff178cdSJimmy Vetayases outb(CMOS_ADDR, SSB); 11877ff178cdSJimmy Vetayases outb(CMOS_DATA, 0); 11887ff178cdSJimmy Vetayases } 11897ff178cdSJimmy Vetayases 11907ff178cdSJimmy Vetayases ioapic_disable_redirection(); 11917ff178cdSJimmy Vetayases 11927ff178cdSJimmy Vetayases /* disable apic mode if imcr present */ 11937ff178cdSJimmy Vetayases if (apic_imcrp) { 11947ff178cdSJimmy Vetayases outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT); 11957ff178cdSJimmy Vetayases outb(APIC_IMCR_P2, (uchar_t)APIC_IMCR_PIC); 11967ff178cdSJimmy Vetayases } 11977ff178cdSJimmy Vetayases 11987ff178cdSJimmy Vetayases apic_disable_local_apic(); 11997ff178cdSJimmy Vetayases 12007ff178cdSJimmy Vetayases intr_restore(iflag); 12017ff178cdSJimmy Vetayases 12027ff178cdSJimmy Vetayases /* remainder of function is for shutdown cases only */ 12037ff178cdSJimmy Vetayases if (cmd != A_SHUTDOWN) 12047ff178cdSJimmy Vetayases return; 12057ff178cdSJimmy Vetayases 12067ff178cdSJimmy Vetayases /* 12077ff178cdSJimmy Vetayases * Switch system back into Legacy-Mode if using ACPI and 12087ff178cdSJimmy Vetayases * not powering-off. Some BIOSes need to remain in ACPI-mode 12097ff178cdSJimmy Vetayases * for power-off to succeed (Dell Dimension 4600) 12107ff178cdSJimmy Vetayases * Do not disable ACPI while doing fastreboot 12117ff178cdSJimmy Vetayases */ 12127ff178cdSJimmy Vetayases if (apic_enable_acpi && fcn != AD_POWEROFF && fcn != AD_FASTREBOOT) 12137ff178cdSJimmy Vetayases (void) AcpiDisable(); 12147ff178cdSJimmy Vetayases 12157ff178cdSJimmy Vetayases if (fcn == AD_FASTREBOOT) { 12167ff178cdSJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_CMD1, 12177ff178cdSJimmy Vetayases AV_ASSERT | AV_RESET | AV_SH_ALL_EXCSELF); 12187ff178cdSJimmy Vetayases } 12197ff178cdSJimmy Vetayases 12207ff178cdSJimmy Vetayases /* remainder of function is for shutdown+poweroff case only */ 12217ff178cdSJimmy Vetayases if (fcn != AD_POWEROFF) 12227ff178cdSJimmy Vetayases return; 12237ff178cdSJimmy Vetayases 12247ff178cdSJimmy Vetayases switch (apic_poweroff_method) { 12257ff178cdSJimmy Vetayases case APIC_POWEROFF_VIA_RTC: 12267ff178cdSJimmy Vetayases 12277ff178cdSJimmy Vetayases /* select the extended NVRAM bank in the RTC */ 12287ff178cdSJimmy Vetayases outb(CMOS_ADDR, RTC_REGA); 12297ff178cdSJimmy Vetayases byte = inb(CMOS_DATA); 12307ff178cdSJimmy Vetayases outb(CMOS_DATA, (byte | EXT_BANK)); 12317ff178cdSJimmy Vetayases 12327ff178cdSJimmy Vetayases outb(CMOS_ADDR, PFR_REG); 12337ff178cdSJimmy Vetayases 12347ff178cdSJimmy Vetayases /* for Predator must toggle the PAB bit */ 12357ff178cdSJimmy Vetayases byte = inb(CMOS_DATA); 12367ff178cdSJimmy Vetayases 12377ff178cdSJimmy Vetayases /* 12387ff178cdSJimmy Vetayases * clear power active bar, wakeup alarm and 12397ff178cdSJimmy Vetayases * kickstart 12407ff178cdSJimmy Vetayases */ 12417ff178cdSJimmy Vetayases byte &= ~(PAB_CBIT | WF_FLAG | KS_FLAG); 12427ff178cdSJimmy Vetayases outb(CMOS_DATA, byte); 12437ff178cdSJimmy Vetayases 12447ff178cdSJimmy Vetayases /* delay before next write */ 12457ff178cdSJimmy Vetayases drv_usecwait(1000); 12467ff178cdSJimmy Vetayases 12477ff178cdSJimmy Vetayases /* for S40 the following would suffice */ 12487ff178cdSJimmy Vetayases byte = inb(CMOS_DATA); 12497ff178cdSJimmy Vetayases 12507ff178cdSJimmy Vetayases /* power active bar control bit */ 12517ff178cdSJimmy Vetayases byte |= PAB_CBIT; 12527ff178cdSJimmy Vetayases outb(CMOS_DATA, byte); 12537ff178cdSJimmy Vetayases 12547ff178cdSJimmy Vetayases break; 12557ff178cdSJimmy Vetayases 12567ff178cdSJimmy Vetayases case APIC_POWEROFF_VIA_ASPEN_BMC: 12577ff178cdSJimmy Vetayases restarts = 0; 12587ff178cdSJimmy Vetayases restart_aspen_bmc: 12597ff178cdSJimmy Vetayases if (++restarts == 3) 12607ff178cdSJimmy Vetayases break; 12617ff178cdSJimmy Vetayases attempts = 0; 12627ff178cdSJimmy Vetayases do { 12637ff178cdSJimmy Vetayases byte = inb(MISMIC_FLAG_REGISTER); 12647ff178cdSJimmy Vetayases byte &= MISMIC_BUSY_MASK; 12657ff178cdSJimmy Vetayases if (byte != 0) { 12667ff178cdSJimmy Vetayases drv_usecwait(1000); 12677ff178cdSJimmy Vetayases if (attempts >= 3) 12687ff178cdSJimmy Vetayases goto restart_aspen_bmc; 12697ff178cdSJimmy Vetayases ++attempts; 12707ff178cdSJimmy Vetayases } 12717ff178cdSJimmy Vetayases } while (byte != 0); 12727ff178cdSJimmy Vetayases outb(MISMIC_CNTL_REGISTER, CC_SMS_GET_STATUS); 12737ff178cdSJimmy Vetayases byte = inb(MISMIC_FLAG_REGISTER); 12747ff178cdSJimmy Vetayases byte |= 0x1; 12757ff178cdSJimmy Vetayases outb(MISMIC_FLAG_REGISTER, byte); 12767ff178cdSJimmy Vetayases i = 0; 12777ff178cdSJimmy Vetayases for (; i < (sizeof (aspen_bmc)/sizeof (aspen_bmc[0])); 12787ff178cdSJimmy Vetayases i++) { 12797ff178cdSJimmy Vetayases attempts = 0; 12807ff178cdSJimmy Vetayases do { 12817ff178cdSJimmy Vetayases byte = inb(MISMIC_FLAG_REGISTER); 12827ff178cdSJimmy Vetayases byte &= MISMIC_BUSY_MASK; 12837ff178cdSJimmy Vetayases if (byte != 0) { 12847ff178cdSJimmy Vetayases drv_usecwait(1000); 12857ff178cdSJimmy Vetayases if (attempts >= 3) 12867ff178cdSJimmy Vetayases goto restart_aspen_bmc; 12877ff178cdSJimmy Vetayases ++attempts; 12887ff178cdSJimmy Vetayases } 12897ff178cdSJimmy Vetayases } while (byte != 0); 12907ff178cdSJimmy Vetayases outb(MISMIC_CNTL_REGISTER, aspen_bmc[i].cntl); 12917ff178cdSJimmy Vetayases outb(MISMIC_DATA_REGISTER, aspen_bmc[i].data); 12927ff178cdSJimmy Vetayases byte = inb(MISMIC_FLAG_REGISTER); 12937ff178cdSJimmy Vetayases byte |= 0x1; 12947ff178cdSJimmy Vetayases outb(MISMIC_FLAG_REGISTER, byte); 12957ff178cdSJimmy Vetayases } 12967ff178cdSJimmy Vetayases break; 12977ff178cdSJimmy Vetayases 12987ff178cdSJimmy Vetayases case APIC_POWEROFF_VIA_SITKA_BMC: 12997ff178cdSJimmy Vetayases restarts = 0; 13007ff178cdSJimmy Vetayases restart_sitka_bmc: 13017ff178cdSJimmy Vetayases if (++restarts == 3) 13027ff178cdSJimmy Vetayases break; 13037ff178cdSJimmy Vetayases attempts = 0; 13047ff178cdSJimmy Vetayases do { 13057ff178cdSJimmy Vetayases byte = inb(SMS_STATUS_REGISTER); 13067ff178cdSJimmy Vetayases byte &= SMS_STATE_MASK; 13077ff178cdSJimmy Vetayases if ((byte == SMS_READ_STATE) || 13087ff178cdSJimmy Vetayases (byte == SMS_WRITE_STATE)) { 13097ff178cdSJimmy Vetayases drv_usecwait(1000); 13107ff178cdSJimmy Vetayases if (attempts >= 3) 13117ff178cdSJimmy Vetayases goto restart_sitka_bmc; 13127ff178cdSJimmy Vetayases ++attempts; 13137ff178cdSJimmy Vetayases } 13147ff178cdSJimmy Vetayases } while ((byte == SMS_READ_STATE) || 13157ff178cdSJimmy Vetayases (byte == SMS_WRITE_STATE)); 13167ff178cdSJimmy Vetayases outb(SMS_COMMAND_REGISTER, SMS_GET_STATUS); 13177ff178cdSJimmy Vetayases i = 0; 13187ff178cdSJimmy Vetayases for (; i < (sizeof (sitka_bmc)/sizeof (sitka_bmc[0])); 13197ff178cdSJimmy Vetayases i++) { 13207ff178cdSJimmy Vetayases attempts = 0; 13217ff178cdSJimmy Vetayases do { 13227ff178cdSJimmy Vetayases byte = inb(SMS_STATUS_REGISTER); 13237ff178cdSJimmy Vetayases byte &= SMS_IBF_MASK; 13247ff178cdSJimmy Vetayases if (byte != 0) { 13257ff178cdSJimmy Vetayases drv_usecwait(1000); 13267ff178cdSJimmy Vetayases if (attempts >= 3) 13277ff178cdSJimmy Vetayases goto restart_sitka_bmc; 13287ff178cdSJimmy Vetayases ++attempts; 13297ff178cdSJimmy Vetayases } 13307ff178cdSJimmy Vetayases } while (byte != 0); 13317ff178cdSJimmy Vetayases outb(sitka_bmc[i].port, sitka_bmc[i].data); 13327ff178cdSJimmy Vetayases } 13337ff178cdSJimmy Vetayases break; 13347ff178cdSJimmy Vetayases 13357ff178cdSJimmy Vetayases case APIC_POWEROFF_NONE: 13367ff178cdSJimmy Vetayases 13377ff178cdSJimmy Vetayases /* If no APIC direct method, we will try using ACPI */ 13387ff178cdSJimmy Vetayases if (apic_enable_acpi) { 13397ff178cdSJimmy Vetayases if (acpi_poweroff() == 1) 13407ff178cdSJimmy Vetayases return; 13417ff178cdSJimmy Vetayases } else 13427ff178cdSJimmy Vetayases return; 13437ff178cdSJimmy Vetayases 13447ff178cdSJimmy Vetayases break; 13457ff178cdSJimmy Vetayases } 13467ff178cdSJimmy Vetayases /* 13477ff178cdSJimmy Vetayases * Wait a limited time here for power to go off. 13487ff178cdSJimmy Vetayases * If the power does not go off, then there was a 13497ff178cdSJimmy Vetayases * problem and we should continue to the halt which 13507ff178cdSJimmy Vetayases * prints a message for the user to press a key to 13517ff178cdSJimmy Vetayases * reboot. 13527ff178cdSJimmy Vetayases */ 13537ff178cdSJimmy Vetayases drv_usecwait(7000000); /* wait seven seconds */ 13547ff178cdSJimmy Vetayases 13557ff178cdSJimmy Vetayases } 13567ff178cdSJimmy Vetayases 1357a288e5a9SJoshua M. Clulow cyclic_id_t apic_cyclic_id; 13587ff178cdSJimmy Vetayases 13597ff178cdSJimmy Vetayases /* 13607ff178cdSJimmy Vetayases * The following functions are in the platform specific file so that they 13617ff178cdSJimmy Vetayases * can be different functions depending on whether we are running on 13627ff178cdSJimmy Vetayases * bare metal or a hypervisor. 13637ff178cdSJimmy Vetayases */ 13647ff178cdSJimmy Vetayases 13657ff178cdSJimmy Vetayases /* 13667ff178cdSJimmy Vetayases * map an apic for memory-mapped access 13677ff178cdSJimmy Vetayases */ 13687ff178cdSJimmy Vetayases uint32_t * 13697ff178cdSJimmy Vetayases mapin_apic(uint32_t addr, size_t len, int flags) 13707ff178cdSJimmy Vetayases { 13717ff178cdSJimmy Vetayases return ((void *)psm_map_phys(addr, len, flags)); 13727ff178cdSJimmy Vetayases } 13737ff178cdSJimmy Vetayases 13747ff178cdSJimmy Vetayases uint32_t * 13757ff178cdSJimmy Vetayases mapin_ioapic(uint32_t addr, size_t len, int flags) 13767ff178cdSJimmy Vetayases { 13777ff178cdSJimmy Vetayases return (mapin_apic(addr, len, flags)); 13787ff178cdSJimmy Vetayases } 13797ff178cdSJimmy Vetayases 13807ff178cdSJimmy Vetayases /* 13817ff178cdSJimmy Vetayases * unmap an apic 13827ff178cdSJimmy Vetayases */ 13837ff178cdSJimmy Vetayases void 13847ff178cdSJimmy Vetayases mapout_apic(caddr_t addr, size_t len) 13857ff178cdSJimmy Vetayases { 13867ff178cdSJimmy Vetayases psm_unmap_phys(addr, len); 13877ff178cdSJimmy Vetayases } 13887ff178cdSJimmy Vetayases 13897ff178cdSJimmy Vetayases void 13907ff178cdSJimmy Vetayases mapout_ioapic(caddr_t addr, size_t len) 13917ff178cdSJimmy Vetayases { 13927ff178cdSJimmy Vetayases mapout_apic(addr, len); 13937ff178cdSJimmy Vetayases } 13947ff178cdSJimmy Vetayases 13957ff178cdSJimmy Vetayases uint32_t 13967ff178cdSJimmy Vetayases ioapic_read(int ioapic_ix, uint32_t reg) 13977ff178cdSJimmy Vetayases { 13987ff178cdSJimmy Vetayases volatile uint32_t *ioapic; 13997ff178cdSJimmy Vetayases 14007ff178cdSJimmy Vetayases ioapic = apicioadr[ioapic_ix]; 14017ff178cdSJimmy Vetayases ioapic[APIC_IO_REG] = reg; 14027ff178cdSJimmy Vetayases return (ioapic[APIC_IO_DATA]); 14037ff178cdSJimmy Vetayases } 14047ff178cdSJimmy Vetayases 14057ff178cdSJimmy Vetayases void 14067ff178cdSJimmy Vetayases ioapic_write(int ioapic_ix, uint32_t reg, uint32_t value) 14077ff178cdSJimmy Vetayases { 14087ff178cdSJimmy Vetayases volatile uint32_t *ioapic; 14097ff178cdSJimmy Vetayases 14107ff178cdSJimmy Vetayases ioapic = apicioadr[ioapic_ix]; 14117ff178cdSJimmy Vetayases ioapic[APIC_IO_REG] = reg; 14127ff178cdSJimmy Vetayases ioapic[APIC_IO_DATA] = value; 14137ff178cdSJimmy Vetayases } 14147ff178cdSJimmy Vetayases 14157ff178cdSJimmy Vetayases void 14167ff178cdSJimmy Vetayases ioapic_write_eoi(int ioapic_ix, uint32_t value) 14177ff178cdSJimmy Vetayases { 14187ff178cdSJimmy Vetayases volatile uint32_t *ioapic; 14197ff178cdSJimmy Vetayases 14207ff178cdSJimmy Vetayases ioapic = apicioadr[ioapic_ix]; 14217ff178cdSJimmy Vetayases ioapic[APIC_IO_EOI] = value; 14227ff178cdSJimmy Vetayases } 14237ff178cdSJimmy Vetayases 14247ff178cdSJimmy Vetayases /* 14257ff178cdSJimmy Vetayases * Round-robin algorithm to find the next CPU with interrupts enabled. 14267ff178cdSJimmy Vetayases * It can't share the same static variable apic_next_bind_cpu with 14277ff178cdSJimmy Vetayases * apic_get_next_bind_cpu(), since that will cause all interrupts to be 14287ff178cdSJimmy Vetayases * bound to CPU1 at boot time. During boot, only CPU0 is online with 14297ff178cdSJimmy Vetayases * interrupts enabled when apic_get_next_bind_cpu() and apic_find_cpu() 14307ff178cdSJimmy Vetayases * are called. However, the pcplusmp driver assumes that there will be 14317ff178cdSJimmy Vetayases * boot_ncpus CPUs configured eventually so it tries to distribute all 14327ff178cdSJimmy Vetayases * interrupts among CPU0 - CPU[boot_ncpus - 1]. Thus to prevent all 14337ff178cdSJimmy Vetayases * interrupts being targetted at CPU1, we need to use a dedicated static 14347ff178cdSJimmy Vetayases * variable for find_next_cpu() instead of sharing apic_next_bind_cpu. 14357ff178cdSJimmy Vetayases */ 14367ff178cdSJimmy Vetayases 14377ff178cdSJimmy Vetayases processorid_t 14387ff178cdSJimmy Vetayases apic_find_cpu(int flag) 14397ff178cdSJimmy Vetayases { 14407ff178cdSJimmy Vetayases int i; 14417ff178cdSJimmy Vetayases static processorid_t acid = 0; 14427ff178cdSJimmy Vetayases 14437ff178cdSJimmy Vetayases /* Find the first CPU with the passed-in flag set */ 14447ff178cdSJimmy Vetayases for (i = 0; i < apic_nproc; i++) { 14457ff178cdSJimmy Vetayases if (++acid >= apic_nproc) { 14467ff178cdSJimmy Vetayases acid = 0; 14477ff178cdSJimmy Vetayases } 14487ff178cdSJimmy Vetayases if (apic_cpu_in_range(acid) && 14497ff178cdSJimmy Vetayases (apic_cpus[acid].aci_status & flag)) { 14507ff178cdSJimmy Vetayases break; 14517ff178cdSJimmy Vetayases } 14527ff178cdSJimmy Vetayases } 14537ff178cdSJimmy Vetayases 14547ff178cdSJimmy Vetayases ASSERT((apic_cpus[acid].aci_status & flag) != 0); 14557ff178cdSJimmy Vetayases return (acid); 14567ff178cdSJimmy Vetayases } 14577ff178cdSJimmy Vetayases 14587ff178cdSJimmy Vetayases /* 14597ff178cdSJimmy Vetayases * Switch between safe and x2APIC IPI sending method. 14607ff178cdSJimmy Vetayases * CPU may power on in xapic mode or x2apic mode. If CPU needs to send IPI to 14617ff178cdSJimmy Vetayases * other CPUs before entering x2APIC mode, it still needs to xAPIC method. 14627ff178cdSJimmy Vetayases * Before sending StartIPI to target CPU, psm_send_ipi will be changed to 14637ff178cdSJimmy Vetayases * apic_common_send_ipi, which detects current local APIC mode and use right 14647ff178cdSJimmy Vetayases * method to send IPI. If some CPUs fail to start up, apic_poweron_cnt 14657ff178cdSJimmy Vetayases * won't return to zero, so apic_common_send_ipi will always be used. 14667ff178cdSJimmy Vetayases * psm_send_ipi can't be simply changed back to x2apic_send_ipi if some CPUs 14677ff178cdSJimmy Vetayases * failed to start up because those failed CPUs may recover itself later at 14687ff178cdSJimmy Vetayases * unpredictable time. 14697ff178cdSJimmy Vetayases */ 14707ff178cdSJimmy Vetayases void 14717ff178cdSJimmy Vetayases apic_switch_ipi_callback(boolean_t enter) 14727ff178cdSJimmy Vetayases { 14737ff178cdSJimmy Vetayases ulong_t iflag; 14747ff178cdSJimmy Vetayases struct psm_ops *pops = psmops; 14757ff178cdSJimmy Vetayases 14767ff178cdSJimmy Vetayases iflag = intr_clear(); 14777ff178cdSJimmy Vetayases lock_set(&apic_mode_switch_lock); 14787ff178cdSJimmy Vetayases if (enter) { 14797ff178cdSJimmy Vetayases ASSERT(apic_poweron_cnt >= 0); 14807ff178cdSJimmy Vetayases if (apic_poweron_cnt == 0) { 14817ff178cdSJimmy Vetayases pops->psm_send_ipi = apic_common_send_ipi; 14827ff178cdSJimmy Vetayases send_dirintf = pops->psm_send_ipi; 14837ff178cdSJimmy Vetayases } 14847ff178cdSJimmy Vetayases apic_poweron_cnt++; 14857ff178cdSJimmy Vetayases } else { 14867ff178cdSJimmy Vetayases ASSERT(apic_poweron_cnt > 0); 14877ff178cdSJimmy Vetayases apic_poweron_cnt--; 14887ff178cdSJimmy Vetayases if (apic_poweron_cnt == 0) { 14897ff178cdSJimmy Vetayases pops->psm_send_ipi = x2apic_send_ipi; 14907ff178cdSJimmy Vetayases send_dirintf = pops->psm_send_ipi; 14917ff178cdSJimmy Vetayases } 14927ff178cdSJimmy Vetayases } 14937ff178cdSJimmy Vetayases lock_clear(&apic_mode_switch_lock); 14947ff178cdSJimmy Vetayases intr_restore(iflag); 14957ff178cdSJimmy Vetayases } 14967ff178cdSJimmy Vetayases 14977ff178cdSJimmy Vetayases void 14987ff178cdSJimmy Vetayases apic_intrmap_init(int apic_mode) 14997ff178cdSJimmy Vetayases { 15007ff178cdSJimmy Vetayases int suppress_brdcst_eoi = 0; 15017ff178cdSJimmy Vetayases 15027ff178cdSJimmy Vetayases /* 1503*1a9079eeSJosef 'Jeff' Sipek * Intel Software Developer's Manual 3A, 10.12.7: 1504*1a9079eeSJosef 'Jeff' Sipek * 1505*1a9079eeSJosef 'Jeff' Sipek * Routing of device interrupts to local APIC units operating in 1506*1a9079eeSJosef 'Jeff' Sipek * x2APIC mode requires use of the interrupt-remapping architecture 1507*1a9079eeSJosef 'Jeff' Sipek * specified in the Intel Virtualization Technology for Directed 1508*1a9079eeSJosef 'Jeff' Sipek * I/O, Revision 1.3. Because of this, BIOS must enumerate support 1509*1a9079eeSJosef 'Jeff' Sipek * for and software must enable this interrupt remapping with 1510*1a9079eeSJosef 'Jeff' Sipek * Extended Interrupt Mode Enabled before it enabling x2APIC mode in 1511*1a9079eeSJosef 'Jeff' Sipek * the local APIC units. 1512*1a9079eeSJosef 'Jeff' Sipek * 1513*1a9079eeSJosef 'Jeff' Sipek * 1514*1a9079eeSJosef 'Jeff' Sipek * In other words, to use the APIC in x2APIC mode, we need interrupt 1515*1a9079eeSJosef 'Jeff' Sipek * remapping. Since we don't start up the IOMMU by default, we 1516*1a9079eeSJosef 'Jeff' Sipek * won't be able to do any interrupt remapping and therefore have to 1517*1a9079eeSJosef 'Jeff' Sipek * use the APIC in traditional 'local APIC' mode with memory mapped 1518*1a9079eeSJosef 'Jeff' Sipek * I/O. 15197ff178cdSJimmy Vetayases */ 1520*1a9079eeSJosef 'Jeff' Sipek 1521*1a9079eeSJosef 'Jeff' Sipek if (psm_vt_ops != NULL) { 15227ff178cdSJimmy Vetayases if (((apic_intrmap_ops_t *)psm_vt_ops)-> 15237ff178cdSJimmy Vetayases apic_intrmap_init(apic_mode) == DDI_SUCCESS) { 15247ff178cdSJimmy Vetayases 15257ff178cdSJimmy Vetayases apic_vt_ops = psm_vt_ops; 15267ff178cdSJimmy Vetayases 15277ff178cdSJimmy Vetayases /* 15287ff178cdSJimmy Vetayases * We leverage the interrupt remapping engine to 15297ff178cdSJimmy Vetayases * suppress broadcast EOI; thus we must send the 15307ff178cdSJimmy Vetayases * directed EOI with the directed-EOI handler. 15317ff178cdSJimmy Vetayases */ 15327ff178cdSJimmy Vetayases if (apic_directed_EOI_supported() == 0) { 15337ff178cdSJimmy Vetayases suppress_brdcst_eoi = 1; 15347ff178cdSJimmy Vetayases } 15357ff178cdSJimmy Vetayases 15367ff178cdSJimmy Vetayases apic_vt_ops->apic_intrmap_enable(suppress_brdcst_eoi); 15377ff178cdSJimmy Vetayases 15387ff178cdSJimmy Vetayases if (apic_detect_x2apic()) { 15397ff178cdSJimmy Vetayases apic_enable_x2apic(); 15407ff178cdSJimmy Vetayases } 15417ff178cdSJimmy Vetayases 15427ff178cdSJimmy Vetayases if (apic_directed_EOI_supported() == 0) { 15437ff178cdSJimmy Vetayases apic_set_directed_EOI_handler(); 15447ff178cdSJimmy Vetayases } 15457ff178cdSJimmy Vetayases } 15467ff178cdSJimmy Vetayases } 15477ff178cdSJimmy Vetayases } 15487ff178cdSJimmy Vetayases 15497ff178cdSJimmy Vetayases /*ARGSUSED*/ 15507ff178cdSJimmy Vetayases static void 15517ff178cdSJimmy Vetayases apic_record_ioapic_rdt(void *intrmap_private, ioapic_rdt_t *irdt) 15527ff178cdSJimmy Vetayases { 15537ff178cdSJimmy Vetayases irdt->ir_hi <<= APIC_ID_BIT_OFFSET; 15547ff178cdSJimmy Vetayases } 15557ff178cdSJimmy Vetayases 15567ff178cdSJimmy Vetayases /*ARGSUSED*/ 15577ff178cdSJimmy Vetayases static void 15587ff178cdSJimmy Vetayases apic_record_msi(void *intrmap_private, msi_regs_t *mregs) 15597ff178cdSJimmy Vetayases { 15607ff178cdSJimmy Vetayases mregs->mr_addr = MSI_ADDR_HDR | 15617ff178cdSJimmy Vetayases (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 15627ff178cdSJimmy Vetayases (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) | 15637ff178cdSJimmy Vetayases (mregs->mr_addr << MSI_ADDR_DEST_SHIFT); 15647ff178cdSJimmy Vetayases mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | 15657ff178cdSJimmy Vetayases mregs->mr_data; 15667ff178cdSJimmy Vetayases } 15677ff178cdSJimmy Vetayases 15687ff178cdSJimmy Vetayases /* 15697ff178cdSJimmy Vetayases * Functions from apic_introp.c 15707ff178cdSJimmy Vetayases * 15717ff178cdSJimmy Vetayases * Those functions are used by apic_intr_ops(). 15727ff178cdSJimmy Vetayases */ 15737ff178cdSJimmy Vetayases 15747ff178cdSJimmy Vetayases /* 15757ff178cdSJimmy Vetayases * MSI support flag: 15767ff178cdSJimmy Vetayases * reflects whether MSI is supported at APIC level 15777ff178cdSJimmy Vetayases * it can also be patched through /etc/system 15787ff178cdSJimmy Vetayases * 15797ff178cdSJimmy Vetayases * 0 = default value - don't know and need to call apic_check_msi_support() 15807ff178cdSJimmy Vetayases * to find out then set it accordingly 15817ff178cdSJimmy Vetayases * 1 = supported 15827ff178cdSJimmy Vetayases * -1 = not supported 15837ff178cdSJimmy Vetayases */ 15847ff178cdSJimmy Vetayases int apic_support_msi = 0; 15857ff178cdSJimmy Vetayases 15867ff178cdSJimmy Vetayases /* Multiple vector support for MSI-X */ 15877ff178cdSJimmy Vetayases int apic_msix_enable = 1; 15887ff178cdSJimmy Vetayases 15897ff178cdSJimmy Vetayases /* Multiple vector support for MSI */ 15907ff178cdSJimmy Vetayases int apic_multi_msi_enable = 1; 15917ff178cdSJimmy Vetayases 15927ff178cdSJimmy Vetayases /* 15937ff178cdSJimmy Vetayases * check whether the system supports MSI 15947ff178cdSJimmy Vetayases * 15957ff178cdSJimmy Vetayases * If PCI-E capability is found, then this must be a PCI-E system. 15967ff178cdSJimmy Vetayases * Since MSI is required for PCI-E system, it returns PSM_SUCCESS 15977ff178cdSJimmy Vetayases * to indicate this system supports MSI. 15987ff178cdSJimmy Vetayases */ 15997ff178cdSJimmy Vetayases int 16007ff178cdSJimmy Vetayases apic_check_msi_support() 16017ff178cdSJimmy Vetayases { 16027ff178cdSJimmy Vetayases dev_info_t *cdip; 16037ff178cdSJimmy Vetayases char dev_type[16]; 16047ff178cdSJimmy Vetayases int dev_len; 16057ff178cdSJimmy Vetayases 16067ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support:\n")); 16077ff178cdSJimmy Vetayases 16087ff178cdSJimmy Vetayases /* 16097ff178cdSJimmy Vetayases * check whether the first level children of root_node have 16107ff178cdSJimmy Vetayases * PCI-E capability 16117ff178cdSJimmy Vetayases */ 16127ff178cdSJimmy Vetayases for (cdip = ddi_get_child(ddi_root_node()); cdip != NULL; 16137ff178cdSJimmy Vetayases cdip = ddi_get_next_sibling(cdip)) { 16147ff178cdSJimmy Vetayases 16157ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: cdip: 0x%p," 16167ff178cdSJimmy Vetayases " driver: %s, binding: %s, nodename: %s\n", (void *)cdip, 16177ff178cdSJimmy Vetayases ddi_driver_name(cdip), ddi_binding_name(cdip), 16187ff178cdSJimmy Vetayases ddi_node_name(cdip))); 16197ff178cdSJimmy Vetayases dev_len = sizeof (dev_type); 16207ff178cdSJimmy Vetayases if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 16217ff178cdSJimmy Vetayases "device_type", (caddr_t)dev_type, &dev_len) 16227ff178cdSJimmy Vetayases != DDI_PROP_SUCCESS) 16237ff178cdSJimmy Vetayases continue; 16247ff178cdSJimmy Vetayases if (strcmp(dev_type, "pciex") == 0) 16257ff178cdSJimmy Vetayases return (PSM_SUCCESS); 16267ff178cdSJimmy Vetayases } 16277ff178cdSJimmy Vetayases 16287ff178cdSJimmy Vetayases /* MSI is not supported on this system */ 16297ff178cdSJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: no 'pciex' " 16307ff178cdSJimmy Vetayases "device_type found\n")); 16317ff178cdSJimmy Vetayases return (PSM_FAILURE); 16327ff178cdSJimmy Vetayases } 16337ff178cdSJimmy Vetayases 16347ff178cdSJimmy Vetayases /* 16357ff178cdSJimmy Vetayases * apic_pci_msi_unconfigure: 16367ff178cdSJimmy Vetayases * 16377ff178cdSJimmy Vetayases * This and next two interfaces are copied from pci_intr_lib.c 16387ff178cdSJimmy Vetayases * Do ensure that these two files stay in sync. 16397ff178cdSJimmy Vetayases * These needed to be copied over here to avoid a deadlock situation on 16407ff178cdSJimmy Vetayases * certain mp systems that use MSI interrupts. 16417ff178cdSJimmy Vetayases * 16427ff178cdSJimmy Vetayases * IMPORTANT regards next three interfaces: 16437ff178cdSJimmy Vetayases * i) are called only for MSI/X interrupts. 16447ff178cdSJimmy Vetayases * ii) called with interrupts disabled, and must not block 16457ff178cdSJimmy Vetayases */ 16467ff178cdSJimmy Vetayases void 16477ff178cdSJimmy Vetayases apic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum) 16487ff178cdSJimmy Vetayases { 16497ff178cdSJimmy Vetayases ushort_t msi_ctrl; 16507ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); 16517ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); 16527ff178cdSJimmy Vetayases 16537ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0)); 16547ff178cdSJimmy Vetayases 16557ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 16567ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 16577ff178cdSJimmy Vetayases msi_ctrl &= (~PCI_MSI_MME_MASK); 16587ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 16597ff178cdSJimmy Vetayases pci_config_put32(handle, cap_ptr + PCI_MSI_ADDR_OFFSET, 0); 16607ff178cdSJimmy Vetayases 16617ff178cdSJimmy Vetayases if (msi_ctrl & PCI_MSI_64BIT_MASK) { 16627ff178cdSJimmy Vetayases pci_config_put16(handle, 16637ff178cdSJimmy Vetayases cap_ptr + PCI_MSI_64BIT_DATA, 0); 16647ff178cdSJimmy Vetayases pci_config_put32(handle, 16657ff178cdSJimmy Vetayases cap_ptr + PCI_MSI_ADDR_OFFSET + 4, 0); 16667ff178cdSJimmy Vetayases } else { 16677ff178cdSJimmy Vetayases pci_config_put16(handle, 16687ff178cdSJimmy Vetayases cap_ptr + PCI_MSI_32BIT_DATA, 0); 16697ff178cdSJimmy Vetayases } 16707ff178cdSJimmy Vetayases 16717ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) { 16727ff178cdSJimmy Vetayases uintptr_t off; 16737ff178cdSJimmy Vetayases uint32_t mask; 16747ff178cdSJimmy Vetayases ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip); 16757ff178cdSJimmy Vetayases 16767ff178cdSJimmy Vetayases ASSERT(msix_p != NULL); 16777ff178cdSJimmy Vetayases 16787ff178cdSJimmy Vetayases /* Offset into "inum"th entry in the MSI-X table & mask it */ 16797ff178cdSJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 16807ff178cdSJimmy Vetayases PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 16817ff178cdSJimmy Vetayases 16827ff178cdSJimmy Vetayases mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off); 16837ff178cdSJimmy Vetayases 16847ff178cdSJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask | 1)); 16857ff178cdSJimmy Vetayases 16867ff178cdSJimmy Vetayases /* Offset into the "inum"th entry in the MSI-X table */ 16877ff178cdSJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr + 16887ff178cdSJimmy Vetayases (inum * PCI_MSIX_VECTOR_SIZE); 16897ff178cdSJimmy Vetayases 16907ff178cdSJimmy Vetayases /* Reset the "data" and "addr" bits */ 16917ff178cdSJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl, 16927ff178cdSJimmy Vetayases (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0); 16937ff178cdSJimmy Vetayases ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, 0); 16947ff178cdSJimmy Vetayases } 16957ff178cdSJimmy Vetayases } 16967ff178cdSJimmy Vetayases 16977ff178cdSJimmy Vetayases /* 16987ff178cdSJimmy Vetayases * apic_pci_msi_disable_mode: 16997ff178cdSJimmy Vetayases */ 17007ff178cdSJimmy Vetayases void 17017ff178cdSJimmy Vetayases apic_pci_msi_disable_mode(dev_info_t *rdip, int type) 17027ff178cdSJimmy Vetayases { 17037ff178cdSJimmy Vetayases ushort_t msi_ctrl; 17047ff178cdSJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); 17057ff178cdSJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); 17067ff178cdSJimmy Vetayases 17077ff178cdSJimmy Vetayases ASSERT((handle != NULL) && (cap_ptr != 0)); 17087ff178cdSJimmy Vetayases 17097ff178cdSJimmy Vetayases if (type == DDI_INTR_TYPE_MSI) { 17107ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 17117ff178cdSJimmy Vetayases if (!(msi_ctrl & PCI_MSI_ENABLE_BIT)) 17127ff178cdSJimmy Vetayases return; 17137ff178cdSJimmy Vetayases 17147ff178cdSJimmy Vetayases msi_ctrl &= ~PCI_MSI_ENABLE_BIT; /* MSI disable */ 17157ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 17167ff178cdSJimmy Vetayases 17177ff178cdSJimmy Vetayases } else if (type == DDI_INTR_TYPE_MSIX) { 17187ff178cdSJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 17197ff178cdSJimmy Vetayases if (msi_ctrl & PCI_MSIX_ENABLE_BIT) { 17207ff178cdSJimmy Vetayases msi_ctrl &= ~PCI_MSIX_ENABLE_BIT; 17217ff178cdSJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 17227ff178cdSJimmy Vetayases msi_ctrl); 17237ff178cdSJimmy Vetayases } 17247ff178cdSJimmy Vetayases } 17257ff178cdSJimmy Vetayases } 17267ff178cdSJimmy Vetayases 17277ff178cdSJimmy Vetayases uint32_t 17287ff178cdSJimmy Vetayases apic_get_localapicid(uint32_t cpuid) 17297ff178cdSJimmy Vetayases { 17307ff178cdSJimmy Vetayases ASSERT(cpuid < apic_nproc && apic_cpus != NULL); 17317ff178cdSJimmy Vetayases 17327ff178cdSJimmy Vetayases return (apic_cpus[cpuid].aci_local_id); 17337ff178cdSJimmy Vetayases } 17347ff178cdSJimmy Vetayases 17357ff178cdSJimmy Vetayases uchar_t 17367ff178cdSJimmy Vetayases apic_get_ioapicid(uchar_t ioapicindex) 17377ff178cdSJimmy Vetayases { 17387ff178cdSJimmy Vetayases ASSERT(ioapicindex < MAX_IO_APIC); 17397ff178cdSJimmy Vetayases 17407ff178cdSJimmy Vetayases return (apic_io_id[ioapicindex]); 17417ff178cdSJimmy Vetayases } 1742