diff options
Diffstat (limited to 'usr/src/uts/i86pc/io/pcplusmp')
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic.c | 132 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic_common.c | 43 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic_regops.c | 201 |
3 files changed, 37 insertions, 339 deletions
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c index cd06f76967..8523112173 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c @@ -100,7 +100,6 @@ static void apic_picinit(void); static int apic_post_cpu_start(void); static int apic_intr_enter(int ipl, int *vect); static void apic_setspl(int ipl); -static void x2apic_setspl(int ipl); static int apic_addspl(int ipl, int vector, int min_ipl, int max_ipl); static int apic_delspl(int ipl, int vector, int min_ipl, int max_ipl); static int apic_disable_intr(processorid_t cpun); @@ -312,22 +311,19 @@ apic_init_intr(void) apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL); - if (apic_mode == LOCAL_APIC) { - /* - * We are running APIC in MMIO mode. - */ - if (apic_flat_model) { - apic_reg_ops->apic_write(APIC_FORMAT_REG, - APIC_FLAT_MODEL); - } else { - apic_reg_ops->apic_write(APIC_FORMAT_REG, - APIC_CLUSTER_MODEL); - } + ASSERT(apic_mode == LOCAL_APIC); - apic_reg_ops->apic_write(APIC_DEST_REG, - AV_HIGH_ORDER >> cpun); + /* + * We are running APIC in MMIO mode. + */ + if (apic_flat_model) { + apic_reg_ops->apic_write(APIC_FORMAT_REG, APIC_FLAT_MODEL); + } else { + apic_reg_ops->apic_write(APIC_FORMAT_REG, APIC_CLUSTER_MODEL); } + apic_reg_ops->apic_write(APIC_DEST_REG, AV_HIGH_ORDER >> cpun); + if (apic_directed_EOI_supported()) { /* * Setting the 12th bit in the Spurious Interrupt Vector @@ -633,24 +629,6 @@ apic_intr_enter(int ipl, int *vectorp) return (nipl); } -/* - * This macro is a common code used by MMIO local apic and X2APIC - * local apic. - */ -#define APIC_INTR_EXIT() \ -{ \ - cpu_infop = &apic_cpus[psm_get_cpu_id()]; \ - if (apic_level_intr[irq]) \ - apic_reg_ops->apic_send_eoi(irq); \ - cpu_infop->aci_curipl = (uchar_t)prev_ipl; \ - /* ISR above current pri could not be in progress */ \ - cpu_infop->aci_ISR_in_progress &= (2 << prev_ipl) - 1; \ -} - -/* - * Any changes made to this function must also change X2APIC - * version of intr_exit. - */ void apic_intr_exit(int prev_ipl, int irq) { @@ -658,35 +636,22 @@ apic_intr_exit(int prev_ipl, int irq) apic_reg_ops->apic_write_task_reg(apic_ipltopri[prev_ipl]); - APIC_INTR_EXIT(); -} - -/* - * Same as apic_intr_exit() except it uses MSR rather than MMIO - * to access local apic registers. - */ -void -x2apic_intr_exit(int prev_ipl, int irq) -{ - apic_cpus_info_t *cpu_infop; - - X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[prev_ipl]); - APIC_INTR_EXIT(); + cpu_infop = &apic_cpus[psm_get_cpu_id()]; + if (apic_level_intr[irq]) + apic_reg_ops->apic_send_eoi(irq); + cpu_infop->aci_curipl = (uchar_t)prev_ipl; + /* ISR above current pri could not be in progress */ + cpu_infop->aci_ISR_in_progress &= (2 << prev_ipl) - 1; } intr_exit_fn_t psm_intr_exit_fn(void) { - if (apic_mode == LOCAL_X2APIC) - return (x2apic_intr_exit); - return (apic_intr_exit); } /* * Mask all interrupts below or equal to the given IPL. - * Any changes made to this function must also change X2APIC - * version of setspl. */ static void apic_setspl(int ipl) @@ -704,19 +669,6 @@ apic_setspl(int ipl) (void) apic_reg_ops->apic_get_pri(); } -/* - * X2APIC version of setspl. - * Mask all interrupts below or equal to the given IPL - */ -static void -x2apic_setspl(int ipl) -{ - X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[ipl]); - - /* interrupts at ipl above this cannot be in progress */ - apic_cpus[psm_get_cpu_id()].aci_ISR_in_progress &= (2 << ipl) - 1; -} - /*ARGSUSED*/ static int apic_addspl(int irqno, int ipl, int min_ipl, int max_ipl) @@ -739,26 +691,6 @@ apic_post_cpu_start(void) /* We know this CPU + BSP started successfully. */ cpus_started++; - /* - * On BSP we would have enabled X2APIC, if supported by processor, - * in acpi_probe(), but on AP we do it here. - * - * We enable X2APIC mode only if BSP is running in X2APIC & the - * local APIC mode of the current CPU is MMIO (xAPIC). - */ - if (apic_mode == LOCAL_X2APIC && apic_detect_x2apic() && - apic_local_mode() == LOCAL_APIC) { - apic_enable_x2apic(); - } - - /* - * Switch back to x2apic IPI sending method for performance when target - * CPU has entered x2apic mode. - */ - if (apic_mode == LOCAL_X2APIC) { - apic_switch_ipi_callback(B_FALSE); - } - splx(ipltospl(LOCK_LEVEL)); apic_init_intr(); @@ -768,12 +700,7 @@ apic_post_cpu_start(void) */ setcr0(getcr0() & ~(CR0_CD | CR0_NW)); -#ifdef DEBUG APIC_AV_PENDING_SET(); -#else - if (apic_mode == LOCAL_APIC) - APIC_AV_PENDING_SET(); -#endif /* DEBUG */ /* * We may be booting, or resuming from suspend; aci_status will @@ -1330,18 +1257,25 @@ apic_get_apic_type(void) } void -x2apic_update_psm(void) +apic_switch_ipi_callback(boolean_t enter) { - struct psm_ops *pops = &apic_ops; - - ASSERT(pops != NULL); + ASSERT(enter == B_TRUE); +} - pops->psm_intr_exit = x2apic_intr_exit; - pops->psm_setspl = x2apic_setspl; +int +apic_detect_x2apic(void) +{ + return (0); +} - pops->psm_send_ipi = x2apic_send_ipi; - send_dirintf = pops->psm_send_ipi; +void +apic_enable_x2apic(void) +{ + cmn_err(CE_PANIC, "apic_enable_x2apic() called in pcplusmp"); +} - apic_mode = LOCAL_X2APIC; - apic_change_ops(); +void +x2apic_update_psm(void) +{ + cmn_err(CE_PANIC, "x2apic_update_psm() called in pcplusmp"); } diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c index 649e5ce950..7498150d49 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c @@ -23,7 +23,7 @@ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ @@ -128,8 +128,6 @@ extern void cmi_cmci_trap(void); kmutex_t cmci_cpu_setup_lock; /* protects cmci_cpu_setup_registered */ int cmci_cpu_setup_registered; -/* number of CPUs in power-on transition state */ -static int apic_poweron_cnt = 0; lock_t apic_mode_switch_lock; /* @@ -1456,45 +1454,6 @@ apic_find_cpu(int flag) return (acid); } -/* - * Switch between safe and x2APIC IPI sending method. - * CPU may power on in xapic mode or x2apic mode. If CPU needs to send IPI to - * other CPUs before entering x2APIC mode, it still needs to xAPIC method. - * Before sending StartIPI to target CPU, psm_send_ipi will be changed to - * apic_common_send_ipi, which detects current local APIC mode and use right - * method to send IPI. If some CPUs fail to start up, apic_poweron_cnt - * won't return to zero, so apic_common_send_ipi will always be used. - * psm_send_ipi can't be simply changed back to x2apic_send_ipi if some CPUs - * failed to start up because those failed CPUs may recover itself later at - * unpredictable time. - */ -void -apic_switch_ipi_callback(boolean_t enter) -{ - ulong_t iflag; - struct psm_ops *pops = psmops; - - iflag = intr_clear(); - lock_set(&apic_mode_switch_lock); - if (enter) { - ASSERT(apic_poweron_cnt >= 0); - if (apic_poweron_cnt == 0) { - pops->psm_send_ipi = apic_common_send_ipi; - send_dirintf = pops->psm_send_ipi; - } - apic_poweron_cnt++; - } else { - ASSERT(apic_poweron_cnt > 0); - apic_poweron_cnt--; - if (apic_poweron_cnt == 0) { - pops->psm_send_ipi = x2apic_send_ipi; - send_dirintf = pops->psm_send_ipi; - } - } - lock_clear(&apic_mode_switch_lock); - intr_restore(iflag); -} - void apic_intrmap_init(int apic_mode) { diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c index 60ce7a3771..e0b647975d 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c @@ -25,6 +25,7 @@ /* * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * Copyright (c) 2014 by Delphix. All rights reserved. + * Copyright 2017 Joyent, Inc. */ #include <sys/cpuvar.h> @@ -40,17 +41,12 @@ #include <sys/privregs.h> #include <sys/psm_common.h> -/* Function prototypes of local apic and X2APIC */ +/* Function prototypes of local apic */ static uint64_t local_apic_read(uint32_t reg); static void local_apic_write(uint32_t reg, uint64_t value); static int get_local_apic_pri(void); static void local_apic_write_task_reg(uint64_t value); static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); -static uint64_t local_x2apic_read(uint32_t msr); -static void local_x2apic_write(uint32_t msr, uint64_t value); -static int get_local_x2apic_pri(void); -static void local_x2apic_write_task_reg(uint64_t value); -static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); /* * According to the X2APIC specification: @@ -64,14 +60,13 @@ static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); * 1 1 APIC is enabled in X2APIC mode * ----------------------------------------------------------- */ -int x2apic_enable = 1; apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */ /* See apic_directed_EOI_supported(). Currently 3-state variable. */ volatile int apic_directed_eoi_state = 2; /* Uses MMIO (Memory Mapped IO) */ -static apic_reg_ops_t local_apic_regs_ops = { +apic_reg_ops_t local_apic_regs_ops = { local_apic_read, local_apic_write, get_local_apic_pri, @@ -80,16 +75,6 @@ static apic_reg_ops_t local_apic_regs_ops = { apic_send_EOI, }; -/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */ -static apic_reg_ops_t x2apic_regs_ops = { - local_x2apic_read, - local_x2apic_write, - get_local_x2apic_pri, - local_x2apic_write_task_reg, - local_x2apic_write_int_cmd, - apic_send_EOI, -}; - int apic_have_32bit_cr8 = 0; /* The default ops is local APIC (Memory Mapped IO) */ @@ -101,8 +86,6 @@ apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops; void apic_send_EOI(); void apic_send_directed_EOI(uint32_t irq); -#define X2APIC_ENABLE_BIT 10 - /* * Local APIC Implementation */ @@ -150,51 +133,6 @@ local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1) apicadr[APIC_INT_CMD1] = cmd1; } -/* - * X2APIC Implementation. - */ -static uint64_t -local_x2apic_read(uint32_t msr) -{ - uint64_t i; - - i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff); - return (i); -} - -static void -local_x2apic_write(uint32_t msr, uint64_t value) -{ - uint64_t tmp; - - if (msr != APIC_EOI_REG) { - tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)); - tmp = (tmp & 0xffffffff00000000) | value; - } else { - tmp = 0; - } - - wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp); -} - -static int -get_local_x2apic_pri(void) -{ - return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2))); -} - -static void -local_x2apic_write_task_reg(uint64_t value) -{ - X2APIC_WRITE(APIC_TASK_REG, value); -} - -static void -local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1) -{ - wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)), - (((uint64_t)cpu_id << 32) | cmd1)); -} /*ARGSUSED*/ void @@ -236,38 +174,6 @@ apic_send_directed_EOI(uint32_t irq) } } -int -apic_detect_x2apic(void) -{ - if (x2apic_enable == 0) - return (0); - - return (is_x86_feature(x86_featureset, X86FSET_X2APIC)); -} - -void -apic_enable_x2apic(void) -{ - uint64_t apic_base_msr; - - if (apic_local_mode() == LOCAL_X2APIC) { - /* BIOS apparently has enabled X2APIC */ - if (apic_mode != LOCAL_X2APIC) - x2apic_update_psm(); - return; - } - - /* - * This is the first time we are enabling X2APIC on this CPU - */ - apic_base_msr = rdmsr(REG_APIC_BASE_MSR); - apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT); - wrmsr(REG_APIC_BASE_MSR, apic_base_msr); - - if (apic_mode != LOCAL_X2APIC) - x2apic_update_psm(); -} - /* * Determine which mode the current CPU is in. See the table above. * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10]) @@ -339,104 +245,3 @@ apic_directed_EOI_supported() return (0); } - -/* - * Change apic_reg_ops depending upon the apic_mode. - */ -void -apic_change_ops() -{ - if (apic_mode == LOCAL_APIC) - apic_reg_ops = &local_apic_regs_ops; - else if (apic_mode == LOCAL_X2APIC) - apic_reg_ops = &x2apic_regs_ops; -} - -/* - * Generates an interprocessor interrupt to another CPU when X2APIC mode is - * enabled. - */ -void -x2apic_send_ipi(int cpun, int ipl) -{ - int vector; - ulong_t flag; - - ASSERT(apic_mode == LOCAL_X2APIC); - - /* - * With X2APIC, Intel relaxed the semantics of the - * WRMSR instruction such that references to the X2APIC - * MSR registers are no longer serializing instructions. - * The code that initiates IPIs assumes that some sort - * of memory serialization occurs. The old APIC code - * did a write to uncachable memory mapped registers. - * Any reference to uncached memory is a serializing - * operation. To mimic those semantics here, we do an - * atomic operation, which translates to a LOCK OR instruction, - * which is serializing. - */ - atomic_or_ulong(&flag, 1); - - vector = apic_resv_vector[ipl]; - - flag = intr_clear(); - - /* - * According to X2APIC specification in section '2.3.5.1' of - * Interrupt Command Register Semantics, the semantics of - * programming Interrupt Command Register to dispatch an interrupt - * is simplified. A single MSR write to the 64-bit ICR is required - * for dispatching an interrupt. Specifically with the 64-bit MSR - * interface to ICR, system software is not required to check the - * status of the delivery status bit prior to writing to the ICR - * to send an IPI. With the removal of the Delivery Status bit, - * system software no longer has a reason to read the ICR. It remains - * readable only to aid in debugging. - */ -#ifdef DEBUG - APIC_AV_PENDING_SET(); -#endif /* DEBUG */ - - if ((cpun == psm_get_cpu_id())) { - X2APIC_WRITE(X2APIC_SELF_IPI, vector); - } else { - apic_reg_ops->apic_write_int_cmd( - apic_cpus[cpun].aci_local_id, vector); - } - - intr_restore(flag); -} - -/* - * Generates IPI to another CPU depending on the local APIC mode. - * apic_send_ipi() and x2apic_send_ipi() depends on the configured - * mode of the local APIC, but that may not match the actual mode - * early in CPU startup. - * - * Any changes made to this routine must be accompanied by similar - * changes to apic_send_ipi(). - */ -void -apic_common_send_ipi(int cpun, int ipl) -{ - int vector; - ulong_t flag; - int mode = apic_local_mode(); - - if (mode == LOCAL_X2APIC) { - x2apic_send_ipi(cpun, ipl); - return; - } - - ASSERT(mode == LOCAL_APIC); - - vector = apic_resv_vector[ipl]; - ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR)); - flag = intr_clear(); - while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING) - apic_ret(); - local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id, - vector); - intr_restore(flag); -} |