b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * CDDL HEADER START
b6917abefc343244b784f0cc34bc65b01469c3bfmishra *
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * The contents of this file are subject to the terms of the
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * Common Development and Distribution License (the "License").
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * You may not use this file except in compliance with the License.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra *
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * or http://www.opensolaris.org/os/licensing.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * See the License for the specific language governing permissions
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * and limitations under the License.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra *
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * When distributing Covered Code, include this CDDL HEADER in each
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * If applicable, add the following below this CDDL HEADER, with the
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * fields enclosed by brackets "[]" replaced with your own identifying
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * information: Portions Copyright [yyyy] [name of copyright owner]
b6917abefc343244b784f0cc34bc65b01469c3bfmishra *
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * CDDL HEADER END
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * Use is subject to license terms.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
6eedf6a58bb97d935b764a55719f82a486168fbbJosef 'Jeff' Sipek/*
6eedf6a58bb97d935b764a55719f82a486168fbbJosef 'Jeff' Sipek * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * Copyright (c) 2014 by Delphix. All rights reserved.
6eedf6a58bb97d935b764a55719f82a486168fbbJosef 'Jeff' Sipek */
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/cpuvar.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/psm.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/archsystm.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/apic.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/sunddi.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/ddi_impldefs.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/mach_intr.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/sysmacros.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/trap.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/x86_archext.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/privregs.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#include <sys/psm_common.h>
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra/* Function prototypes of local apic and X2APIC */
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic uint64_t local_apic_read(uint32_t reg);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_apic_write(uint32_t reg, uint64_t value);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic int get_local_apic_pri(void);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_apic_write_task_reg(uint64_t value);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic uint64_t local_x2apic_read(uint32_t msr);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_x2apic_write(uint32_t msr, uint64_t value);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic int get_local_x2apic_pri(void);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_x2apic_write_task_reg(uint64_t value);
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * According to the X2APIC specification:
b6917abefc343244b784f0cc34bc65b01469c3bfmishra *
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * xAPIC global enable X2APIC enable Description
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * -----------------------------------------------------------
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * 0 0 APIC is disabled
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * 0 1 Invalid
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * 1 0 APIC is enabled in xAPIC mode
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * 1 1 APIC is enabled in X2APIC mode
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * -----------------------------------------------------------
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishraint x2apic_enable = 1;
9b1d70f8223c4278acf4ca60eaf5dd285f72eeeeJosef 'Jeff' Sipekapic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald/* See apic_directed_EOI_supported(). Currently 3-state variable. */
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonaldvolatile int apic_directed_eoi_state = 2;
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/* Uses MMIO (Memory Mapped IO) */
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic apic_reg_ops_t local_apic_regs_ops = {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_apic_read,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_apic_write,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra get_local_apic_pri,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_apic_write_task_reg,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_apic_write_int_cmd,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_send_EOI,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra};
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic apic_reg_ops_t x2apic_regs_ops = {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_x2apic_read,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_x2apic_write,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra get_local_x2apic_pri,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_x2apic_write_task_reg,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra local_x2apic_write_int_cmd,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_send_EOI,
b6917abefc343244b784f0cc34bc65b01469c3bfmishra};
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
4c1c9391ff5b1b69f6fc02ce905b96759cc50fc0Joe Bonaseraint apic_have_32bit_cr8 = 0;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/* The default ops is local APIC (Memory Mapped IO) */
b6917abefc343244b784f0cc34bc65b01469c3bfmishraapic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * APIC register ops related data sturctures and functions.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid apic_send_EOI();
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid apic_send_directed_EOI(uint32_t irq);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#define X2APIC_ENABLE_BIT 10
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * Local APIC Implementation
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic uint64_t
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_apic_read(uint32_t reg)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra return ((uint32_t)apicadr[reg]);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_apic_write(uint32_t reg, uint64_t value)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apicadr[reg] = (uint32_t)value;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic int
b6917abefc343244b784f0cc34bc65b01469c3bfmishraget_local_apic_pri(void)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#if defined(__amd64)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra return ((int)getcr8());
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#else
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera if (apic_have_32bit_cr8)
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera return ((int)getcr8());
b6917abefc343244b784f0cc34bc65b01469c3bfmishra return (apicadr[APIC_TASK_REG]);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#endif
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_apic_write_task_reg(uint64_t value)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#if defined(__amd64)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#else
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera if (apic_have_32bit_cr8)
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera else
2ef50f010f7a3a07eb5a9f6001b9843fd868e26bJoe Bonasera apicadr[APIC_TASK_REG] = (uint32_t)value;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra#endif
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apicadr[APIC_INT_CMD1] = cmd1;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * X2APIC Implementation.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic uint64_t
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_x2apic_read(uint32_t msr)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra uint64_t i;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra return (i);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_x2apic_write(uint32_t msr, uint64_t value)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra uint64_t tmp;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra if (msr != APIC_EOI_REG) {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
b6917abefc343244b784f0cc34bc65b01469c3bfmishra tmp = (tmp & 0xffffffff00000000) | value;
f9c480cd662f42d54475b87370bc2f4811ec0679Saurabh Misra } else {
f9c480cd662f42d54475b87370bc2f4811ec0679Saurabh Misra tmp = 0;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra }
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic int
b6917abefc343244b784f0cc34bc65b01469c3bfmishraget_local_x2apic_pri(void)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_x2apic_write_task_reg(uint64_t value)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra X2APIC_WRITE(APIC_TASK_REG, value);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishrastatic void
b6917abefc343244b784f0cc34bc65b01469c3bfmishralocal_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
b6917abefc343244b784f0cc34bc65b01469c3bfmishra (((uint64_t)cpu_id << 32) | cmd1));
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*ARGSUSED*/
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid
b6917abefc343244b784f0cc34bc65b01469c3bfmishraapic_send_EOI(uint32_t irq)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_reg_ops->apic_write(APIC_EOI_REG, 0);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett/*
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * Support for Directed EOI capability is available in both the xAPIC
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * and x2APIC mode.
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett */
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid
b6917abefc343244b784f0cc34bc65b01469c3bfmishraapic_send_directed_EOI(uint32_t irq)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra uchar_t ioapicindex;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra uchar_t vector;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_irq_t *apic_irq;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra short intr_index;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett /*
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * Following the EOI to the local APIC unit, perform a directed
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * EOI to the IOxAPIC generating the interrupt by writing to its
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * EOI register.
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett *
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett * A broadcast EOI is not generated.
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett */
d23e508cd51e6b3ec3f10a427259d7dd2592fa94Edward Gillett apic_reg_ops->apic_write(APIC_EOI_REG, 0);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_irq = apic_irq_table[irq];
b6917abefc343244b784f0cc34bc65b01469c3bfmishra while (apic_irq) {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra intr_index = apic_irq->airq_mps_intr_index;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra if (intr_index == ACPI_INDEX || intr_index >= 0) {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra ioapicindex = apic_irq->airq_ioapicindex;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra vector = apic_irq->airq_vector;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra ioapic_write_eoi(ioapicindex, vector);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra }
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_irq = apic_irq->airq_next;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra }
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishraint
b6917abefc343244b784f0cc34bc65b01469c3bfmishraapic_detect_x2apic(void)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra if (x2apic_enable == 0)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra return (0);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
6eedf6a58bb97d935b764a55719f82a486168fbbJosef 'Jeff' Sipek return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid
b6917abefc343244b784f0cc34bc65b01469c3bfmishraapic_enable_x2apic(void)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra uint64_t apic_base_msr;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if (apic_local_mode() == LOCAL_X2APIC) {
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra /* BIOS apparently has enabled X2APIC */
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if (apic_mode != LOCAL_X2APIC)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra x2apic_update_psm();
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra return;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra }
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra /*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * This is the first time we are enabling X2APIC on this CPU
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if (apic_mode != LOCAL_X2APIC)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra x2apic_update_psm();
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * Determine which mode the current CPU is in. See the table above.
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10])
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra */
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misraint
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misraapic_local_mode(void)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra{
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra uint64_t apic_base_msr;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra (0x1 << X2APIC_ENABLE_BIT));
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if ((apic_base_msr & bit) == bit)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra return (LOCAL_X2APIC);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra else
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra return (LOCAL_APIC);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra}
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misravoid
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misraapic_set_directed_EOI_handler()
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra{
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra}
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misraint
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misraapic_directed_EOI_supported()
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra{
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra uint32_t ver;
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald /*
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * There are some known issues with some versions of Linux KVM and QEMU
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * where by directed EOIs do not properly function and instead get
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * coalesced at the hypervisor, causing the host not to see interrupts.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * Thus, when the platform is KVM, we would like to disable it by
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * default, but keep it available otherwise.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald *
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * We use a three-state variable (apic_directed_eoi_state) to determine
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * how we handle directed EOI.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald *
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * 0 --> Don't do directed EOI at all.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * 1 --> Do directed EOI if available, no matter the HW environment.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * 2 --> Don't do directed EOI on KVM, but do it otherwise if available.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald *
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * If some grinning weirdo put something else in there, treat it as '2'
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * (i.e. the current default).
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald *
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * Note, at this time illumos KVM does not identify as KVM. If it does,
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * we'll need to do some work to determine if it should be caught by
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald * this or if it should show up as its own value of platform_type.
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald */
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald switch (apic_directed_eoi_state) {
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald case 0:
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald /* Don't do it at all. */
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald return (0);
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald case 1:
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald break;
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald case 2:
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald default:
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald /* Only do it if we aren't on KVM. */
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald if (get_hwenv() == HW_KVM)
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald return (0);
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald /* FALLTHRU */
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald }
3f745f41d6d087602fbb2f748e1baabc3768f5fbDan McDonald
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra ver = apic_reg_ops->apic_read(APIC_VERS_REG);
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra if (ver & APIC_DIRECTED_EOI_BIT)
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra return (1);
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra return (0);
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra}
e511d54dfc1c7eb3aea1a9125b54791fc2f23d42Saurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * Change apic_reg_ops depending upon the apic_mode.
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra */
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misravoid
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misraapic_change_ops()
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra{
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if (apic_mode == LOCAL_APIC)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra apic_reg_ops = &local_apic_regs_ops;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra else if (apic_mode == LOCAL_X2APIC)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra apic_reg_ops = &x2apic_regs_ops;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra}
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * Generates an interprocessor interrupt to another CPU when X2APIC mode is
b6917abefc343244b784f0cc34bc65b01469c3bfmishra * enabled.
b6917abefc343244b784f0cc34bc65b01469c3bfmishra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid
b6917abefc343244b784f0cc34bc65b01469c3bfmishrax2apic_send_ipi(int cpun, int ipl)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
b6917abefc343244b784f0cc34bc65b01469c3bfmishra int vector;
b6917abefc343244b784f0cc34bc65b01469c3bfmishra ulong_t flag;
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra ASSERT(apic_mode == LOCAL_X2APIC);
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra /*
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * With X2APIC, Intel relaxed the semantics of the
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * WRMSR instruction such that references to the X2APIC
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * MSR registers are no longer serializing instructions.
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * The code that initiates IPIs assumes that some sort
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * of memory serialization occurs. The old APIC code
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * did a write to uncachable memory mapped registers.
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * Any reference to uncached memory is a serializing
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * operation. To mimic those semantics here, we do an
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * atomic operation, which translates to a LOCK OR instruction,
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * which is serializing.
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra */
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra atomic_or_ulong(&flag, 1);
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra vector = apic_resv_vector[ipl];
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra flag = intr_clear();
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra /*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * According to X2APIC specification in section '2.3.5.1' of
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * Interrupt Command Register Semantics, the semantics of
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * programming Interrupt Command Register to dispatch an interrupt
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * is simplified. A single MSR write to the 64-bit ICR is required
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * for dispatching an interrupt. Specifically with the 64-bit MSR
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * interface to ICR, system software is not required to check the
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * status of the delivery status bit prior to writing to the ICR
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * to send an IPI. With the removal of the Delivery Status bit,
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * system software no longer has a reason to read the ICR. It remains
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra * readable only to aid in debugging.
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra */
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra#ifdef DEBUG
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra APIC_AV_PENDING_SET();
5d8efbbc545e36559256557618fcd256b7da72e4Saurabh Misra#endif /* DEBUG */
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra if ((cpun == psm_get_cpu_id())) {
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra X2APIC_WRITE(X2APIC_SELF_IPI, vector);
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra } else {
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_reg_ops->apic_write_int_cmd(
b6917abefc343244b784f0cc34bc65b01469c3bfmishra apic_cpus[cpun].aci_local_id, vector);
87cc626978cedbea111888dba5e4042df5cf532cSaurabh Misra }
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
b6917abefc343244b784f0cc34bc65b01469c3bfmishra intr_restore(flag);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}
b6917abefc343244b784f0cc34bc65b01469c3bfmishra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra/*
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * Generates IPI to another CPU depending on the local APIC mode.
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * apic_send_ipi() and x2apic_send_ipi() depends on the configured
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * mode of the local APIC, but that may not match the actual mode
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * early in CPU startup.
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra *
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * Any changes made to this routine must be accompanied by similar
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra * changes to apic_send_ipi().
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra */
b6917abefc343244b784f0cc34bc65b01469c3bfmishravoid
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misraapic_common_send_ipi(int cpun, int ipl)
b6917abefc343244b784f0cc34bc65b01469c3bfmishra{
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra int vector;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra ulong_t flag;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra int mode = apic_local_mode();
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra if (mode == LOCAL_X2APIC) {
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra x2apic_send_ipi(cpun, ipl);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra return;
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra }
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra ASSERT(mode == LOCAL_APIC);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra vector = apic_resv_vector[ipl];
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra flag = intr_clear();
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra apic_ret();
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra vector);
325e77f4fc68ea7eea21f5e705d3cf89fd3a7e3dSaurabh Misra intr_restore(flag);
b6917abefc343244b784f0cc34bc65b01469c3bfmishra}