7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * CDDL HEADER START
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * The contents of this file are subject to the terms of the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Common Development and Distribution License (the "License").
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * You may not use this file except in compliance with the License.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * or http://www.opensolaris.org/os/licensing.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * See the License for the specific language governing permissions
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * and limitations under the License.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner]
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * CDDL HEADER END
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
a288e5a9793fdffe5e842d7e61ab45263e75eacaJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved.
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * Copyright (c) 2016 by Delphix. All rights reserved.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.1 extensions are supported only in 2.6 and later versions.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.2 extensions are supported only in 2.7 and later versions.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.5 extensions are supported in Solaris Nevada.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.6 extensions are supported in Solaris Nevada.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * PSMI 1.7 extensions are supported in Solaris Nevada.
41afdfa77f9af46beb3aaab2eccc0d9afe660d31Krishnendu Sadhukhan - Sun Microsystems#include <sys/apic_timer.h>
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesstatic void apic_record_ioapic_rdt(void *intrmap_private,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesstatic void apic_record_msi(void *intrmap_private, msi_regs_t *mregs);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Common routines between pcplusmp & apix (taken from apic.c).
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesprocessorid_t apic_get_next_processorid(processorid_t);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesenum apic_ioapic_method_type apix_mul_ioapic_method = APIC_MUL_IOAPIC_PCPLUSMP;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* Now the ones for Dynamic Interrupt distribution */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* maximum loop count when sending Start IPIs. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * These variables are frequently accessed in apic_intr_enter(),
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_intr_exit and apic_setspl, so group them together
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesvolatile uint32_t *apicadr = NULL; /* virtual addr of local APIC */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_setspl_delay = 1; /* apic_setspl - delay enable */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* vector at which error interrupts come in */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* vector at which performance counter overflow interrupts come in */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* vector at which CMCI interrupts come in */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesextern void cmi_cmci_trap(void);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayaseskmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* number of CPUs in power-on transition state */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Patchable global variables.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_coarse_hrtime = 1; /* 0 - use accurate slow gethrtime() */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_flat_model = 0; /* 0 - clustered. 1 - flat */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_debug_msgbuf[APIC_DEBUG_MSGBUFSIZE];
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* use to make sure only one cpu handles the nmi */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* use to make sure only one cpu handles the error interrupt */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesstatic struct {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0x84 }, /* DataByte 1: SMS/OS no log */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0x2 }, /* DataByte 2: Power Down */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 3: no pre-timeout */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 4: timer expir. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_NEXT, 0xa }, /* DataByte 5: init countdown */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_END, 0x0 }, /* DataByte 6: init countdown */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { CC_SMS_WR_END, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesstatic struct {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x84 }, /* DataByte 1: SMS/OS no log */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x2 }, /* DataByte 2: Power Down */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 3: no pre-timeout */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 4: timer expir. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0xa }, /* DataByte 5: init countdown */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x0 }, /* DataByte 6: init countdown */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases { SMS_DATA_REGISTER, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* Patchable global variables. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_kmdb_on_nmi = 0; /* 0 - no, 1 - yes enter kmdb */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesuint32_t apic_divide_reg_init = 0; /* 0 - divide by 2 */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* default apic ops without interrupt remapping */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesstatic apic_intrmap_ops_t apic_nointrmap_ops = {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (void (*)(int))return_instr,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (void (*)(void **, dev_info_t *, uint16_t, int, uchar_t))return_instr,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (void (*)(void *, void *, uint16_t, int))return_instr,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (void (*)(void **))return_instr,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_intrmap_ops_t *apic_vt_ops = &apic_nointrmap_ops;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* Flag to indicate that we need to shut down all processors */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Probe the ioapic method for apix module. Called in apic_probe_common()
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Set IOAPIC EOI handling method. The priority from low to high is:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 1. IOxAPIC: with EOI register
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 2. IOMMU interrupt mapping
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 3. Mask-Before-EOI method for systems without boot
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * interrupt routing, such as systems with only one IOAPIC;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * NVIDIA CK8-04/MCP55 systems; systems with bridge solution
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * which disables the boot interrupt routing already.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 4. Directed EOI
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_IOXAPIC;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if ((apic_io_max == 1) || (apic_nvidia_io_max == apic_io_max))
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_MASK;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apix_mul_ioapic_method = APIC_MUL_IOAPIC_DEOI;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* fall back to pcplusmp */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apix_mul_ioapic_method == APIC_MUL_IOAPIC_PCPLUSMP) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* make sure apix is after pcplusmp in /etc/mach */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apix_enable = 0; /* go ahead with pcplusmp install next */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * handler for APIC Error interrupt. Just print a warning and continue
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * We need to write before read as per 7.4.17 of system prog manual.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * We do both and or the results to be safe
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases error0 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases error1 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Clear the APIC error status (do this on all cpus that enter here)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * (two writes are required due to the semantics of accessing the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * error status register.)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Prevent more than 1 CPU from handling error interrupt causing
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * double printing (interleave of characters from multiple
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * CPU's when using prom_printf)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases return (error ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases debug_enter("pcplusmp: APIC Error interrupt received");
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "APIC Error interrupt on CPU %d. Status = %x",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* cksum error only */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * prom_printf is the best shot we have of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * something which is problem free from
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * high level/NMI type of interrupts
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases prom_printf("APIC Error interrupt on CPU %d. "
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "Status 0 = %x, Status 1 = %x\n",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_error_display_delay; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * provide more delay next time limited to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * roughly 1 clock tick time
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Turn off the mask bit in the performance counter Local Vector Table entry.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_cmci_enable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_cmci_disable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasescmci_cpu_setup(cpu_setup_t what, int cpuid, void *arg)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set),
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set),
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* local intr reg 0 */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* disable NMI */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_INT_VECT1, AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* and error interrupt */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_ERR_VECT, AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* and perf counter intr */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_PCINT_VECT, AV_MASK);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write(APIC_SPUR_INT_REG, APIC_SPUR_INTR);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_cpu_send_SIPI(processorid_t cpun, boolean_t start)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Interrupts on current CPU will be disabled during the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * steps in order to avoid unwanted side effects from
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * executing interrupt handlers on a problematic BIOS.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * According to X2APIC specification in section '2.3.5.1' of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Interrupt Command Register Semantics, the semantics of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * programming the Interrupt Command Register to dispatch an interrupt
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * is simplified. A single MSR write to the 64-bit ICR is required
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * for dispatching an interrupt. Specifically, with the 64-bit MSR
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * interface to ICR, system software is not required to check the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * status of the delivery status bit prior to writing to the ICR
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * to send an IPI. With the removal of the Delivery Status bit,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * system software no longer has a reason to read the ICR. It remains
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * readable only to aid in debugging.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* for integrated - make sure there is one INIT IPI in buffer */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* for external - it will wake up the cpu */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, AV_ASSERT | AV_RESET);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* If only 1 CPU is installed, PENDING bit will not go low */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (loop_count = apic_sipi_max_loop_count; loop_count; loop_count--) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, AV_DEASSERT | AV_RESET);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_cpus[cpun].aci_local_ver >= APIC_INTEGRATED_VERS) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* integrated apic */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* to offset the INIT IPI queue up in the buffer */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * send the second SIPI (Startup IPI) as recommended by Intel
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * software development manual.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_cpu_start(processorid_t cpun, caddr_t arg)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Switch to apic_common_send_ipi for safety during starting other CPUs.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Put CPU into halted state with interrupts disabled.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_cpu_stop(processorid_t cpun, caddr_t arg)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases extern void cpu_idle_intercept_cpu(cpu_t *cp);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT((cp->cpu_flags & CPU_QUIESCED) != 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Clear CPU_READY flag to disable cross calls. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Intercept target CPU at a safe point before powering it off. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases return (apic_cpu_stop(reqp->req.cpu_stop.cpuid,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesint apic_stretch_ISR = 1 << 3; /* IPL of 3 matches nothing now */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * generates an interprocessor interrupt to another CPU. Any changes made to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * this routine must be accompanied by similar changes to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_common_send_ipi().
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_reg_ops->apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * If apic_coarse_time == 1, then apic_gettime() is used instead of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_gethrtime(). This is used for performance instead of accuracy.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * In one-shot mode, we do not keep time, so if anyone
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * calls psm_gettime() directly, we vector over to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * gethrtime().
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * one-shot mode MUST NOT be enabled if this psm is the source of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases while ((old_hrtime_stamp = apic_hrtime_stamp) & 1)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Here we return the number of nanoseconds since booting. Note every
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * clock interrupt increments apic_nsec_since_boot by the appropriate
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * In one-shot mode, we do not keep time, so if anyone
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * calls psm_gethrtime() directly, we vector over to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * gethrtime().
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * one-shot mode MUST NOT be enabled if this psm is the source of
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases oflags = intr_clear(); /* prevent migration */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases cpun = apic_reg_ops->apic_read(APIC_LID_REG);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases while ((old_hrtime_stamp = apic_hrtime_stamp) & 1)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Check to see which CPU we are on. Note the time is kept on
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * the local APIC of CPU 0. If on CPU 0, simply read the current
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * counter. If on another CPU, issue a remote read command to CPU 0.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases countval = apic_reg_ops->apic_read(APIC_CURR_COUNT);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_cpus[0].aci_local_id, APIC_CURR_ADD | AV_REMOTE);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases while ((status = apic_reg_ops->apic_read(APIC_INT_CMD1))
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (status & AV_REMOTE_STATUS) /* 1 = valid */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases countval = apic_reg_ops->apic_read(APIC_REMOTE_READ);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases else { /* 0 = invalid */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * return last hrtime right now, will need more
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * testing if change to retry
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases elapsed_ticks = apic_hertz_count - countval;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases curr_timeval = APIC_TICKS_TO_NSECS(elapsed_ticks);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* we might have clobbered last_count_read. Restore it */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* return last hrtime if error occurs */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* apic NMI handler */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases debug_enter("NMI received: entering kmdb\n");
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Keep panic from entering kmdb. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * prom_printf is the best shot we have of something which is
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * problem free from high level/NMI type of interrupts
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_get_next_processorid(processorid_t cpu_id)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases reqp->req.cpu_add.cpuid = (processorid_t)-1;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Check whether CPU hotplug is supported. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (!plat_dr_support_cpu() || apic_max_nproc == -1) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ap = (mach_cpu_add_arg_t *)reqp->req.cpu_add.argp;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: apicid(%u) or procid(%u) is invalid.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: x2apicid(%u) is invalid.", localid);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } else if (localid >= 255 && apic_mode == LOCAL_APIC) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases cmn_err(CE_WARN, "!apic: system is in APIC mode, "
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "can't support x2APIC processor.");
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: unknown argument type %d to apic_cpu_add().",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Check whether local APIC id already exists. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_nproc; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: local apic id %u already exists.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } else if (apic_cpus[i].aci_processor_id == procid) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: processor id %u already exists.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * There's no local APIC version number available in MADT table,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * so assume that all CPUs are homogeneous and use local APIC
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * version number of the first existing CPU.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Try to assign the same cpuid if APIC id exists in the dirty cache.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT((apic_cpus[i].aci_status & APIC_CPU_FREE) == 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT(apic_cpus[i].aci_status & APIC_CPU_FREE);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if ((apic_cpus[i].aci_status & APIC_CPU_DIRTY) &&
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Avoid the dirty cache and allocate fresh slot if possible. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if ((apic_cpus[i].aci_status & APIC_CPU_FREE) &&
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (apic_cpus[i].aci_status & APIC_CPU_DIRTY) == 0) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Try to find any free slot as last resort. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_max_nproc; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_cpus[i].aci_status & APIC_CPU_FREE) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: failed to allocate cpu id for processor %u.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } else if (ACPI_FAILURE(acpica_map_cpu(cpuid, procid))) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: failed to build mapping for processor %u.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT(cpuid < apic_max_nproc && cpuid < max_ncpus);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases bzero(&apic_cpus[cpuid], sizeof (apic_cpus[0]));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Check whether CPU hotplug is supported. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (!plat_dr_support_cpu() || apic_max_nproc == -1) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "!apic: cpuid %d doesn't exist in apic_cpus array.",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT((apic_cpus[cpuid].aci_status & APIC_CPU_FREE) == 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (ACPI_FAILURE(acpica_unmap_cpu(cpuid))) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * We are removing the highest numbered cpuid so we need to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * find the next highest cpuid as the new value for apic_nproc.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = apic_nproc; i > 0; i--) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* at least one CPU left */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* mark slot as free and keep it in the dirty cache */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_cpus[cpuid].aci_status = APIC_CPU_FREE | APIC_CPU_DIRTY;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Return the number of APIC clock ticks elapsed for 8245 to decrement
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * (APIC_TIME_COUNT + pit_ticks_adj) ticks.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_calibrate(volatile uint32_t *addr, uint16_t *pit_ticks_adj)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pit_tick_lo <= APIC_LB_MIN || pit_tick_lo >= APIC_LB_MAX);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Wait for the 8254 to decrement by 5 ticks to ensure
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * we didn't start in the middle of a tick.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Compare with 0x10 for the wrap around case.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases start_apic_tick = apic_reg_ops->apic_read(reg);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Wait for the 8254 to decrement by
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * (APIC_TIME_COUNT + pit_ticks_adj) ticks
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases target_pit_tick = pit_tick - APIC_TIME_COUNT;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases end_apic_tick = apic_reg_ops->apic_read(reg);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases *pit_ticks_adj = target_pit_tick - pit_tick;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Initialise the APIC timer on the local APIC of CPU 0 to the desired
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * frequency. Note at this stage in the boot sequence, the boot processor
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * is the only active processor.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * hertz value of 0 indicates a one-shot mode request. In this case
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * the function returns the resolution (in nanoseconds) for the hardware
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * timer interrupt. If one-shot mode capability is not available,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * the return value will be 0. apic_enable_oneshot is a global switch
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * for disabling the functionality.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * A non-zero positive value for hertz indicates a periodic mode request.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * In this case the hardware will be programmed to generate clock interrupts
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * at hertz frequency and returns the resolution of interrupts in
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * nanosecond.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_diff_for_redistribution = (apic_diff_for_redistribution *
41afdfa77f9af46beb3aaab2eccc0d9afe660d31Krishnendu Sadhukhan - Sun Microsystems ret = apic_timer_init(hertz);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_preshutdown:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Called early in shutdown whilst we can still access filesystems to do
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * things like loading modules which will be required to complete shutdown
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * after filesystems are all unmounted.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases APIC_VERBOSE_POWEROFF(("apic_preshutdown(%d,%d); m=%d a=%d\n",
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases cmd, fcn, apic_poweroff_method, apic_enable_acpi));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Send NMI to all CPUs except self to do per processor shutdown */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases#endif /* DEBUG */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* restore cmos shutdown byte before reboot */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* disable apic mode if imcr present */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* remainder of function is for shutdown cases only */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Switch system back into Legacy-Mode if using ACPI and
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * not powering-off. Some BIOSes need to remain in ACPI-mode
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * for power-off to succeed (Dell Dimension 4600)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Do not disable ACPI while doing fastreboot
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (apic_enable_acpi && fcn != AD_POWEROFF && fcn != AD_FASTREBOOT)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* remainder of function is for shutdown+poweroff case only */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* select the extended NVRAM bank in the RTC */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* for Predator must toggle the PAB bit */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * clear power active bar, wakeup alarm and
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* delay before next write */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* for S40 the following would suffice */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* power active bar control bit */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } while (byte != 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases outb(MISMIC_CNTL_REGISTER, CC_SMS_GET_STATUS);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (; i < (sizeof (aspen_bmc)/sizeof (aspen_bmc[0]));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } while (byte != 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases outb(MISMIC_CNTL_REGISTER, aspen_bmc[i].cntl);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases outb(MISMIC_DATA_REGISTER, aspen_bmc[i].data);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (; i < (sizeof (sitka_bmc)/sizeof (sitka_bmc[0]));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases } while (byte != 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* If no APIC direct method, we will try using ACPI */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Wait a limited time here for power to go off.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * If the power does not go off, then there was a
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * problem and we should continue to the halt which
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * prints a message for the user to press a key to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases drv_usecwait(7000000); /* wait seven seconds */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * The following functions are in the platform specific file so that they
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * can be different functions depending on whether we are running on
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * bare metal or a hypervisor.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * map an apic for memory-mapped access
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesmapin_apic(uint32_t addr, size_t len, int flags)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases return ((void *)psm_map_phys(addr, len, flags));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesmapin_ioapic(uint32_t addr, size_t len, int flags)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * unmap an apic
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesioapic_write(int ioapic_ix, uint32_t reg, uint32_t value)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesioapic_write_eoi(int ioapic_ix, uint32_t value)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Round-robin algorithm to find the next CPU with interrupts enabled.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * It can't share the same static variable apic_next_bind_cpu with
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_get_next_bind_cpu(), since that will cause all interrupts to be
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * bound to CPU1 at boot time. During boot, only CPU0 is online with
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * interrupts enabled when apic_get_next_bind_cpu() and apic_find_cpu()
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * are called. However, the pcplusmp driver assumes that there will be
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * boot_ncpus CPUs configured eventually so it tries to distribute all
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * interrupts among CPU0 - CPU[boot_ncpus - 1]. Thus to prevent all
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * interrupts being targetted at CPU1, we need to use a dedicated static
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * variable for find_next_cpu() instead of sharing apic_next_bind_cpu.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Find the first CPU with the passed-in flag set */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (i = 0; i < apic_nproc; i++) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ASSERT((apic_cpus[acid].aci_status & flag) != 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Switch between safe and x2APIC IPI sending method.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * CPU may power on in xapic mode or x2apic mode. If CPU needs to send IPI to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * other CPUs before entering x2APIC mode, it still needs to xAPIC method.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Before sending StartIPI to target CPU, psm_send_ipi will be changed to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_common_send_ipi, which detects current local APIC mode and use right
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * method to send IPI. If some CPUs fail to start up, apic_poweron_cnt
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * won't return to zero, so apic_common_send_ipi will always be used.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * psm_send_ipi can't be simply changed back to x2apic_send_ipi if some CPUs
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * failed to start up because those failed CPUs may recover itself later at
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * unpredictable time.
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * Intel Software Developer's Manual 3A, 10.12.7:
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * Routing of device interrupts to local APIC units operating in
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * x2APIC mode requires use of the interrupt-remapping architecture
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * specified in the Intel Virtualization Technology for Directed
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * I/O, Revision 1.3. Because of this, BIOS must enumerate support
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * for and software must enable this interrupt remapping with
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * Extended Interrupt Mode Enabled before it enabling x2APIC mode in
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * the local APIC units.
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * In other words, to use the APIC in x2APIC mode, we need interrupt
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * remapping. Since we don't start up the IOMMU by default, we
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * won't be able to do any interrupt remapping and therefore have to
1a9079eeb6a460980656d5e022ec89bbbfb84732Josef 'Jeff' Sipek * use the APIC in traditional 'local APIC' mode with memory mapped
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_intrmap_init(apic_mode) == DDI_SUCCESS) {
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * We leverage the interrupt remapping engine to
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * suppress broadcast EOI; thus we must send the
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * directed EOI with the directed-EOI handler.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases apic_vt_ops->apic_intrmap_enable(suppress_brdcst_eoi);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_record_ioapic_rdt(void *intrmap_private, ioapic_rdt_t *irdt)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_record_msi(void *intrmap_private, msi_regs_t *mregs)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) |
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) |
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Functions from apic_introp.c
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Those functions are used by apic_intr_ops().
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * MSI support flag:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * reflects whether MSI is supported at APIC level
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * it can also be patched through /etc/system
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 0 = default value - don't know and need to call apic_check_msi_support()
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * to find out then set it accordingly
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * 1 = supported
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * -1 = not supported
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* Multiple vector support for MSI-X */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases/* Multiple vector support for MSI */
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * Check whether the system supports MSI.
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * MSI is required for PCI-E and for PCI versions later than 2.2, so if we find
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * a PCI-E bus or we find a PCI bus whose version we know is >= 2.2, then we
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * return PSM_SUCCESS to indicate this system supports MSI.
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * (Currently the only way we check whether a given PCI bus supports >= 2.2 is
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * by detecting if we are running inside the KVM hypervisor, which guarantees
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * this version number.)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support:\n"));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * check whether the first level children of root_node have
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel * PCI-E or PCI capability.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases for (cdip = ddi_get_child(ddi_root_node()); cdip != NULL;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: cdip: 0x%p,"
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases " driver: %s, binding: %s, nodename: %s\n", (void *)cdip,
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_driver_name(cdip), ddi_binding_name(cdip),
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
970db7b7a5b4656c659fc7c5226da7be313dc336Dan Kimmel if (strcmp(dev_type, "pci") == 0 && get_hwenv() == HW_KVM)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* MSI is not supported on this system */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: no 'pciex' "
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases "device_type found\n"));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_pci_msi_unconfigure:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * This and next two interfaces are copied from pci_intr_lib.c
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * Do ensure that these two files stay in sync.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * These needed to be copied over here to avoid a deadlock situation on
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * certain mp systems that use MSI interrupts.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * IMPORTANT regards next three interfaces:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * i) are called only for MSI/X interrupts.
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * ii) called with interrupts disabled, and must not block
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pci_config_put32(handle, cap_ptr + PCI_MSI_ADDR_OFFSET, 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Offset into "inum"th entry in the MSI-X table & mask it */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask | 1));
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Offset into the "inum"th entry in the MSI-X table */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases /* Reset the "data" and "addr" bits */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, 0);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases * apic_pci_msi_disable_mode:
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayasesapic_pci_msi_disable_mode(dev_info_t *rdip, int type)
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases msi_ctrl &= ~PCI_MSI_ENABLE_BIT; /* MSI disable */
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
7ff178cd8db129d385d3177eb20744d3b6efc59bJimmy Vetayases pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,