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 */
257ff178cJimmy Vetayases/*
267ff178cJimmy Vetayases * Copyright (c) 2010, Intel Corporation.
277ff178cJimmy Vetayases * All rights reserved.
281c2d047Patrick Mooney * Copyright 2018 Joyent, Inc.
29636dfb4Jerry Jelinek */
30636dfb4Jerry Jelinek
31636dfb4Jerry Jelinek/*
32636dfb4Jerry Jelinek * To understand how the apix module interacts with the interrupt subsystem read
33636dfb4Jerry Jelinek * the theory statement in uts/i86pc/os/intr.c.
34636dfb4Jerry Jelinek */
357ff178cJimmy Vetayases
367ff178cJimmy Vetayases/*
377ff178cJimmy Vetayases * PSMI 1.1 extensions are supported only in 2.6 and later versions.
387ff178cJimmy Vetayases * PSMI 1.2 extensions are supported only in 2.7 and later versions.
397ff178cJimmy Vetayases * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
407ff178cJimmy Vetayases * PSMI 1.5 extensions are supported in Solaris Nevada.
417ff178cJimmy Vetayases * PSMI 1.6 extensions are supported in Solaris Nevada.
427ff178cJimmy Vetayases * PSMI 1.7 extensions are supported in Solaris Nevada.
437ff178cJimmy Vetayases */
447ff178cJimmy Vetayases#define	PSMI_1_7
457ff178cJimmy Vetayases
467ff178cJimmy Vetayases#include <sys/processor.h>
477ff178cJimmy Vetayases#include <sys/time.h>
487ff178cJimmy Vetayases#include <sys/psm.h>
497ff178cJimmy Vetayases#include <sys/smp_impldefs.h>
507ff178cJimmy Vetayases#include <sys/cram.h>
517ff178cJimmy Vetayases#include <sys/acpi/acpi.h>
527ff178cJimmy Vetayases#include <sys/acpica.h>
537ff178cJimmy Vetayases#include <sys/psm_common.h>
547ff178cJimmy Vetayases#include <sys/pit.h>
557ff178cJimmy Vetayases#include <sys/ddi.h>
567ff178cJimmy Vetayases#include <sys/sunddi.h>
577ff178cJimmy Vetayases#include <sys/ddi_impldefs.h>
587ff178cJimmy Vetayases#include <sys/pci.h>
597ff178cJimmy Vetayases#include <sys/promif.h>
607ff178cJimmy Vetayases#include <sys/x86_archext.h>
617ff178cJimmy Vetayases#include <sys/cpc_impl.h>
627ff178cJimmy Vetayases#include <sys/uadmin.h>
637ff178cJimmy Vetayases#include <sys/panic.h>
647ff178cJimmy Vetayases#include <sys/debug.h>
657ff178cJimmy Vetayases#include <sys/archsystm.h>
667ff178cJimmy Vetayases#include <sys/trap.h>
677ff178cJimmy Vetayases#include <sys/machsystm.h>
687ff178cJimmy Vetayases#include <sys/sysmacros.h>
697ff178cJimmy Vetayases#include <sys/cpuvar.h>
707ff178cJimmy Vetayases#include <sys/rm_platter.h>
717ff178cJimmy Vetayases#include <sys/privregs.h>
727ff178cJimmy Vetayases#include <sys/note.h>
737ff178cJimmy Vetayases#include <sys/pci_intr_lib.h>
747ff178cJimmy Vetayases#include <sys/spl.h>
757ff178cJimmy Vetayases#include <sys/clock.h>
76a288e5aJoshua M. Clulow#include <sys/cyclic.h>
777ff178cJimmy Vetayases#include <sys/dditypes.h>
787ff178cJimmy Vetayases#include <sys/sunddi.h>
797ff178cJimmy Vetayases#include <sys/x_call.h>
807ff178cJimmy Vetayases#include <sys/reboot.h>
817ff178cJimmy Vetayases#include <sys/mach_intr.h>
827ff178cJimmy Vetayases#include <sys/apix.h>
837ff178cJimmy Vetayases#include <sys/apix_irm_impl.h>
847ff178cJimmy Vetayases
857ff178cJimmy Vetayasesstatic int apix_probe();
867ff178cJimmy Vetayasesstatic void apix_init();
877ff178cJimmy Vetayasesstatic void apix_picinit(void);
887ff178cJimmy Vetayasesstatic int apix_intr_enter(int, int *);
897ff178cJimmy Vetayasesstatic void apix_intr_exit(int, int);
907ff178cJimmy Vetayasesstatic void apix_setspl(int);
917ff178cJimmy Vetayasesstatic int apix_disable_intr(processorid_t);
927ff178cJimmy Vetayasesstatic void apix_enable_intr(processorid_t);
937ff178cJimmy Vetayasesstatic int apix_get_clkvect(int);
947ff178cJimmy Vetayasesstatic int apix_get_ipivect(int, int);
957ff178cJimmy Vetayasesstatic void apix_post_cyclic_setup(void *);
967ff178cJimmy Vetayasesstatic int apix_post_cpu_start();
977ff178cJimmy Vetayasesstatic int apix_intr_ops(dev_info_t *, ddi_intr_handle_impl_t *,
987ff178cJimmy Vetayases    psm_intr_op_t, int *);
997ff178cJimmy Vetayases
1007ff178cJimmy Vetayases/*
1017ff178cJimmy Vetayases * Helper functions for apix_intr_ops()
1027ff178cJimmy Vetayases */
1037ff178cJimmy Vetayasesstatic void apix_redistribute_compute(void);
1047ff178cJimmy Vetayasesstatic int apix_get_pending(apix_vector_t *);
1057ff178cJimmy Vetayasesstatic apix_vector_t *apix_get_req_vector(ddi_intr_handle_impl_t *, ushort_t);
1067ff178cJimmy Vetayasesstatic int apix_get_intr_info(ddi_intr_handle_impl_t *, apic_get_intr_t *);
1077ff178cJimmy Vetayasesstatic char *apix_get_apic_type(void);
1087ff178cJimmy Vetayasesstatic int apix_intx_get_pending(int);
1097ff178cJimmy Vetayasesstatic void apix_intx_set_mask(int irqno);
1107ff178cJimmy Vetayasesstatic void apix_intx_clear_mask(int irqno);
1117ff178cJimmy Vetayasesstatic int apix_intx_get_shared(int irqno);
1127ff178cJimmy Vetayasesstatic void apix_intx_set_shared(int irqno, int delta);
1137ff178cJimmy Vetayasesstatic apix_vector_t *apix_intx_xlate_vector(dev_info_t *, int,
1147ff178cJimmy Vetayases    struct intrspec *);
1157ff178cJimmy Vetayasesstatic int apix_intx_alloc_vector(dev_info_t *, int, struct intrspec *);
1167ff178cJimmy Vetayases
1177ff178cJimmy Vetayasesextern int apic_clkinit(int);
1187ff178cJimmy Vetayases
1197ff178cJimmy Vetayases/* IRM initialization for APIX PSM module */
1207ff178cJimmy Vetayasesextern void apix_irm_init(void);
1217ff178cJimmy Vetayases
1227ff178cJimmy Vetayasesextern int irm_enable;
1237ff178cJimmy Vetayases
1247ff178cJimmy Vetayases/*
1257ff178cJimmy Vetayases *	Local static data
1267ff178cJimmy Vetayases */
1277ff178cJimmy Vetayasesstatic struct	psm_ops apix_ops = {
1287ff178cJimmy Vetayases	apix_probe,
1297ff178cJimmy Vetayases
1307ff178cJimmy Vetayases	apix_init,
1317ff178cJimmy Vetayases	apix_picinit,
1327ff178cJimmy Vetayases	apix_intr_enter,
1337ff178cJimmy Vetayases	apix_intr_exit,
1347ff178cJimmy Vetayases	apix_setspl,
1357ff178cJimmy Vetayases	apix_addspl,
1367ff178cJimmy Vetayases	apix_delspl,
1377ff178cJimmy Vetayases	apix_disable_intr,
1387ff178cJimmy Vetayases	apix_enable_intr,
1397ff178cJimmy Vetayases	NULL,			/* psm_softlvl_to_irq */
1407ff178cJimmy Vetayases	NULL,			/* psm_set_softintr */
1417ff178cJimmy Vetayases
1427ff178cJimmy Vetayases	apic_set_idlecpu,
1437ff178cJimmy Vetayases	apic_unset_idlecpu,
1447ff178cJimmy Vetayases
1457ff178cJimmy Vetayases	apic_clkinit,
1467ff178cJimmy Vetayases	apix_get_clkvect,
1477ff178cJimmy Vetayases	NULL,			/* psm_hrtimeinit */
1487ff178cJimmy Vetayases	apic_gethrtime,
1497ff178cJimmy Vetayases
1507ff178cJimmy Vetayases	apic_get_next_processorid,
1517ff178cJimmy Vetayases	apic_cpu_start,
1527ff178cJimmy Vetayases	apix_post_cpu_start,
1537ff178cJimmy Vetayases	apic_shutdown,
1547ff178cJimmy Vetayases	apix_get_ipivect,
1557ff178cJimmy Vetayases	apic_send_ipi,
1567ff178cJimmy Vetayases
1577ff178cJimmy Vetayases	NULL,			/* psm_translate_irq */
1587ff178cJimmy Vetayases	NULL,			/* psm_notify_error */
1597ff178cJimmy Vetayases	NULL,			/* psm_notify_func */
1607ff178cJimmy Vetayases	apic_timer_reprogram,
1617ff178cJimmy Vetayases	apic_timer_enable,
1627ff178cJimmy Vetayases	apic_timer_disable,
1637ff178cJimmy Vetayases	apix_post_cyclic_setup,
1647ff178cJimmy Vetayases	apic_preshutdown,
1657ff178cJimmy Vetayases	apix_intr_ops,		/* Advanced DDI Interrupt framework */
1667ff178cJimmy Vetayases	apic_state,		/* save, restore apic state for S3 */
1677ff178cJimmy Vetayases	apic_cpu_ops,		/* CPU control interface. */
1681c2d047Patrick Mooney
1691c2d047Patrick Mooney	apic_get_pir_ipivect,
1701c2d047Patrick Mooney	apic_send_pir_ipi,
171918e0d9Robert Mustacchi	apic_cmci_setup
1727ff178cJimmy Vetayases};
1737ff178cJimmy Vetayases
1747ff178cJimmy Vetayasesstruct psm_ops *psmops = &apix_ops;
1757ff178cJimmy Vetayases
1767ff178cJimmy Vetayasesstatic struct	psm_info apix_psm_info = {
1777ff178cJimmy Vetayases	PSM_INFO_VER01_7,			/* version */
1787ff178cJimmy Vetayases	PSM_OWN_EXCLUSIVE,			/* ownership */
1797ff178cJimmy Vetayases	&apix_ops,				/* operation */
1807ff178cJimmy Vetayases	APIX_NAME,				/* machine name */
1817ff178cJimmy Vetayases	"apix MPv1.4 compatible",
1827ff178cJimmy Vetayases};
1837ff178cJimmy Vetayases
1847ff178cJimmy Vetayasesstatic void *apix_hdlp;
1857ff178cJimmy Vetayases
1867ff178cJimmy Vetayasesstatic int apix_is_enabled = 0;
1877ff178cJimmy Vetayases
1887ff178cJimmy Vetayases/*
1897ff178cJimmy Vetayases * apix_lock is used for cpu selection and vector re-binding
1907ff178cJimmy Vetayases */
1917ff178cJimmy Vetayaseslock_t apix_lock;
1927ff178cJimmy Vetayasesapix_impl_t *apixs[NCPU];
1937ff178cJimmy Vetayases/*
1947ff178cJimmy Vetayases * Mapping between device interrupt and the allocated vector. Indexed
1957ff178cJimmy Vetayases * by major number.
1967ff178cJimmy Vetayases */
1977ff178cJimmy Vetayasesapix_dev_vector_t **apix_dev_vector;
1987ff178cJimmy Vetayases/*
1997ff178cJimmy Vetayases * Mapping between device major number and cpu id. It gets used
2007ff178cJimmy Vetayases * when interrupt binding policy round robin with affinity is
2017ff178cJimmy Vetayases * applied. With that policy, devices with the same major number
2027ff178cJimmy Vetayases * will be bound to the same CPU.
2037ff178cJimmy Vetayases */
2047ff178cJimmy Vetayasesprocessorid_t *apix_major_to_cpu;	/* major to cpu mapping */
2057ff178cJimmy Vetayaseskmutex_t apix_mutex;	/* for apix_dev_vector & apix_major_to_cpu */
2067ff178cJimmy Vetayases
2077ff178cJimmy Vetayasesint apix_nipis = 16;	/* Maximum number of IPIs */
2087ff178cJimmy Vetayases/*
2097ff178cJimmy Vetayases * Maximum number of vectors in a CPU that can be used for interrupt
2107ff178cJimmy Vetayases * allocation (including IPIs and the reserved vectors).
2117ff178cJimmy Vetayases */
2127ff178cJimmy Vetayasesint apix_cpu_nvectors = APIX_NVECTOR;
2137ff178cJimmy Vetayases
214583cd33Hans Rosenfeld/* number of CPUs in power-on transition state */
215583cd33Hans Rosenfeldstatic int apic_poweron_cnt = 0;
216583cd33Hans Rosenfeld
2177ff178cJimmy Vetayases/* gcpu.h */
2187ff178cJimmy Vetayases
2197ff178cJimmy Vetayasesextern void apic_do_interrupt(struct regs *rp, trap_trace_rec_t *ttp);
2207ff178cJimmy Vetayasesextern void apic_change_eoi();
2217ff178cJimmy Vetayases
2227ff178cJimmy Vetayases/*
2237ff178cJimmy Vetayases *	This is the loadable module wrapper
2247ff178cJimmy Vetayases */
2257ff178cJimmy Vetayases
2267ff178cJimmy Vetayasesint
2277ff178cJimmy Vetayases_init(void)
2287ff178cJimmy Vetayases{
2297ff178cJimmy Vetayases	if (apic_coarse_hrtime)
2307ff178cJimmy Vetayases		apix_ops.psm_gethrtime = &apic_gettime;
2317ff178cJimmy Vetayases	return (psm_mod_init(&apix_hdlp, &apix_psm_info));
2327ff178cJimmy Vetayases}
2337ff178cJimmy Vetayases
2347ff178cJimmy Vetayasesint
2357ff178cJimmy Vetayases_fini(void)
2367ff178cJimmy Vetayases{
2377ff178cJimmy Vetayases	return (psm_mod_fini(&apix_hdlp, &apix_psm_info));
2387ff178cJimmy Vetayases}
2397ff178cJimmy Vetayases
2407ff178cJimmy Vetayasesint
2417ff178cJimmy Vetayases_info(struct modinfo *modinfop)
2427ff178cJimmy Vetayases{
2437ff178cJimmy Vetayases	return (psm_mod_info(&apix_hdlp, &apix_psm_info, modinfop));
2447ff178cJimmy Vetayases}
2457ff178cJimmy Vetayases
2467ff178cJimmy Vetayasesstatic int
2477ff178cJimmy Vetayasesapix_probe()
2487ff178cJimmy Vetayases{
2497ff178cJimmy Vetayases	int rval;
2507ff178cJimmy Vetayases
2517ff178cJimmy Vetayases	if (apix_enable == 0)
2527ff178cJimmy Vetayases		return (PSM_FAILURE);
2537ff178cJimmy Vetayases
25415f8fb3Yuri Pankov	/*
25515f8fb3Yuri Pankov	 * FIXME Temporarily disable apix module on Xen HVM platform due to
25615f8fb3Yuri Pankov	 * known hang during boot (see #3605).
25715f8fb3Yuri Pankov	 *
25815f8fb3Yuri Pankov	 * Please remove when/if the issue is resolved.
25915f8fb3Yuri Pankov	 */
2600f8051aYuri Pankov	if (get_hwenv() & HW_XEN_HVM)
26115f8fb3Yuri Pankov		return (PSM_FAILURE);
26215f8fb3Yuri Pankov
263eee1786Robert Mustacchi	if (apic_local_mode() == LOCAL_X2APIC) {
264eee1786Robert Mustacchi		/* x2APIC mode activated by BIOS, switch ops */
265eee1786Robert Mustacchi		apic_mode = LOCAL_X2APIC;
266eee1786Robert Mustacchi		apic_change_ops();
2677ff178cJimmy Vetayases	}
2687ff178cJimmy Vetayases
2697ff178cJimmy Vetayases	rval = apic_probe_common(apix_psm_info.p_mach_idstring);
2707ff178cJimmy Vetayases	if (rval == PSM_SUCCESS)
2717ff178cJimmy Vetayases		apix_is_enabled = 1;
2727ff178cJimmy Vetayases	else
2737ff178cJimmy Vetayases		apix_is_enabled = 0;
2747ff178cJimmy Vetayases	return (rval);
2757ff178cJimmy Vetayases}
2767ff178cJimmy Vetayases
2777ff178cJimmy Vetayases/*
2787ff178cJimmy Vetayases * Initialize the data structures needed by pcplusmpx module.
2797ff178cJimmy Vetayases * Specifically, the data structures used by addspl() and delspl()
2807ff178cJimmy Vetayases * routines.
2817ff178cJimmy Vetayases */
2827ff178cJimmy Vetayasesstatic void
2837ff178cJimmy Vetayasesapix_softinit()
2847ff178cJimmy Vetayases{
2857ff178cJimmy Vetayases	int i, *iptr;
2867ff178cJimmy Vetayases	apix_impl_t *hdlp;
2877ff178cJimmy Vetayases	int nproc;
2887ff178cJimmy Vetayases
2897ff178cJimmy Vetayases	nproc = max(apic_nproc, apic_max_nproc);
2907ff178cJimmy Vetayases
2917ff178cJimmy Vetayases	hdlp = kmem_zalloc(nproc * sizeof (apix_impl_t), KM_SLEEP);
2927ff178cJimmy Vetayases	for (i = 0; i < nproc; i++) {
2937ff178cJimmy Vetayases		apixs[i] = &hdlp[i];
2947ff178cJimmy Vetayases		apixs[i]->x_cpuid = i;
2957ff178cJimmy Vetayases		LOCK_INIT_CLEAR(&apixs[i]->x_lock);
2967ff178cJimmy Vetayases	}
2977ff178cJimmy Vetayases
2987ff178cJimmy Vetayases	/* cpu 0 is always up (for now) */
2997ff178cJimmy Vetayases	apic_cpus[0].aci_status = APIC_CPU_ONLINE | APIC_CPU_INTR_ENABLE;
3007ff178cJimmy Vetayases
3017ff178cJimmy Vetayases	iptr = (int *)&apic_irq_table[0];
3027ff178cJimmy Vetayases	for (i = 0; i <= APIC_MAX_VECTOR; i++) {
3037ff178cJimmy Vetayases		apic_level_intr[i] = 0;
3045ffc253Toomas Soome		*iptr++ = 0;
3057ff178cJimmy Vetayases	}
3067ff178cJimmy Vetayases	mutex_init(&airq_mutex, NULL, MUTEX_DEFAULT, NULL);
3077ff178cJimmy Vetayases
3087ff178cJimmy Vetayases	apix_dev_vector = kmem_zalloc(sizeof (apix_dev_vector_t *) * devcnt,
3097ff178cJimmy Vetayases	    KM_SLEEP);
3107ff178cJimmy Vetayases
3117ff178cJimmy Vetayases	if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) {
3127ff178cJimmy Vetayases		apix_major_to_cpu = kmem_zalloc(sizeof (int) * devcnt,
3137ff178cJimmy Vetayases		    KM_SLEEP);
3147ff178cJimmy Vetayases		for (i = 0; i < devcnt; i++)
3157ff178cJimmy Vetayases			apix_major_to_cpu[i] = IRQ_UNINIT;
3167ff178cJimmy Vetayases	}
3177ff178cJimmy Vetayases
3187ff178cJimmy Vetayases	mutex_init(&apix_mutex, NULL, MUTEX_DEFAULT, NULL);
3197ff178cJimmy Vetayases}
3207ff178cJimmy Vetayases
3217ff178cJimmy Vetayasesstatic int
3227ff178cJimmy Vetayasesapix_get_pending_spl(void)
3237ff178cJimmy Vetayases{
3247ff178cJimmy Vetayases	int cpuid = CPU->cpu_id;
3257ff178cJimmy Vetayases
3267ff178cJimmy Vetayases	return (bsrw_insn(apixs[cpuid]->x_intr_pending));
3277ff178cJimmy Vetayases}
3287ff178cJimmy Vetayases
3297ff178cJimmy Vetayasesstatic uintptr_t
3307ff178cJimmy Vetayasesapix_get_intr_handler(int cpu, short vec)
3317ff178cJimmy Vetayases{
3327ff178cJimmy Vetayases	apix_vector_t *apix_vector;
3337ff178cJimmy Vetayases
3347ff178cJimmy Vetayases	ASSERT(cpu < apic_nproc && vec < APIX_NVECTOR);
3356272273Hans Rosenfeld	if (cpu >= apic_nproc || vec >= APIX_NVECTOR)
3365ffc253Toomas Soome		return (0);
3377ff178cJimmy Vetayases
3387ff178cJimmy Vetayases	apix_vector = apixs[cpu]->x_vectbl[vec];
3397ff178cJimmy Vetayases
3407ff178cJimmy Vetayases	return ((uintptr_t)(apix_vector->v_autovect));
3417ff178cJimmy Vetayases}
3427ff178cJimmy Vetayases
3437ff178cJimmy Vetayasesstatic void
3447ff178cJimmy Vetayasesapix_init()
3457ff178cJimmy Vetayases{
3467ff178cJimmy Vetayases	extern void (*do_interrupt_common)(struct regs *, trap_trace_rec_t *);
3477ff178cJimmy Vetayases
3487ff178cJimmy Vetayases	APIC_VERBOSE(INIT, (CE_CONT, "apix: psm_softinit\n"));
3497ff178cJimmy Vetayases
3507ff178cJimmy Vetayases	do_interrupt_common = apix_do_interrupt;
3517ff178cJimmy Vetayases	addintr = apix_add_avintr;
3527ff178cJimmy Vetayases	remintr = apix_rem_avintr;
3537ff178cJimmy Vetayases	get_pending_spl = apix_get_pending_spl;
3547ff178cJimmy Vetayases	get_intr_handler = apix_get_intr_handler;
3557ff178cJimmy Vetayases	psm_get_localapicid = apic_get_localapicid;
3567ff178cJimmy Vetayases	psm_get_ioapicid = apic_get_ioapicid;
3577ff178cJimmy Vetayases
3587ff178cJimmy Vetayases	apix_softinit();
35932842aaJosef 'Jeff' Sipek
36032842aaJosef 'Jeff' Sipek#if !defined(__amd64)
3617ff178cJimmy Vetayases	if (cpuid_have_cr8access(CPU))
3627ff178cJimmy Vetayases		apic_have_32bit_cr8 = 1;
36332842aaJosef 'Jeff' Sipek#endif
3647ff178cJimmy Vetayases
3651c2d047Patrick Mooney	apic_pir_vect = apix_get_ipivect(XC_CPUPOKE_PIL, -1);
3661c2d047Patrick Mooney
3677ff178cJimmy Vetayases	/*
3687ff178cJimmy Vetayases	 * Initialize IRM pool parameters
3697ff178cJimmy Vetayases	 */
3707ff178cJimmy Vetayases	if (irm_enable) {
3717ff178cJimmy Vetayases		int	i;
3727ff178cJimmy Vetayases		int	lowest_irq;
3737ff178cJimmy Vetayases		int	highest_irq;
3747ff178cJimmy Vetayases
3757ff178cJimmy Vetayases		/* number of CPUs present */
3767ff178cJimmy Vetayases		apix_irminfo.apix_ncpus = apic_nproc;
3777ff178cJimmy Vetayases		/* total number of entries in all of the IOAPICs present */
3787ff178cJimmy Vetayases		lowest_irq = apic_io_vectbase[0];
3797ff178cJimmy Vetayases		highest_irq = apic_io_vectend[0];
3807ff178cJimmy Vetayases		for (i = 1; i < apic_io_max; i++) {
3817ff178cJimmy Vetayases			if (apic_io_vectbase[i] < lowest_irq)
3827ff178cJimmy Vetayases				lowest_irq = apic_io_vectbase[i];
3837ff178cJimmy Vetayases			if (apic_io_vectend[i] > highest_irq)
3847ff178cJimmy Vetayases				highest_irq = apic_io_vectend[i];
3857ff178cJimmy Vetayases		}
3867ff178cJimmy Vetayases		apix_irminfo.apix_ioapic_max_vectors =
3877ff178cJimmy Vetayases		    highest_irq - lowest_irq + 1;
3887ff178cJimmy Vetayases		/*
3897ff178cJimmy Vetayases		 * Number of available per-CPU vectors excluding
3907ff178cJimmy Vetayases		 * reserved vectors for Dtrace, int80, system-call,
3917ff178cJimmy Vetayases		 * fast-trap, etc.
3927ff178cJimmy Vetayases		 */
3937ff178cJimmy Vetayases		apix_irminfo.apix_per_cpu_vectors = APIX_NAVINTR -
3947ff178cJimmy Vetayases		    APIX_SW_RESERVED_VECTORS;
3957ff178cJimmy Vetayases
3967ff178cJimmy Vetayases		/* Number of vectors (pre) allocated (SCI and HPET) */
3977ff178cJimmy Vetayases		apix_irminfo.apix_vectors_allocated = 0;
3987ff178cJimmy Vetayases		if (apic_hpet_vect != -1)
3997ff178cJimmy Vetayases			apix_irminfo.apix_vectors_allocated++;
4007ff178cJimmy Vetayases		if (apic_sci_vect != -1)
4017ff178cJimmy Vetayases			apix_irminfo.apix_vectors_allocated++;
4027ff178cJimmy Vetayases	}
4037ff178cJimmy Vetayases}
4047ff178cJimmy Vetayases
4057ff178cJimmy Vetayasesstatic void
4067ff178cJimmy Vetayasesapix_init_intr()
4077ff178cJimmy Vetayases{
4087ff178cJimmy Vetayases	processorid_t	cpun = psm_get_cpu_id();
4097ff178cJimmy Vetayases	uint_t nlvt;
4107ff178cJimmy Vetayases	uint32_t svr = AV_UNIT_ENABLE | APIC_SPUR_INTR;
4117ff178cJimmy Vetayases	extern void cmi_cmci_trap(void);
4127ff178cJimmy Vetayases
4137ff178cJimmy Vetayases	apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL);
4147ff178cJimmy Vetayases
4157ff178cJimmy Vetayases	if (apic_mode == LOCAL_APIC) {
4167ff178cJimmy Vetayases		/*
4177ff178cJimmy Vetayases		 * We are running APIC in MMIO mode.
4187ff178cJimmy Vetayases		 */
4197ff178cJimmy Vetayases		if (apic_flat_model) {
4207ff178cJimmy Vetayases			apic_reg_ops->apic_write(APIC_FORMAT_REG,
4217ff178cJimmy Vetayases			    APIC_FLAT_MODEL);
4227ff178cJimmy Vetayases		} else {
4237ff178cJimmy Vetayases			apic_reg_ops->apic_write(APIC_FORMAT_REG,
4247ff178cJimmy Vetayases			    APIC_CLUSTER_MODEL);
4257ff178cJimmy Vetayases		}
4267ff178cJimmy Vetayases
4277ff178cJimmy Vetayases		apic_reg_ops->apic_write(APIC_DEST_REG,
4287ff178cJimmy Vetayases		    AV_HIGH_ORDER >> cpun);
4297ff178cJimmy Vetayases	}
4307ff178cJimmy Vetayases
4317ff178cJimmy Vetayases	if (apic_directed_EOI_supported()) {
4327ff178cJimmy Vetayases		/*
4337ff178cJimmy Vetayases		 * Setting the 12th bit in the Spurious Interrupt Vector
4347ff178cJimmy Vetayases		 * Register suppresses broadcast EOIs generated by the local
4357ff178cJimmy Vetayases		 * APIC. The suppression of broadcast EOIs happens only when
4367ff178cJimmy Vetayases		 * interrupts are level-triggered.
4377ff178cJimmy Vetayases		 */
4387ff178cJimmy Vetayases		svr |= APIC_SVR_SUPPRESS_BROADCAST_EOI;
4397ff178cJimmy Vetayases	}
4407ff178cJimmy Vetayases
4417ff178cJimmy Vetayases	/* need to enable APIC before unmasking NMI */
4427ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_SPUR_INT_REG, svr);
4437ff178cJimmy Vetayases
4447ff178cJimmy Vetayases	/*
4457ff178cJimmy Vetayases	 * Presence of an invalid vector with delivery mode AV_FIXED can
4467ff178cJimmy Vetayases	 * cause an error interrupt, even if the entry is masked...so
4477ff178cJimmy Vetayases	 * write a valid vector to LVT entries along with the mask bit
4487ff178cJimmy Vetayases	 */
4497ff178cJimmy Vetayases
4507ff178cJimmy Vetayases	/* All APICs have timer and LINT0/1 */
4517ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK|APIC_RESV_IRQ);
4527ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK|APIC_RESV_IRQ);
4537ff178cJimmy Vetayases	apic_reg_ops->apic_write(APIC_INT_VECT1, AV_NMI);	/* enable NMI */
4547ff178cJimmy Vetayases
4557ff178cJimmy Vetayases	/*
4567ff178cJimmy Vetayases	 * On integrated APICs, the number of LVT entries is
4577ff178cJimmy Vetayases	 * 'Max LVT entry' + 1; on 82489DX's (non-integrated
4587ff178cJimmy Vetayases	 * APICs), nlvt is "3" (LINT0, LINT1, and timer)
4597ff178cJimmy Vetayases	 */
4607ff178cJimmy Vetayases
4617ff178cJimmy Vetayases	if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) {
4627ff178cJimmy Vetayases		nlvt = 3;
4637ff178cJimmy Vetayases	} else {
4647ff178cJimmy Vetayases		nlvt = ((apic_reg_ops->apic_read(APIC_VERS_REG) >> 16) &
4657ff178cJimmy Vetayases		    0xFF) + 1;
4667ff178cJimmy Vetayases	}
4677ff178cJimmy Vetayases
4687ff178cJimmy Vetayases	if (nlvt >= 5) {
4697ff178cJimmy Vetayases		/* Enable performance counter overflow interrupt */
4707ff178cJimmy Vetayases
4717417cfdKuriakose Kuruvilla		if (!is_x86_feature(x86_featureset, X86FSET_MSR))
4727ff178cJimmy Vetayases			apic_enable_cpcovf_intr = 0;
4737ff178cJimmy Vetayases		if (apic_enable_cpcovf_intr) {
4747ff178cJimmy Vetayases			if (apic_cpcovf_vect == 0) {
4757ff178cJimmy Vetayases				int ipl = APIC_PCINT_IPL;
4767ff178cJimmy Vetayases
4777ff178cJimmy Vetayases				apic_cpcovf_vect = apix_get_ipivect(ipl, -1);
4787ff178cJimmy Vetayases				ASSERT(apic_cpcovf_vect);
4797ff178cJimmy Vetayases
4807ff178cJimmy Vetayases				(void) add_avintr(NULL, ipl,
4817ff178cJimmy Vetayases				    (avfunc)kcpc_hw_overflow_intr,
4827ff178cJimmy Vetayases				    "apic pcint", apic_cpcovf_vect,
4837ff178cJimmy Vetayases				    NULL, NULL, NULL, NULL);
4847ff178cJimmy Vetayases				kcpc_hw_overflow_intr_installed = 1;
4857ff178cJimmy Vetayases				kcpc_hw_enable_cpc_intr =
4867ff178cJimmy Vetayases				    apic_cpcovf_mask_clear;
4877ff178cJimmy Vetayases			}
4887ff178cJimmy Vetayases			apic_reg_ops->apic_write(APIC_PCINT_VECT,
4897ff178cJimmy Vetayases			    apic_cpcovf_vect);
4907ff178cJimmy Vetayases		}
4917ff178cJimmy Vetayases	}
4927ff178cJimmy Vetayases
4937ff178cJimmy Vetayases	if (nlvt >= 6) {
4947ff178cJimmy Vetayases		/* Only mask TM intr if the BIOS apparently doesn't use it */
4957ff178cJimmy Vetayases
4967ff178cJimmy Vetayases		uint32_t lvtval;
4977ff178cJimmy Vetayases
4987ff178cJimmy Vetayases		lvtval = apic_reg_ops->apic_read(APIC_THERM_VECT);
4997ff178cJimmy Vetayases		if (((lvtval & AV_MASK) == AV_MASK) ||
5007ff178cJimmy Vetayases		    ((lvtval & AV_DELIV_MODE) != AV_SMI)) {
5017ff178cJimmy Vetayases			apic_reg_ops->apic_write(APIC_THERM_VECT,
5027ff178cJimmy Vetayases			    AV_MASK|APIC_RESV_IRQ);
5037ff178cJimmy Vetayases		}
5047ff178cJimmy Vetayases	}
5057ff178cJimmy Vetayases
5067ff178cJimmy Vetayases	/* Enable error interrupt */
5077ff178cJimmy Vetayases
5087ff178cJimmy Vetayases	if (nlvt >= 4 && apic_enable_error_intr) {
5097ff178cJimmy Vetayases		if (apic_errvect == 0) {
5107ff178cJimmy Vetayases			int ipl = 0xf;	/* get highest priority intr */
5117ff178cJimmy Vetayases			apic_errvect = apix_get_ipivect(ipl, -1);
5127ff178cJimmy Vetayases			ASSERT(apic_errvect);
5137ff178cJimmy Vetayases			/*
5147ff178cJimmy Vetayases			 * Not PSMI compliant, but we are going to merge
5157ff178cJimmy Vetayases			 * with ON anyway
5167ff178cJimmy Vetayases			 */
5177ff178cJimmy Vetayases			(void) add_avintr(NULL, ipl,
5187ff178cJimmy Vetayases			    (avfunc)apic_error_intr, "apic error intr",
5197ff178cJimmy Vetayases			    apic_errvect, NULL, NULL, NULL, NULL);
5207ff178cJimmy Vetayases		}
5217ff178cJimmy Vetayases		apic_reg_ops->apic_write(APIC_ERR_VECT, apic_errvect);
5227ff178cJimmy Vetayases		apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
5237ff178cJimmy Vetayases		apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
5247ff178cJimmy Vetayases	}
5257ff178cJimmy Vetayases
526918e0d9Robert Mustacchi	/*
527918e0d9Robert Mustacchi	 * Ensure a CMCI interrupt is allocated, regardless of whether it is
528918e0d9Robert Mustacchi	 * enabled or not.
529918e0d9Robert Mustacchi	 */
530918e0d9Robert Mustacchi	if (apic_cmci_vect == 0) {
531918e0d9Robert Mustacchi		const int ipl = 0x2;
532918e0d9Robert Mustacchi		apic_cmci_vect = apix_get_ipivect(ipl, -1);
533918e0d9Robert Mustacchi		ASSERT(apic_cmci_vect);
534918e0d9Robert Mustacchi
535918e0d9Robert Mustacchi		(void) add_avintr(NULL, ipl,
536918e0d9Robert Mustacchi		    (avfunc)cmi_cmci_trap, "apic cmci intr",
537918e0d9Robert Mustacchi		    apic_cmci_vect, NULL, NULL, NULL, NULL);
5387ff178cJimmy Vetayases	}
5397ff178cJimmy Vetayases
5407ff178cJimmy Vetayases	apic_reg_ops->apic_write_task_reg(0);
5417ff178cJimmy Vetayases}
5427ff178cJimmy Vetayases
5437ff178cJimmy Vetayasesstatic void
5447ff178cJimmy Vetayasesapix_picinit(void)
5457ff178cJimmy Vetayases{
5467ff178cJimmy Vetayases	int i, j;
5477ff178cJimmy Vetayases	uint_t isr;
5487ff178cJimmy Vetayases
5497ff178cJimmy Vetayases	APIC_VERBOSE(INIT, (CE_CONT, "apix: psm_picinit\n"));
5507ff178cJimmy Vetayases
5517ff178cJimmy Vetayases	/*
5527ff178cJimmy Vetayases	 * initialize interrupt remapping before apic
5537ff178cJimmy Vetayases	 * hardware initialization
5547ff178cJimmy Vetayases	 */
5557ff178cJimmy Vetayases	apic_intrmap_init(apic_mode);
5567ff178cJimmy Vetayases	if (apic_vt_ops == psm_vt_ops)
5577ff178cJimmy Vetayases		apix_mul_ioapic_method = APIC_MUL_IOAPIC_IIR;
5587ff178cJimmy Vetayases
5597ff178cJimmy Vetayases	/*
5607ff178cJimmy Vetayases	 * On UniSys Model 6520, the BIOS leaves vector 0x20 isr
5617ff178cJimmy Vetayases	 * bit on without clearing it with EOI.  Since softint
5627ff178cJimmy Vetayases	 * uses vector 0x20 to interrupt itself, so softint will
5637ff178cJimmy Vetayases	 * not work on this machine.  In order to fix this problem
5647ff178cJimmy Vetayases	 * a check is made to verify all the isr bits are clear.
5657ff178cJimmy Vetayases	 * If not, EOIs are issued to clear the bits.
5667ff178cJimmy Vetayases	 */
5677ff178cJimmy Vetayases	for (i = 7; i >= 1; i--) {
5687ff178cJimmy Vetayases		isr = apic_reg_ops->apic_read(APIC_ISR_REG + (i * 4));
5697ff178cJimmy Vetayases		if (isr != 0)
5707ff178cJimmy Vetayases			for (j = 0; ((j < 32) && (isr != 0)); j++)
5717ff178cJimmy Vetayases				if (isr & (1 << j)) {
5727ff178cJimmy Vetayases					apic_reg_ops->apic_write(
5737ff178cJimmy Vetayases					    APIC_EOI_REG, 0);
5747ff178cJimmy Vetayases					isr &= ~(1 << j);
5757ff178cJimmy Vetayases					apic_error |= APIC_ERR_BOOT_EOI;
5767ff178cJimmy Vetayases				}
5777ff178cJimmy Vetayases	}
5787ff178cJimmy Vetayases
5797ff178cJimmy Vetayases	/* set a flag so we know we have run apic_picinit() */
5807ff178cJimmy Vetayases	apic_picinit_called = 1;
5817ff178cJimmy Vetayases	LOCK_INIT_CLEAR(&apic_gethrtime_lock);
5827ff178cJimmy Vetayases	LOCK_INIT_CLEAR(&apic_ioapic_lock);
5837ff178cJimmy Vetayases	LOCK_INIT_CLEAR(&apic_error_lock);
5847ff178cJimmy Vetayases	LOCK_INIT_CLEAR(&apic_mode_switch_lock);
5857ff178cJimmy Vetayases
5867ff178cJimmy Vetayases	picsetup();	 /* initialise the 8259 */