Print this page
8620 pcplusmp shouldn't support x2APIC mode
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
        
*** 23,32 ****
--- 23,33 ----
   * Use is subject to license terms.
   */
  /*
   * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
   * Copyright (c) 2014 by Delphix. All rights reserved.
+  * Copyright 2017 Joyent, Inc.
   */
  
  #include <sys/cpuvar.h>
  #include <sys/psm.h>
  #include <sys/archsystm.h>
*** 38,58 ****
  #include <sys/trap.h>
  #include <sys/x86_archext.h>
  #include <sys/privregs.h>
  #include <sys/psm_common.h>
  
! /* Function prototypes of local apic and X2APIC */
  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:
   *
   *   xAPIC global enable    X2APIC enable         Description
--- 39,54 ----
  #include <sys/trap.h>
  #include <sys/x86_archext.h>
  #include <sys/privregs.h>
  #include <sys/psm_common.h>
  
! /* 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);
  
  /*
   * According to the X2APIC specification:
   *
   *   xAPIC global enable    X2APIC enable         Description
*** 62,97 ****
   *      0                       1       Invalid
   *      1                       0       APIC is enabled in xAPIC mode
   *      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 = {
          local_apic_read,
          local_apic_write,
          get_local_apic_pri,
          local_apic_write_task_reg,
          local_apic_write_int_cmd,
          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) */
  apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
  
--- 58,82 ----
   *      0                       1       Invalid
   *      1                       0       APIC is enabled in xAPIC mode
   *      1                       1       APIC is enabled in X2APIC mode
   * -----------------------------------------------------------
   */
  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) */
! apic_reg_ops_t local_apic_regs_ops = {
          local_apic_read,
          local_apic_write,
          get_local_apic_pri,
          local_apic_write_task_reg,
          local_apic_write_int_cmd,
          apic_send_EOI,
  };
  
  int apic_have_32bit_cr8 = 0;
  
  /* The default ops is local APIC (Memory Mapped IO) */
  apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
  
*** 99,110 ****
   * APIC register ops related data sturctures and functions.
   */
  void apic_send_EOI();
  void apic_send_directed_EOI(uint32_t irq);
  
- #define X2APIC_ENABLE_BIT       10
- 
  /*
   * Local APIC Implementation
   */
  static uint64_t
  local_apic_read(uint32_t reg)
--- 84,93 ----
*** 148,203 ****
  {
          apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
          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
  apic_send_EOI(uint32_t irq)
  {
          apic_reg_ops->apic_write(APIC_EOI_REG, 0);
--- 131,141 ----
*** 234,275 ****
                  }
                  apic_irq = apic_irq->airq_next;
          }
  }
  
- 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])
   */
  int
--- 172,181 ----
*** 336,442 ****
          ver = apic_reg_ops->apic_read(APIC_VERS_REG);
          if (ver & APIC_DIRECTED_EOI_BIT)
                  return (1);
  
          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);
  }
--- 242,247 ----