10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51456Sdmick * Common Development and Distribution License (the "License"). 61456Sdmick * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 213446Smrj 220Sstevel@tonic-gate /* 238675SVikram.Hegde@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * PSMI 1.1 extensions are supported only in 2.6 and later versions. 290Sstevel@tonic-gate * PSMI 1.2 extensions are supported only in 2.7 and later versions. 300Sstevel@tonic-gate * PSMI 1.3 and 1.4 extensions are supported in Solaris 10. 310Sstevel@tonic-gate * PSMI 1.5 extensions are supported in Solaris Nevada. 325295Srandyf * PSMI 1.6 extensions are supported in Solaris Nevada. 330Sstevel@tonic-gate */ 345295Srandyf #define PSMI_1_6 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <sys/processor.h> 370Sstevel@tonic-gate #include <sys/time.h> 380Sstevel@tonic-gate #include <sys/psm.h> 390Sstevel@tonic-gate #include <sys/smp_impldefs.h> 400Sstevel@tonic-gate #include <sys/cram.h> 410Sstevel@tonic-gate #include <sys/acpi/acpi.h> 420Sstevel@tonic-gate #include <sys/acpica.h> 430Sstevel@tonic-gate #include <sys/psm_common.h> 443446Smrj #include <sys/apic.h> 450Sstevel@tonic-gate #include <sys/pit.h> 460Sstevel@tonic-gate #include <sys/ddi.h> 470Sstevel@tonic-gate #include <sys/sunddi.h> 480Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 490Sstevel@tonic-gate #include <sys/pci.h> 500Sstevel@tonic-gate #include <sys/promif.h> 510Sstevel@tonic-gate #include <sys/x86_archext.h> 520Sstevel@tonic-gate #include <sys/cpc_impl.h> 530Sstevel@tonic-gate #include <sys/uadmin.h> 540Sstevel@tonic-gate #include <sys/panic.h> 550Sstevel@tonic-gate #include <sys/debug.h> 560Sstevel@tonic-gate #include <sys/archsystm.h> 570Sstevel@tonic-gate #include <sys/trap.h> 580Sstevel@tonic-gate #include <sys/machsystm.h> 593446Smrj #include <sys/sysmacros.h> 600Sstevel@tonic-gate #include <sys/cpuvar.h> 610Sstevel@tonic-gate #include <sys/rm_platter.h> 620Sstevel@tonic-gate #include <sys/privregs.h> 630Sstevel@tonic-gate #include <sys/note.h> 640Sstevel@tonic-gate #include <sys/pci_intr_lib.h> 653446Smrj #include <sys/spl.h> 665084Sjohnlev #include <sys/clock.h> 675107Seota #include <sys/dditypes.h> 685107Seota #include <sys/sunddi.h> 697349SAdrian.Frost@Sun.COM #include <sys/x_call.h> 707986SSaurabh.Mishra@Sun.COM #include <sys/reboot.h> 718906SEric.Saxe@Sun.COM #include <sys/hpet.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Local Function Prototypes 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate static void apic_init_intr(); 775084Sjohnlev static void apic_nmi_intr(caddr_t arg, struct regs *rp); 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * standard MP entries 810Sstevel@tonic-gate */ 820Sstevel@tonic-gate static int apic_probe(); 830Sstevel@tonic-gate static int apic_clkinit(); 840Sstevel@tonic-gate static int apic_getclkirq(int ipl); 850Sstevel@tonic-gate static uint_t apic_calibrate(volatile uint32_t *addr, 860Sstevel@tonic-gate uint16_t *pit_ticks_adj); 870Sstevel@tonic-gate static hrtime_t apic_gettime(); 880Sstevel@tonic-gate static hrtime_t apic_gethrtime(); 890Sstevel@tonic-gate static void apic_init(); 900Sstevel@tonic-gate static void apic_picinit(void); 913446Smrj static int apic_cpu_start(processorid_t, caddr_t); 920Sstevel@tonic-gate static int apic_post_cpu_start(void); 930Sstevel@tonic-gate static void apic_send_ipi(int cpun, int ipl); 940Sstevel@tonic-gate static void apic_set_idlecpu(processorid_t cpun); 950Sstevel@tonic-gate static void apic_unset_idlecpu(processorid_t cpun); 960Sstevel@tonic-gate static int apic_intr_enter(int ipl, int *vect); 970Sstevel@tonic-gate static void apic_setspl(int ipl); 987282Smishra static void x2apic_setspl(int ipl); 990Sstevel@tonic-gate static int apic_addspl(int ipl, int vector, int min_ipl, int max_ipl); 1000Sstevel@tonic-gate static int apic_delspl(int ipl, int vector, int min_ipl, int max_ipl); 1010Sstevel@tonic-gate static void apic_shutdown(int cmd, int fcn); 1020Sstevel@tonic-gate static void apic_preshutdown(int cmd, int fcn); 1030Sstevel@tonic-gate static int apic_disable_intr(processorid_t cpun); 1040Sstevel@tonic-gate static void apic_enable_intr(processorid_t cpun); 1050Sstevel@tonic-gate static processorid_t apic_get_next_processorid(processorid_t cpun); 1060Sstevel@tonic-gate static int apic_get_ipivect(int ipl, int type); 1070Sstevel@tonic-gate static void apic_timer_reprogram(hrtime_t time); 1080Sstevel@tonic-gate static void apic_timer_enable(void); 1090Sstevel@tonic-gate static void apic_timer_disable(void); 1100Sstevel@tonic-gate static void apic_post_cyclic_setup(void *arg); 1118675SVikram.Hegde@Sun.COM static void apic_intrr_init(int apic_mode); 1128675SVikram.Hegde@Sun.COM static void apic_record_ioapic_rdt(apic_irq_t *irq_ptr, ioapic_rdt_t *irdt); 1138675SVikram.Hegde@Sun.COM static void apic_record_msi(apic_irq_t *irq_ptr, msi_regs_t *mregs); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate static int apic_oneshot = 0; 1160Sstevel@tonic-gate int apic_oneshot_enable = 1; /* to allow disabling one-shot capability */ 1170Sstevel@tonic-gate 1183446Smrj /* Now the ones for Dynamic Interrupt distribution */ 1193446Smrj int apic_enable_dynamic_migration = 0; 1203446Smrj 121*10080SJoe.Bonasera@sun.com int apic_have_32bit_cr8 = 0; 1223446Smrj 1230Sstevel@tonic-gate /* 1240Sstevel@tonic-gate * These variables are frequently accessed in apic_intr_enter(), 1250Sstevel@tonic-gate * apic_intr_exit and apic_setspl, so group them together 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate volatile uint32_t *apicadr = NULL; /* virtual addr of local APIC */ 1280Sstevel@tonic-gate int apic_setspl_delay = 1; /* apic_setspl - delay enable */ 1290Sstevel@tonic-gate int apic_clkvect; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* vector at which error interrupts come in */ 1320Sstevel@tonic-gate int apic_errvect; 1330Sstevel@tonic-gate int apic_enable_error_intr = 1; 1340Sstevel@tonic-gate int apic_error_display_delay = 100; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /* vector at which performance counter overflow interrupts come in */ 1370Sstevel@tonic-gate int apic_cpcovf_vect; 1380Sstevel@tonic-gate int apic_enable_cpcovf_intr = 1; 1390Sstevel@tonic-gate 1407349SAdrian.Frost@Sun.COM /* vector at which CMCI interrupts come in */ 1417349SAdrian.Frost@Sun.COM int apic_cmci_vect; 1427349SAdrian.Frost@Sun.COM extern int cmi_enable_cmci; 1437349SAdrian.Frost@Sun.COM extern void cmi_cmci_trap(void); 1447349SAdrian.Frost@Sun.COM 1457349SAdrian.Frost@Sun.COM static kmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */ 1467349SAdrian.Frost@Sun.COM static int cmci_cpu_setup_registered; 1477349SAdrian.Frost@Sun.COM 1480Sstevel@tonic-gate /* 1490Sstevel@tonic-gate * The following vector assignments influence the value of ipltopri and 1500Sstevel@tonic-gate * vectortoipl. Note that vectors 0 - 0x1f are not used. We can program 1513745Ssethg * idle to 0 and IPL 0 to 0xf to differentiate idle in case 1520Sstevel@tonic-gate * we care to do so in future. Note some IPLs which are rarely used 1530Sstevel@tonic-gate * will share the vector ranges and heavily used IPLs (5 and 6) have 1540Sstevel@tonic-gate * a wide range. 1553745Ssethg * 1563745Ssethg * This array is used to initialize apic_ipls[] (in apic_init()). 1573745Ssethg * 1580Sstevel@tonic-gate * IPL Vector range. as passed to intr_enter 1590Sstevel@tonic-gate * 0 none. 1600Sstevel@tonic-gate * 1,2,3 0x20-0x2f 0x0-0xf 1610Sstevel@tonic-gate * 4 0x30-0x3f 0x10-0x1f 1620Sstevel@tonic-gate * 5 0x40-0x5f 0x20-0x3f 1630Sstevel@tonic-gate * 6 0x60-0x7f 0x40-0x5f 1640Sstevel@tonic-gate * 7,8,9 0x80-0x8f 0x60-0x6f 1650Sstevel@tonic-gate * 10 0x90-0x9f 0x70-0x7f 1660Sstevel@tonic-gate * 11 0xa0-0xaf 0x80-0x8f 1670Sstevel@tonic-gate * ... ... 1683745Ssethg * 15 0xe0-0xef 0xc0-0xcf 1693745Ssethg * 15 0xf0-0xff 0xd0-0xdf 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate uchar_t apic_vectortoipl[APIC_AVAIL_VECTOR / APIC_VECTOR_PER_IPL] = { 1723745Ssethg 3, 4, 5, 5, 6, 6, 9, 10, 11, 12, 13, 14, 15, 15 1730Sstevel@tonic-gate }; 1740Sstevel@tonic-gate /* 1753745Ssethg * The ipl of an ISR at vector X is apic_vectortoipl[X>>4] 1760Sstevel@tonic-gate * NOTE that this is vector as passed into intr_enter which is 1770Sstevel@tonic-gate * programmed vector - 0x20 (APIC_BASE_VECT) 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate uchar_t apic_ipltopri[MAXIPL + 1]; /* unix ipl to apic pri */ 1810Sstevel@tonic-gate /* The taskpri to be programmed into apic to mask given ipl */ 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate #if defined(__amd64) 1840Sstevel@tonic-gate uchar_t apic_cr8pri[MAXIPL + 1]; /* unix ipl to cr8 pri */ 1850Sstevel@tonic-gate #endif 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1883745Ssethg * Correlation of the hardware vector to the IPL in use, initialized 1893745Ssethg * from apic_vectortoipl[] in apic_init(). The final IPLs may not correlate 1903745Ssethg * to the IPLs in apic_vectortoipl on some systems that share interrupt lines 1913745Ssethg * connected to errata-stricken IOAPICs 1923745Ssethg */ 1933745Ssethg uchar_t apic_ipls[APIC_AVAIL_VECTOR]; 1943745Ssethg 1953745Ssethg /* 1960Sstevel@tonic-gate * Patchable global variables. 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate int apic_forceload = 0; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate int apic_coarse_hrtime = 1; /* 0 - use accurate slow gethrtime() */ 2010Sstevel@tonic-gate /* 1 - use gettime() for performance */ 2020Sstevel@tonic-gate int apic_flat_model = 0; /* 0 - clustered. 1 - flat */ 2030Sstevel@tonic-gate int apic_enable_hwsoftint = 0; /* 0 - disable, 1 - enable */ 2040Sstevel@tonic-gate int apic_enable_bind_log = 1; /* 1 - display interrupt binding log */ 2050Sstevel@tonic-gate int apic_panic_on_nmi = 0; 2060Sstevel@tonic-gate int apic_panic_on_apic_error = 0; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate int apic_verbose = 0; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* minimum number of timer ticks to program to */ 2110Sstevel@tonic-gate int apic_min_timer_ticks = 1; 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Local static data 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate static struct psm_ops apic_ops = { 2160Sstevel@tonic-gate apic_probe, 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate apic_init, 2190Sstevel@tonic-gate apic_picinit, 2200Sstevel@tonic-gate apic_intr_enter, 2210Sstevel@tonic-gate apic_intr_exit, 2220Sstevel@tonic-gate apic_setspl, 2230Sstevel@tonic-gate apic_addspl, 2240Sstevel@tonic-gate apic_delspl, 2250Sstevel@tonic-gate apic_disable_intr, 2260Sstevel@tonic-gate apic_enable_intr, 2274652Scwb (int (*)(int))NULL, /* psm_softlvl_to_irq */ 2284652Scwb (void (*)(int))NULL, /* psm_set_softintr */ 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate apic_set_idlecpu, 2310Sstevel@tonic-gate apic_unset_idlecpu, 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate apic_clkinit, 2340Sstevel@tonic-gate apic_getclkirq, 2350Sstevel@tonic-gate (void (*)(void))NULL, /* psm_hrtimeinit */ 2360Sstevel@tonic-gate apic_gethrtime, 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate apic_get_next_processorid, 2390Sstevel@tonic-gate apic_cpu_start, 2400Sstevel@tonic-gate apic_post_cpu_start, 2410Sstevel@tonic-gate apic_shutdown, 2420Sstevel@tonic-gate apic_get_ipivect, 2430Sstevel@tonic-gate apic_send_ipi, 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate (int (*)(dev_info_t *, int))NULL, /* psm_translate_irq */ 2460Sstevel@tonic-gate (void (*)(int, char *))NULL, /* psm_notify_error */ 2470Sstevel@tonic-gate (void (*)(int))NULL, /* psm_notify_func */ 2480Sstevel@tonic-gate apic_timer_reprogram, 2490Sstevel@tonic-gate apic_timer_enable, 2500Sstevel@tonic-gate apic_timer_disable, 2510Sstevel@tonic-gate apic_post_cyclic_setup, 2520Sstevel@tonic-gate apic_preshutdown, 2535295Srandyf apic_intr_ops, /* Advanced DDI Interrupt framework */ 2545295Srandyf apic_state, /* save, restore apic state for S3 */ 2550Sstevel@tonic-gate }; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate static struct psm_info apic_psm_info = { 2595295Srandyf PSM_INFO_VER01_6, /* version */ 2600Sstevel@tonic-gate PSM_OWN_EXCLUSIVE, /* ownership */ 2610Sstevel@tonic-gate (struct psm_ops *)&apic_ops, /* operation */ 2624397Sschwartz APIC_PCPLUSMP_NAME, /* machine name */ 2636896Sdmick "pcplusmp v1.4 compatible", 2640Sstevel@tonic-gate }; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate static void *apic_hdlp; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate #ifdef DEBUG 2690Sstevel@tonic-gate int apic_debug = 0; 2700Sstevel@tonic-gate int apic_restrict_vector = 0; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate int apic_debug_msgbuf[APIC_DEBUG_MSGBUFSIZE]; 2730Sstevel@tonic-gate int apic_debug_msgbufindex = 0; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate #endif /* DEBUG */ 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate apic_cpus_info_t *apic_cpus; 2780Sstevel@tonic-gate 2793446Smrj cpuset_t apic_cpumask; 2805084Sjohnlev uint_t apic_picinit_called; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /* Flag to indicate that we need to shut down all processors */ 2830Sstevel@tonic-gate static uint_t apic_shutdown_processors; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate uint_t apic_nsec_per_intr = 0; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * apic_let_idle_redistribute can have the following values: 2890Sstevel@tonic-gate * 0 - If clock decremented it from 1 to 0, clock has to call redistribute. 2900Sstevel@tonic-gate * apic_redistribute_lock prevents multiple idle cpus from redistributing 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate int apic_num_idle_redistributions = 0; 2930Sstevel@tonic-gate static int apic_let_idle_redistribute = 0; 2940Sstevel@tonic-gate static uint_t apic_nticks = 0; 2950Sstevel@tonic-gate static uint_t apic_skipped_redistribute = 0; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* to gather intr data and redistribute */ 2980Sstevel@tonic-gate static void apic_redistribute_compute(void); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate static uint_t last_count_read = 0; 3010Sstevel@tonic-gate static lock_t apic_gethrtime_lock; 3020Sstevel@tonic-gate volatile int apic_hrtime_stamp = 0; 3030Sstevel@tonic-gate volatile hrtime_t apic_nsec_since_boot = 0; 3042992Sdmick static uint_t apic_hertz_count; 3052992Sdmick 3062992Sdmick uint64_t apic_ticks_per_SFnsecs; /* # of ticks in SF nsecs */ 3072992Sdmick 3080Sstevel@tonic-gate static hrtime_t apic_nsec_max; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate static hrtime_t apic_last_hrtime = 0; 3110Sstevel@tonic-gate int apic_hrtime_error = 0; 3120Sstevel@tonic-gate int apic_remote_hrterr = 0; 3130Sstevel@tonic-gate int apic_num_nmis = 0; 3140Sstevel@tonic-gate int apic_apic_error = 0; 3150Sstevel@tonic-gate int apic_num_apic_errors = 0; 3160Sstevel@tonic-gate int apic_num_cksum_errors = 0; 3170Sstevel@tonic-gate 3183446Smrj int apic_error = 0; 3190Sstevel@tonic-gate static int apic_cmos_ssb_set = 0; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* use to make sure only one cpu handles the nmi */ 3220Sstevel@tonic-gate static lock_t apic_nmi_lock; 3230Sstevel@tonic-gate /* use to make sure only one cpu handles the error interrupt */ 3240Sstevel@tonic-gate static lock_t apic_error_lock; 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate static struct { 3270Sstevel@tonic-gate uchar_t cntl; 3280Sstevel@tonic-gate uchar_t data; 3290Sstevel@tonic-gate } aspen_bmc[] = { 3300Sstevel@tonic-gate { CC_SMS_WR_START, 0x18 }, /* NetFn/LUN */ 3310Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */ 3320Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0x84 }, /* DataByte 1: SMS/OS no log */ 3330Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0x2 }, /* DataByte 2: Power Down */ 3340Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 3: no pre-timeout */ 3350Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0x0 }, /* DataByte 4: timer expir. */ 3360Sstevel@tonic-gate { CC_SMS_WR_NEXT, 0xa }, /* DataByte 5: init countdown */ 3370Sstevel@tonic-gate { CC_SMS_WR_END, 0x0 }, /* DataByte 6: init countdown */ 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate { CC_SMS_WR_START, 0x18 }, /* NetFn/LUN */ 3400Sstevel@tonic-gate { CC_SMS_WR_END, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */ 3410Sstevel@tonic-gate }; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate static struct { 3440Sstevel@tonic-gate int port; 3450Sstevel@tonic-gate uchar_t data; 3460Sstevel@tonic-gate } sitka_bmc[] = { 3470Sstevel@tonic-gate { SMS_COMMAND_REGISTER, SMS_WRITE_START }, 3480Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */ 3490Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x24 }, /* Cmd SET_WATCHDOG_TIMER */ 3500Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x84 }, /* DataByte 1: SMS/OS no log */ 3510Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x2 }, /* DataByte 2: Power Down */ 3520Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x0 }, /* DataByte 3: no pre-timeout */ 3530Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x0 }, /* DataByte 4: timer expir. */ 3540Sstevel@tonic-gate { SMS_DATA_REGISTER, 0xa }, /* DataByte 5: init countdown */ 3550Sstevel@tonic-gate { SMS_COMMAND_REGISTER, SMS_WRITE_END }, 3560Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x0 }, /* DataByte 6: init countdown */ 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate { SMS_COMMAND_REGISTER, SMS_WRITE_START }, 3590Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x18 }, /* NetFn/LUN */ 3600Sstevel@tonic-gate { SMS_COMMAND_REGISTER, SMS_WRITE_END }, 3610Sstevel@tonic-gate { SMS_DATA_REGISTER, 0x22 } /* Cmd RESET_WATCHDOG_TIMER */ 3620Sstevel@tonic-gate }; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* Patchable global variables. */ 3650Sstevel@tonic-gate int apic_kmdb_on_nmi = 0; /* 0 - no, 1 - yes enter kmdb */ 3662992Sdmick uint32_t apic_divide_reg_init = 0; /* 0 - divide by 2 */ 3670Sstevel@tonic-gate 3688675SVikram.Hegde@Sun.COM /* default apic ops without interrupt remapping */ 3698675SVikram.Hegde@Sun.COM static apic_intrr_ops_t apic_nointrr_ops = { 3708675SVikram.Hegde@Sun.COM (int (*)(int))return_instr, 3718675SVikram.Hegde@Sun.COM (void (*)(void))return_instr, 3728675SVikram.Hegde@Sun.COM (void (*)(apic_irq_t *))return_instr, 3738675SVikram.Hegde@Sun.COM (void (*)(apic_irq_t *, void *))return_instr, 3748675SVikram.Hegde@Sun.COM (void (*)(apic_irq_t *))return_instr, 3758675SVikram.Hegde@Sun.COM apic_record_ioapic_rdt, 3768675SVikram.Hegde@Sun.COM apic_record_msi, 3778675SVikram.Hegde@Sun.COM }; 3788675SVikram.Hegde@Sun.COM 3798675SVikram.Hegde@Sun.COM apic_intrr_ops_t *apic_vt_ops = &apic_nointrr_ops; 3808675SVikram.Hegde@Sun.COM 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * This is the loadable module wrapper 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate int 3860Sstevel@tonic-gate _init(void) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate if (apic_coarse_hrtime) 3890Sstevel@tonic-gate apic_ops.psm_gethrtime = &apic_gettime; 3900Sstevel@tonic-gate return (psm_mod_init(&apic_hdlp, &apic_psm_info)); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate int 3940Sstevel@tonic-gate _fini(void) 3950Sstevel@tonic-gate { 3960Sstevel@tonic-gate return (psm_mod_fini(&apic_hdlp, &apic_psm_info)); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate int 4000Sstevel@tonic-gate _info(struct modinfo *modinfop) 4010Sstevel@tonic-gate { 4020Sstevel@tonic-gate return (psm_mod_info(&apic_hdlp, &apic_psm_info, modinfop)); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate static int 4070Sstevel@tonic-gate apic_probe() 4080Sstevel@tonic-gate { 4093446Smrj return (apic_probe_common(apic_psm_info.p_mach_idstring)); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate void 4130Sstevel@tonic-gate apic_init() 4140Sstevel@tonic-gate { 4153446Smrj int i; 4163446Smrj int j = 1; 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate apic_ipltopri[0] = APIC_VECTOR_PER_IPL; /* leave 0 for idle */ 4190Sstevel@tonic-gate for (i = 0; i < (APIC_AVAIL_VECTOR / APIC_VECTOR_PER_IPL); i++) { 4200Sstevel@tonic-gate if ((i < ((APIC_AVAIL_VECTOR / APIC_VECTOR_PER_IPL) - 1)) && 4210Sstevel@tonic-gate (apic_vectortoipl[i + 1] == apic_vectortoipl[i])) 4220Sstevel@tonic-gate /* get to highest vector at the same ipl */ 4230Sstevel@tonic-gate continue; 4240Sstevel@tonic-gate for (; j <= apic_vectortoipl[i]; j++) { 4250Sstevel@tonic-gate apic_ipltopri[j] = (i << APIC_IPL_SHIFT) + 4260Sstevel@tonic-gate APIC_BASE_VECT; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate for (; j < MAXIPL + 1; j++) 4300Sstevel@tonic-gate /* fill up any empty ipltopri slots */ 4310Sstevel@tonic-gate apic_ipltopri[j] = (i << APIC_IPL_SHIFT) + APIC_BASE_VECT; 4323446Smrj apic_init_common(); 4330Sstevel@tonic-gate #if defined(__amd64) 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * Make cpu-specific interrupt info point to cr8pri vector 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate for (i = 0; i <= MAXIPL; i++) 4380Sstevel@tonic-gate apic_cr8pri[i] = apic_ipltopri[i] >> APIC_IPL_SHIFT; 4390Sstevel@tonic-gate CPU->cpu_pri_data = apic_cr8pri; 440*10080SJoe.Bonasera@sun.com #else 441*10080SJoe.Bonasera@sun.com if (cpuid_have_cr8access(CPU)) 442*10080SJoe.Bonasera@sun.com apic_have_32bit_cr8 = 1; 4430Sstevel@tonic-gate #endif /* __amd64 */ 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* 4470Sstevel@tonic-gate * handler for APIC Error interrupt. Just print a warning and continue 4480Sstevel@tonic-gate */ 4490Sstevel@tonic-gate static int 4500Sstevel@tonic-gate apic_error_intr() 4510Sstevel@tonic-gate { 4520Sstevel@tonic-gate uint_t error0, error1, error; 4530Sstevel@tonic-gate uint_t i; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * We need to write before read as per 7.4.17 of system prog manual. 4570Sstevel@tonic-gate * We do both and or the results to be safe 4580Sstevel@tonic-gate */ 4597282Smishra error0 = apic_reg_ops->apic_read(APIC_ERROR_STATUS); 4607282Smishra apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 4617282Smishra error1 = apic_reg_ops->apic_read(APIC_ERROR_STATUS); 4620Sstevel@tonic-gate error = error0 | error1; 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* 465846Ssethg * Clear the APIC error status (do this on all cpus that enter here) 466846Ssethg * (two writes are required due to the semantics of accessing the 467846Ssethg * error status register.) 468846Ssethg */ 4697282Smishra apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 4707282Smishra apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 471846Ssethg 472846Ssethg /* 4730Sstevel@tonic-gate * Prevent more than 1 CPU from handling error interrupt causing 4740Sstevel@tonic-gate * double printing (interleave of characters from multiple 4750Sstevel@tonic-gate * CPU's when using prom_printf) 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate if (lock_try(&apic_error_lock) == 0) 4780Sstevel@tonic-gate return (error ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 4790Sstevel@tonic-gate if (error) { 4800Sstevel@tonic-gate #if DEBUG 4810Sstevel@tonic-gate if (apic_debug) 4820Sstevel@tonic-gate debug_enter("pcplusmp: APIC Error interrupt received"); 4830Sstevel@tonic-gate #endif /* DEBUG */ 4840Sstevel@tonic-gate if (apic_panic_on_apic_error) 4850Sstevel@tonic-gate cmn_err(CE_PANIC, 4860Sstevel@tonic-gate "APIC Error interrupt on CPU %d. Status = %x\n", 4870Sstevel@tonic-gate psm_get_cpu_id(), error); 4880Sstevel@tonic-gate else { 4890Sstevel@tonic-gate if ((error & ~APIC_CS_ERRORS) == 0) { 4900Sstevel@tonic-gate /* cksum error only */ 4910Sstevel@tonic-gate apic_error |= APIC_ERR_APIC_ERROR; 4920Sstevel@tonic-gate apic_apic_error |= error; 4930Sstevel@tonic-gate apic_num_apic_errors++; 4940Sstevel@tonic-gate apic_num_cksum_errors++; 4950Sstevel@tonic-gate } else { 4960Sstevel@tonic-gate /* 4970Sstevel@tonic-gate * prom_printf is the best shot we have of 4980Sstevel@tonic-gate * something which is problem free from 4990Sstevel@tonic-gate * high level/NMI type of interrupts 5000Sstevel@tonic-gate */ 5010Sstevel@tonic-gate prom_printf("APIC Error interrupt on CPU %d. " 5020Sstevel@tonic-gate "Status 0 = %x, Status 1 = %x\n", 5030Sstevel@tonic-gate psm_get_cpu_id(), error0, error1); 5040Sstevel@tonic-gate apic_error |= APIC_ERR_APIC_ERROR; 5050Sstevel@tonic-gate apic_apic_error |= error; 5060Sstevel@tonic-gate apic_num_apic_errors++; 5070Sstevel@tonic-gate for (i = 0; i < apic_error_display_delay; i++) { 5080Sstevel@tonic-gate tenmicrosec(); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * provide more delay next time limited to 5120Sstevel@tonic-gate * roughly 1 clock tick time 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate if (apic_error_display_delay < 500) 5150Sstevel@tonic-gate apic_error_display_delay *= 2; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate lock_clear(&apic_error_lock); 5190Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate lock_clear(&apic_error_lock); 5220Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate /* NOTREACHED */ 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * Turn off the mask bit in the performance counter Local Vector Table entry. 5290Sstevel@tonic-gate */ 5300Sstevel@tonic-gate static void 5310Sstevel@tonic-gate apic_cpcovf_mask_clear(void) 5320Sstevel@tonic-gate { 5337282Smishra apic_reg_ops->apic_write(APIC_PCINT_VECT, 5347282Smishra (apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK)); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5377349SAdrian.Frost@Sun.COM /*ARGSUSED*/ 5387349SAdrian.Frost@Sun.COM static int 5397349SAdrian.Frost@Sun.COM apic_cmci_enable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 5407349SAdrian.Frost@Sun.COM { 5417349SAdrian.Frost@Sun.COM apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect); 5427349SAdrian.Frost@Sun.COM return (0); 5437349SAdrian.Frost@Sun.COM } 5447349SAdrian.Frost@Sun.COM 5457349SAdrian.Frost@Sun.COM /*ARGSUSED*/ 5467349SAdrian.Frost@Sun.COM static int 5477349SAdrian.Frost@Sun.COM apic_cmci_disable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 5487349SAdrian.Frost@Sun.COM { 5497349SAdrian.Frost@Sun.COM apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK); 5507349SAdrian.Frost@Sun.COM return (0); 5517349SAdrian.Frost@Sun.COM } 5527349SAdrian.Frost@Sun.COM 5537349SAdrian.Frost@Sun.COM /*ARGSUSED*/ 5547349SAdrian.Frost@Sun.COM static int 5557349SAdrian.Frost@Sun.COM cmci_cpu_setup(cpu_setup_t what, int cpuid, void *arg) 5567349SAdrian.Frost@Sun.COM { 5577349SAdrian.Frost@Sun.COM cpuset_t cpu_set; 5587349SAdrian.Frost@Sun.COM 5597349SAdrian.Frost@Sun.COM CPUSET_ONLY(cpu_set, cpuid); 5607349SAdrian.Frost@Sun.COM 5617349SAdrian.Frost@Sun.COM switch (what) { 5627349SAdrian.Frost@Sun.COM case CPU_ON: 5639489SJoe.Bonasera@sun.com xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set), 5647349SAdrian.Frost@Sun.COM (xc_func_t)apic_cmci_enable); 5657349SAdrian.Frost@Sun.COM break; 5667349SAdrian.Frost@Sun.COM 5677349SAdrian.Frost@Sun.COM case CPU_OFF: 5689489SJoe.Bonasera@sun.com xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set), 5697349SAdrian.Frost@Sun.COM (xc_func_t)apic_cmci_disable); 5707349SAdrian.Frost@Sun.COM break; 5717349SAdrian.Frost@Sun.COM 5727349SAdrian.Frost@Sun.COM default: 5737349SAdrian.Frost@Sun.COM break; 5747349SAdrian.Frost@Sun.COM } 5757349SAdrian.Frost@Sun.COM 5767349SAdrian.Frost@Sun.COM return (0); 5777349SAdrian.Frost@Sun.COM } 5787349SAdrian.Frost@Sun.COM 5790Sstevel@tonic-gate static void 5800Sstevel@tonic-gate apic_init_intr() 5810Sstevel@tonic-gate { 5820Sstevel@tonic-gate processorid_t cpun = psm_get_cpu_id(); 5836896Sdmick uint_t nlvt; 5847282Smishra uint32_t svr = AV_UNIT_ENABLE | APIC_SPUR_INTR; 5850Sstevel@tonic-gate 5867282Smishra apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL); 5870Sstevel@tonic-gate 5887282Smishra if (apic_mode == LOCAL_APIC) { 5897282Smishra /* 5907282Smishra * We are running APIC in MMIO mode. 5917282Smishra */ 5927282Smishra if (apic_flat_model) { 5937282Smishra apic_reg_ops->apic_write(APIC_FORMAT_REG, 5947282Smishra APIC_FLAT_MODEL); 5957282Smishra } else { 5967282Smishra apic_reg_ops->apic_write(APIC_FORMAT_REG, 5977282Smishra APIC_CLUSTER_MODEL); 5987282Smishra } 5997282Smishra 6007282Smishra apic_reg_ops->apic_write(APIC_DEST_REG, 6017282Smishra AV_HIGH_ORDER >> cpun); 6027282Smishra } 6037282Smishra 6047282Smishra if (apic_direct_EOI) { 6057282Smishra /* 6067282Smishra * Set 12th bit in Spurious Interrupt Vector 6077282Smishra * Register to support level triggered interrupt 6087282Smishra * directed EOI. 6097282Smishra */ 6107282Smishra svr |= (0x1 << APIC_SVR); 6117282Smishra } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate /* need to enable APIC before unmasking NMI */ 6147282Smishra apic_reg_ops->apic_write(APIC_SPUR_INT_REG, svr); 6150Sstevel@tonic-gate 6166896Sdmick /* 6176896Sdmick * Presence of an invalid vector with delivery mode AV_FIXED can 6186896Sdmick * cause an error interrupt, even if the entry is masked...so 6196896Sdmick * write a valid vector to LVT entries along with the mask bit 6206896Sdmick */ 6216896Sdmick 6226896Sdmick /* All APICs have timer and LINT0/1 */ 6237282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK|APIC_RESV_IRQ); 6247282Smishra apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK|APIC_RESV_IRQ); 6257282Smishra apic_reg_ops->apic_write(APIC_INT_VECT1, AV_NMI); /* enable NMI */ 6260Sstevel@tonic-gate 6276896Sdmick /* 6286896Sdmick * On integrated APICs, the number of LVT entries is 6296896Sdmick * 'Max LVT entry' + 1; on 82489DX's (non-integrated 6306896Sdmick * APICs), nlvt is "3" (LINT0, LINT1, and timer) 6316896Sdmick */ 6320Sstevel@tonic-gate 6336896Sdmick if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) { 6346896Sdmick nlvt = 3; 6356896Sdmick } else { 6368767SSaurabh.Mishra@Sun.COM nlvt = ((apic_reg_ops->apic_read(APIC_VERS_REG) >> 16) & 6378767SSaurabh.Mishra@Sun.COM 0xFF) + 1; 6386896Sdmick } 6396896Sdmick 6406896Sdmick if (nlvt >= 5) { 6416896Sdmick /* Enable performance counter overflow interrupt */ 6426896Sdmick 6436896Sdmick if ((x86_feature & X86_MSR) != X86_MSR) 6446896Sdmick apic_enable_cpcovf_intr = 0; 6456896Sdmick if (apic_enable_cpcovf_intr) { 6466896Sdmick if (apic_cpcovf_vect == 0) { 6476896Sdmick int ipl = APIC_PCINT_IPL; 6486896Sdmick int irq = apic_get_ipivect(ipl, -1); 6490Sstevel@tonic-gate 6506896Sdmick ASSERT(irq != -1); 6516896Sdmick apic_cpcovf_vect = 6526896Sdmick apic_irq_table[irq]->airq_vector; 6536896Sdmick ASSERT(apic_cpcovf_vect); 6546896Sdmick (void) add_avintr(NULL, ipl, 6556896Sdmick (avfunc)kcpc_hw_overflow_intr, 6566896Sdmick "apic pcint", irq, NULL, NULL, NULL, NULL); 6576896Sdmick kcpc_hw_overflow_intr_installed = 1; 6586896Sdmick kcpc_hw_enable_cpc_intr = 6596896Sdmick apic_cpcovf_mask_clear; 6606896Sdmick } 6617282Smishra apic_reg_ops->apic_write(APIC_PCINT_VECT, 6627282Smishra apic_cpcovf_vect); 6636896Sdmick } 6646896Sdmick } 6650Sstevel@tonic-gate 6666896Sdmick if (nlvt >= 6) { 6676896Sdmick /* Only mask TM intr if the BIOS apparently doesn't use it */ 6686896Sdmick 6696896Sdmick uint32_t lvtval; 6706896Sdmick 6717282Smishra lvtval = apic_reg_ops->apic_read(APIC_THERM_VECT); 6726896Sdmick if (((lvtval & AV_MASK) == AV_MASK) || 6736896Sdmick ((lvtval & AV_DELIV_MODE) != AV_SMI)) { 6747282Smishra apic_reg_ops->apic_write(APIC_THERM_VECT, 6757282Smishra AV_MASK|APIC_RESV_IRQ); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* Enable error interrupt */ 6800Sstevel@tonic-gate 6816896Sdmick if (nlvt >= 4 && apic_enable_error_intr) { 6820Sstevel@tonic-gate if (apic_errvect == 0) { 6830Sstevel@tonic-gate int ipl = 0xf; /* get highest priority intr */ 6840Sstevel@tonic-gate int irq = apic_get_ipivect(ipl, -1); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate ASSERT(irq != -1); 6870Sstevel@tonic-gate apic_errvect = apic_irq_table[irq]->airq_vector; 6880Sstevel@tonic-gate ASSERT(apic_errvect); 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * Not PSMI compliant, but we are going to merge 6910Sstevel@tonic-gate * with ON anyway 6920Sstevel@tonic-gate */ 6930Sstevel@tonic-gate (void) add_avintr((void *)NULL, ipl, 6940Sstevel@tonic-gate (avfunc)apic_error_intr, "apic error intr", 695916Sschwartz irq, NULL, NULL, NULL, NULL); 6960Sstevel@tonic-gate } 6977282Smishra apic_reg_ops->apic_write(APIC_ERR_VECT, apic_errvect); 6987282Smishra apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 6997282Smishra apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0); 7000Sstevel@tonic-gate } 7016896Sdmick 7027349SAdrian.Frost@Sun.COM /* Enable CMCI interrupt */ 7037349SAdrian.Frost@Sun.COM if (cmi_enable_cmci) { 7047349SAdrian.Frost@Sun.COM 7057349SAdrian.Frost@Sun.COM mutex_enter(&cmci_cpu_setup_lock); 7067349SAdrian.Frost@Sun.COM if (cmci_cpu_setup_registered == 0) { 7077349SAdrian.Frost@Sun.COM mutex_enter(&cpu_lock); 7087349SAdrian.Frost@Sun.COM register_cpu_setup_func(cmci_cpu_setup, NULL); 7097349SAdrian.Frost@Sun.COM mutex_exit(&cpu_lock); 7107349SAdrian.Frost@Sun.COM cmci_cpu_setup_registered = 1; 7117349SAdrian.Frost@Sun.COM } 7127349SAdrian.Frost@Sun.COM mutex_exit(&cmci_cpu_setup_lock); 7137349SAdrian.Frost@Sun.COM 7147349SAdrian.Frost@Sun.COM if (apic_cmci_vect == 0) { 7157349SAdrian.Frost@Sun.COM int ipl = 0x2; 7167349SAdrian.Frost@Sun.COM int irq = apic_get_ipivect(ipl, -1); 7177349SAdrian.Frost@Sun.COM 7187349SAdrian.Frost@Sun.COM ASSERT(irq != -1); 7197349SAdrian.Frost@Sun.COM apic_cmci_vect = apic_irq_table[irq]->airq_vector; 7207349SAdrian.Frost@Sun.COM ASSERT(apic_cmci_vect); 7217349SAdrian.Frost@Sun.COM 7227349SAdrian.Frost@Sun.COM (void) add_avintr(NULL, ipl, 7237349SAdrian.Frost@Sun.COM (avfunc)cmi_cmci_trap, 7247349SAdrian.Frost@Sun.COM "apic cmci intr", irq, NULL, NULL, NULL, NULL); 7257349SAdrian.Frost@Sun.COM } 7267349SAdrian.Frost@Sun.COM apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect); 7277349SAdrian.Frost@Sun.COM } 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate static void 7310Sstevel@tonic-gate apic_disable_local_apic() 7320Sstevel@tonic-gate { 7337282Smishra apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL); 7347282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK); 7357282Smishra 7367282Smishra /* local intr reg 0 */ 7377282Smishra apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK); 7387282Smishra 7397282Smishra /* disable NMI */ 7407282Smishra apic_reg_ops->apic_write(APIC_INT_VECT1, AV_MASK); 7417282Smishra 7427282Smishra /* and error interrupt */ 7437282Smishra apic_reg_ops->apic_write(APIC_ERR_VECT, AV_MASK); 7447282Smishra 7457282Smishra /* and perf counter intr */ 7467282Smishra apic_reg_ops->apic_write(APIC_PCINT_VECT, AV_MASK); 7477282Smishra 7487282Smishra apic_reg_ops->apic_write(APIC_SPUR_INT_REG, APIC_SPUR_INTR); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate static void 7520Sstevel@tonic-gate apic_picinit(void) 7530Sstevel@tonic-gate { 7543446Smrj int i, j; 7550Sstevel@tonic-gate uint_t isr; 7567282Smishra uint32_t ver; 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate /* 7599940SVikram.Hegde@Sun.COM * initialize interrupt remapping before apic 7609940SVikram.Hegde@Sun.COM * hardware initialization 7619940SVikram.Hegde@Sun.COM */ 7629940SVikram.Hegde@Sun.COM apic_intrr_init(apic_mode); 7639940SVikram.Hegde@Sun.COM 7649940SVikram.Hegde@Sun.COM /* 7650Sstevel@tonic-gate * On UniSys Model 6520, the BIOS leaves vector 0x20 isr 7660Sstevel@tonic-gate * bit on without clearing it with EOI. Since softint 7670Sstevel@tonic-gate * uses vector 0x20 to interrupt itself, so softint will 7680Sstevel@tonic-gate * not work on this machine. In order to fix this problem 7690Sstevel@tonic-gate * a check is made to verify all the isr bits are clear. 7700Sstevel@tonic-gate * If not, EOIs are issued to clear the bits. 7710Sstevel@tonic-gate */ 7720Sstevel@tonic-gate for (i = 7; i >= 1; i--) { 7737282Smishra isr = apic_reg_ops->apic_read(APIC_ISR_REG + (i * 4)); 7747282Smishra if (isr != 0) 7750Sstevel@tonic-gate for (j = 0; ((j < 32) && (isr != 0)); j++) 7760Sstevel@tonic-gate if (isr & (1 << j)) { 7777282Smishra apic_reg_ops->apic_write( 7787282Smishra APIC_EOI_REG, 0); 7790Sstevel@tonic-gate isr &= ~(1 << j); 7800Sstevel@tonic-gate apic_error |= APIC_ERR_BOOT_EOI; 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate /* set a flag so we know we have run apic_picinit() */ 7855084Sjohnlev apic_picinit_called = 1; 7860Sstevel@tonic-gate LOCK_INIT_CLEAR(&apic_gethrtime_lock); 7870Sstevel@tonic-gate LOCK_INIT_CLEAR(&apic_ioapic_lock); 7880Sstevel@tonic-gate LOCK_INIT_CLEAR(&apic_error_lock); 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate picsetup(); /* initialise the 8259 */ 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* add nmi handler - least priority nmi handler */ 7930Sstevel@tonic-gate LOCK_INIT_CLEAR(&apic_nmi_lock); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate if (!psm_add_nmintr(0, (avfunc) apic_nmi_intr, 7960Sstevel@tonic-gate "pcplusmp NMI handler", (caddr_t)NULL)) 7970Sstevel@tonic-gate cmn_err(CE_WARN, "pcplusmp: Unable to add nmi handler"); 7980Sstevel@tonic-gate 7997282Smishra ver = apic_reg_ops->apic_read(APIC_VERS_REG); 8007282Smishra /* 8017282Smishra * In order to determine support for Directed EOI capability, 8027282Smishra * we check for 24th bit in Local APIC Version Register. 8037282Smishra */ 8047282Smishra if (ver & (0x1 << APIC_DIRECTED_EOI)) { 8057282Smishra apic_direct_EOI = 1; 8067282Smishra apic_change_eoi(); 8077282Smishra } 8087282Smishra 8090Sstevel@tonic-gate apic_init_intr(); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate /* enable apic mode if imcr present */ 8120Sstevel@tonic-gate if (apic_imcrp) { 8130Sstevel@tonic-gate outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT); 8140Sstevel@tonic-gate outb(APIC_IMCR_P2, (uchar_t)APIC_IMCR_APIC); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8173446Smrj ioapic_init_intr(IOAPIC_MASK); 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate 8213446Smrj /*ARGSUSED1*/ 8223446Smrj static int 8233446Smrj apic_cpu_start(processorid_t cpun, caddr_t arg) 8240Sstevel@tonic-gate { 8250Sstevel@tonic-gate int loop_count; 8260Sstevel@tonic-gate uint32_t vector; 8273446Smrj uint_t cpu_id; 8283446Smrj ulong_t iflag; 8290Sstevel@tonic-gate 8307282Smishra cpu_id = apic_cpus[cpun].aci_local_id; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate apic_cmos_ssb_set = 1; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * Interrupts on BSP cpu will be disabled during these startup 8360Sstevel@tonic-gate * steps in order to avoid unwanted side effects from 8370Sstevel@tonic-gate * executing interrupt handlers on a problematic BIOS. 8380Sstevel@tonic-gate */ 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate iflag = intr_clear(); 8410Sstevel@tonic-gate outb(CMOS_ADDR, SSB); 8420Sstevel@tonic-gate outb(CMOS_DATA, BIOS_SHUTDOWN); 8430Sstevel@tonic-gate 8447798SSaurabh.Mishra@Sun.COM /* 8457986SSaurabh.Mishra@Sun.COM * According to X2APIC specification in section '2.3.5.1' of 8467798SSaurabh.Mishra@Sun.COM * Interrupt Command Register Semantics, the semantics of 8477798SSaurabh.Mishra@Sun.COM * programming the Interrupt Command Register to dispatch an interrupt 8487798SSaurabh.Mishra@Sun.COM * is simplified. A single MSR write to the 64-bit ICR is required 8497798SSaurabh.Mishra@Sun.COM * for dispatching an interrupt. Specifically, with the 64-bit MSR 8507798SSaurabh.Mishra@Sun.COM * interface to ICR, system software is not required to check the 8517798SSaurabh.Mishra@Sun.COM * status of the delivery status bit prior to writing to the ICR 8527798SSaurabh.Mishra@Sun.COM * to send an IPI. With the removal of the Delivery Status bit, 8537798SSaurabh.Mishra@Sun.COM * system software no longer has a reason to read the ICR. It remains 8547798SSaurabh.Mishra@Sun.COM * readable only to aid in debugging. 8557798SSaurabh.Mishra@Sun.COM */ 8567798SSaurabh.Mishra@Sun.COM #ifdef DEBUG 8577798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 8587798SSaurabh.Mishra@Sun.COM #else 8597798SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC) { 8607798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 8617798SSaurabh.Mishra@Sun.COM } 8627798SSaurabh.Mishra@Sun.COM #endif /* DEBUG */ 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate /* for integrated - make sure there is one INIT IPI in buffer */ 8650Sstevel@tonic-gate /* for external - it will wake up the cpu */ 8667282Smishra apic_reg_ops->apic_write_int_cmd(cpu_id, AV_ASSERT | AV_RESET); 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* If only 1 CPU is installed, PENDING bit will not go low */ 8697798SSaurabh.Mishra@Sun.COM for (loop_count = 0x1000; loop_count; loop_count--) { 8707798SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC && 8717798SSaurabh.Mishra@Sun.COM apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING) 8720Sstevel@tonic-gate apic_ret(); 8730Sstevel@tonic-gate else 8740Sstevel@tonic-gate break; 8757798SSaurabh.Mishra@Sun.COM } 8760Sstevel@tonic-gate 8777282Smishra apic_reg_ops->apic_write_int_cmd(cpu_id, AV_DEASSERT | AV_RESET); 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate drv_usecwait(20000); /* 20 milli sec */ 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate if (apic_cpus[cpun].aci_local_ver >= APIC_INTEGRATED_VERS) { 8820Sstevel@tonic-gate /* integrated apic */ 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate vector = (rm_platter_pa >> MMU_PAGESHIFT) & 8850Sstevel@tonic-gate (APIC_VECTOR_MASK | APIC_IPL_MASK); 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate /* to offset the INIT IPI queue up in the buffer */ 8887282Smishra apic_reg_ops->apic_write_int_cmd(cpu_id, vector | AV_STARTUP); 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate drv_usecwait(200); /* 20 micro sec */ 8910Sstevel@tonic-gate 8927282Smishra apic_reg_ops->apic_write_int_cmd(cpu_id, vector | AV_STARTUP); 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate drv_usecwait(200); /* 20 micro sec */ 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate intr_restore(iflag); 8973446Smrj return (0); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate #ifdef DEBUG 9020Sstevel@tonic-gate int apic_break_on_cpu = 9; 9030Sstevel@tonic-gate int apic_stretch_interrupts = 0; 9040Sstevel@tonic-gate int apic_stretch_ISR = 1 << 3; /* IPL of 3 matches nothing now */ 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate void 9070Sstevel@tonic-gate apic_break() 9080Sstevel@tonic-gate { 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate #endif /* DEBUG */ 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate /* 9130Sstevel@tonic-gate * platform_intr_enter 9140Sstevel@tonic-gate * 9150Sstevel@tonic-gate * Called at the beginning of the interrupt service routine to 9160Sstevel@tonic-gate * mask all level equal to and below the interrupt priority 9170Sstevel@tonic-gate * of the interrupting vector. An EOI should be given to 9180Sstevel@tonic-gate * the interrupt controller to enable other HW interrupts. 9190Sstevel@tonic-gate * 9200Sstevel@tonic-gate * Return -1 for spurious interrupts 9210Sstevel@tonic-gate * 9220Sstevel@tonic-gate */ 9230Sstevel@tonic-gate /*ARGSUSED*/ 9240Sstevel@tonic-gate static int 9250Sstevel@tonic-gate apic_intr_enter(int ipl, int *vectorp) 9260Sstevel@tonic-gate { 9270Sstevel@tonic-gate uchar_t vector; 9280Sstevel@tonic-gate int nipl; 9293446Smrj int irq; 9303446Smrj ulong_t iflag; 9310Sstevel@tonic-gate apic_cpus_info_t *cpu_infop; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9343745Ssethg * The real vector delivered is (*vectorp + 0x20), but our caller 9353745Ssethg * subtracts 0x20 from the vector before passing it to us. 9363745Ssethg * (That's why APIC_BASE_VECT is 0x20.) 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate vector = (uchar_t)*vectorp; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate /* if interrupted by the clock, increment apic_nsec_since_boot */ 9410Sstevel@tonic-gate if (vector == apic_clkvect) { 9420Sstevel@tonic-gate if (!apic_oneshot) { 9430Sstevel@tonic-gate /* NOTE: this is not MT aware */ 9440Sstevel@tonic-gate apic_hrtime_stamp++; 9450Sstevel@tonic-gate apic_nsec_since_boot += apic_nsec_per_intr; 9460Sstevel@tonic-gate apic_hrtime_stamp++; 9470Sstevel@tonic-gate last_count_read = apic_hertz_count; 9480Sstevel@tonic-gate apic_redistribute_compute(); 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate /* We will avoid all the book keeping overhead for clock */ 9523745Ssethg nipl = apic_ipls[vector]; 9533745Ssethg 9547282Smishra *vectorp = apic_vector_to_irq[vector + APIC_BASE_VECT]; 9557282Smishra if (apic_mode == LOCAL_APIC) { 9560Sstevel@tonic-gate #if defined(__amd64) 9577282Smishra setcr8((ulong_t)(apic_ipltopri[nipl] >> 9587282Smishra APIC_IPL_SHIFT)); 9590Sstevel@tonic-gate #else 960*10080SJoe.Bonasera@sun.com if (apic_have_32bit_cr8) 961*10080SJoe.Bonasera@sun.com setcr8((ulong_t)(apic_ipltopri[nipl] >> 962*10080SJoe.Bonasera@sun.com APIC_IPL_SHIFT)); 963*10080SJoe.Bonasera@sun.com else 964*10080SJoe.Bonasera@sun.com LOCAL_APIC_WRITE_REG(APIC_TASK_REG, 965*10080SJoe.Bonasera@sun.com (uint32_t)apic_ipltopri[nipl]); 9660Sstevel@tonic-gate #endif 9677282Smishra LOCAL_APIC_WRITE_REG(APIC_EOI_REG, 0); 9687282Smishra } else { 9697282Smishra X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[nipl]); 9707282Smishra X2APIC_WRITE(APIC_EOI_REG, 0); 9717282Smishra } 9727282Smishra 9730Sstevel@tonic-gate return (nipl); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate cpu_infop = &apic_cpus[psm_get_cpu_id()]; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (vector == (APIC_SPUR_INTR - APIC_BASE_VECT)) { 9790Sstevel@tonic-gate cpu_infop->aci_spur_cnt++; 9800Sstevel@tonic-gate return (APIC_INT_SPURIOUS); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate /* Check if the vector we got is really what we need */ 9840Sstevel@tonic-gate if (apic_revector_pending) { 9850Sstevel@tonic-gate /* 9860Sstevel@tonic-gate * Disable interrupts for the duration of 9870Sstevel@tonic-gate * the vector translation to prevent a self-race for 9880Sstevel@tonic-gate * the apic_revector_lock. This cannot be done 9890Sstevel@tonic-gate * in apic_xlate_vector because it is recursive and 9900Sstevel@tonic-gate * we want the vector translation to be atomic with 9910Sstevel@tonic-gate * respect to other (higher-priority) interrupts. 9920Sstevel@tonic-gate */ 9930Sstevel@tonic-gate iflag = intr_clear(); 9940Sstevel@tonic-gate vector = apic_xlate_vector(vector + APIC_BASE_VECT) - 9950Sstevel@tonic-gate APIC_BASE_VECT; 9960Sstevel@tonic-gate intr_restore(iflag); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9993745Ssethg nipl = apic_ipls[vector]; 10000Sstevel@tonic-gate *vectorp = irq = apic_vector_to_irq[vector + APIC_BASE_VECT]; 10010Sstevel@tonic-gate 10027282Smishra if (apic_mode == LOCAL_APIC) { 10030Sstevel@tonic-gate #if defined(__amd64) 10047282Smishra setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT)); 10050Sstevel@tonic-gate #else 1006*10080SJoe.Bonasera@sun.com if (apic_have_32bit_cr8) 1007*10080SJoe.Bonasera@sun.com setcr8((ulong_t)(apic_ipltopri[nipl] >> 1008*10080SJoe.Bonasera@sun.com APIC_IPL_SHIFT)); 1009*10080SJoe.Bonasera@sun.com else 1010*10080SJoe.Bonasera@sun.com LOCAL_APIC_WRITE_REG(APIC_TASK_REG, 1011*10080SJoe.Bonasera@sun.com (uint32_t)apic_ipltopri[nipl]); 10120Sstevel@tonic-gate #endif 10137282Smishra } else { 10147282Smishra X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[nipl]); 10157282Smishra } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate cpu_infop->aci_current[nipl] = (uchar_t)irq; 10180Sstevel@tonic-gate cpu_infop->aci_curipl = (uchar_t)nipl; 10190Sstevel@tonic-gate cpu_infop->aci_ISR_in_progress |= 1 << nipl; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate /* 10220Sstevel@tonic-gate * apic_level_intr could have been assimilated into the irq struct. 10230Sstevel@tonic-gate * but, having it as a character array is more efficient in terms of 10240Sstevel@tonic-gate * cache usage. So, we leave it as is. 10250Sstevel@tonic-gate */ 10267282Smishra if (!apic_level_intr[irq]) { 10278918SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC) { 10287282Smishra LOCAL_APIC_WRITE_REG(APIC_EOI_REG, 0); 10298918SSaurabh.Mishra@Sun.COM } else { 10307282Smishra X2APIC_WRITE(APIC_EOI_REG, 0); 10318918SSaurabh.Mishra@Sun.COM } 10327282Smishra } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate #ifdef DEBUG 10350Sstevel@tonic-gate APIC_DEBUG_BUF_PUT(vector); 10360Sstevel@tonic-gate APIC_DEBUG_BUF_PUT(irq); 10370Sstevel@tonic-gate APIC_DEBUG_BUF_PUT(nipl); 10380Sstevel@tonic-gate APIC_DEBUG_BUF_PUT(psm_get_cpu_id()); 10390Sstevel@tonic-gate if ((apic_stretch_interrupts) && (apic_stretch_ISR & (1 << nipl))) 10400Sstevel@tonic-gate drv_usecwait(apic_stretch_interrupts); 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate if (apic_break_on_cpu == psm_get_cpu_id()) 10430Sstevel@tonic-gate apic_break(); 10440Sstevel@tonic-gate #endif /* DEBUG */ 10450Sstevel@tonic-gate return (nipl); 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate 10487282Smishra /* 10497986SSaurabh.Mishra@Sun.COM * This macro is a common code used by MMIO local apic and X2APIC 10507282Smishra * local apic. 10517282Smishra */ 10527282Smishra #define APIC_INTR_EXIT() \ 10537282Smishra { \ 10547282Smishra cpu_infop = &apic_cpus[psm_get_cpu_id()]; \ 10557282Smishra if (apic_level_intr[irq]) \ 10567282Smishra apic_reg_ops->apic_send_eoi(irq); \ 10577282Smishra cpu_infop->aci_curipl = (uchar_t)prev_ipl; \ 10587282Smishra /* ISR above current pri could not be in progress */ \ 10597282Smishra cpu_infop->aci_ISR_in_progress &= (2 << prev_ipl) - 1; \ 10607282Smishra } 10617282Smishra 10627282Smishra /* 10637986SSaurabh.Mishra@Sun.COM * Any changes made to this function must also change X2APIC 10647282Smishra * version of intr_exit. 10657282Smishra */ 10663446Smrj void 10670Sstevel@tonic-gate apic_intr_exit(int prev_ipl, int irq) 10680Sstevel@tonic-gate { 10690Sstevel@tonic-gate apic_cpus_info_t *cpu_infop; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate #if defined(__amd64) 10720Sstevel@tonic-gate setcr8((ulong_t)apic_cr8pri[prev_ipl]); 10730Sstevel@tonic-gate #else 1074*10080SJoe.Bonasera@sun.com if (apic_have_32bit_cr8) 1075*10080SJoe.Bonasera@sun.com setcr8((ulong_t)(apic_ipltopri[prev_ipl] >> APIC_IPL_SHIFT)); 1076*10080SJoe.Bonasera@sun.com else 1077*10080SJoe.Bonasera@sun.com apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl]; 10780Sstevel@tonic-gate #endif 10790Sstevel@tonic-gate 10807282Smishra APIC_INTR_EXIT(); 10817282Smishra } 10820Sstevel@tonic-gate 10837282Smishra /* 10847282Smishra * Same as apic_intr_exit() except it uses MSR rather than MMIO 10857282Smishra * to access local apic registers. 10867282Smishra */ 10877282Smishra void 10887282Smishra x2apic_intr_exit(int prev_ipl, int irq) 10897282Smishra { 10907282Smishra apic_cpus_info_t *cpu_infop; 10917282Smishra 10927282Smishra X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[prev_ipl]); 10937282Smishra APIC_INTR_EXIT(); 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10965084Sjohnlev intr_exit_fn_t 10975084Sjohnlev psm_intr_exit_fn(void) 10985084Sjohnlev { 10997282Smishra if (apic_mode == LOCAL_X2APIC) 11007282Smishra return (x2apic_intr_exit); 11017282Smishra 11025084Sjohnlev return (apic_intr_exit); 11035084Sjohnlev } 11045084Sjohnlev 11050Sstevel@tonic-gate /* 11067282Smishra * Mask all interrupts below or equal to the given IPL. 11077986SSaurabh.Mishra@Sun.COM * Any changes made to this function must also change X2APIC 11087282Smishra * version of setspl. 11090Sstevel@tonic-gate */ 11100Sstevel@tonic-gate static void 11110Sstevel@tonic-gate apic_setspl(int ipl) 11120Sstevel@tonic-gate { 11130Sstevel@tonic-gate #if defined(__amd64) 11140Sstevel@tonic-gate setcr8((ulong_t)apic_cr8pri[ipl]); 11150Sstevel@tonic-gate #else 1116*10080SJoe.Bonasera@sun.com if (apic_have_32bit_cr8) 1117*10080SJoe.Bonasera@sun.com setcr8((ulong_t)(apic_ipltopri[ipl] >> APIC_IPL_SHIFT)); 1118*10080SJoe.Bonasera@sun.com else 1119*10080SJoe.Bonasera@sun.com apicadr[APIC_TASK_REG] = apic_ipltopri[ipl]; 11200Sstevel@tonic-gate #endif 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* interrupts at ipl above this cannot be in progress */ 11230Sstevel@tonic-gate apic_cpus[psm_get_cpu_id()].aci_ISR_in_progress &= (2 << ipl) - 1; 11240Sstevel@tonic-gate /* 11250Sstevel@tonic-gate * this is a patch fix for the ALR QSMP P5 machine, so that interrupts 11260Sstevel@tonic-gate * have enough time to come in before the priority is raised again 11270Sstevel@tonic-gate * during the idle() loop. 11280Sstevel@tonic-gate */ 11290Sstevel@tonic-gate if (apic_setspl_delay) 11307282Smishra (void) apic_reg_ops->apic_get_pri(); 11317282Smishra } 11327282Smishra 11337282Smishra /* 11347986SSaurabh.Mishra@Sun.COM * X2APIC version of setspl. 11357282Smishra * Mask all interrupts below or equal to the given IPL 11367282Smishra */ 11377282Smishra static void 11387282Smishra x2apic_setspl(int ipl) 11397282Smishra { 11407282Smishra X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[ipl]); 11417282Smishra 11427282Smishra /* interrupts at ipl above this cannot be in progress */ 11437282Smishra apic_cpus[psm_get_cpu_id()].aci_ISR_in_progress &= (2 << ipl) - 1; 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate /* 11477986SSaurabh.Mishra@Sun.COM * generates an interprocessor interrupt to another CPU. Any changes made to 11487986SSaurabh.Mishra@Sun.COM * this routine must be accompanied by similar changes to 11497986SSaurabh.Mishra@Sun.COM * apic_common_send_ipi(). 11500Sstevel@tonic-gate */ 11510Sstevel@tonic-gate static void 11520Sstevel@tonic-gate apic_send_ipi(int cpun, int ipl) 11530Sstevel@tonic-gate { 11540Sstevel@tonic-gate int vector; 11553446Smrj ulong_t flag; 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate vector = apic_resv_vector[ipl]; 11580Sstevel@tonic-gate 11596896Sdmick ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR)); 11606896Sdmick 11610Sstevel@tonic-gate flag = intr_clear(); 11620Sstevel@tonic-gate 11637798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 11640Sstevel@tonic-gate 11657282Smishra apic_reg_ops->apic_write_int_cmd(apic_cpus[cpun].aci_local_id, 11667282Smishra vector); 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate intr_restore(flag); 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate /*ARGSUSED*/ 11730Sstevel@tonic-gate static void 11740Sstevel@tonic-gate apic_set_idlecpu(processorid_t cpun) 11750Sstevel@tonic-gate { 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate /*ARGSUSED*/ 11790Sstevel@tonic-gate static void 11800Sstevel@tonic-gate apic_unset_idlecpu(processorid_t cpun) 11810Sstevel@tonic-gate { 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate 11857282Smishra void 11860Sstevel@tonic-gate apic_ret() 11870Sstevel@tonic-gate { 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 11910Sstevel@tonic-gate * If apic_coarse_time == 1, then apic_gettime() is used instead of 11920Sstevel@tonic-gate * apic_gethrtime(). This is used for performance instead of accuracy. 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate static hrtime_t 11960Sstevel@tonic-gate apic_gettime() 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate int old_hrtime_stamp; 11990Sstevel@tonic-gate hrtime_t temp; 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate /* 12020Sstevel@tonic-gate * In one-shot mode, we do not keep time, so if anyone 12030Sstevel@tonic-gate * calls psm_gettime() directly, we vector over to 12040Sstevel@tonic-gate * gethrtime(). 12050Sstevel@tonic-gate * one-shot mode MUST NOT be enabled if this psm is the source of 12060Sstevel@tonic-gate * hrtime. 12070Sstevel@tonic-gate */ 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate if (apic_oneshot) 12100Sstevel@tonic-gate return (gethrtime()); 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate gettime_again: 12140Sstevel@tonic-gate while ((old_hrtime_stamp = apic_hrtime_stamp) & 1) 12150Sstevel@tonic-gate apic_ret(); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate temp = apic_nsec_since_boot; 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */ 12200Sstevel@tonic-gate goto gettime_again; 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate return (temp); 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate /* 12260Sstevel@tonic-gate * Here we return the number of nanoseconds since booting. Note every 12270Sstevel@tonic-gate * clock interrupt increments apic_nsec_since_boot by the appropriate 12280Sstevel@tonic-gate * amount. 12290Sstevel@tonic-gate */ 12300Sstevel@tonic-gate static hrtime_t 12310Sstevel@tonic-gate apic_gethrtime() 12320Sstevel@tonic-gate { 12333446Smrj int curr_timeval, countval, elapsed_ticks; 12340Sstevel@tonic-gate int old_hrtime_stamp, status; 12350Sstevel@tonic-gate hrtime_t temp; 12367282Smishra uint32_t cpun; 12373446Smrj ulong_t oflags; 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * In one-shot mode, we do not keep time, so if anyone 12410Sstevel@tonic-gate * calls psm_gethrtime() directly, we vector over to 12420Sstevel@tonic-gate * gethrtime(). 12430Sstevel@tonic-gate * one-shot mode MUST NOT be enabled if this psm is the source of 12440Sstevel@tonic-gate * hrtime. 12450Sstevel@tonic-gate */ 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (apic_oneshot) 12480Sstevel@tonic-gate return (gethrtime()); 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate oflags = intr_clear(); /* prevent migration */ 12510Sstevel@tonic-gate 12527282Smishra cpun = apic_reg_ops->apic_read(APIC_LID_REG); 12537282Smishra if (apic_mode == LOCAL_APIC) 12547282Smishra cpun >>= APIC_ID_BIT_OFFSET; 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate lock_set(&apic_gethrtime_lock); 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate gethrtime_again: 12590Sstevel@tonic-gate while ((old_hrtime_stamp = apic_hrtime_stamp) & 1) 12600Sstevel@tonic-gate apic_ret(); 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate /* 12630Sstevel@tonic-gate * Check to see which CPU we are on. Note the time is kept on 12640Sstevel@tonic-gate * the local APIC of CPU 0. If on CPU 0, simply read the current 12650Sstevel@tonic-gate * counter. If on another CPU, issue a remote read command to CPU 0. 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate if (cpun == apic_cpus[0].aci_local_id) { 12687282Smishra countval = apic_reg_ops->apic_read(APIC_CURR_COUNT); 12690Sstevel@tonic-gate } else { 12707798SSaurabh.Mishra@Sun.COM #ifdef DEBUG 12717798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 12727798SSaurabh.Mishra@Sun.COM #else 12737798SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC) 12747798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 12757798SSaurabh.Mishra@Sun.COM #endif /* DEBUG */ 12760Sstevel@tonic-gate 12777282Smishra apic_reg_ops->apic_write_int_cmd( 12787282Smishra apic_cpus[0].aci_local_id, APIC_CURR_ADD | AV_REMOTE); 12790Sstevel@tonic-gate 12807282Smishra while ((status = apic_reg_ops->apic_read(APIC_INT_CMD1)) 12817282Smishra & AV_READ_PENDING) { 12820Sstevel@tonic-gate apic_ret(); 12837282Smishra } 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate if (status & AV_REMOTE_STATUS) /* 1 = valid */ 12867282Smishra countval = apic_reg_ops->apic_read(APIC_REMOTE_READ); 12870Sstevel@tonic-gate else { /* 0 = invalid */ 12880Sstevel@tonic-gate apic_remote_hrterr++; 12890Sstevel@tonic-gate /* 12900Sstevel@tonic-gate * return last hrtime right now, will need more 12910Sstevel@tonic-gate * testing if change to retry 12920Sstevel@tonic-gate */ 12930Sstevel@tonic-gate temp = apic_last_hrtime; 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate lock_clear(&apic_gethrtime_lock); 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate intr_restore(oflags); 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate return (temp); 13000Sstevel@tonic-gate } 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate if (countval > last_count_read) 13030Sstevel@tonic-gate countval = 0; 13040Sstevel@tonic-gate else 13050Sstevel@tonic-gate last_count_read = countval; 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate elapsed_ticks = apic_hertz_count - countval; 13080Sstevel@tonic-gate 13092992Sdmick curr_timeval = APIC_TICKS_TO_NSECS(elapsed_ticks); 13100Sstevel@tonic-gate temp = apic_nsec_since_boot + curr_timeval; 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate if (apic_hrtime_stamp != old_hrtime_stamp) { /* got an interrupt */ 13130Sstevel@tonic-gate /* we might have clobbered last_count_read. Restore it */ 13140Sstevel@tonic-gate last_count_read = apic_hertz_count; 13150Sstevel@tonic-gate goto gethrtime_again; 13160Sstevel@tonic-gate } 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate if (temp < apic_last_hrtime) { 13190Sstevel@tonic-gate /* return last hrtime if error occurs */ 13200Sstevel@tonic-gate apic_hrtime_error++; 13210Sstevel@tonic-gate temp = apic_last_hrtime; 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate else 13240Sstevel@tonic-gate apic_last_hrtime = temp; 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate lock_clear(&apic_gethrtime_lock); 13270Sstevel@tonic-gate intr_restore(oflags); 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate return (temp); 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate /* apic NMI handler */ 13330Sstevel@tonic-gate /*ARGSUSED*/ 13340Sstevel@tonic-gate static void 13355084Sjohnlev apic_nmi_intr(caddr_t arg, struct regs *rp) 13360Sstevel@tonic-gate { 13370Sstevel@tonic-gate if (apic_shutdown_processors) { 13380Sstevel@tonic-gate apic_disable_local_apic(); 13390Sstevel@tonic-gate return; 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate 13425084Sjohnlev apic_error |= APIC_ERR_NMI; 13435084Sjohnlev 13445084Sjohnlev if (!lock_try(&apic_nmi_lock)) 13455084Sjohnlev return; 13465084Sjohnlev apic_num_nmis++; 13475084Sjohnlev 13485084Sjohnlev if (apic_kmdb_on_nmi && psm_debugger()) { 13495084Sjohnlev debug_enter("NMI received: entering kmdb\n"); 13505084Sjohnlev } else if (apic_panic_on_nmi) { 13515084Sjohnlev /* Keep panic from entering kmdb. */ 13525084Sjohnlev nopanicdebug = 1; 13535084Sjohnlev panic("NMI received\n"); 13545084Sjohnlev } else { 13555084Sjohnlev /* 13565084Sjohnlev * prom_printf is the best shot we have of something which is 13575084Sjohnlev * problem free from high level/NMI type of interrupts 13585084Sjohnlev */ 13595084Sjohnlev prom_printf("NMI received\n"); 13600Sstevel@tonic-gate } 13615084Sjohnlev 13625084Sjohnlev lock_clear(&apic_nmi_lock); 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate /*ARGSUSED*/ 13660Sstevel@tonic-gate static int 13670Sstevel@tonic-gate apic_addspl(int irqno, int ipl, int min_ipl, int max_ipl) 13680Sstevel@tonic-gate { 13693446Smrj return (apic_addspl_common(irqno, ipl, min_ipl, max_ipl)); 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate static int 13730Sstevel@tonic-gate apic_delspl(int irqno, int ipl, int min_ipl, int max_ipl) 13740Sstevel@tonic-gate { 13753446Smrj return (apic_delspl_common(irqno, ipl, min_ipl, max_ipl)); 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate static int 13790Sstevel@tonic-gate apic_post_cpu_start() 13800Sstevel@tonic-gate { 13816749Ssherrym int cpun; 13827986SSaurabh.Mishra@Sun.COM static int cpus_started = 1; 13837986SSaurabh.Mishra@Sun.COM struct psm_ops *pops = &apic_ops; 13847986SSaurabh.Mishra@Sun.COM 13857986SSaurabh.Mishra@Sun.COM /* We know this CPU + BSP started successfully. */ 13867986SSaurabh.Mishra@Sun.COM cpus_started++; 13870Sstevel@tonic-gate 13887798SSaurabh.Mishra@Sun.COM /* 13897798SSaurabh.Mishra@Sun.COM * On BSP we would have enabled X2APIC, if supported by processor, 13907798SSaurabh.Mishra@Sun.COM * in acpi_probe(), but on AP we do it here. 13917986SSaurabh.Mishra@Sun.COM * 13927986SSaurabh.Mishra@Sun.COM * We enable X2APIC mode only if BSP is running in X2APIC & the 13937986SSaurabh.Mishra@Sun.COM * local APIC mode of the current CPU is MMIO (xAPIC). 13947798SSaurabh.Mishra@Sun.COM */ 13957986SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_X2APIC && apic_detect_x2apic() && 13967986SSaurabh.Mishra@Sun.COM apic_local_mode() == LOCAL_APIC) { 13977798SSaurabh.Mishra@Sun.COM apic_enable_x2apic(); 13987798SSaurabh.Mishra@Sun.COM } 13997798SSaurabh.Mishra@Sun.COM 14007986SSaurabh.Mishra@Sun.COM /* 14017986SSaurabh.Mishra@Sun.COM * We change psm_send_ipi and send_dirintf only if Solaris 14027986SSaurabh.Mishra@Sun.COM * is booted in kmdb & the current CPU is the last CPU being 14037986SSaurabh.Mishra@Sun.COM * brought up. We don't need to do anything if Solaris is running 14047986SSaurabh.Mishra@Sun.COM * in MMIO mode (xAPIC). 14057986SSaurabh.Mishra@Sun.COM */ 14067986SSaurabh.Mishra@Sun.COM if ((boothowto & RB_DEBUG) && 14077986SSaurabh.Mishra@Sun.COM (cpus_started == boot_ncpus || cpus_started == apic_nproc) && 14087986SSaurabh.Mishra@Sun.COM apic_mode == LOCAL_X2APIC) { 14097986SSaurabh.Mishra@Sun.COM /* 14107986SSaurabh.Mishra@Sun.COM * We no longer need help from apic_common_send_ipi() 14117986SSaurabh.Mishra@Sun.COM * since we will not start any more CPUs. 14127986SSaurabh.Mishra@Sun.COM * 14137986SSaurabh.Mishra@Sun.COM * We will need to revisit this if we start supporting 14147986SSaurabh.Mishra@Sun.COM * hot-plugging of CPUs. 14157986SSaurabh.Mishra@Sun.COM */ 14167986SSaurabh.Mishra@Sun.COM pops->psm_send_ipi = x2apic_send_ipi; 14177986SSaurabh.Mishra@Sun.COM send_dirintf = pops->psm_send_ipi; 14187986SSaurabh.Mishra@Sun.COM } 14197986SSaurabh.Mishra@Sun.COM 14207798SSaurabh.Mishra@Sun.COM splx(ipltospl(LOCK_LEVEL)); 14210Sstevel@tonic-gate apic_init_intr(); 14220Sstevel@tonic-gate 14230Sstevel@tonic-gate /* 14240Sstevel@tonic-gate * since some systems don't enable the internal cache on the non-boot 14250Sstevel@tonic-gate * cpus, so we have to enable them here 14260Sstevel@tonic-gate */ 14273446Smrj setcr0(getcr0() & ~(CR0_CD | CR0_NW)); 14280Sstevel@tonic-gate 14297798SSaurabh.Mishra@Sun.COM #ifdef DEBUG 14307798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 14317798SSaurabh.Mishra@Sun.COM #else 14327798SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC) 14337798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 14347798SSaurabh.Mishra@Sun.COM #endif /* DEBUG */ 14350Sstevel@tonic-gate 14367113Sbholler /* 14377113Sbholler * We may be booting, or resuming from suspend; aci_status will 14387113Sbholler * be APIC_CPU_INTR_ENABLE if coming from suspend, so we add the 14397113Sbholler * APIC_CPU_ONLINE flag here rather than setting aci_status completely. 14407113Sbholler */ 14410Sstevel@tonic-gate cpun = psm_get_cpu_id(); 14427113Sbholler apic_cpus[cpun].aci_status |= APIC_CPU_ONLINE; 14430Sstevel@tonic-gate 14447282Smishra apic_reg_ops->apic_write(APIC_DIVIDE_REG, apic_divide_reg_init); 14450Sstevel@tonic-gate return (PSM_SUCCESS); 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate processorid_t 14490Sstevel@tonic-gate apic_get_next_processorid(processorid_t cpu_id) 14500Sstevel@tonic-gate { 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate int i; 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate if (cpu_id == -1) 14550Sstevel@tonic-gate return ((processorid_t)0); 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate for (i = cpu_id + 1; i < NCPU; i++) { 14582006Sandrei if (CPU_IN_SET(apic_cpumask, i)) 14590Sstevel@tonic-gate return (i); 14600Sstevel@tonic-gate } 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate return ((processorid_t)-1); 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate /* 14670Sstevel@tonic-gate * type == -1 indicates it is an internal request. Do not change 14680Sstevel@tonic-gate * resv_vector for these requests 14690Sstevel@tonic-gate */ 14700Sstevel@tonic-gate static int 14710Sstevel@tonic-gate apic_get_ipivect(int ipl, int type) 14720Sstevel@tonic-gate { 14730Sstevel@tonic-gate uchar_t vector; 14740Sstevel@tonic-gate int irq; 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate if (irq = apic_allocate_irq(APIC_VECTOR(ipl))) { 14770Sstevel@tonic-gate if (vector = apic_allocate_vector(ipl, irq, 1)) { 14780Sstevel@tonic-gate apic_irq_table[irq]->airq_mps_intr_index = 14790Sstevel@tonic-gate RESERVE_INDEX; 14800Sstevel@tonic-gate apic_irq_table[irq]->airq_vector = vector; 14810Sstevel@tonic-gate if (type != -1) { 14820Sstevel@tonic-gate apic_resv_vector[ipl] = vector; 14830Sstevel@tonic-gate } 14840Sstevel@tonic-gate return (irq); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate apic_error |= APIC_ERR_GET_IPIVECT_FAIL; 14880Sstevel@tonic-gate return (-1); /* shouldn't happen */ 14890Sstevel@tonic-gate } 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate static int 14920Sstevel@tonic-gate apic_getclkirq(int ipl) 14930Sstevel@tonic-gate { 14940Sstevel@tonic-gate int irq; 14950Sstevel@tonic-gate 14960Sstevel@tonic-gate if ((irq = apic_get_ipivect(ipl, -1)) == -1) 14970Sstevel@tonic-gate return (-1); 14980Sstevel@tonic-gate /* 14990Sstevel@tonic-gate * Note the vector in apic_clkvect for per clock handling. 15000Sstevel@tonic-gate */ 15010Sstevel@tonic-gate apic_clkvect = apic_irq_table[irq]->airq_vector - APIC_BASE_VECT; 15020Sstevel@tonic-gate APIC_VERBOSE_IOAPIC((CE_NOTE, "get_clkirq: vector = %x\n", 15030Sstevel@tonic-gate apic_clkvect)); 15040Sstevel@tonic-gate return (irq); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15072992Sdmick 15080Sstevel@tonic-gate /* 15090Sstevel@tonic-gate * Return the number of APIC clock ticks elapsed for 8245 to decrement 15100Sstevel@tonic-gate * (APIC_TIME_COUNT + pit_ticks_adj) ticks. 15110Sstevel@tonic-gate */ 15120Sstevel@tonic-gate static uint_t 15130Sstevel@tonic-gate apic_calibrate(volatile uint32_t *addr, uint16_t *pit_ticks_adj) 15140Sstevel@tonic-gate { 15150Sstevel@tonic-gate uint8_t pit_tick_lo; 15160Sstevel@tonic-gate uint16_t pit_tick, target_pit_tick; 15170Sstevel@tonic-gate uint32_t start_apic_tick, end_apic_tick; 15183446Smrj ulong_t iflag; 15197282Smishra uint32_t reg; 15200Sstevel@tonic-gate 15217282Smishra reg = addr + APIC_CURR_COUNT - apicadr; 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate iflag = intr_clear(); 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate do { 15260Sstevel@tonic-gate pit_tick_lo = inb(PITCTR0_PORT); 15270Sstevel@tonic-gate pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 15280Sstevel@tonic-gate } while (pit_tick < APIC_TIME_MIN || 15290Sstevel@tonic-gate pit_tick_lo <= APIC_LB_MIN || pit_tick_lo >= APIC_LB_MAX); 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate /* 15320Sstevel@tonic-gate * Wait for the 8254 to decrement by 5 ticks to ensure 15330Sstevel@tonic-gate * we didn't start in the middle of a tick. 15340Sstevel@tonic-gate * Compare with 0x10 for the wrap around case. 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate target_pit_tick = pit_tick - 5; 15370Sstevel@tonic-gate do { 15380Sstevel@tonic-gate pit_tick_lo = inb(PITCTR0_PORT); 15390Sstevel@tonic-gate pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 15400Sstevel@tonic-gate } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10); 15410Sstevel@tonic-gate 15427282Smishra start_apic_tick = apic_reg_ops->apic_read(reg); 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate /* 15450Sstevel@tonic-gate * Wait for the 8254 to decrement by 15460Sstevel@tonic-gate * (APIC_TIME_COUNT + pit_ticks_adj) ticks 15470Sstevel@tonic-gate */ 15480Sstevel@tonic-gate target_pit_tick = pit_tick - APIC_TIME_COUNT; 15490Sstevel@tonic-gate do { 15500Sstevel@tonic-gate pit_tick_lo = inb(PITCTR0_PORT); 15510Sstevel@tonic-gate pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo; 15520Sstevel@tonic-gate } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10); 15530Sstevel@tonic-gate 15547282Smishra end_apic_tick = apic_reg_ops->apic_read(reg); 15550Sstevel@tonic-gate 15560Sstevel@tonic-gate *pit_ticks_adj = target_pit_tick - pit_tick; 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate intr_restore(iflag); 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate return (start_apic_tick - end_apic_tick); 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate /* 15640Sstevel@tonic-gate * Initialise the APIC timer on the local APIC of CPU 0 to the desired 15650Sstevel@tonic-gate * frequency. Note at this stage in the boot sequence, the boot processor 15660Sstevel@tonic-gate * is the only active processor. 15670Sstevel@tonic-gate * hertz value of 0 indicates a one-shot mode request. In this case 15680Sstevel@tonic-gate * the function returns the resolution (in nanoseconds) for the hardware 15690Sstevel@tonic-gate * timer interrupt. If one-shot mode capability is not available, 15700Sstevel@tonic-gate * the return value will be 0. apic_enable_oneshot is a global switch 15710Sstevel@tonic-gate * for disabling the functionality. 15720Sstevel@tonic-gate * A non-zero positive value for hertz indicates a periodic mode request. 15730Sstevel@tonic-gate * In this case the hardware will be programmed to generate clock interrupts 15740Sstevel@tonic-gate * at hertz frequency and returns the resolution of interrupts in 15750Sstevel@tonic-gate * nanosecond. 15760Sstevel@tonic-gate */ 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate static int 15790Sstevel@tonic-gate apic_clkinit(int hertz) 15800Sstevel@tonic-gate { 15810Sstevel@tonic-gate uint_t apic_ticks = 0; 15822992Sdmick uint_t pit_ticks; 15830Sstevel@tonic-gate int ret; 15840Sstevel@tonic-gate uint16_t pit_ticks_adj; 15850Sstevel@tonic-gate static int firsttime = 1; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate if (firsttime) { 15882992Sdmick /* first time calibrate on CPU0 only */ 15892992Sdmick 15907282Smishra apic_reg_ops->apic_write(APIC_DIVIDE_REG, apic_divide_reg_init); 15917282Smishra apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL); 15920Sstevel@tonic-gate apic_ticks = apic_calibrate(apicadr, &pit_ticks_adj); 15930Sstevel@tonic-gate 15942992Sdmick /* total number of PIT ticks corresponding to apic_ticks */ 15952992Sdmick pit_ticks = APIC_TIME_COUNT + pit_ticks_adj; 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * Determine the number of nanoseconds per APIC clock tick 15990Sstevel@tonic-gate * and then determine how many APIC ticks to interrupt at the 16000Sstevel@tonic-gate * desired frequency 16012992Sdmick * apic_ticks / (pitticks / PIT_HZ) = apic_ticks_per_s 16022992Sdmick * (apic_ticks * PIT_HZ) / pitticks = apic_ticks_per_s 16032992Sdmick * apic_ticks_per_ns = (apic_ticks * PIT_HZ) / (pitticks * 10^9) 16043446Smrj * pic_ticks_per_SFns = 16052992Sdmick * (SF * apic_ticks * PIT_HZ) / (pitticks * 10^9) 16060Sstevel@tonic-gate */ 16072992Sdmick apic_ticks_per_SFnsecs = 16082992Sdmick ((SF * apic_ticks * PIT_HZ) / 16092992Sdmick ((uint64_t)pit_ticks * NANOSEC)); 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate /* the interval timer initial count is 32 bit max */ 16122992Sdmick apic_nsec_max = APIC_TICKS_TO_NSECS(APIC_MAXVAL); 16130Sstevel@tonic-gate firsttime = 0; 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate if (hertz != 0) { 16170Sstevel@tonic-gate /* periodic */ 16180Sstevel@tonic-gate apic_nsec_per_intr = NANOSEC / hertz; 16192992Sdmick apic_hertz_count = APIC_NSECS_TO_TICKS(apic_nsec_per_intr); 16200Sstevel@tonic-gate } 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate apic_int_busy_mark = (apic_int_busy_mark * 16230Sstevel@tonic-gate apic_sample_factor_redistribution) / 100; 16240Sstevel@tonic-gate apic_int_free_mark = (apic_int_free_mark * 16250Sstevel@tonic-gate apic_sample_factor_redistribution) / 100; 16260Sstevel@tonic-gate apic_diff_for_redistribution = (apic_diff_for_redistribution * 16270Sstevel@tonic-gate apic_sample_factor_redistribution) / 100; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate if (hertz == 0) { 16300Sstevel@tonic-gate /* requested one_shot */ 16315084Sjohnlev if (!tsc_gethrtime_enable || !apic_oneshot_enable) 16320Sstevel@tonic-gate return (0); 16330Sstevel@tonic-gate apic_oneshot = 1; 16342992Sdmick ret = (int)APIC_TICKS_TO_NSECS(1); 16350Sstevel@tonic-gate } else { 16360Sstevel@tonic-gate /* program the local APIC to interrupt at the given frequency */ 16377282Smishra apic_reg_ops->apic_write(APIC_INIT_COUNT, apic_hertz_count); 16387282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 16397282Smishra (apic_clkvect + APIC_BASE_VECT) | AV_TIME); 16400Sstevel@tonic-gate apic_oneshot = 0; 16410Sstevel@tonic-gate ret = NANOSEC / hertz; 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate return (ret); 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate /* 16490Sstevel@tonic-gate * apic_preshutdown: 16500Sstevel@tonic-gate * Called early in shutdown whilst we can still access filesystems to do 16510Sstevel@tonic-gate * things like loading modules which will be required to complete shutdown 16520Sstevel@tonic-gate * after filesystems are all unmounted. 16530Sstevel@tonic-gate */ 16540Sstevel@tonic-gate static void 16550Sstevel@tonic-gate apic_preshutdown(int cmd, int fcn) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate APIC_VERBOSE_POWEROFF(("apic_preshutdown(%d,%d); m=%d a=%d\n", 16580Sstevel@tonic-gate cmd, fcn, apic_poweroff_method, apic_enable_acpi)); 16590Sstevel@tonic-gate 16605295Srandyf if ((cmd != A_SHUTDOWN) || (fcn != AD_POWEROFF)) { 16615295Srandyf return; 16625295Srandyf } 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate static void 16660Sstevel@tonic-gate apic_shutdown(int cmd, int fcn) 16670Sstevel@tonic-gate { 16683446Smrj int restarts, attempts; 16693446Smrj int i; 16700Sstevel@tonic-gate uchar_t byte; 16713446Smrj ulong_t iflag; 16720Sstevel@tonic-gate 16738906SEric.Saxe@Sun.COM hpet_acpi_fini(); 16748906SEric.Saxe@Sun.COM 16750Sstevel@tonic-gate /* Send NMI to all CPUs except self to do per processor shutdown */ 16760Sstevel@tonic-gate iflag = intr_clear(); 16777798SSaurabh.Mishra@Sun.COM #ifdef DEBUG 16787798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 16797798SSaurabh.Mishra@Sun.COM #else 16807798SSaurabh.Mishra@Sun.COM if (apic_mode == LOCAL_APIC) 16817798SSaurabh.Mishra@Sun.COM APIC_AV_PENDING_SET(); 16827798SSaurabh.Mishra@Sun.COM #endif /* DEBUG */ 16830Sstevel@tonic-gate apic_shutdown_processors = 1; 16847282Smishra apic_reg_ops->apic_write(APIC_INT_CMD1, 16857282Smishra AV_NMI | AV_LEVEL | AV_SH_ALL_EXCSELF); 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* restore cmos shutdown byte before reboot */ 16880Sstevel@tonic-gate if (apic_cmos_ssb_set) { 16890Sstevel@tonic-gate outb(CMOS_ADDR, SSB); 16900Sstevel@tonic-gate outb(CMOS_DATA, 0); 16910Sstevel@tonic-gate } 16923446Smrj 16933446Smrj ioapic_disable_redirection(); 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate /* disable apic mode if imcr present */ 16960Sstevel@tonic-gate if (apic_imcrp) { 16970Sstevel@tonic-gate outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT); 16980Sstevel@tonic-gate outb(APIC_IMCR_P2, (uchar_t)APIC_IMCR_PIC); 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate apic_disable_local_apic(); 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate intr_restore(iflag); 17040Sstevel@tonic-gate 17053472Smyers /* remainder of function is for shutdown cases only */ 17063472Smyers if (cmd != A_SHUTDOWN) 17070Sstevel@tonic-gate return; 17083472Smyers 17094189Smyers /* 17104189Smyers * Switch system back into Legacy-Mode if using ACPI and 17114189Smyers * not powering-off. Some BIOSes need to remain in ACPI-mode 17124189Smyers * for power-off to succeed (Dell Dimension 4600) 17137656SSherry.Moore@Sun.COM * Do not disable ACPI while doing fastreboot 17144189Smyers */ 17157656SSherry.Moore@Sun.COM if (apic_enable_acpi && fcn != AD_POWEROFF && fcn != AD_FASTREBOOT) 17163472Smyers (void) AcpiDisable(); 17173472Smyers 17187656SSherry.Moore@Sun.COM if (fcn == AD_FASTREBOOT) { 17198767SSaurabh.Mishra@Sun.COM apic_reg_ops->apic_write(APIC_INT_CMD1, 17208767SSaurabh.Mishra@Sun.COM AV_ASSERT | AV_RESET | AV_SH_ALL_EXCSELF); 17217656SSherry.Moore@Sun.COM } 17227656SSherry.Moore@Sun.COM 17233472Smyers /* remainder of function is for shutdown+poweroff case only */ 17243472Smyers if (fcn != AD_POWEROFF) 17253472Smyers return; 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate switch (apic_poweroff_method) { 17280Sstevel@tonic-gate case APIC_POWEROFF_VIA_RTC: 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate /* select the extended NVRAM bank in the RTC */ 17310Sstevel@tonic-gate outb(CMOS_ADDR, RTC_REGA); 17320Sstevel@tonic-gate byte = inb(CMOS_DATA); 17330Sstevel@tonic-gate outb(CMOS_DATA, (byte | EXT_BANK)); 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate outb(CMOS_ADDR, PFR_REG); 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate /* for Predator must toggle the PAB bit */ 17380Sstevel@tonic-gate byte = inb(CMOS_DATA); 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate /* 17410Sstevel@tonic-gate * clear power active bar, wakeup alarm and 17420Sstevel@tonic-gate * kickstart 17430Sstevel@tonic-gate */ 17440Sstevel@tonic-gate byte &= ~(PAB_CBIT | WF_FLAG | KS_FLAG); 17450Sstevel@tonic-gate outb(CMOS_DATA, byte); 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* delay before next write */ 17480Sstevel@tonic-gate drv_usecwait(1000); 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate /* for S40 the following would suffice */ 17510Sstevel@tonic-gate byte = inb(CMOS_DATA); 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate /* power active bar control bit */ 17540Sstevel@tonic-gate byte |= PAB_CBIT; 17550Sstevel@tonic-gate outb(CMOS_DATA, byte); 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate break; 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate case APIC_POWEROFF_VIA_ASPEN_BMC: 17600Sstevel@tonic-gate restarts = 0; 17610Sstevel@tonic-gate restart_aspen_bmc: 17620Sstevel@tonic-gate if (++restarts == 3) 17630Sstevel@tonic-gate break; 17640Sstevel@tonic-gate attempts = 0; 17650Sstevel@tonic-gate do { 17660Sstevel@tonic-gate byte = inb(MISMIC_FLAG_REGISTER); 17670Sstevel@tonic-gate byte &= MISMIC_BUSY_MASK; 17680Sstevel@tonic-gate if (byte != 0) { 17690Sstevel@tonic-gate drv_usecwait(1000); 17700Sstevel@tonic-gate if (attempts >= 3) 17710Sstevel@tonic-gate goto restart_aspen_bmc; 17720Sstevel@tonic-gate ++attempts; 17730Sstevel@tonic-gate } 17740Sstevel@tonic-gate } while (byte != 0); 17750Sstevel@tonic-gate outb(MISMIC_CNTL_REGISTER, CC_SMS_GET_STATUS); 17760Sstevel@tonic-gate byte = inb(MISMIC_FLAG_REGISTER); 17770Sstevel@tonic-gate byte |= 0x1; 17780Sstevel@tonic-gate outb(MISMIC_FLAG_REGISTER, byte); 17790Sstevel@tonic-gate i = 0; 17800Sstevel@tonic-gate for (; i < (sizeof (aspen_bmc)/sizeof (aspen_bmc[0])); 17810Sstevel@tonic-gate i++) { 17820Sstevel@tonic-gate attempts = 0; 17830Sstevel@tonic-gate do { 17840Sstevel@tonic-gate byte = inb(MISMIC_FLAG_REGISTER); 17850Sstevel@tonic-gate byte &= MISMIC_BUSY_MASK; 17860Sstevel@tonic-gate if (byte != 0) { 17870Sstevel@tonic-gate drv_usecwait(1000); 17880Sstevel@tonic-gate if (attempts >= 3) 17890Sstevel@tonic-gate goto restart_aspen_bmc; 17900Sstevel@tonic-gate ++attempts; 17910Sstevel@tonic-gate } 17920Sstevel@tonic-gate } while (byte != 0); 17930Sstevel@tonic-gate outb(MISMIC_CNTL_REGISTER, aspen_bmc[i].cntl); 17940Sstevel@tonic-gate outb(MISMIC_DATA_REGISTER, aspen_bmc[i].data); 17950Sstevel@tonic-gate byte = inb(MISMIC_FLAG_REGISTER); 17960Sstevel@tonic-gate byte |= 0x1; 17970Sstevel@tonic-gate outb(MISMIC_FLAG_REGISTER, byte); 17980Sstevel@tonic-gate } 17990Sstevel@tonic-gate break; 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate case APIC_POWEROFF_VIA_SITKA_BMC: 18020Sstevel@tonic-gate restarts = 0; 18030Sstevel@tonic-gate restart_sitka_bmc: 18040Sstevel@tonic-gate if (++restarts == 3) 18050Sstevel@tonic-gate break; 18060Sstevel@tonic-gate attempts = 0; 18070Sstevel@tonic-gate do { 18080Sstevel@tonic-gate byte = inb(SMS_STATUS_REGISTER); 18090Sstevel@tonic-gate byte &= SMS_STATE_MASK; 18100Sstevel@tonic-gate if ((byte == SMS_READ_STATE) || 18110Sstevel@tonic-gate (byte == SMS_WRITE_STATE)) { 18120Sstevel@tonic-gate drv_usecwait(1000); 18130Sstevel@tonic-gate if (attempts >= 3) 18140Sstevel@tonic-gate goto restart_sitka_bmc; 18150Sstevel@tonic-gate ++attempts; 18160Sstevel@tonic-gate } 18170Sstevel@tonic-gate } while ((byte == SMS_READ_STATE) || 18180Sstevel@tonic-gate (byte == SMS_WRITE_STATE)); 18190Sstevel@tonic-gate outb(SMS_COMMAND_REGISTER, SMS_GET_STATUS); 18200Sstevel@tonic-gate i = 0; 18210Sstevel@tonic-gate for (; i < (sizeof (sitka_bmc)/sizeof (sitka_bmc[0])); 18220Sstevel@tonic-gate i++) { 18230Sstevel@tonic-gate attempts = 0; 18240Sstevel@tonic-gate do { 18250Sstevel@tonic-gate byte = inb(SMS_STATUS_REGISTER); 18260Sstevel@tonic-gate byte &= SMS_IBF_MASK; 18270Sstevel@tonic-gate if (byte != 0) { 18280Sstevel@tonic-gate drv_usecwait(1000); 18290Sstevel@tonic-gate if (attempts >= 3) 18300Sstevel@tonic-gate goto restart_sitka_bmc; 18310Sstevel@tonic-gate ++attempts; 18320Sstevel@tonic-gate } 18330Sstevel@tonic-gate } while (byte != 0); 18340Sstevel@tonic-gate outb(sitka_bmc[i].port, sitka_bmc[i].data); 18350Sstevel@tonic-gate } 18360Sstevel@tonic-gate break; 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate case APIC_POWEROFF_NONE: 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate /* If no APIC direct method, we will try using ACPI */ 18410Sstevel@tonic-gate if (apic_enable_acpi) { 18420Sstevel@tonic-gate if (acpi_poweroff() == 1) 18430Sstevel@tonic-gate return; 18440Sstevel@tonic-gate } else 18450Sstevel@tonic-gate return; 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate break; 18480Sstevel@tonic-gate } 18490Sstevel@tonic-gate /* 18500Sstevel@tonic-gate * Wait a limited time here for power to go off. 18510Sstevel@tonic-gate * If the power does not go off, then there was a 18520Sstevel@tonic-gate * problem and we should continue to the halt which 18530Sstevel@tonic-gate * prints a message for the user to press a key to 18540Sstevel@tonic-gate * reboot. 18550Sstevel@tonic-gate */ 18560Sstevel@tonic-gate drv_usecwait(7000000); /* wait seven seconds */ 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate } 18590Sstevel@tonic-gate 18600Sstevel@tonic-gate /* 18610Sstevel@tonic-gate * Try and disable all interrupts. We just assign interrupts to other 18620Sstevel@tonic-gate * processors based on policy. If any were bound by user request, we 18630Sstevel@tonic-gate * let them continue and return failure. We do not bother to check 18640Sstevel@tonic-gate * for cache affinity while rebinding. 18650Sstevel@tonic-gate */ 18660Sstevel@tonic-gate 18670Sstevel@tonic-gate static int 18680Sstevel@tonic-gate apic_disable_intr(processorid_t cpun) 18690Sstevel@tonic-gate { 18703446Smrj int bind_cpu = 0, i, hardbound = 0; 18710Sstevel@tonic-gate apic_irq_t *irq_ptr; 18723446Smrj ulong_t iflag; 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate iflag = intr_clear(); 18750Sstevel@tonic-gate lock_set(&apic_ioapic_lock); 18763139Ssethg 18773139Ssethg for (i = 0; i <= APIC_MAX_VECTOR; i++) { 18783139Ssethg if (apic_reprogram_info[i].done == B_FALSE) { 18793139Ssethg if (apic_reprogram_info[i].bindcpu == cpun) { 18803139Ssethg /* 18813139Ssethg * CPU is busy -- it's the target of 18823139Ssethg * a pending reprogramming attempt 18833139Ssethg */ 18843139Ssethg lock_clear(&apic_ioapic_lock); 18853139Ssethg intr_restore(iflag); 18863139Ssethg return (PSM_FAILURE); 18873139Ssethg } 18883139Ssethg } 18893139Ssethg } 18903139Ssethg 18910Sstevel@tonic-gate apic_cpus[cpun].aci_status &= ~APIC_CPU_INTR_ENABLE; 18923139Ssethg 18930Sstevel@tonic-gate apic_cpus[cpun].aci_curipl = 0; 18943139Ssethg 18950Sstevel@tonic-gate i = apic_min_device_irq; 18960Sstevel@tonic-gate for (; i <= apic_max_device_irq; i++) { 18970Sstevel@tonic-gate /* 18980Sstevel@tonic-gate * If there are bound interrupts on this cpu, then 18990Sstevel@tonic-gate * rebind them to other processors. 19000Sstevel@tonic-gate */ 19010Sstevel@tonic-gate if ((irq_ptr = apic_irq_table[i]) != NULL) { 19020Sstevel@tonic-gate ASSERT((irq_ptr->airq_temp_cpu == IRQ_UNBOUND) || 19030Sstevel@tonic-gate (irq_ptr->airq_temp_cpu == IRQ_UNINIT) || 19040Sstevel@tonic-gate ((irq_ptr->airq_temp_cpu & ~IRQ_USER_BOUND) < 19050Sstevel@tonic-gate apic_nproc)); 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate if (irq_ptr->airq_temp_cpu == (cpun | IRQ_USER_BOUND)) { 19080Sstevel@tonic-gate hardbound = 1; 19090Sstevel@tonic-gate continue; 19100Sstevel@tonic-gate } 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate if (irq_ptr->airq_temp_cpu == cpun) { 19130Sstevel@tonic-gate do { 19143446Smrj bind_cpu = apic_next_bind_cpu++; 19150Sstevel@tonic-gate if (bind_cpu >= apic_nproc) { 19160Sstevel@tonic-gate apic_next_bind_cpu = 1; 19170Sstevel@tonic-gate bind_cpu = 0; 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate } 19203139Ssethg } while (apic_rebind_all(irq_ptr, bind_cpu)); 19210Sstevel@tonic-gate } 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate } 19243139Ssethg 19253139Ssethg lock_clear(&apic_ioapic_lock); 19263139Ssethg intr_restore(iflag); 19273139Ssethg 19280Sstevel@tonic-gate if (hardbound) { 19290Sstevel@tonic-gate cmn_err(CE_WARN, "Could not disable interrupts on %d" 19300Sstevel@tonic-gate "due to user bound interrupts", cpun); 19310Sstevel@tonic-gate return (PSM_FAILURE); 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate else 19340Sstevel@tonic-gate return (PSM_SUCCESS); 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate 19377113Sbholler /* 19387113Sbholler * Bind interrupts to the CPU's local APIC. 19397113Sbholler * Interrupts should not be bound to a CPU's local APIC until the CPU 19407113Sbholler * is ready to receive interrupts. 19417113Sbholler */ 19420Sstevel@tonic-gate static void 19430Sstevel@tonic-gate apic_enable_intr(processorid_t cpun) 19440Sstevel@tonic-gate { 19453446Smrj int i; 19460Sstevel@tonic-gate apic_irq_t *irq_ptr; 19473446Smrj ulong_t iflag; 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate iflag = intr_clear(); 19500Sstevel@tonic-gate lock_set(&apic_ioapic_lock); 19513139Ssethg 19520Sstevel@tonic-gate apic_cpus[cpun].aci_status |= APIC_CPU_INTR_ENABLE; 19530Sstevel@tonic-gate 19540Sstevel@tonic-gate i = apic_min_device_irq; 19550Sstevel@tonic-gate for (i = apic_min_device_irq; i <= apic_max_device_irq; i++) { 19560Sstevel@tonic-gate if ((irq_ptr = apic_irq_table[i]) != NULL) { 19570Sstevel@tonic-gate if ((irq_ptr->airq_cpu & ~IRQ_USER_BOUND) == cpun) { 19580Sstevel@tonic-gate (void) apic_rebind_all(irq_ptr, 19593139Ssethg irq_ptr->airq_cpu); 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate } 19620Sstevel@tonic-gate } 19633139Ssethg 19643139Ssethg lock_clear(&apic_ioapic_lock); 19653139Ssethg intr_restore(iflag); 19660Sstevel@tonic-gate } 19670Sstevel@tonic-gate 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate /* 19700Sstevel@tonic-gate * This function will reprogram the timer. 19710Sstevel@tonic-gate * 19720Sstevel@tonic-gate * When in oneshot mode the argument is the absolute time in future to 19730Sstevel@tonic-gate * generate the interrupt at. 19740Sstevel@tonic-gate * 19750Sstevel@tonic-gate * When in periodic mode, the argument is the interval at which the 19760Sstevel@tonic-gate * interrupts should be generated. There is no need to support the periodic 19770Sstevel@tonic-gate * mode timer change at this time. 19780Sstevel@tonic-gate */ 19790Sstevel@tonic-gate static void 19800Sstevel@tonic-gate apic_timer_reprogram(hrtime_t time) 19810Sstevel@tonic-gate { 19820Sstevel@tonic-gate hrtime_t now; 19830Sstevel@tonic-gate uint_t ticks; 19843446Smrj int64_t delta; 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate /* 19870Sstevel@tonic-gate * We should be called from high PIL context (CBE_HIGH_PIL), 19880Sstevel@tonic-gate * so kpreempt is disabled. 19890Sstevel@tonic-gate */ 19900Sstevel@tonic-gate 19910Sstevel@tonic-gate if (!apic_oneshot) { 19920Sstevel@tonic-gate /* time is the interval for periodic mode */ 19932992Sdmick ticks = APIC_NSECS_TO_TICKS(time); 19940Sstevel@tonic-gate } else { 19950Sstevel@tonic-gate /* one shot mode */ 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate now = gethrtime(); 19982992Sdmick delta = time - now; 19992992Sdmick 20002992Sdmick if (delta <= 0) { 20010Sstevel@tonic-gate /* 20020Sstevel@tonic-gate * requested to generate an interrupt in the past 20030Sstevel@tonic-gate * generate an interrupt as soon as possible 20040Sstevel@tonic-gate */ 20050Sstevel@tonic-gate ticks = apic_min_timer_ticks; 20062992Sdmick } else if (delta > apic_nsec_max) { 20070Sstevel@tonic-gate /* 20080Sstevel@tonic-gate * requested to generate an interrupt at a time 20090Sstevel@tonic-gate * further than what we are capable of. Set to max 20100Sstevel@tonic-gate * the hardware can handle 20110Sstevel@tonic-gate */ 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate ticks = APIC_MAXVAL; 20140Sstevel@tonic-gate #ifdef DEBUG 20150Sstevel@tonic-gate cmn_err(CE_CONT, "apic_timer_reprogram, request at" 20160Sstevel@tonic-gate " %lld too far in future, current time" 20170Sstevel@tonic-gate " %lld \n", time, now); 20182992Sdmick #endif 20190Sstevel@tonic-gate } else 20202992Sdmick ticks = APIC_NSECS_TO_TICKS(delta); 20210Sstevel@tonic-gate } 20220Sstevel@tonic-gate 20230Sstevel@tonic-gate if (ticks < apic_min_timer_ticks) 20240Sstevel@tonic-gate ticks = apic_min_timer_ticks; 20250Sstevel@tonic-gate 20267282Smishra apic_reg_ops->apic_write(APIC_INIT_COUNT, ticks); 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate 20290Sstevel@tonic-gate /* 20300Sstevel@tonic-gate * This function will enable timer interrupts. 20310Sstevel@tonic-gate */ 20320Sstevel@tonic-gate static void 20330Sstevel@tonic-gate apic_timer_enable(void) 20340Sstevel@tonic-gate { 20350Sstevel@tonic-gate /* 20360Sstevel@tonic-gate * We should be Called from high PIL context (CBE_HIGH_PIL), 20370Sstevel@tonic-gate * so kpreempt is disabled. 20380Sstevel@tonic-gate */ 20390Sstevel@tonic-gate 20407282Smishra if (!apic_oneshot) { 20417282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 20427282Smishra (apic_clkvect + APIC_BASE_VECT) | AV_TIME); 20437282Smishra } else { 20440Sstevel@tonic-gate /* one shot */ 20457282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 20467282Smishra (apic_clkvect + APIC_BASE_VECT)); 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate } 20490Sstevel@tonic-gate 20500Sstevel@tonic-gate /* 20510Sstevel@tonic-gate * This function will disable timer interrupts. 20520Sstevel@tonic-gate */ 20530Sstevel@tonic-gate static void 20540Sstevel@tonic-gate apic_timer_disable(void) 20550Sstevel@tonic-gate { 20560Sstevel@tonic-gate /* 20570Sstevel@tonic-gate * We should be Called from high PIL context (CBE_HIGH_PIL), 20580Sstevel@tonic-gate * so kpreempt is disabled. 20590Sstevel@tonic-gate */ 20607282Smishra apic_reg_ops->apic_write(APIC_LOCAL_TIMER, 20617282Smishra (apic_clkvect + APIC_BASE_VECT) | AV_MASK); 20620Sstevel@tonic-gate } 20630Sstevel@tonic-gate 20648906SEric.Saxe@Sun.COM /* 20658906SEric.Saxe@Sun.COM * Set timer far into the future and return timer 20668906SEric.Saxe@Sun.COM * current Count in nanoseconds. 20678906SEric.Saxe@Sun.COM */ 20688906SEric.Saxe@Sun.COM hrtime_t 20698906SEric.Saxe@Sun.COM apic_timer_stop_count(void) 20708906SEric.Saxe@Sun.COM { 20718906SEric.Saxe@Sun.COM hrtime_t ns_val; 20728906SEric.Saxe@Sun.COM int enable_val, count_val; 20738906SEric.Saxe@Sun.COM 20748906SEric.Saxe@Sun.COM /* 20758906SEric.Saxe@Sun.COM * Should be called with interrupts disabled. 20768906SEric.Saxe@Sun.COM */ 20778906SEric.Saxe@Sun.COM ASSERT(!interrupts_enabled()); 20788906SEric.Saxe@Sun.COM 20798906SEric.Saxe@Sun.COM enable_val = apic_reg_ops->apic_read(APIC_LOCAL_TIMER); 20808906SEric.Saxe@Sun.COM if ((enable_val & AV_MASK) == AV_MASK) 20818906SEric.Saxe@Sun.COM return ((hrtime_t)-1); /* timer is disabled */ 20828906SEric.Saxe@Sun.COM 20838906SEric.Saxe@Sun.COM count_val = apic_reg_ops->apic_read(APIC_CURR_COUNT); 20848906SEric.Saxe@Sun.COM ns_val = APIC_TICKS_TO_NSECS(count_val); 20858906SEric.Saxe@Sun.COM 20868906SEric.Saxe@Sun.COM apic_reg_ops->apic_write(APIC_INIT_COUNT, APIC_MAXVAL); 20878906SEric.Saxe@Sun.COM 20888906SEric.Saxe@Sun.COM return (ns_val); 20898906SEric.Saxe@Sun.COM } 20908906SEric.Saxe@Sun.COM 20918906SEric.Saxe@Sun.COM /* 20928906SEric.Saxe@Sun.COM * Reprogram timer after Deep C-State. 20938906SEric.Saxe@Sun.COM */ 20948906SEric.Saxe@Sun.COM void 20958906SEric.Saxe@Sun.COM apic_timer_restart(hrtime_t time) 20968906SEric.Saxe@Sun.COM { 20978906SEric.Saxe@Sun.COM apic_timer_reprogram(time); 20988906SEric.Saxe@Sun.COM } 20990Sstevel@tonic-gate 21005107Seota ddi_periodic_t apic_periodic_id; 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate /* 21035107Seota * If this module needs a periodic handler for the interrupt distribution, it 21045107Seota * can be added here. The argument to the periodic handler is not currently 21055107Seota * used, but is reserved for future. 21060Sstevel@tonic-gate */ 21070Sstevel@tonic-gate static void 21080Sstevel@tonic-gate apic_post_cyclic_setup(void *arg) 21090Sstevel@tonic-gate { 21100Sstevel@tonic-gate _NOTE(ARGUNUSED(arg)) 21110Sstevel@tonic-gate /* cpu_lock is held */ 21125107Seota /* set up a periodic handler for intr redistribution */ 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate /* 21150Sstevel@tonic-gate * In peridoc mode intr redistribution processing is done in 21160Sstevel@tonic-gate * apic_intr_enter during clk intr processing 21170Sstevel@tonic-gate */ 21180Sstevel@tonic-gate if (!apic_oneshot) 21190Sstevel@tonic-gate return; 21205107Seota /* 21215107Seota * Register a periodical handler for the redistribution processing. 21225107Seota * On X86, CY_LOW_LEVEL is mapped to the level 2 interrupt, so 21235107Seota * DDI_IPL_2 should be passed to ddi_periodic_add() here. 21245107Seota */ 21255107Seota apic_periodic_id = ddi_periodic_add( 21265107Seota (void (*)(void *))apic_redistribute_compute, NULL, 21275107Seota apic_redistribute_sample_interval, DDI_IPL_2); 21280Sstevel@tonic-gate } 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate static void 21310Sstevel@tonic-gate apic_redistribute_compute(void) 21320Sstevel@tonic-gate { 21330Sstevel@tonic-gate int i, j, max_busy; 21340Sstevel@tonic-gate 21350Sstevel@tonic-gate if (apic_enable_dynamic_migration) { 21360Sstevel@tonic-gate if (++apic_nticks == apic_sample_factor_redistribution) { 21370Sstevel@tonic-gate /* 21380Sstevel@tonic-gate * Time to call apic_intr_redistribute(). 21390Sstevel@tonic-gate * reset apic_nticks. This will cause max_busy 21400Sstevel@tonic-gate * to be calculated below and if it is more than 21410Sstevel@tonic-gate * apic_int_busy, we will do the whole thing 21420Sstevel@tonic-gate */ 21430Sstevel@tonic-gate apic_nticks = 0; 21440Sstevel@tonic-gate } 21450Sstevel@tonic-gate max_busy = 0; 21460Sstevel@tonic-gate for (i = 0; i < apic_nproc; i++) { 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate /* 21490Sstevel@tonic-gate * Check if curipl is non zero & if ISR is in 21500Sstevel@tonic-gate * progress 21510Sstevel@tonic-gate */ 21520Sstevel@tonic-gate if (((j = apic_cpus[i].aci_curipl) != 0) && 21530Sstevel@tonic-gate (apic_cpus[i].aci_ISR_in_progress & (1 << j))) { 21540Sstevel@tonic-gate 21550Sstevel@tonic-gate int irq; 21560Sstevel@tonic-gate apic_cpus[i].aci_busy++; 21570Sstevel@tonic-gate irq = apic_cpus[i].aci_current[j]; 21580Sstevel@tonic-gate apic_irq_table[irq]->airq_busy++; 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate if (!apic_nticks && 21620Sstevel@tonic-gate (apic_cpus[i].aci_busy > max_busy)) 21630Sstevel@tonic-gate max_busy = apic_cpus[i].aci_busy; 21640Sstevel@tonic-gate } 21650Sstevel@tonic-gate if (!apic_nticks) { 21660Sstevel@tonic-gate if (max_busy > apic_int_busy_mark) { 21670Sstevel@tonic-gate /* 21680Sstevel@tonic-gate * We could make the following check be 21690Sstevel@tonic-gate * skipped > 1 in which case, we get a 21700Sstevel@tonic-gate * redistribution at half the busy mark (due to 21710Sstevel@tonic-gate * double interval). Need to be able to collect 21720Sstevel@tonic-gate * more empirical data to decide if that is a 21730Sstevel@tonic-gate * good strategy. Punt for now. 21740Sstevel@tonic-gate */ 21753446Smrj if (apic_skipped_redistribute) { 21760Sstevel@tonic-gate apic_cleanup_busy(); 21773446Smrj apic_skipped_redistribute = 0; 21783446Smrj } else { 21790Sstevel@tonic-gate apic_intr_redistribute(); 21803446Smrj } 21810Sstevel@tonic-gate } else 21820Sstevel@tonic-gate apic_skipped_redistribute++; 21830Sstevel@tonic-gate } 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate 21870Sstevel@tonic-gate 21883446Smrj /* 21893446Smrj * The following functions are in the platform specific file so that they 21903446Smrj * can be different functions depending on whether we are running on 21913446Smrj * bare metal or a hypervisor. 21923446Smrj */ 21930Sstevel@tonic-gate 21943446Smrj /* 21953446Smrj * map an apic for memory-mapped access 21963446Smrj */ 21973446Smrj uint32_t * 21983446Smrj mapin_apic(uint32_t addr, size_t len, int flags) 21993446Smrj { 22003446Smrj /*LINTED: pointer cast may result in improper alignment */ 22013446Smrj return ((uint32_t *)psm_map_phys(addr, len, flags)); 22023446Smrj } 22030Sstevel@tonic-gate 22043446Smrj uint32_t * 22053446Smrj mapin_ioapic(uint32_t addr, size_t len, int flags) 22063446Smrj { 22073446Smrj return (mapin_apic(addr, len, flags)); 22080Sstevel@tonic-gate } 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate /* 22113446Smrj * unmap an apic 22123139Ssethg */ 22133446Smrj void 22143446Smrj mapout_apic(caddr_t addr, size_t len) 22153139Ssethg { 22163446Smrj psm_unmap_phys(addr, len); 22173139Ssethg } 22183139Ssethg 22193446Smrj void 22203446Smrj mapout_ioapic(caddr_t addr, size_t len) 22213139Ssethg { 22223446Smrj mapout_apic(addr, len); 22233139Ssethg } 22243139Ssethg 22253139Ssethg /* 22264937Sjohnny * Check to make sure there are enough irq slots 22273139Ssethg */ 22283446Smrj int 22294937Sjohnny apic_check_free_irqs(int count) 22304937Sjohnny { 22314937Sjohnny int i, avail; 22324937Sjohnny 22334937Sjohnny avail = 0; 22344937Sjohnny for (i = APIC_FIRST_FREE_IRQ; i < APIC_RESV_IRQ; i++) { 22354937Sjohnny if ((apic_irq_table[i] == NULL) || 22364937Sjohnny apic_irq_table[i]->airq_mps_intr_index == FREE_INDEX) { 22374937Sjohnny if (++avail >= count) 22384937Sjohnny return (PSM_SUCCESS); 22394937Sjohnny } 22404937Sjohnny } 22414937Sjohnny return (PSM_FAILURE); 22424937Sjohnny } 22434937Sjohnny 22444937Sjohnny /* 22454937Sjohnny * This function allocates "count" MSI vector(s) for the given "dip/pri/type" 22464937Sjohnny */ 22474937Sjohnny int 22484937Sjohnny apic_alloc_msi_vectors(dev_info_t *dip, int inum, int count, int pri, 22493446Smrj int behavior) 22503139Ssethg { 22513446Smrj int rcount, i; 22527282Smishra uchar_t start, irqno; 22537282Smishra uint32_t cpu; 22543446Smrj major_t major; 22553446Smrj apic_irq_t *irqptr; 22563139Ssethg 22574937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msi_vectors: dip=0x%p " 22583446Smrj "inum=0x%x pri=0x%x count=0x%x behavior=%d\n", 22594937Sjohnny (void *)dip, inum, pri, count, behavior)); 22603139Ssethg 22613446Smrj if (count > 1) { 22623446Smrj if (behavior == DDI_INTR_ALLOC_STRICT && 22638925SEvan.Yan@Sun.COM apic_multi_msi_enable == 0) 22643446Smrj return (0); 22653446Smrj if (apic_multi_msi_enable == 0) 22663446Smrj count = 1; 22673446Smrj } 22683139Ssethg 22693446Smrj if ((rcount = apic_navail_vector(dip, pri)) > count) 22703446Smrj rcount = count; 22713446Smrj else if (rcount == 0 || (rcount < count && 22723446Smrj behavior == DDI_INTR_ALLOC_STRICT)) 22733446Smrj return (0); 22743139Ssethg 22753446Smrj /* if not ISP2, then round it down */ 22763446Smrj if (!ISP2(rcount)) 22773446Smrj rcount = 1 << (highbit(rcount) - 1); 22783139Ssethg 22793446Smrj mutex_enter(&airq_mutex); 22803446Smrj 22813446Smrj for (start = 0; rcount > 0; rcount >>= 1) { 22823446Smrj if ((start = apic_find_multi_vectors(pri, rcount)) != 0 || 22833446Smrj behavior == DDI_INTR_ALLOC_STRICT) 22843446Smrj break; 22853139Ssethg } 22863139Ssethg 22873446Smrj if (start == 0) { 22883446Smrj /* no vector available */ 22893446Smrj mutex_exit(&airq_mutex); 22903446Smrj return (0); 22913446Smrj } 22923446Smrj 22934937Sjohnny if (apic_check_free_irqs(rcount) == PSM_FAILURE) { 22944937Sjohnny /* not enough free irq slots available */ 22954937Sjohnny mutex_exit(&airq_mutex); 22964937Sjohnny return (0); 22974937Sjohnny } 22984937Sjohnny 22998459SJerry.Gilliam@Sun.COM major = (dip != NULL) ? ddi_driver_major(dip) : 0; 23003446Smrj for (i = 0; i < rcount; i++) { 23013446Smrj if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == 23023446Smrj (uchar_t)-1) { 23034937Sjohnny /* 23044937Sjohnny * shouldn't happen because of the 23054937Sjohnny * apic_check_free_irqs() check earlier 23064937Sjohnny */ 23073446Smrj mutex_exit(&airq_mutex); 23084937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msi_vectors: " 23093446Smrj "apic_allocate_irq failed\n")); 23103446Smrj return (i); 23113446Smrj } 23123446Smrj apic_max_device_irq = max(irqno, apic_max_device_irq); 23133446Smrj apic_min_device_irq = min(irqno, apic_min_device_irq); 23143446Smrj irqptr = apic_irq_table[irqno]; 23153446Smrj #ifdef DEBUG 23163446Smrj if (apic_vector_to_irq[start + i] != APIC_RESV_IRQ) 23174937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msi_vectors: " 23183446Smrj "apic_vector_to_irq is not APIC_RESV_IRQ\n")); 23193446Smrj #endif 23203446Smrj apic_vector_to_irq[start + i] = (uchar_t)irqno; 23213446Smrj 23223446Smrj irqptr->airq_vector = (uchar_t)(start + i); 23233446Smrj irqptr->airq_ioapicindex = (uchar_t)inum; /* start */ 23243446Smrj irqptr->airq_intin_no = (uchar_t)rcount; 23253446Smrj irqptr->airq_ipl = pri; 23263446Smrj irqptr->airq_vector = start + i; 23273446Smrj irqptr->airq_origirq = (uchar_t)(inum + i); 23283446Smrj irqptr->airq_share_id = 0; 23293446Smrj irqptr->airq_mps_intr_index = MSI_INDEX; 23303446Smrj irqptr->airq_dip = dip; 23313446Smrj irqptr->airq_major = major; 23323446Smrj if (i == 0) /* they all bound to the same cpu */ 23333446Smrj cpu = irqptr->airq_cpu = apic_bind_intr(dip, irqno, 23344397Sschwartz 0xff, 0xff); 23353446Smrj else 23363446Smrj irqptr->airq_cpu = cpu; 23374937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msi_vectors: irq=0x%x " 23383446Smrj "dip=0x%p vector=0x%x origirq=0x%x pri=0x%x\n", irqno, 23393446Smrj (void *)irqptr->airq_dip, irqptr->airq_vector, 23403446Smrj irqptr->airq_origirq, pri)); 23413446Smrj } 23423446Smrj mutex_exit(&airq_mutex); 23433446Smrj return (rcount); 23443139Ssethg } 23453139Ssethg 23463139Ssethg /* 23474937Sjohnny * This function allocates "count" MSI-X vector(s) for the given "dip/pri/type" 23484937Sjohnny */ 23494937Sjohnny int 23504937Sjohnny apic_alloc_msix_vectors(dev_info_t *dip, int inum, int count, int pri, 23514937Sjohnny int behavior) 23524937Sjohnny { 23534937Sjohnny int rcount, i; 23544937Sjohnny major_t major; 23554937Sjohnny 23564937Sjohnny mutex_enter(&airq_mutex); 23574937Sjohnny 23584937Sjohnny if ((rcount = apic_navail_vector(dip, pri)) > count) 23594937Sjohnny rcount = count; 23604937Sjohnny else if (rcount == 0 || (rcount < count && 23614937Sjohnny behavior == DDI_INTR_ALLOC_STRICT)) { 23624937Sjohnny rcount = 0; 23634937Sjohnny goto out; 23644937Sjohnny } 23654937Sjohnny 23664937Sjohnny if (apic_check_free_irqs(rcount) == PSM_FAILURE) { 23674937Sjohnny /* not enough free irq slots available */ 23684937Sjohnny rcount = 0; 23694937Sjohnny goto out; 23704937Sjohnny } 23714937Sjohnny 23728459SJerry.Gilliam@Sun.COM major = (dip != NULL) ? ddi_driver_major(dip) : 0; 23734937Sjohnny for (i = 0; i < rcount; i++) { 23744937Sjohnny uchar_t vector, irqno; 23754937Sjohnny apic_irq_t *irqptr; 23764937Sjohnny 23774937Sjohnny if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == 23784937Sjohnny (uchar_t)-1) { 23794937Sjohnny /* 23804937Sjohnny * shouldn't happen because of the 23814937Sjohnny * apic_check_free_irqs() check earlier 23824937Sjohnny */ 23834937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msix_vectors: " 23844937Sjohnny "apic_allocate_irq failed\n")); 23854937Sjohnny rcount = i; 23864937Sjohnny goto out; 23874937Sjohnny } 23884937Sjohnny if ((vector = apic_allocate_vector(pri, irqno, 1)) == 0) { 23894937Sjohnny /* 23904937Sjohnny * shouldn't happen because of the 23914937Sjohnny * apic_navail_vector() call earlier 23924937Sjohnny */ 23934937Sjohnny DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_msix_vectors: " 23944937Sjohnny "apic_allocate_vector failed\n")); 23954937Sjohnny rcount = i; 23964937Sjohnny goto out; 23974937Sjohnny } 23984937Sjohnny apic_max_device_irq = max(irqno, apic_max_device_irq); 23994937Sjohnny apic_min_device_irq = min(irqno, apic_min_device_irq); 24004937Sjohnny irqptr = apic_irq_table[irqno]; 24014937Sjohnny irqptr->airq_vector = (uchar_t)vector; 24024937Sjohnny irqptr->airq_ipl = pri; 24034937Sjohnny irqptr->airq_origirq = (uchar_t)(inum + i); 24044937Sjohnny irqptr->airq_share_id = 0; 24054937Sjohnny irqptr->airq_mps_intr_index = MSIX_INDEX; 24064937Sjohnny irqptr->airq_dip = dip; 24074937Sjohnny irqptr->airq_major = major; 24084937Sjohnny irqptr->airq_cpu = apic_bind_intr(dip, irqno, 0xff, 0xff); 24094937Sjohnny } 24104937Sjohnny out: 24114937Sjohnny mutex_exit(&airq_mutex); 24124937Sjohnny return (rcount); 24134937Sjohnny } 24144937Sjohnny 24154937Sjohnny /* 24163446Smrj * Allocate a free vector for irq at ipl. Takes care of merging of multiple 24173446Smrj * IPLs into a single APIC level as well as stretching some IPLs onto multiple 24183446Smrj * levels. APIC_HI_PRI_VECTS interrupts are reserved for high priority 24193446Smrj * requests and allocated only when pri is set. 24200Sstevel@tonic-gate */ 24213446Smrj uchar_t 24223446Smrj apic_allocate_vector(int ipl, int irq, int pri) 24230Sstevel@tonic-gate { 24243446Smrj int lowest, highest, i; 24250Sstevel@tonic-gate 24263446Smrj highest = apic_ipltopri[ipl] + APIC_VECTOR_MASK; 24273446Smrj lowest = apic_ipltopri[ipl - 1] + APIC_VECTOR_PER_IPL; 24280Sstevel@tonic-gate 24293446Smrj if (highest < lowest) /* Both ipl and ipl - 1 map to same pri */ 24303446Smrj lowest -= APIC_VECTOR_PER_IPL; 24313139Ssethg 24323446Smrj #ifdef DEBUG 24333446Smrj if (apic_restrict_vector) /* for testing shared interrupt logic */ 24343446Smrj highest = lowest + apic_restrict_vector + APIC_HI_PRI_VECTS; 24353446Smrj #endif /* DEBUG */ 24363446Smrj if (pri == 0) 24373446Smrj highest -= APIC_HI_PRI_VECTS; 24383139Ssethg 24393446Smrj for (i = lowest; i < highest; i++) { 24403446Smrj if (APIC_CHECK_RESERVE_VECTORS(i)) 24413446Smrj continue; 24423446Smrj if (apic_vector_to_irq[i] == APIC_RESV_IRQ) { 24433446Smrj apic_vector_to_irq[i] = (uchar_t)irq; 24443446Smrj return (i); 24450Sstevel@tonic-gate } 24460Sstevel@tonic-gate } 24470Sstevel@tonic-gate 24483446Smrj return (0); 24493446Smrj } 24503446Smrj 24513446Smrj /* Mark vector as not being used by any irq */ 24523446Smrj void 24533446Smrj apic_free_vector(uchar_t vector) 24543446Smrj { 24553446Smrj apic_vector_to_irq[vector] = APIC_RESV_IRQ; 24563446Smrj } 24573446Smrj 24583446Smrj uint32_t 24593446Smrj ioapic_read(int ioapic_ix, uint32_t reg) 24603446Smrj { 24613446Smrj volatile uint32_t *ioapic; 24623446Smrj 24633446Smrj ioapic = apicioadr[ioapic_ix]; 24643446Smrj ioapic[APIC_IO_REG] = reg; 24653446Smrj return (ioapic[APIC_IO_DATA]); 24663446Smrj } 24673139Ssethg 24683446Smrj void 24693446Smrj ioapic_write(int ioapic_ix, uint32_t reg, uint32_t value) 24703446Smrj { 24713446Smrj volatile uint32_t *ioapic; 24723446Smrj 24733446Smrj ioapic = apicioadr[ioapic_ix]; 24743446Smrj ioapic[APIC_IO_REG] = reg; 24753446Smrj ioapic[APIC_IO_DATA] = value; 24763446Smrj } 24773446Smrj 24787282Smishra void 24797282Smishra ioapic_write_eoi(int ioapic_ix, uint32_t value) 24807282Smishra { 24817282Smishra volatile uint32_t *ioapic; 24827282Smishra 24837282Smishra ioapic = apicioadr[ioapic_ix]; 24847282Smishra ioapic[APIC_IO_EOI] = value; 24857282Smishra } 24867282Smishra 24873446Smrj static processorid_t 24883446Smrj apic_find_cpu(int flag) 24893446Smrj { 24903446Smrj processorid_t acid = 0; 24913446Smrj int i; 24923446Smrj 24933446Smrj /* Find the first CPU with the passed-in flag set */ 24943446Smrj for (i = 0; i < apic_nproc; i++) { 24953446Smrj if (apic_cpus[i].aci_status & flag) { 24963446Smrj acid = i; 24973446Smrj break; 24983446Smrj } 24993446Smrj } 25003446Smrj 25013446Smrj ASSERT((apic_cpus[acid].aci_status & flag) != 0); 25023446Smrj return (acid); 25033446Smrj } 25043139Ssethg 25053446Smrj /* 25063446Smrj * Call rebind to do the actual programming. 25073446Smrj * Must be called with interrupts disabled and apic_ioapic_lock held 25083446Smrj * 'p' is polymorphic -- if this function is called to process a deferred 25093446Smrj * reprogramming, p is of type 'struct ioapic_reprogram_data *', from which 25103446Smrj * the irq pointer is retrieved. If not doing deferred reprogramming, 25113446Smrj * p is of the type 'apic_irq_t *'. 25123446Smrj * 25133446Smrj * apic_ioapic_lock must be held across this call, as it protects apic_rebind 25143446Smrj * and it protects apic_find_cpu() from a race in which a CPU can be taken 25153446Smrj * offline after a cpu is selected, but before apic_rebind is called to 25163446Smrj * bind interrupts to it. 25173446Smrj */ 25183446Smrj int 25193446Smrj apic_setup_io_intr(void *p, int irq, boolean_t deferred) 25203446Smrj { 25213446Smrj apic_irq_t *irqptr; 25223446Smrj struct ioapic_reprogram_data *drep = NULL; 25233446Smrj int rv; 25243446Smrj 25253446Smrj if (deferred) { 25263446Smrj drep = (struct ioapic_reprogram_data *)p; 25273446Smrj ASSERT(drep != NULL); 25283446Smrj irqptr = drep->irqp; 25293446Smrj } else 25303446Smrj irqptr = (apic_irq_t *)p; 25313446Smrj 25323446Smrj ASSERT(irqptr != NULL); 25333446Smrj 25343446Smrj rv = apic_rebind(irqptr, apic_irq_table[irq]->airq_cpu, drep); 25353446Smrj if (rv) { 25363446Smrj /* 25373446Smrj * CPU is not up or interrupts are disabled. Fall back to 25383446Smrj * the first available CPU 25393446Smrj */ 25403446Smrj rv = apic_rebind(irqptr, apic_find_cpu(APIC_CPU_INTR_ENABLE), 25413446Smrj drep); 25423446Smrj } 25433446Smrj 25443446Smrj return (rv); 25450Sstevel@tonic-gate } 25463446Smrj 25473446Smrj 25483446Smrj uchar_t 25493446Smrj apic_modify_vector(uchar_t vector, int irq) 25503446Smrj { 25513446Smrj apic_vector_to_irq[vector] = (uchar_t)irq; 25523446Smrj return (vector); 25533446Smrj } 25544397Sschwartz 25554397Sschwartz char * 25564397Sschwartz apic_get_apic_type() 25574397Sschwartz { 25584397Sschwartz return (apic_psm_info.p_mach_idstring); 25594397Sschwartz } 25607282Smishra 25617282Smishra void 25627282Smishra x2apic_update_psm() 25637282Smishra { 25647282Smishra struct psm_ops *pops = &apic_ops; 25657282Smishra 25667282Smishra ASSERT(pops != NULL); 25677282Smishra 25687986SSaurabh.Mishra@Sun.COM /* 25697986SSaurabh.Mishra@Sun.COM * We don't need to do any magic if one of the following 25707986SSaurabh.Mishra@Sun.COM * conditions is true : 25717986SSaurabh.Mishra@Sun.COM * - Not being run under kernel debugger. 25727986SSaurabh.Mishra@Sun.COM * - MP is not set. 25737986SSaurabh.Mishra@Sun.COM * - Booted with one CPU only. 25747986SSaurabh.Mishra@Sun.COM * - One CPU configured. 25757986SSaurabh.Mishra@Sun.COM * 25767986SSaurabh.Mishra@Sun.COM * We set apic_common_send_ipi() since kernel debuggers 25777986SSaurabh.Mishra@Sun.COM * attempt to send IPIs to other slave CPUs during 25787986SSaurabh.Mishra@Sun.COM * entry (exit) from (to) debugger. 25797986SSaurabh.Mishra@Sun.COM */ 25807986SSaurabh.Mishra@Sun.COM if (!(boothowto & RB_DEBUG) || use_mp == 0 || 25817986SSaurabh.Mishra@Sun.COM apic_nproc == 1 || boot_ncpus == 1) { 25827986SSaurabh.Mishra@Sun.COM pops->psm_send_ipi = x2apic_send_ipi; 25837986SSaurabh.Mishra@Sun.COM } else { 25847986SSaurabh.Mishra@Sun.COM pops->psm_send_ipi = apic_common_send_ipi; 25857986SSaurabh.Mishra@Sun.COM } 25867986SSaurabh.Mishra@Sun.COM 25877282Smishra pops->psm_intr_exit = x2apic_intr_exit; 25887282Smishra pops->psm_setspl = x2apic_setspl; 25897282Smishra 25907282Smishra send_dirintf = pops->psm_send_ipi; 25917986SSaurabh.Mishra@Sun.COM 25927986SSaurabh.Mishra@Sun.COM apic_mode = LOCAL_X2APIC; 25937986SSaurabh.Mishra@Sun.COM apic_change_ops(); 25947282Smishra } 25958675SVikram.Hegde@Sun.COM 25968675SVikram.Hegde@Sun.COM static void 25978675SVikram.Hegde@Sun.COM apic_intrr_init(int apic_mode) 25988675SVikram.Hegde@Sun.COM { 25998675SVikram.Hegde@Sun.COM if (psm_vt_ops != NULL) { 26008675SVikram.Hegde@Sun.COM if (((apic_intrr_ops_t *)psm_vt_ops)->apic_intrr_init(apic_mode) 26018675SVikram.Hegde@Sun.COM == DDI_SUCCESS) { 26028675SVikram.Hegde@Sun.COM apic_vt_ops = psm_vt_ops; 26038675SVikram.Hegde@Sun.COM apic_vt_ops->apic_intrr_enable(); 26048675SVikram.Hegde@Sun.COM } 26058675SVikram.Hegde@Sun.COM } 26068675SVikram.Hegde@Sun.COM } 26078675SVikram.Hegde@Sun.COM 26088675SVikram.Hegde@Sun.COM /*ARGSUSED*/ 26098675SVikram.Hegde@Sun.COM static void 26108675SVikram.Hegde@Sun.COM apic_record_ioapic_rdt(apic_irq_t *irq_ptr, ioapic_rdt_t *irdt) 26118675SVikram.Hegde@Sun.COM { 26128675SVikram.Hegde@Sun.COM irdt->ir_hi <<= APIC_ID_BIT_OFFSET; 26138675SVikram.Hegde@Sun.COM } 26148675SVikram.Hegde@Sun.COM 26158675SVikram.Hegde@Sun.COM /*ARGSUSED*/ 26168675SVikram.Hegde@Sun.COM static void 26178675SVikram.Hegde@Sun.COM apic_record_msi(apic_irq_t *irq_ptr, msi_regs_t *mregs) 26188675SVikram.Hegde@Sun.COM { 26198675SVikram.Hegde@Sun.COM mregs->mr_addr = MSI_ADDR_HDR | 26208675SVikram.Hegde@Sun.COM (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 26218675SVikram.Hegde@Sun.COM (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) | 26228675SVikram.Hegde@Sun.COM (mregs->mr_addr << MSI_ADDR_DEST_SHIFT); 26238675SVikram.Hegde@Sun.COM mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | 26248675SVikram.Hegde@Sun.COM mregs->mr_data; 26258675SVikram.Hegde@Sun.COM } 2626