Home | History | Annotate | Download | only in pcplusmp
      1   7282   mishra /*
      2   7282   mishra  * CDDL HEADER START
      3   7282   mishra  *
      4   7282   mishra  * The contents of this file are subject to the terms of the
      5   7282   mishra  * Common Development and Distribution License (the "License").
      6   7282   mishra  * You may not use this file except in compliance with the License.
      7   7282   mishra  *
      8   7282   mishra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9   7282   mishra  * or http://www.opensolaris.org/os/licensing.
     10   7282   mishra  * See the License for the specific language governing permissions
     11   7282   mishra  * and limitations under the License.
     12   7282   mishra  *
     13   7282   mishra  * When distributing Covered Code, include this CDDL HEADER in each
     14   7282   mishra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15   7282   mishra  * If applicable, add the following below this CDDL HEADER, with the
     16   7282   mishra  * fields enclosed by brackets "[]" replaced with your own identifying
     17   7282   mishra  * information: Portions Copyright [yyyy] [name of copyright owner]
     18   7282   mishra  *
     19   7282   mishra  * CDDL HEADER END
     20   7282   mishra  */
     21   7282   mishra /*
     22   8816   Edward  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23   7282   mishra  * Use is subject to license terms.
     24   7282   mishra  */
     25   7282   mishra 
     26   7282   mishra #include <sys/cpuvar.h>
     27   7282   mishra #include <sys/psm.h>
     28   7282   mishra #include <sys/archsystm.h>
     29   7282   mishra #include <sys/apic.h>
     30   7282   mishra #include <sys/sunddi.h>
     31   7282   mishra #include <sys/ddi_impldefs.h>
     32   7282   mishra #include <sys/mach_intr.h>
     33   7282   mishra #include <sys/sysmacros.h>
     34   7282   mishra #include <sys/trap.h>
     35   7282   mishra #include <sys/x86_archext.h>
     36   7282   mishra #include <sys/privregs.h>
     37   7282   mishra #include <sys/psm_common.h>
     38   7282   mishra 
     39   7986  Saurabh /* Function prototypes of local apic and X2APIC */
     40   7282   mishra static uint64_t local_apic_read(uint32_t reg);
     41   7282   mishra static void local_apic_write(uint32_t reg, uint64_t value);
     42   7282   mishra static int get_local_apic_pri(void);
     43   7282   mishra static void local_apic_write_task_reg(uint64_t value);
     44   7282   mishra static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
     45   7282   mishra static uint64_t local_x2apic_read(uint32_t msr);
     46   7282   mishra static void local_x2apic_write(uint32_t msr, uint64_t value);
     47   7282   mishra static int get_local_x2apic_pri(void);
     48   7282   mishra static void local_x2apic_write_task_reg(uint64_t value);
     49   7282   mishra static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
     50   7282   mishra 
     51   7282   mishra /*
     52   7986  Saurabh  * According to the X2APIC specification:
     53   7282   mishra  *
     54   7986  Saurabh  *   xAPIC global enable    X2APIC enable         Description
     55   7282   mishra  *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
     56   7282   mishra  * -----------------------------------------------------------
     57   7282   mishra  *      0 			0 	APIC is disabled
     58   7282   mishra  * 	0			1	Invalid
     59   7282   mishra  *	1			0	APIC is enabled in xAPIC mode
     60   7986  Saurabh  *	1			1	APIC is enabled in X2APIC mode
     61   7282   mishra  * -----------------------------------------------------------
     62   7282   mishra  */
     63   7282   mishra int	x2apic_enable = 1;
     64   7282   mishra int 	apic_mode = LOCAL_APIC;		/* Default mode is Local APIC */
     65   7282   mishra 
     66   7282   mishra /* Uses MMIO (Memory Mapped IO) */
     67   7282   mishra static apic_reg_ops_t local_apic_regs_ops = {
     68   7282   mishra 	local_apic_read,
     69   7282   mishra 	local_apic_write,
     70   7282   mishra 	get_local_apic_pri,
     71   7282   mishra 	local_apic_write_task_reg,
     72   7282   mishra 	local_apic_write_int_cmd,
     73   7282   mishra 	apic_send_EOI,
     74   7282   mishra };
     75   7282   mishra 
     76   7986  Saurabh /* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
     77   7282   mishra static apic_reg_ops_t x2apic_regs_ops = {
     78   7282   mishra 	local_x2apic_read,
     79   7282   mishra 	local_x2apic_write,
     80   7282   mishra 	get_local_x2apic_pri,
     81   7282   mishra 	local_x2apic_write_task_reg,
     82   7282   mishra 	local_x2apic_write_int_cmd,
     83   7282   mishra 	apic_send_EOI,
     84   7282   mishra };
     85   7282   mishra 
     86  10252      Joe int apic_have_32bit_cr8 = 0;
     87   7282   mishra 
     88   7282   mishra /* The default ops is local APIC (Memory Mapped IO) */
     89   7282   mishra apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
     90   7282   mishra 
     91   7282   mishra /*
     92   7282   mishra  * APIC register ops related data sturctures and functions.
     93   7282   mishra  */
     94   7282   mishra void apic_send_EOI();
     95   7282   mishra void apic_send_directed_EOI(uint32_t irq);
     96   7282   mishra 
     97   7282   mishra #define	X2APIC_CPUID_BIT	21
     98   7282   mishra #define	X2APIC_ENABLE_BIT	10
     99   7282   mishra 
    100   7282   mishra /*
    101   7282   mishra  * Local APIC Implementation
    102   7282   mishra  */
    103   7282   mishra static uint64_t
    104   7282   mishra local_apic_read(uint32_t reg)
    105   7282   mishra {
    106   7282   mishra 	return ((uint32_t)apicadr[reg]);
    107   7282   mishra }
    108   7282   mishra 
    109   7282   mishra static void
    110   7282   mishra local_apic_write(uint32_t reg, uint64_t value)
    111   7282   mishra {
    112   7282   mishra 	apicadr[reg] = (uint32_t)value;
    113   7282   mishra }
    114   7282   mishra 
    115   7282   mishra static int
    116   7282   mishra get_local_apic_pri(void)
    117   7282   mishra {
    118   7282   mishra #if defined(__amd64)
    119   7282   mishra 	return ((int)getcr8());
    120   7282   mishra #else
    121  10080      Joe 	if (apic_have_32bit_cr8)
    122  10080      Joe 		return ((int)getcr8());
    123   7282   mishra 	return (apicadr[APIC_TASK_REG]);
    124   7282   mishra #endif
    125   7282   mishra }
    126   7282   mishra 
    127   7282   mishra static void
    128   7282   mishra local_apic_write_task_reg(uint64_t value)
    129   7282   mishra {
    130   7282   mishra #if defined(__amd64)
    131   7282   mishra 	setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
    132   7282   mishra #else
    133  10080      Joe 	if (apic_have_32bit_cr8)
    134  10080      Joe 		setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
    135  10080      Joe 	else
    136  10080      Joe 		apicadr[APIC_TASK_REG] = (uint32_t)value;
    137   7282   mishra #endif
    138   7282   mishra }
    139   7282   mishra 
    140   7282   mishra static void
    141   7282   mishra local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
    142   7282   mishra {
    143   7282   mishra 	apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
    144   7282   mishra 	apicadr[APIC_INT_CMD1] = cmd1;
    145   7282   mishra }
    146   7282   mishra 
    147   7282   mishra /*
    148   7986  Saurabh  * X2APIC Implementation.
    149   7282   mishra  */
    150   7282   mishra static uint64_t
    151   7282   mishra local_x2apic_read(uint32_t msr)
    152   7282   mishra {
    153   7282   mishra 	uint64_t i;
    154   7282   mishra 
    155   7282   mishra 	i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
    156   7282   mishra 	return (i);
    157   7282   mishra }
    158   7282   mishra 
    159   7282   mishra static void
    160   7282   mishra local_x2apic_write(uint32_t msr, uint64_t value)
    161   7282   mishra {
    162   7282   mishra 	uint64_t tmp;
    163   7282   mishra 
    164   7282   mishra 	if (msr != APIC_EOI_REG) {
    165   7282   mishra 		tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
    166   7282   mishra 		tmp = (tmp & 0xffffffff00000000) | value;
    167   7445  Saurabh 	} else {
    168   7445  Saurabh 		tmp = 0;
    169   7282   mishra 	}
    170   7282   mishra 
    171   7282   mishra 	wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
    172   7282   mishra }
    173   7282   mishra 
    174   7282   mishra static int
    175   7282   mishra get_local_x2apic_pri(void)
    176   7282   mishra {
    177   7798  Saurabh 	return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
    178   7282   mishra }
    179   7282   mishra 
    180   7282   mishra static void
    181   7282   mishra local_x2apic_write_task_reg(uint64_t value)
    182   7282   mishra {
    183   7282   mishra 	X2APIC_WRITE(APIC_TASK_REG, value);
    184   7282   mishra }
    185   7282   mishra 
    186   7282   mishra static void
    187   7282   mishra local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
    188   7282   mishra {
    189   7282   mishra 	wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
    190   7282   mishra 	    (((uint64_t)cpu_id << 32) | cmd1));
    191   7282   mishra }
    192   7282   mishra 
    193   7282   mishra /*ARGSUSED*/
    194   7282   mishra void
    195   7282   mishra apic_send_EOI(uint32_t irq)
    196   7282   mishra {
    197   7282   mishra 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
    198   7282   mishra }
    199   7282   mishra 
    200   8816   Edward /*
    201   8816   Edward  * Support for Directed EOI capability is available in both the xAPIC
    202   8816   Edward  * and x2APIC mode.
    203   8816   Edward  */
    204   7282   mishra void
    205   7282   mishra apic_send_directed_EOI(uint32_t irq)
    206   7282   mishra {
    207   7282   mishra 	uchar_t ioapicindex;
    208   7282   mishra 	uchar_t vector;
    209   7282   mishra 	apic_irq_t *apic_irq;
    210   7282   mishra 	short intr_index;
    211   7282   mishra 
    212   8816   Edward 	/*
    213   8816   Edward 	 * Following the EOI to the local APIC unit, perform a directed
    214   8816   Edward 	 * EOI to the IOxAPIC generating the interrupt by writing to its
    215   8816   Edward 	 * EOI register.
    216   8816   Edward 	 *
    217   8816   Edward 	 * A broadcast EOI is not generated.
    218   8816   Edward 	 */
    219   8816   Edward 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
    220   7282   mishra 
    221   7282   mishra 	apic_irq = apic_irq_table[irq];
    222   7282   mishra 	while (apic_irq) {
    223   7282   mishra 		intr_index = apic_irq->airq_mps_intr_index;
    224   7282   mishra 		if (intr_index == ACPI_INDEX || intr_index >= 0) {
    225   7282   mishra 			ioapicindex = apic_irq->airq_ioapicindex;
    226   7282   mishra 			vector = apic_irq->airq_vector;
    227   7282   mishra 			ioapic_write_eoi(ioapicindex, vector);
    228   7282   mishra 		}
    229   7282   mishra 		apic_irq = apic_irq->airq_next;
    230   7282   mishra 	}
    231   7282   mishra }
    232   7282   mishra 
    233   7282   mishra int
    234   7282   mishra apic_detect_x2apic(void)
    235   7282   mishra {
    236   7282   mishra 	struct cpuid_regs cp;
    237   7282   mishra 
    238   7282   mishra 	if (x2apic_enable == 0)
    239   7282   mishra 		return (0);
    240   7282   mishra 
    241   7282   mishra 	cp.cp_eax = 1;
    242   7282   mishra 	(void) __cpuid_insn(&cp);
    243   7282   mishra 
    244   7282   mishra 	return ((cp.cp_ecx & (0x1 << X2APIC_CPUID_BIT)) ? 1 : 0);
    245   7282   mishra }
    246   7282   mishra 
    247   7282   mishra void
    248   7282   mishra apic_enable_x2apic(void)
    249   7282   mishra {
    250   7282   mishra 	uint64_t apic_base_msr;
    251   7282   mishra 
    252   7986  Saurabh 	if (apic_local_mode() == LOCAL_X2APIC) {
    253   7986  Saurabh 		/* BIOS apparently has enabled X2APIC */
    254   7986  Saurabh 		if (apic_mode != LOCAL_X2APIC)
    255   7986  Saurabh 			x2apic_update_psm();
    256   7986  Saurabh 		return;
    257   7986  Saurabh 	}
    258   7986  Saurabh 
    259   7986  Saurabh 	/*
    260   7986  Saurabh 	 * This is the first time we are enabling X2APIC on this CPU
    261   7986  Saurabh 	 */
    262   7282   mishra 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
    263   7282   mishra 	apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
    264   7282   mishra 	wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
    265   7282   mishra 
    266   7986  Saurabh 	if (apic_mode != LOCAL_X2APIC)
    267   7282   mishra 		x2apic_update_psm();
    268   7282   mishra }
    269   7282   mishra 
    270   7282   mishra /*
    271   7986  Saurabh  * Determine which mode the current CPU is in. See the table above.
    272   7986  Saurabh  * (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
    273   7986  Saurabh  */
    274   7986  Saurabh int
    275   7986  Saurabh apic_local_mode(void)
    276   7986  Saurabh {
    277   7986  Saurabh 	uint64_t apic_base_msr;
    278   7986  Saurabh 	int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
    279   7986  Saurabh 	    (0x1 << X2APIC_ENABLE_BIT));
    280   7986  Saurabh 
    281   7986  Saurabh 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
    282   7986  Saurabh 
    283   7986  Saurabh 	if ((apic_base_msr & bit) == bit)
    284   7986  Saurabh 		return (LOCAL_X2APIC);
    285   7986  Saurabh 	else
    286   7986  Saurabh 		return (LOCAL_APIC);
    287   7986  Saurabh }
    288   7986  Saurabh 
    289   7986  Saurabh void
    290  10345  Saurabh apic_set_directed_EOI_handler()
    291   7986  Saurabh {
    292   7986  Saurabh 	apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
    293  10345  Saurabh }
    294  10345  Saurabh 
    295  10345  Saurabh int
    296  10345  Saurabh apic_directed_EOI_supported()
    297  10345  Saurabh {
    298  10345  Saurabh 	uint32_t ver;
    299  10345  Saurabh 
    300  10345  Saurabh 	ver = apic_reg_ops->apic_read(APIC_VERS_REG);
    301  10345  Saurabh 	if (ver & APIC_DIRECTED_EOI_BIT)
    302  10345  Saurabh 		return (1);
    303  10345  Saurabh 
    304  10345  Saurabh 	return (0);
    305   7986  Saurabh }
    306   7986  Saurabh 
    307   7986  Saurabh /*
    308   7986  Saurabh  * Change apic_reg_ops depending upon the apic_mode.
    309   7986  Saurabh  */
    310   7986  Saurabh void
    311   7986  Saurabh apic_change_ops()
    312   7986  Saurabh {
    313   7986  Saurabh 	if (apic_mode == LOCAL_APIC)
    314   7986  Saurabh 		apic_reg_ops = &local_apic_regs_ops;
    315   7986  Saurabh 	else if (apic_mode == LOCAL_X2APIC)
    316   7986  Saurabh 		apic_reg_ops = &x2apic_regs_ops;
    317   7986  Saurabh }
    318   7986  Saurabh 
    319   7986  Saurabh /*
    320   7986  Saurabh  * Generates an interprocessor interrupt to another CPU when X2APIC mode is
    321   7282   mishra  * enabled.
    322   7282   mishra  */
    323   7282   mishra void
    324   7282   mishra x2apic_send_ipi(int cpun, int ipl)
    325   7282   mishra {
    326   7282   mishra 	int vector;
    327   7282   mishra 	ulong_t flag;
    328   7798  Saurabh 
    329   8918  Saurabh 	ASSERT(apic_mode == LOCAL_X2APIC);
    330   8918  Saurabh 
    331   7798  Saurabh 	/*
    332   7798  Saurabh 	 * With X2APIC, Intel relaxed the semantics of the
    333   7798  Saurabh 	 * WRMSR instruction such that references to the X2APIC
    334   7798  Saurabh 	 * MSR registers are no longer serializing instructions.
    335   7798  Saurabh 	 * The code that initiates IPIs assumes that some sort
    336   7798  Saurabh 	 * of memory serialization occurs. The old APIC code
    337   7798  Saurabh 	 * did a write to uncachable memory mapped registers.
    338   7798  Saurabh 	 * Any reference to uncached memory is a serializing
    339   7798  Saurabh 	 * operation. To mimic those semantics here, we do an
    340   7798  Saurabh 	 * atomic operation, which translates to a LOCK OR instruction,
    341   7798  Saurabh 	 * which is serializing.
    342   7798  Saurabh 	 */
    343   7798  Saurabh 	atomic_or_ulong(&flag, 1);
    344   7282   mishra 
    345   7282   mishra 	vector = apic_resv_vector[ipl];
    346   7282   mishra 
    347   7282   mishra 	flag = intr_clear();
    348   7282   mishra 
    349   7798  Saurabh 	/*
    350   7986  Saurabh 	 * According to X2APIC specification in section '2.3.5.1' of
    351   7798  Saurabh 	 * Interrupt Command Register Semantics, the semantics of
    352   7798  Saurabh 	 * programming Interrupt Command Register to dispatch an interrupt
    353   7798  Saurabh 	 * is simplified. A single MSR write to the 64-bit ICR is required
    354   7798  Saurabh 	 * for dispatching an interrupt. Specifically with the 64-bit MSR
    355   7798  Saurabh 	 * interface to ICR, system software is not required to check the
    356   7798  Saurabh 	 * status of the delivery status bit prior to writing to the ICR
    357   7798  Saurabh 	 * to send an IPI. With the removal of the Delivery Status bit,
    358   7798  Saurabh 	 * system software no longer has a reason to read the ICR. It remains
    359   7798  Saurabh 	 * readable only to aid in debugging.
    360   7798  Saurabh 	 */
    361   7798  Saurabh #ifdef	DEBUG
    362   7798  Saurabh 	APIC_AV_PENDING_SET();
    363   7798  Saurabh #endif	/* DEBUG */
    364   7282   mishra 
    365   8918  Saurabh 	if ((cpun == psm_get_cpu_id())) {
    366   8918  Saurabh 		X2APIC_WRITE(X2APIC_SELF_IPI, vector);
    367   8918  Saurabh 	} else {
    368   7282   mishra 		apic_reg_ops->apic_write_int_cmd(
    369   7282   mishra 		    apic_cpus[cpun].aci_local_id, vector);
    370   8918  Saurabh 	}
    371   7282   mishra 
    372   7282   mishra 	intr_restore(flag);
    373   7282   mishra }
    374   7282   mishra 
    375   7986  Saurabh /*
    376   7986  Saurabh  * Generates IPI to another CPU depending on the local APIC mode.
    377   7986  Saurabh  * apic_send_ipi() and x2apic_send_ipi() depends on the configured
    378   7986  Saurabh  * mode of the local APIC, but that may not match the actual mode
    379   7986  Saurabh  * early in CPU startup.
    380   7986  Saurabh  *
    381   7986  Saurabh  * Any changes made to this routine must be accompanied by similar
    382   7986  Saurabh  * changes to apic_send_ipi().
    383   7986  Saurabh  */
    384   7986  Saurabh void
    385   7986  Saurabh apic_common_send_ipi(int cpun, int ipl)
    386   7986  Saurabh {
    387   7986  Saurabh 	int vector;
    388   7986  Saurabh 	ulong_t flag;
    389   7986  Saurabh 	int mode = apic_local_mode();
    390   7282   mishra 
    391   7986  Saurabh 	if (mode == LOCAL_X2APIC) {
    392   7986  Saurabh 		x2apic_send_ipi(cpun, ipl);
    393   7986  Saurabh 		return;
    394   7986  Saurabh 	}
    395   7986  Saurabh 
    396   7986  Saurabh 	ASSERT(mode == LOCAL_APIC);
    397   7986  Saurabh 
    398   7986  Saurabh 	vector = apic_resv_vector[ipl];
    399   7986  Saurabh 	ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
    400   7986  Saurabh 	flag = intr_clear();
    401   7986  Saurabh 	while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
    402   7986  Saurabh 		apic_ret();
    403   7986  Saurabh 	local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
    404   7986  Saurabh 	    vector);
    405   7986  Saurabh 	intr_restore(flag);
    406   7282   mishra }
    407