17ff178cJimmy Vetayases/*
27ff178cJimmy Vetayases * CDDL HEADER START
37ff178cJimmy Vetayases *
47ff178cJimmy Vetayases * The contents of this file are subject to the terms of the
57ff178cJimmy Vetayases * Common Development and Distribution License (the "License").
67ff178cJimmy Vetayases * You may not use this file except in compliance with the License.
77ff178cJimmy Vetayases *
87ff178cJimmy Vetayases * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97ff178cJimmy Vetayases * or http://www.opensolaris.org/os/licensing.
107ff178cJimmy Vetayases * See the License for the specific language governing permissions
117ff178cJimmy Vetayases * and limitations under the License.
127ff178cJimmy Vetayases *
137ff178cJimmy Vetayases * When distributing Covered Code, include this CDDL HEADER in each
147ff178cJimmy Vetayases * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157ff178cJimmy Vetayases * If applicable, add the following below this CDDL HEADER, with the
167ff178cJimmy Vetayases * fields enclosed by brackets "[]" replaced with your own identifying
177ff178cJimmy Vetayases * information: Portions Copyright [yyyy] [name of copyright owner]
187ff178cJimmy Vetayases *
197ff178cJimmy Vetayases * CDDL HEADER END
207ff178cJimmy Vetayases */
217ff178cJimmy Vetayases
227ff178cJimmy Vetayases/*
237ff178cJimmy Vetayases * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
247ff178cJimmy Vetayases */
25a288e5aJoshua M. Clulow/*
260c26abfJohn Levon * Copyright 2019, Joyent, Inc.
27e876368Pavel Zakharov * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
2811ed32aJoshua M. Clulow * Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
29a288e5aJoshua M. Clulow */
307ff178cJimmy Vetayases
317ff178cJimmy Vetayases/*
327ff178cJimmy Vetayases * PSMI 1.1 extensions are supported only in 2.6 and later versions.
337ff178cJimmy Vetayases * PSMI 1.2 extensions are supported only in 2.7 and later versions.
347ff178cJimmy Vetayases * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
357ff178cJimmy Vetayases * PSMI 1.5 extensions are supported in Solaris Nevada.
367ff178cJimmy Vetayases * PSMI 1.6 extensions are supported in Solaris Nevada.
377ff178cJimmy Vetayases * PSMI 1.7 extensions are supported in Solaris Nevada.
387ff178cJimmy Vetayases */
397ff178cJimmy Vetayases#define	PSMI_1_7
407ff178cJimmy Vetayases
417ff178cJimmy Vetayases#include <sys/processor.h>
427ff178cJimmy Vetayases#include <sys/time.h>
437ff178cJimmy Vetayases#include <sys/psm.h>
447ff178cJimmy Vetayases#include <sys/smp_impldefs.h>
457ff178cJimmy Vetayases#include <sys/cram.h>
467ff178cJimmy Vetayases#include <sys/acpi/acpi.h>
477ff178cJimmy Vetayases#include <sys/acpica.h>
487ff178cJimmy Vetayases#include <sys/psm_common.h>
497ff178cJimmy Vetayases#include <sys/apic.h>
507ff178cJimmy Vetayases#include <sys/pit.h>
517ff178cJimmy Vetayases#include <sys/ddi.h>
527ff178cJimmy Vetayases#include <sys/sunddi.h>
537ff178cJimmy Vetayases#include <sys/ddi_impldefs.h>
547ff178cJimmy Vetayases#include <sys/pci.h>
557ff178cJimmy Vetayases#include <sys/promif.h>
567ff178cJimmy Vetayases#include <sys/x86_archext.h>
577ff178cJimmy Vetayases#include <sys/cpc_impl.h>
587ff178cJimmy Vetayases#include <sys/uadmin.h>
597ff178cJimmy Vetayases#include <sys/panic.h>
607ff178cJimmy Vetayases#include <sys/debug.h>
617ff178cJimmy Vetayases#include <sys/archsystm.h>
627ff178cJimmy Vetayases#include <sys/trap.h>
637ff178cJimmy Vetayases#include <sys/machsystm.h>
647ff178cJimmy Vetayases#include <sys/sysmacros.h>
657ff178cJimmy Vetayases#include <sys/cpuvar.h>
667ff178cJimmy Vetayases#include <sys/rm_platter.h>
677ff178cJimmy Vetayases#include <sys/privregs.h>
687ff178cJimmy Vetayases#include <sys/note.h>
697ff178cJimmy Vetayases#include <sys/pci_intr_lib.h>
707ff178cJimmy Vetayases#include <sys/spl.h>
717ff178cJimmy Vetayases#include <sys/clock.h>
727ff178cJimmy Vetayases#include <sys/dditypes.h>
737ff178cJimmy Vetayases#include <sys/sunddi.h>
747ff178cJimmy Vetayases#include <sys/x_call.h>
757ff178cJimmy Vetayases#include <sys/reboot.h>
767ff178cJimmy Vetayases#include <sys/hpet.h>
777ff178cJimmy Vetayases#include <sys/apic_common.h>
7841afdfaKrishnendu Sadhukhan - Sun Microsystems#include <sys/apic_timer.h>
797ff178cJimmy Vetayases
807ff178cJimmy Vetayasesstatic void	apic_record_ioapic_rdt(void *intrmap_private,
817ff178cJimmy Vetayases		    ioapic_rdt_t *irdt);
827ff178cJimmy Vetayasesstatic void	apic_record_msi(void *intrmap_private, msi_regs_t *mregs);
837ff178cJimmy Vetayases
847ff178cJimmy Vetayases/*
857ff178cJimmy Vetayases * Common routines between pcplusmp & apix (taken from apic.c).
867ff178cJimmy Vetayases */
877ff178cJimmy Vetayases
887ff178cJimmy Vetayasesint	apic_clkinit(int);
897ff178cJimmy Vetayaseshrtime_t apic_gethrtime(void);
907ff178cJimmy Vetayasesvoid	apic_send_ipi(int, int);
917ff178cJimmy Vetayasesvoid	apic_set_idlecpu(processorid_t);
927ff178cJimmy Vetayasesvoid	apic_unset_idlecpu(processorid_t);
937ff178cJimmy Vetayasesvoid	apic_shutdown(int, int);
947ff178cJimmy Vetayasesvoid	apic_preshutdown(int, int);
957ff178cJimmy Vetayasesprocessorid_t	apic_get_next_processorid(processorid_t);
967ff178cJimmy Vetayases
977ff178cJimmy Vetayaseshrtime_t apic_gettime();
987ff178cJimmy Vetayases
997ff178cJimmy Vetayasesenum apic_ioapic_method_type apix_mul_ioapic_method = APIC_MUL_IOAPIC_PCPLUSMP;
1007ff178cJimmy Vetayases
1017ff178cJimmy Vetayases/* Now the ones for Dynamic Interrupt distribution */
1027ff178cJimmy Vetayasesint	apic_enable_dynamic_migration = 0;
1037ff178cJimmy Vetayases
1047ff178cJimmy Vetayases/* maximum loop count when sending Start IPIs. */
1057ff178cJimmy Vetayasesint apic_sipi_max_loop_count = 0x1000;
1067ff178cJimmy Vetayases
1077ff178cJimmy Vetayases/*
1087ff178cJimmy Vetayases * These variables are frequently accessed in apic_intr_enter(),
1097ff178cJimmy Vetayases * apic_intr_exit and apic_setspl, so group them together
1107ff178cJimmy Vetayases */
1117ff178cJimmy Vetayasesvolatile uint32_t *apicadr =  NULL;	/* virtual addr of local APIC	*/
1127ff178cJimmy Vetayasesint apic_setspl_delay = 1;		/* apic_setspl - delay enable	*/
1137ff178cJimmy Vetayasesint apic_clkvect;
1147ff178cJimmy Vetayases
1157ff178cJimmy Vetayases/* vector at which error interrupts come in */
1167ff178cJimmy Vetayasesint apic_errvect;
1177ff178cJimmy Vetayasesint apic_enable_error_intr = 1;
1187ff178cJimmy Vetayasesint apic_error_display_delay = 100;
1197ff178cJimmy Vetayases
1207ff178cJimmy Vetayases/* vector at which performance counter overflow interrupts come in */
1217ff178cJimmy Vetayasesint apic_cpcovf_vect;
1227ff178cJimmy Vetayasesint apic_enable_cpcovf_intr = 1;
1237ff178cJimmy Vetayases
1247ff178cJimmy Vetayases/* vector at which CMCI interrupts come in */
1257ff178cJimmy Vetayasesint apic_cmci_vect;
1267ff178cJimmy Vetayasesextern void cmi_cmci_trap(void);
1277ff178cJimmy Vetayases
1287ff178cJimmy Vetayaseslock_t apic_mode_switch_lock;
1297ff178cJimmy Vetayases
1301c2d047Patrick Mooneyint apic_pir_vect;
1311c2d047Patrick Mooney
1327ff178cJimmy Vetayases/*
1337ff178cJimmy Vetayases * Patchable global variables.
1347ff178cJimmy Vetayases */
1357ff178cJimmy Vetayasesint	apic_forceload = 0;
1367ff178cJimmy Vetayases
1377ff178cJimmy Vetayasesint	apic_coarse_hrtime = 1;		/* 0 - use accurate slow gethrtime() */
1387ff178cJimmy Vetayases
1397ff178cJimmy Vetayasesint	apic_flat_model = 0;		/* 0 - clustered. 1 - flat */
1407ff178cJimmy Vetayasesint	apic_panic_on_nmi = 0;
1417ff178cJimmy Vetayasesint	apic_panic_on_apic_error = 0;
1427ff178cJimmy Vetayases
1437ff178cJimmy Vetayasesint	apic_verbose = 0;	/* 0x1ff */
1447ff178cJimmy Vetayases
1457ff178cJimmy Vetayases#ifdef DEBUG
1467ff178cJimmy Vetayasesint	apic_debug = 0;
1477ff178cJimmy Vetayasesint	apic_restrict_vector = 0;
1487ff178cJimmy Vetayases
1497ff178cJimmy Vetayasesint	apic_debug_msgbuf[APIC_DEBUG_MSGBUFSIZE];
1507ff178cJimmy Vetayasesint	apic_debug_msgbufindex = 0;
1517ff178cJimmy Vetayases
1527ff178cJimmy Vetayases#endif /* DEBUG */
1537ff178cJimmy Vetayases
1547ff178cJimmy Vetayasesuint_t apic_nticks = 0;
1557ff178cJimmy Vetayasesuint_t apic_skipped_redistribute = 0;
1567ff178cJimmy Vetayases
1577ff178cJimmy Vetayasesuint_t last_count_read = 0;
1587ff178cJimmy Vetayaseslock_t	apic_gethrtime_lock;
1597ff178cJimmy Vetayasesvolatile int	apic_hrtime_stamp = 0;
1607ff178cJimmy Vetayasesvolatile hrtime_t apic_nsec_since_boot = 0;
1617ff178cJimmy Vetayases
1627ff178cJimmy Vetayasesstatic	hrtime_t	apic_last_hrtime = 0;
1637ff178cJimmy Vetayasesint		apic_hrtime_error = 0;
1647ff178cJimmy Vetayasesint		apic_remote_hrterr = 0;
1657ff178cJimmy Vetayasesint		apic_num_nmis = 0;
1667ff178cJimmy Vetayasesint		apic_apic_error = 0;
1677ff178cJimmy Vetayasesint		apic_num_apic_errors = 0;
1687ff178cJimmy Vetayasesint		apic_num_cksum_errors = 0;
1697ff178cJimmy Vetayases
1707ff178cJimmy Vetayasesint	apic_error = 0;
1717ff178cJimmy Vetayases
1727ff178cJimmy Vetayasesstatic	int	apic_cmos_ssb_set = 0;
1737ff178cJimmy Vetayases
1747ff178cJimmy Vetayases/* use to make sure only one cpu handles the nmi */
1757ff178cJimmy Vetayaseslock_t	apic_nmi_lock;
1767ff178cJimmy Vetayases/* use to make sure only one cpu handles the error interrupt */
1777ff178cJimmy Vetayaseslock_t	apic_error_lock;
1787ff178cJimmy Vetayases
1797ff178cJimmy Vetayasesstatic	struct {
1807ff178cJimmy Vetayases	uchar_t	cntl;
1817ff178cJimmy Vetayases	uchar_t	data;
1827ff178cJimmy Vetayases} aspen_bmc[] = {
1837ff178cJimmy Vetayases	{ CC_SMS_WR_START,	0x18 },		/* NetFn/LUN */
1847ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0x24 },		/* Cmd SET_WATCHDOG_TIMER */
1857ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0x84 },		/* DataByte 1: SMS/OS no log */
1867ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0x2 },		/* DataByte 2: Power Down */
1877ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0x0 },		/* DataByte 3: no pre-timeout */
1887ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0x0 },		/* DataByte 4: timer expir. */
1897ff178cJimmy Vetayases	{ CC_SMS_WR_NEXT,	0xa },		/* DataByte 5: init countdown */
1907ff178cJimmy Vetayases	{ CC_SMS_WR_END,	0x0 },		/* DataByte 6: init countdown */
1917ff178cJimmy Vetayases
1927ff178cJimmy Vetayases	{ CC_SMS_WR_START,	0x18 },		/* NetFn/LUN */
1937ff178cJimmy Vetayases	{ CC_SMS_WR_END,	0x22 }		/* Cmd RESET_WATCHDOG_TIMER */
1947ff178cJimmy Vetayases};
1957ff178cJimmy Vetayases
1967ff178cJimmy Vetayasesstatic	struct {
1977ff178cJimmy Vetayases	int	port;
1987ff178cJimmy Vetayases	uchar_t	data;
1997ff178cJimmy Vetayases} sitka_bmc[] = {
2007ff178cJimmy Vetayases	{ SMS_COMMAND_REGISTER,	SMS_WRITE_START },
2017ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x18 },		/* NetFn/LUN */
2027ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x24 },		/* Cmd SET_WATCHDOG_TIMER */
2037ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x84 },		/* DataByte 1: SMS/OS no log */
2047ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x2 },		/* DataByte 2: Power Down */
2057ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x0 },		/* DataByte 3: no pre-timeout */
2067ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x0 },		/* DataByte 4: timer expir. */
2077ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0xa },		/* DataByte 5: init countdown */
2087ff178cJimmy Vetayases	{ SMS_COMMAND_REGISTER,	SMS_WRITE_END },
2097ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x0 },		/* DataByte 6: init countdown */
2107ff178cJimmy Vetayases
2117ff178cJimmy Vetayases	{ SMS_COMMAND_REGISTER,	SMS_WRITE_START },
2127ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x18 },		/* NetFn/LUN */
2137ff178cJimmy Vetayases	{ SMS_COMMAND_REGISTER,	SMS_WRITE_END },
2147ff178cJimmy Vetayases	{ SMS_DATA_REGISTER,	0x22 }		/* Cmd RESET_WATCHDOG_TIMER */
2157ff178cJimmy Vetayases};
2167ff178cJimmy Vetayases
2177ff178cJimmy Vetayases/* Patchable global variables. */
2187ff178cJimmy Vetayasesint		apic_kmdb_on_nmi = 0;		/* 0 - no, 1 - yes enter kmdb */
2197ff178cJimmy Vetayasesuint32_t	apic_divide_reg_init = 0;	/* 0 - divide by 2 */
2207ff178cJimmy Vetayases
2217ff178cJimmy Vetayases/* default apic ops without interrupt remapping */
2227ff178cJimmy Vetayasesstatic apic_intrmap_ops_t apic_nointrmap_ops = {
2237ff178cJimmy Vetayases	(int (*)(int))return_instr,
2247ff178cJimmy Vetayases	(void (*)(int))return_instr,
2257ff178cJimmy Vetayases	(void (*)(void **, dev_info_t *, uint16_t, int, uchar_t))return_instr,
2267ff178cJimmy Vetayases	(void (*)(void *, void *, uint16_t, int))return_instr,
2277ff178cJimmy Vetayases	(void (*)(void **))return_instr,
2287ff178cJimmy Vetayases	apic_record_ioapic_rdt,
2297ff178cJimmy Vetayases	apic_record_msi,
2307ff178cJimmy Vetayases};
2317ff178cJimmy Vetayases
2327ff178cJimmy Vetayasesapic_intrmap_ops_t *apic_vt_ops = &apic_nointrmap_ops;
2337ff178cJimmy Vetayasesapic_cpus_info_t	*apic_cpus = NULL;
2347ff178cJimmy Vetayasescpuset_t	apic_cpumask;
2357ff178cJimmy Vetayasesuint_t		apic_picinit_called;
2367ff178cJimmy Vetayases
2377ff178cJimmy Vetayases/* Flag to indicate that we need to shut down all processors */
2387ff178cJimmy Vetayasesstatic uint_t	apic_shutdown_processors;
2397ff178cJimmy Vetayases
2407ff178cJimmy Vetayases/*
2417ff178cJimmy Vetayases * Probe the ioapic method for apix module. Called in apic_probe_common()
2427ff178cJimmy Vetayases */
2437ff178cJimmy Vetayasesint
2447ff178cJimmy Vetayasesapic_ioapic_method_probe()
2457ff178cJimmy Vetayases{
2467ff178cJimmy Vetayases	if (apix_enable == 0)
2477ff178cJimmy Vetayases		return (PSM_SUCCESS);
2487ff178cJimmy Vetayases
2497ff178cJimmy Vetayases	/*
2507ff178cJimmy Vetayases	 * Set IOAPIC EOI handling method. The priority from low to high is:
25158b4950Hans Rosenfeld	 *	1. IOxAPIC: with EOI register
25258b4950Hans Rosenfeld	 *	2. IOMMU interrupt mapping
2537ff178cJimmy Vetayases	 *	3. Mask-Before-EOI method for systems without boot
2547ff178cJimmy Vetayases	 *	interrupt routing, such as systems with only one IOAPIC;
2557ff178cJimmy Vetayases	 *	NVIDIA CK8-04/MCP55 systems; systems with bridge solution
2567ff178cJimmy Vetayases	 *	which disables the boot interrupt routing already.
25758b4950Hans Rosenfeld	 *	4. Directed EOI
2587ff178cJimmy Vetayases	 */
2597ff178cJimmy Vetayases	if (apic_io_ver[0] >= 0x20)
2607ff178cJimmy Vetayases		apix_mul_ioapic_method = APIC_MUL_IOAPIC_IOXAPIC;
2617ff178cJimmy Vetayases	if ((apic_io_max == 1) || (apic_nvidia_io_max == apic_io_max))
2627ff178cJimmy Vetayases		apix_mul_ioapic_method = APIC_MUL_IOAPIC_MASK;
2637ff178cJimmy Vetayases	if (apic_directed_EOI_supported())
2647ff178cJimmy Vetayases		apix_mul_ioapic_method = APIC_MUL_IOAPIC_DEOI;
2657ff178cJimmy Vetayases
2667ff178cJimmy Vetayases	/* fall back to pcplusmp */
2677ff178cJimmy Vetayases	if (apix_mul_ioapic_method == APIC_MUL_IOAPIC_PCPLUSMP) {
2687ff178cJimmy Vetayases		/* make sure apix is after pcplusmp in /etc/mach */
2697ff178cJimmy Vetayases		apix_enable = 0; /* go ahead with pcplusmp install next */
2707ff178cJimmy Vetayases		return (PSM_FAILURE);
2717ff178cJimmy Vetayases	}
2727ff178cJimmy Vetayases
2737ff178cJimmy Vetayases	return (PSM_SUCCESS);
2747ff178cJimmy Vetayases}
2757ff178cJimmy Vetayases
2767ff178cJimmy Vetayases/*
2777ff178cJimmy Vetayases * handler for APIC Error interrupt. Just print a warning and continue
2787ff178cJimmy Vetayases */
2797ff178cJimmy Vetayasesint
2807ff178cJimmy Vetayasesapic_error_intr()
2817ff178cJimmy Vetayases{
2827ff178cJimmy Vetayases	uint_t	error0, error1, error;
2837ff178cJimmy Vetayases	uint_t	i;
2847ff178cJimmy Vetayases
2857ff178cJimmy Vetayases	/*
2867ff178cJimmy Vetayases	 * We need to write before read as per 7.4.17 of system prog manual.
2877ff178cJimmy Vetayases	 * We do both and or the results to be safe
2887ff178cJimmy Vetayases	 */
2897ff178cJimmy Vetayases	error0 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
2907ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
2917ff178cJimmy Vetayases	error1 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
2927ff178cJimmy Vetayases	error = error0 | error1;
2937ff178cJimmy Vetayases
2947ff178cJimmy Vetayases	/*
2957ff178cJimmy Vetayases	 * Clear the APIC error status (do this on all cpus that enter here)
2967ff178cJimmy Vetayases	 * (two writes are required due to the semantics of accessing the
2977ff178cJimmy Vetayases	 * error status register.)
2987ff178cJimmy Vetayases	 */
2997ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
3007ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
3017ff178cJimmy Vetayases
3027ff178cJimmy Vetayases	/*
3037ff178cJimmy Vetayases	 * Prevent more than 1 CPU from handling error interrupt causing
3047ff178cJimmy Vetayases	 * double printing (interleave of characters from multiple
3057ff178cJimmy Vetayases	 * CPU's when using prom_printf)
3067ff178cJimmy Vetayases	 */
3077ff178cJimmy Vetayases	if (lock_try(&apic_error_lock) == 0)
3087ff178cJimmy Vetayases		return (error ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
3097ff178cJimmy Vetayases	if (error) {
3107ff178cJimmy Vetayases#if	DEBUG
3117ff178cJimmy Vetayases		if (apic_debug)
3127ff178cJimmy Vetayases			debug_enter("pcplusmp: APIC Error interrupt received");
3137ff178cJimmy Vetayases#endif /* DEBUG */
3147ff178cJimmy Vetayases		if (apic_panic_on_apic_error)
3157ff178cJimmy Vetayases			cmn_err(CE_PANIC,
3167ff178cJimmy Vetayases			    "APIC Error interrupt on CPU %d. Status = %x",
3177ff178cJimmy Vetayases			    psm_get_cpu_id(), error);
3187ff178cJimmy Vetayases		else {
3197ff178cJimmy Vetayases			if ((error & ~APIC_CS_ERRORS) == 0) {
3207ff178cJimmy Vetayases				/* cksum error only */
3217ff178cJimmy Vetayases				apic_error |= APIC_ERR_APIC_ERROR;
3227ff178cJimmy Vetayases				apic_apic_error |= error;
3237ff178cJimmy Vetayases				apic_num_apic_errors++;
3247ff178cJimmy Vetayases				apic_num_cksum_errors++;
3257ff178cJimmy Vetayases			} else {
3267ff178cJimmy Vetayases				/*
3277ff178cJimmy Vetayases				 * prom_printf is the best shot we have of
3287ff178cJimmy Vetayases				 * something which is problem free from
3297ff178cJimmy Vetayases				 * high level/NMI type of interrupts
3307ff178cJimmy Vetayases				 */
3317ff178cJimmy Vetayases				prom_printf("APIC Error interrupt on CPU %d. "
3327ff178cJimmy Vetayases				    "Status 0 = %x, Status 1 = %x\n",
3337ff178cJimmy Vetayases				    psm_get_cpu_id(), error0, error1);
3347ff178cJimmy Vetayases				apic_error |= APIC_ERR_APIC_ERROR;
3357ff178cJimmy Vetayases				apic_apic_error |= error;
3367ff178cJimmy Vetayases				apic_num_apic_errors++;
3377ff178cJimmy Vetayases				for (i = 0; i < apic_error_display_delay; i++) {
3387ff178cJimmy Vetayases					tenmicrosec();
3397ff178cJimmy Vetayases				}
3407ff178cJimmy Vetayases				/*
3417ff178cJimmy Vetayases				 * provide more delay next time limited to
3427ff178cJimmy Vetayases				 * roughly 1 clock tick time
3437ff178cJimmy Vetayases				 */
3447ff178cJimmy Vetayases				if (apic_error_display_delay < 500)
3457ff178cJimmy Vetayases					apic_error_display_delay *= 2;
3467ff178cJimmy Vetayases			}
3477ff178cJimmy Vetayases		}
3487ff178cJimmy Vetayases		lock_clear(&apic_error_lock);
3497ff178cJimmy Vetayases		return (DDI_INTR_CLAIMED);
3507ff178cJimmy Vetayases	} else {
3517ff178cJimmy Vetayases		lock_clear(&apic_error_lock);
3527ff178cJimmy Vetayases		return (DDI_INTR_UNCLAIMED);
3537ff178cJimmy Vetayases	}
3547ff178cJimmy Vetayases}
3557ff178cJimmy Vetayases
3567ff178cJimmy Vetayases/*
3577ff178cJimmy Vetayases * Turn off the mask bit in the performance counter Local Vector Table entry.
3587ff178cJimmy Vetayases */
3597ff178cJimmy Vetayasesvoid
3607ff178cJimmy Vetayasesapic_cpcovf_mask_clear(void)
3617ff178cJimmy Vetayases{
3627ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_PCINT_VECT,
3637ff178cJimmy Vetayases	    (apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK));
3647ff178cJimmy Vetayases}
3657ff178cJimmy Vetayases
3667ff178cJimmy Vetayasesstatic int
367d1f3e3cToomas Soomeapic_cmci_enable(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
368d1f3e3cToomas Soome    xc_arg_t arg3 __unused)
3697ff178cJimmy Vetayases{
3707ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect);
3717ff178cJimmy Vetayases	return (0);
3727ff178cJimmy Vetayases}
3737ff178cJimmy Vetayases
3747ff178cJimmy Vetayasesstatic int
375d1f3e3cToomas Soomeapic_cmci_disable(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
376d1f3e3cToomas Soome    xc_arg_t arg3 __unused)
3777ff178cJimmy Vetayases{
3787ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK);
3797ff178cJimmy Vetayases	return (0);
3807ff178cJimmy Vetayases}
3817ff178cJimmy Vetayases
382918e0d9Robert Mustacchivoid
383918e0d9Robert Mustacchiapic_cmci_setup(processorid_t cpuid, boolean_t enable)
3847ff178cJimmy Vetayases{
3857ff178cJimmy Vetayases	cpuset_t	cpu_set;
3867ff178cJimmy Vetayases
3877ff178cJimmy Vetayases	CPUSET_ONLY(cpu_set, cpuid);
3887ff178cJimmy Vetayases
389918e0d9Robert Mustacchi	if (enable) {
3905ffc253Toomas Soome		xc_call(0, 0, 0, CPUSET2BV(cpu_set),
391918e0d9Robert Mustacchi		    (xc_func_t)apic_cmci_enable);
392918e0d9Robert Mustacchi	} else {
3935ffc253Toomas Soome		xc_call(0, 0, 0, CPUSET2BV(cpu_set),
394918e0d9Robert Mustacchi		    (xc_func_t)apic_cmci_disable);
3957ff178cJimmy Vetayases	}
3967ff178cJimmy Vetayases}
3977ff178cJimmy Vetayases
3987ff178cJimmy Vetayasesstatic void
3997ff178cJimmy Vetayasesapic_disable_local_apic(void)
4007ff178cJimmy Vetayases{
4017ff178cJimmy Vetayases	apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL);
4027ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK);
4037ff178cJimmy Vetayases
4047ff178cJimmy Vetayases	/* local intr reg 0 */
4057ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK);
4067ff178cJimmy Vetayases
4077ff178cJimmy Vetayases	/* disable NMI */
4087ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_INT_VECT1, AV_MASK);
4097ff178cJimmy Vetayases
4107ff178cJimmy Vetayases	/* and error interrupt */
4117ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_ERR_VECT, AV_MASK);
4127ff178cJimmy Vetayases
4137ff178cJimmy Vetayases	/* and perf counter intr */
4147ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_PCINT_VECT, AV_MASK);
4157ff178cJimmy Vetayases
4167ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_SPUR_INT_REG, APIC_SPUR_INTR);
4177ff178cJimmy Vetayases}
4187ff178cJimmy Vetayases
4197ff178cJimmy Vetayasesstatic void
4207ff178cJimmy Vetayasesapic_cpu_send_SIPI(processorid_t cpun, boolean_t start)
4217ff178cJimmy Vetayases{
4227ff178cJimmy Vetayases	int		loop_count;
4237ff178cJimmy Vetayases	uint32_t	vector;
4247ff178cJimmy Vetayases	uint_t		apicid;
4257ff178cJimmy Vetayases	ulong_t		iflag;
4267ff178cJimmy Vetayases
4277ff178cJimmy Vetayases	apicid =  apic_cpus[cpun].aci_local_id;
4287ff178cJimmy Vetayases
4297ff178cJimmy Vetayases	/*
4307ff178cJimmy Vetayases	 * Interrupts on current CPU will be disabled during the
4317ff178cJimmy Vetayases	 * steps in order to avoid unwanted side effects from
4327ff178cJimmy Vetayases	 * executing interrupt handlers on a problematic BIOS.
4337ff178cJimmy Vetayases	 */
4347ff178cJimmy Vetayases	iflag = intr_clear();
4357ff178cJimmy Vetayases
4367ff178cJimmy Vetayases	if (start) {
4377ff178cJimmy Vetayases		outb(CMOS_ADDR, SSB);
4387ff178cJimmy Vetayases		outb(CMOS_DATA, BIOS_SHUTDOWN);
4397ff178cJimmy Vetayases	}
4407ff178cJimmy Vetayases
4417ff178cJimmy Vetayases	/*
4427ff178cJimmy Vetayases	 * According to X2APIC specification in section '' of
4437ff178cJimmy Vetayases	 * Interrupt Command Register Semantics, the semantics of
4447ff178cJimmy Vetayases	 * programming the Interrupt Command Register to dispatch an interrupt
4457ff178cJimmy Vetayases	 * is simplified. A single MSR write to the 64-bit ICR is required
4467ff178cJimmy Vetayases	 * for dispatching an interrupt. Specifically, with the 64-bit MSR
4477ff178cJimmy Vetayases	 * interface to ICR, system software is not required to check the
4487ff178cJimmy Vetayases	 * status of the delivery status bit prior to writing to the ICR
4497ff178cJimmy Vetayases	 * to send an IPI. With the removal of the Delivery Status bit,
4507ff178cJimmy Vetayases	 * system software no longer has a reason to read the ICR. It remains
4517ff178cJimmy Vetayases	 * readable only to aid in debugging.
4527ff178cJimmy Vetayases	 */
4537ff178cJimmy Vetayases#ifdef	DEBUG
4547ff178cJimmy Vetayases	APIC_AV_PENDING_SET();
4557ff178cJimmy Vetayases#else
4567ff178cJimmy Vetayases	if (apic_mode == LOCAL_APIC) {
4577ff178cJimmy Vetayases		APIC_AV_PENDING_SET();
4587ff178cJimmy Vetayases	}
4597ff178cJimmy Vetayases#endif /* DEBUG */
4607ff178cJimmy Vetayases
4617ff178cJimmy Vetayases	/* for integrated - make sure there is one INIT IPI in buffer */
4627ff178cJimmy Vetayases	/* for external - it will wake up the cpu */
4637ff178cJimmy Vetayases	apic_reg_ops->apic_write_int_cmd(apicid, AV_ASSERT | AV_RESET);
4647ff178cJimmy Vetayases
4657ff178cJimmy Vetayases	/* If only 1 CPU is installed, PENDING bit will not go low */
4667ff178cJimmy Vetayases	for (loop_count = apic_sipi_max_loop_count; loop_count; loop_count--) {
4677ff178cJimmy Vetayases		if (apic_mode == LOCAL_APIC &&
4687ff178cJimmy Vetayases		    apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING)
4697ff178cJimmy Vetayases			apic_ret();
4707ff178cJimmy Vetayases		else
4717ff178cJimmy Vetayases			break;
4727ff178cJimmy Vetayases	}
4737ff178cJimmy Vetayases
4747ff178cJimmy Vetayases	apic_reg_ops->apic_write_int_cmd(apicid, AV_DEASSERT | AV_RESET);
4757ff178cJimmy Vetayases	drv_usecwait(20000);		/* 20 milli sec */
4767ff178cJimmy Vetayases
4777ff178cJimmy Vetayases	if (apic_cpus[cpun].aci_local_ver >= APIC_INTEGRATED_VERS) {
4787ff178cJimmy Vetayases		/* integrated apic */
4797ff178cJimmy Vetayases
4807ff178cJimmy Vetayases		vector = (rm_platter_pa >> MMU_PAGESHIFT) &
4817ff178cJimmy Vetayases		    (APIC_VECTOR_MASK | APIC_IPL_MASK);
4827ff178cJimmy Vetayases
4837ff178cJimmy Vetayases		/* to offset the INIT IPI queue up in the buffer */
4847ff178cJimmy Vetayases		apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
4857ff178cJimmy Vetayases		drv_usecwait(200);		/* 20 micro sec */
4867ff178cJimmy Vetayases
4877ff178cJimmy Vetayases		/*
4887ff178cJimmy Vetayases		 * send the second SIPI (Startup IPI) as recommended by Intel
4897ff178cJimmy Vetayases		 * software development manual.
4907ff178cJimmy Vetayases		 */
4917ff178cJimmy Vetayases		apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
4927ff178cJimmy Vetayases		drv_usecwait(200);	/* 20 micro sec */
4937ff178cJimmy Vetayases	}
4947ff178cJimmy Vetayases
4957ff178cJimmy Vetayases	intr_restore(iflag);
4967ff178cJimmy Vetayases}
4977ff178cJimmy Vetayases
4987ff178cJimmy Vetayases/*ARGSUSED1*/
4997ff178cJimmy Vetayasesint
500d1f3e3cToomas Soomeapic_cpu_start(processorid_t cpun, caddr_t arg __unused)
5017ff178cJimmy Vetayases{
5027ff178cJimmy Vetayases	ASSERT(MUTEX_HELD(&cpu_lock));
5037ff178cJimmy Vetayases
5047ff178cJimmy Vetayases	if (!apic_cpu_in_range(cpun)) {
5057ff178cJimmy Vetayases		return (EINVAL);
5067ff178cJimmy Vetayases	}
5077ff178cJimmy Vetayases
5087ff178cJimmy Vetayases	/*
5097ff178cJimmy Vetayases	 * Switch to apic_common_send_ipi for safety during starting other CPUs.
5107ff178cJimmy Vetayases	 */
5117ff178cJimmy Vetayases	if (apic_mode == LOCAL_X2APIC) {
5127ff178cJimmy Vetayases		apic_switch_ipi_callback(B_TRUE);
5137ff178cJimmy Vetayases	}
5147ff178cJimmy Vetayases
5157ff178cJimmy Vetayases	apic_cmos_ssb_set = 1;
5167ff178cJimmy Vetayases	apic_cpu_send_SIPI(cpun, B_TRUE);
5177ff178cJimmy Vetayases
5187ff178cJimmy Vetayases	return (0);
5197ff178cJimmy Vetayases}
5207ff178cJimmy Vetayases
5217ff178cJimmy Vetayases/*
5227ff178cJimmy Vetayases * Put CPU into halted state with interrupts disabled.
5237ff178cJimmy Vetayases */
5247ff178cJimmy Vetayases/*ARGSUSED1*/
5257ff178cJimmy Vetayasesint
526d1f3e3cToomas Soomeapic_cpu_stop(processorid_t cpun, caddr_t arg __unused)
5277ff178cJimmy Vetayases{
5287ff178cJimmy Vetayases	int		rc;
52958b4950Hans Rosenfeld	cpu_t		*cp;
5307ff178cJimmy Vetayases	extern cpuset_t cpu_ready_set;
5317ff178cJimmy Vetayases	extern void cpu_idle_intercept_cpu(cpu_t *cp);
5327ff178cJimmy Vetayases
5337ff178cJimmy Vetayases	ASSERT(MUTEX_HELD(&cpu_lock));
5347ff178cJimmy Vetayases
5357ff178cJimmy Vetayases	if (!apic_cpu_in_range(cpun)) {
5367ff178cJimmy Vetayases		return (EINVAL);
5377ff178cJimmy Vetayases	}
5387ff178cJimmy Vetayases	if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) {
5397ff178cJimmy Vetayases		return (ENOTSUP);
5407ff178cJimmy Vetayases	}
5417ff178cJimmy Vetayases
5427ff178cJimmy Vetayases	cp = cpu_get(cpun);
5437ff178cJimmy Vetayases	ASSERT(cp != NULL);
5447ff178cJimmy Vetayases	ASSERT((cp->cpu_flags & CPU_OFFLINE) != 0);
5457ff178cJimmy Vetayases	ASSERT((cp->cpu_flags & CPU_QUIESCED) != 0);
5467ff178cJimmy Vetayases	ASSERT((cp->cpu_flags & CPU_ENABLE) == 0);
5477ff178cJimmy Vetayases
5487ff178cJimmy Vetayases	/* Clear CPU_READY flag to disable cross calls. */
5497ff178cJimmy Vetayases	cp->cpu_flags &= ~CPU_READY;
5507ff178cJimmy Vetayases	CPUSET_ATOMIC_DEL(cpu_ready_set, cpun);
5517ff178cJimmy Vetayases	rc = xc_flush_cpu(cp);
5527ff178cJimmy Vetayases	if (rc != 0) {
5537ff178cJimmy Vetayases		CPUSET_ATOMIC_ADD(cpu_ready_set, cpun);
5547ff178cJimmy Vetayases		cp->cpu_flags |= CPU_READY;
5557ff178cJimmy Vetayases		return (rc);
5567ff178cJimmy Vetayases	}
5577ff178cJimmy Vetayases
5587ff178cJimmy Vetayases	/* Intercept target CPU at a safe point before powering it off. */
5597ff178cJimmy Vetayases	cpu_idle_intercept_cpu(cp);
5607ff178cJimmy Vetayases
5617ff178cJimmy Vetayases	apic_cpu_send_SIPI(cpun, B_FALSE);
5627ff178cJimmy Vetayases	cp->cpu_flags &= ~CPU_RUNNING;
5637ff178cJimmy Vetayases
5647ff178cJimmy Vetayases	return (0);
5657ff178cJimmy Vetayases}
5667ff178cJimmy Vetayases
5677ff178cJimmy Vetayasesint
5687ff178cJimmy Vetayasesapic_cpu_ops(psm_cpu_request_t *reqp)
5697ff178cJimmy Vetayases{
5707ff178cJimmy Vetayases	if (reqp == NULL) {
5717ff178cJimmy Vetayases		return (EINVAL);
5727ff178cJimmy Vetayases	}
5737ff178cJimmy Vetayases