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>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
          +++ new/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c
↓ open down ↓ 17 lines elided ↑ open up ↑
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  /*
  26   26   * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  27   27   * Copyright (c) 2014 by Delphix. All rights reserved.
       28 + * Copyright 2017 Joyent, Inc.
  28   29   */
  29   30  
  30   31  #include <sys/cpuvar.h>
  31   32  #include <sys/psm.h>
  32   33  #include <sys/archsystm.h>
  33   34  #include <sys/apic.h>
  34   35  #include <sys/sunddi.h>
  35   36  #include <sys/ddi_impldefs.h>
  36   37  #include <sys/mach_intr.h>
  37   38  #include <sys/sysmacros.h>
  38   39  #include <sys/trap.h>
  39   40  #include <sys/x86_archext.h>
  40   41  #include <sys/privregs.h>
  41   42  #include <sys/psm_common.h>
  42   43  
  43      -/* Function prototypes of local apic and X2APIC */
       44 +/* Function prototypes of local apic */
  44   45  static uint64_t local_apic_read(uint32_t reg);
  45   46  static void local_apic_write(uint32_t reg, uint64_t value);
  46   47  static int get_local_apic_pri(void);
  47   48  static void local_apic_write_task_reg(uint64_t value);
  48   49  static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
  49      -static uint64_t local_x2apic_read(uint32_t msr);
  50      -static void local_x2apic_write(uint32_t msr, uint64_t value);
  51      -static int get_local_x2apic_pri(void);
  52      -static void local_x2apic_write_task_reg(uint64_t value);
  53      -static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
  54   50  
  55   51  /*
  56   52   * According to the X2APIC specification:
  57   53   *
  58   54   *   xAPIC global enable    X2APIC enable         Description
  59   55   *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
  60   56   * -----------------------------------------------------------
  61   57   *      0                       0       APIC is disabled
  62   58   *      0                       1       Invalid
  63   59   *      1                       0       APIC is enabled in xAPIC mode
  64   60   *      1                       1       APIC is enabled in X2APIC mode
  65   61   * -----------------------------------------------------------
  66   62   */
  67      -int     x2apic_enable = 1;
  68   63  apic_mode_t apic_mode = LOCAL_APIC;     /* Default mode is Local APIC */
  69   64  
  70   65  /* See apic_directed_EOI_supported().  Currently 3-state variable. */
  71   66  volatile int apic_directed_eoi_state = 2;
  72   67  
  73   68  /* Uses MMIO (Memory Mapped IO) */
  74      -static apic_reg_ops_t local_apic_regs_ops = {
       69 +apic_reg_ops_t local_apic_regs_ops = {
  75   70          local_apic_read,
  76   71          local_apic_write,
  77   72          get_local_apic_pri,
  78   73          local_apic_write_task_reg,
  79   74          local_apic_write_int_cmd,
  80   75          apic_send_EOI,
  81   76  };
  82   77  
  83      -/* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
  84      -static apic_reg_ops_t x2apic_regs_ops = {
  85      -        local_x2apic_read,
  86      -        local_x2apic_write,
  87      -        get_local_x2apic_pri,
  88      -        local_x2apic_write_task_reg,
  89      -        local_x2apic_write_int_cmd,
  90      -        apic_send_EOI,
  91      -};
  92      -
  93   78  int apic_have_32bit_cr8 = 0;
  94   79  
  95   80  /* The default ops is local APIC (Memory Mapped IO) */
  96   81  apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
  97   82  
  98   83  /*
  99   84   * APIC register ops related data sturctures and functions.
 100   85   */
 101   86  void apic_send_EOI();
 102   87  void apic_send_directed_EOI(uint32_t irq);
 103   88  
 104      -#define X2APIC_ENABLE_BIT       10
 105      -
 106   89  /*
 107   90   * Local APIC Implementation
 108   91   */
 109   92  static uint64_t
 110   93  local_apic_read(uint32_t reg)
 111   94  {
 112   95          return ((uint32_t)apicadr[reg]);
 113   96  }
 114   97  
 115   98  static void
↓ open down ↓ 27 lines elided ↑ open up ↑
 143  126  #endif
 144  127  }
 145  128  
 146  129  static void
 147  130  local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
 148  131  {
 149  132          apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
 150  133          apicadr[APIC_INT_CMD1] = cmd1;
 151  134  }
 152  135  
 153      -/*
 154      - * X2APIC Implementation.
 155      - */
 156      -static uint64_t
 157      -local_x2apic_read(uint32_t msr)
 158      -{
 159      -        uint64_t i;
 160  136  
 161      -        i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
 162      -        return (i);
 163      -}
 164      -
 165      -static void
 166      -local_x2apic_write(uint32_t msr, uint64_t value)
 167      -{
 168      -        uint64_t tmp;
 169      -
 170      -        if (msr != APIC_EOI_REG) {
 171      -                tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
 172      -                tmp = (tmp & 0xffffffff00000000) | value;
 173      -        } else {
 174      -                tmp = 0;
 175      -        }
 176      -
 177      -        wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
 178      -}
 179      -
 180      -static int
 181      -get_local_x2apic_pri(void)
 182      -{
 183      -        return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
 184      -}
 185      -
 186      -static void
 187      -local_x2apic_write_task_reg(uint64_t value)
 188      -{
 189      -        X2APIC_WRITE(APIC_TASK_REG, value);
 190      -}
 191      -
 192      -static void
 193      -local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
 194      -{
 195      -        wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
 196      -            (((uint64_t)cpu_id << 32) | cmd1));
 197      -}
 198      -
 199  137  /*ARGSUSED*/
 200  138  void
 201  139  apic_send_EOI(uint32_t irq)
 202  140  {
 203  141          apic_reg_ops->apic_write(APIC_EOI_REG, 0);
 204  142  }
 205  143  
 206  144  /*
 207  145   * Support for Directed EOI capability is available in both the xAPIC
 208  146   * and x2APIC mode.
↓ open down ↓ 20 lines elided ↑ open up ↑
 229  167                  intr_index = apic_irq->airq_mps_intr_index;
 230  168                  if (intr_index == ACPI_INDEX || intr_index >= 0) {
 231  169                          ioapicindex = apic_irq->airq_ioapicindex;
 232  170                          vector = apic_irq->airq_vector;
 233  171                          ioapic_write_eoi(ioapicindex, vector);
 234  172                  }
 235  173                  apic_irq = apic_irq->airq_next;
 236  174          }
 237  175  }
 238  176  
 239      -int
 240      -apic_detect_x2apic(void)
 241      -{
 242      -        if (x2apic_enable == 0)
 243      -                return (0);
 244      -
 245      -        return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
 246      -}
 247      -
 248      -void
 249      -apic_enable_x2apic(void)
 250      -{
 251      -        uint64_t apic_base_msr;
 252      -
 253      -        if (apic_local_mode() == LOCAL_X2APIC) {
 254      -                /* BIOS apparently has enabled X2APIC */
 255      -                if (apic_mode != LOCAL_X2APIC)
 256      -                        x2apic_update_psm();
 257      -                return;
 258      -        }
 259      -
 260      -        /*
 261      -         * This is the first time we are enabling X2APIC on this CPU
 262      -         */
 263      -        apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
 264      -        apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
 265      -        wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
 266      -
 267      -        if (apic_mode != LOCAL_X2APIC)
 268      -                x2apic_update_psm();
 269      -}
 270      -
 271  177  /*
 272  178   * Determine which mode the current CPU is in. See the table above.
 273  179   * (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
 274  180   */
 275  181  int
 276  182  apic_local_mode(void)
 277  183  {
 278  184          uint64_t apic_base_msr;
 279  185          int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
 280  186              (0x1 << X2APIC_ENABLE_BIT));
↓ open down ↓ 50 lines elided ↑ open up ↑
 331  237                  if (get_hwenv() == HW_KVM)
 332  238                          return (0);
 333  239                  /* FALLTHRU */
 334  240          }
 335  241  
 336  242          ver = apic_reg_ops->apic_read(APIC_VERS_REG);
 337  243          if (ver & APIC_DIRECTED_EOI_BIT)
 338  244                  return (1);
 339  245  
 340  246          return (0);
 341      -}
 342      -
 343      -/*
 344      - * Change apic_reg_ops depending upon the apic_mode.
 345      - */
 346      -void
 347      -apic_change_ops()
 348      -{
 349      -        if (apic_mode == LOCAL_APIC)
 350      -                apic_reg_ops = &local_apic_regs_ops;
 351      -        else if (apic_mode == LOCAL_X2APIC)
 352      -                apic_reg_ops = &x2apic_regs_ops;
 353      -}
 354      -
 355      -/*
 356      - * Generates an interprocessor interrupt to another CPU when X2APIC mode is
 357      - * enabled.
 358      - */
 359      -void
 360      -x2apic_send_ipi(int cpun, int ipl)
 361      -{
 362      -        int vector;
 363      -        ulong_t flag;
 364      -
 365      -        ASSERT(apic_mode == LOCAL_X2APIC);
 366      -
 367      -        /*
 368      -         * With X2APIC, Intel relaxed the semantics of the
 369      -         * WRMSR instruction such that references to the X2APIC
 370      -         * MSR registers are no longer serializing instructions.
 371      -         * The code that initiates IPIs assumes that some sort
 372      -         * of memory serialization occurs. The old APIC code
 373      -         * did a write to uncachable memory mapped registers.
 374      -         * Any reference to uncached memory is a serializing
 375      -         * operation. To mimic those semantics here, we do an
 376      -         * atomic operation, which translates to a LOCK OR instruction,
 377      -         * which is serializing.
 378      -         */
 379      -        atomic_or_ulong(&flag, 1);
 380      -
 381      -        vector = apic_resv_vector[ipl];
 382      -
 383      -        flag = intr_clear();
 384      -
 385      -        /*
 386      -         * According to X2APIC specification in section '2.3.5.1' of
 387      -         * Interrupt Command Register Semantics, the semantics of
 388      -         * programming Interrupt Command Register to dispatch an interrupt
 389      -         * is simplified. A single MSR write to the 64-bit ICR is required
 390      -         * for dispatching an interrupt. Specifically with the 64-bit MSR
 391      -         * interface to ICR, system software is not required to check the
 392      -         * status of the delivery status bit prior to writing to the ICR
 393      -         * to send an IPI. With the removal of the Delivery Status bit,
 394      -         * system software no longer has a reason to read the ICR. It remains
 395      -         * readable only to aid in debugging.
 396      -         */
 397      -#ifdef  DEBUG
 398      -        APIC_AV_PENDING_SET();
 399      -#endif  /* DEBUG */
 400      -
 401      -        if ((cpun == psm_get_cpu_id())) {
 402      -                X2APIC_WRITE(X2APIC_SELF_IPI, vector);
 403      -        } else {
 404      -                apic_reg_ops->apic_write_int_cmd(
 405      -                    apic_cpus[cpun].aci_local_id, vector);
 406      -        }
 407      -
 408      -        intr_restore(flag);
 409      -}
 410      -
 411      -/*
 412      - * Generates IPI to another CPU depending on the local APIC mode.
 413      - * apic_send_ipi() and x2apic_send_ipi() depends on the configured
 414      - * mode of the local APIC, but that may not match the actual mode
 415      - * early in CPU startup.
 416      - *
 417      - * Any changes made to this routine must be accompanied by similar
 418      - * changes to apic_send_ipi().
 419      - */
 420      -void
 421      -apic_common_send_ipi(int cpun, int ipl)
 422      -{
 423      -        int vector;
 424      -        ulong_t flag;
 425      -        int mode = apic_local_mode();
 426      -
 427      -        if (mode == LOCAL_X2APIC) {
 428      -                x2apic_send_ipi(cpun, ipl);
 429      -                return;
 430      -        }
 431      -
 432      -        ASSERT(mode == LOCAL_APIC);
 433      -
 434      -        vector = apic_resv_vector[ipl];
 435      -        ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
 436      -        flag = intr_clear();
 437      -        while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
 438      -                apic_ret();
 439      -        local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
 440      -            vector);
 441      -        intr_restore(flag);
 442  247  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX