Print this page
    
8626 make pcplusmp and apix warning-free
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_common.c
          +++ new/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   */
  25   25  /*
  26   26   * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  27   27   * Copyright (c) 2016 by Delphix. All rights reserved.
  28   28   */
  29   29  
  30   30  /*
  31   31   * PSMI 1.1 extensions are supported only in 2.6 and later versions.
  32   32   * PSMI 1.2 extensions are supported only in 2.7 and later versions.
  33   33   * PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
  34   34   * PSMI 1.5 extensions are supported in Solaris Nevada.
  35   35   * PSMI 1.6 extensions are supported in Solaris Nevada.
  36   36   * PSMI 1.7 extensions are supported in Solaris Nevada.
  37   37   */
  38   38  #define PSMI_1_7
  39   39  
  40   40  #include <sys/processor.h>
  41   41  #include <sys/time.h>
  42   42  #include <sys/psm.h>
  43   43  #include <sys/smp_impldefs.h>
  44   44  #include <sys/cram.h>
  45   45  #include <sys/acpi/acpi.h>
  46   46  #include <sys/acpica.h>
  47   47  #include <sys/psm_common.h>
  48   48  #include <sys/apic.h>
  49   49  #include <sys/pit.h>
  50   50  #include <sys/ddi.h>
  51   51  #include <sys/sunddi.h>
  52   52  #include <sys/ddi_impldefs.h>
  53   53  #include <sys/pci.h>
  54   54  #include <sys/promif.h>
  55   55  #include <sys/x86_archext.h>
  56   56  #include <sys/cpc_impl.h>
  57   57  #include <sys/uadmin.h>
  58   58  #include <sys/panic.h>
  59   59  #include <sys/debug.h>
  60   60  #include <sys/archsystm.h>
  61   61  #include <sys/trap.h>
  62   62  #include <sys/machsystm.h>
  63   63  #include <sys/sysmacros.h>
  64   64  #include <sys/cpuvar.h>
  65   65  #include <sys/rm_platter.h>
  66   66  #include <sys/privregs.h>
  67   67  #include <sys/note.h>
  68   68  #include <sys/pci_intr_lib.h>
  69   69  #include <sys/spl.h>
  70   70  #include <sys/clock.h>
  71   71  #include <sys/dditypes.h>
  72   72  #include <sys/sunddi.h>
  73   73  #include <sys/x_call.h>
  74   74  #include <sys/reboot.h>
  75   75  #include <sys/hpet.h>
  76   76  #include <sys/apic_common.h>
  77   77  #include <sys/apic_timer.h>
  78   78  
  79   79  static void     apic_record_ioapic_rdt(void *intrmap_private,
  80   80                      ioapic_rdt_t *irdt);
  81   81  static void     apic_record_msi(void *intrmap_private, msi_regs_t *mregs);
  82   82  
  83   83  /*
  84   84   * Common routines between pcplusmp & apix (taken from apic.c).
  85   85   */
  86   86  
  87   87  int     apic_clkinit(int);
  88   88  hrtime_t apic_gethrtime(void);
  89   89  void    apic_send_ipi(int, int);
  90   90  void    apic_set_idlecpu(processorid_t);
  91   91  void    apic_unset_idlecpu(processorid_t);
  92   92  void    apic_shutdown(int, int);
  93   93  void    apic_preshutdown(int, int);
  94   94  processorid_t   apic_get_next_processorid(processorid_t);
  95   95  
  96   96  hrtime_t apic_gettime();
  97   97  
  98   98  enum apic_ioapic_method_type apix_mul_ioapic_method = APIC_MUL_IOAPIC_PCPLUSMP;
  99   99  
 100  100  /* Now the ones for Dynamic Interrupt distribution */
 101  101  int     apic_enable_dynamic_migration = 0;
 102  102  
 103  103  /* maximum loop count when sending Start IPIs. */
 104  104  int apic_sipi_max_loop_count = 0x1000;
 105  105  
 106  106  /*
 107  107   * These variables are frequently accessed in apic_intr_enter(),
 108  108   * apic_intr_exit and apic_setspl, so group them together
 109  109   */
 110  110  volatile uint32_t *apicadr =  NULL;     /* virtual addr of local APIC   */
 111  111  int apic_setspl_delay = 1;              /* apic_setspl - delay enable   */
 112  112  int apic_clkvect;
 113  113  
 114  114  /* vector at which error interrupts come in */
 115  115  int apic_errvect;
 116  116  int apic_enable_error_intr = 1;
 117  117  int apic_error_display_delay = 100;
 118  118  
 119  119  /* vector at which performance counter overflow interrupts come in */
 120  120  int apic_cpcovf_vect;
 121  121  int apic_enable_cpcovf_intr = 1;
 122  122  
 123  123  /* vector at which CMCI interrupts come in */
 124  124  int apic_cmci_vect;
 125  125  extern int cmi_enable_cmci;
 126  126  extern void cmi_cmci_trap(void);
 127  127  
 128  128  kmutex_t cmci_cpu_setup_lock;   /* protects cmci_cpu_setup_registered */
 129  129  int cmci_cpu_setup_registered;
 130  130  
 131  131  /* number of CPUs in power-on transition state */
 132  132  static int apic_poweron_cnt = 0;
 133  133  lock_t apic_mode_switch_lock;
 134  134  
 135  135  /*
 136  136   * Patchable global variables.
 137  137   */
 138  138  int     apic_forceload = 0;
 139  139  
 140  140  int     apic_coarse_hrtime = 1;         /* 0 - use accurate slow gethrtime() */
 141  141  
 142  142  int     apic_flat_model = 0;            /* 0 - clustered. 1 - flat */
 143  143  int     apic_panic_on_nmi = 0;
 144  144  int     apic_panic_on_apic_error = 0;
 145  145  
 146  146  int     apic_verbose = 0;       /* 0x1ff */
 147  147  
 148  148  #ifdef DEBUG
 149  149  int     apic_debug = 0;
 150  150  int     apic_restrict_vector = 0;
 151  151  
 152  152  int     apic_debug_msgbuf[APIC_DEBUG_MSGBUFSIZE];
 153  153  int     apic_debug_msgbufindex = 0;
 154  154  
 155  155  #endif /* DEBUG */
 156  156  
 157  157  uint_t apic_nticks = 0;
 158  158  uint_t apic_skipped_redistribute = 0;
 159  159  
 160  160  uint_t last_count_read = 0;
 161  161  lock_t  apic_gethrtime_lock;
 162  162  volatile int    apic_hrtime_stamp = 0;
 163  163  volatile hrtime_t apic_nsec_since_boot = 0;
 164  164  
 165  165  static  hrtime_t        apic_last_hrtime = 0;
 166  166  int             apic_hrtime_error = 0;
 167  167  int             apic_remote_hrterr = 0;
 168  168  int             apic_num_nmis = 0;
 169  169  int             apic_apic_error = 0;
 170  170  int             apic_num_apic_errors = 0;
 171  171  int             apic_num_cksum_errors = 0;
 172  172  
 173  173  int     apic_error = 0;
 174  174  
 175  175  static  int     apic_cmos_ssb_set = 0;
 176  176  
 177  177  /* use to make sure only one cpu handles the nmi */
 178  178  lock_t  apic_nmi_lock;
 179  179  /* use to make sure only one cpu handles the error interrupt */
 180  180  lock_t  apic_error_lock;
 181  181  
 182  182  static  struct {
 183  183          uchar_t cntl;
 184  184          uchar_t data;
 185  185  } aspen_bmc[] = {
 186  186          { CC_SMS_WR_START,      0x18 },         /* NetFn/LUN */
 187  187          { CC_SMS_WR_NEXT,       0x24 },         /* Cmd SET_WATCHDOG_TIMER */
 188  188          { CC_SMS_WR_NEXT,       0x84 },         /* DataByte 1: SMS/OS no log */
 189  189          { CC_SMS_WR_NEXT,       0x2 },          /* DataByte 2: Power Down */
 190  190          { CC_SMS_WR_NEXT,       0x0 },          /* DataByte 3: no pre-timeout */
 191  191          { CC_SMS_WR_NEXT,       0x0 },          /* DataByte 4: timer expir. */
 192  192          { CC_SMS_WR_NEXT,       0xa },          /* DataByte 5: init countdown */
 193  193          { CC_SMS_WR_END,        0x0 },          /* DataByte 6: init countdown */
 194  194  
 195  195          { CC_SMS_WR_START,      0x18 },         /* NetFn/LUN */
 196  196          { CC_SMS_WR_END,        0x22 }          /* Cmd RESET_WATCHDOG_TIMER */
 197  197  };
 198  198  
 199  199  static  struct {
 200  200          int     port;
 201  201          uchar_t data;
 202  202  } sitka_bmc[] = {
 203  203          { SMS_COMMAND_REGISTER, SMS_WRITE_START },
 204  204          { SMS_DATA_REGISTER,    0x18 },         /* NetFn/LUN */
 205  205          { SMS_DATA_REGISTER,    0x24 },         /* Cmd SET_WATCHDOG_TIMER */
 206  206          { SMS_DATA_REGISTER,    0x84 },         /* DataByte 1: SMS/OS no log */
 207  207          { SMS_DATA_REGISTER,    0x2 },          /* DataByte 2: Power Down */
 208  208          { SMS_DATA_REGISTER,    0x0 },          /* DataByte 3: no pre-timeout */
 209  209          { SMS_DATA_REGISTER,    0x0 },          /* DataByte 4: timer expir. */
 210  210          { SMS_DATA_REGISTER,    0xa },          /* DataByte 5: init countdown */
 211  211          { SMS_COMMAND_REGISTER, SMS_WRITE_END },
 212  212          { SMS_DATA_REGISTER,    0x0 },          /* DataByte 6: init countdown */
 213  213  
 214  214          { SMS_COMMAND_REGISTER, SMS_WRITE_START },
 215  215          { SMS_DATA_REGISTER,    0x18 },         /* NetFn/LUN */
 216  216          { SMS_COMMAND_REGISTER, SMS_WRITE_END },
 217  217          { SMS_DATA_REGISTER,    0x22 }          /* Cmd RESET_WATCHDOG_TIMER */
 218  218  };
 219  219  
 220  220  /* Patchable global variables. */
 221  221  int             apic_kmdb_on_nmi = 0;           /* 0 - no, 1 - yes enter kmdb */
 222  222  uint32_t        apic_divide_reg_init = 0;       /* 0 - divide by 2 */
 223  223  
 224  224  /* default apic ops without interrupt remapping */
 225  225  static apic_intrmap_ops_t apic_nointrmap_ops = {
 226  226          (int (*)(int))return_instr,
 227  227          (void (*)(int))return_instr,
 228  228          (void (*)(void **, dev_info_t *, uint16_t, int, uchar_t))return_instr,
 229  229          (void (*)(void *, void *, uint16_t, int))return_instr,
 230  230          (void (*)(void **))return_instr,
 231  231          apic_record_ioapic_rdt,
 232  232          apic_record_msi,
 233  233  };
 234  234  
 235  235  apic_intrmap_ops_t *apic_vt_ops = &apic_nointrmap_ops;
 236  236  apic_cpus_info_t        *apic_cpus = NULL;
 237  237  cpuset_t        apic_cpumask;
 238  238  uint_t          apic_picinit_called;
 239  239  
 240  240  /* Flag to indicate that we need to shut down all processors */
 241  241  static uint_t   apic_shutdown_processors;
 242  242  
 243  243  /*
 244  244   * Probe the ioapic method for apix module. Called in apic_probe_common()
 245  245   */
 246  246  int
 247  247  apic_ioapic_method_probe()
 248  248  {
 249  249          if (apix_enable == 0)
 250  250                  return (PSM_SUCCESS);
 251  251  
 252  252          /*
 253  253           * Set IOAPIC EOI handling method. The priority from low to high is:
 254  254           *      1. IOxAPIC: with EOI register
 255  255           *      2. IOMMU interrupt mapping
 256  256           *      3. Mask-Before-EOI method for systems without boot
 257  257           *      interrupt routing, such as systems with only one IOAPIC;
 258  258           *      NVIDIA CK8-04/MCP55 systems; systems with bridge solution
 259  259           *      which disables the boot interrupt routing already.
 260  260           *      4. Directed EOI
 261  261           */
 262  262          if (apic_io_ver[0] >= 0x20)
 263  263                  apix_mul_ioapic_method = APIC_MUL_IOAPIC_IOXAPIC;
 264  264          if ((apic_io_max == 1) || (apic_nvidia_io_max == apic_io_max))
 265  265                  apix_mul_ioapic_method = APIC_MUL_IOAPIC_MASK;
 266  266          if (apic_directed_EOI_supported())
 267  267                  apix_mul_ioapic_method = APIC_MUL_IOAPIC_DEOI;
 268  268  
 269  269          /* fall back to pcplusmp */
 270  270          if (apix_mul_ioapic_method == APIC_MUL_IOAPIC_PCPLUSMP) {
 271  271                  /* make sure apix is after pcplusmp in /etc/mach */
 272  272                  apix_enable = 0; /* go ahead with pcplusmp install next */
 273  273                  return (PSM_FAILURE);
 274  274          }
 275  275  
 276  276          return (PSM_SUCCESS);
 277  277  }
 278  278  
 279  279  /*
 280  280   * handler for APIC Error interrupt. Just print a warning and continue
 281  281   */
 282  282  int
 283  283  apic_error_intr()
 284  284  {
 285  285          uint_t  error0, error1, error;
 286  286          uint_t  i;
 287  287  
 288  288          /*
 289  289           * We need to write before read as per 7.4.17 of system prog manual.
 290  290           * We do both and or the results to be safe
 291  291           */
 292  292          error0 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
 293  293          apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
 294  294          error1 = apic_reg_ops->apic_read(APIC_ERROR_STATUS);
 295  295          error = error0 | error1;
 296  296  
 297  297          /*
 298  298           * Clear the APIC error status (do this on all cpus that enter here)
 299  299           * (two writes are required due to the semantics of accessing the
 300  300           * error status register.)
 301  301           */
 302  302          apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
 303  303          apic_reg_ops->apic_write(APIC_ERROR_STATUS, 0);
 304  304  
 305  305          /*
 306  306           * Prevent more than 1 CPU from handling error interrupt causing
 307  307           * double printing (interleave of characters from multiple
 308  308           * CPU's when using prom_printf)
 309  309           */
 310  310          if (lock_try(&apic_error_lock) == 0)
 311  311                  return (error ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED);
 312  312          if (error) {
 313  313  #if     DEBUG
 314  314                  if (apic_debug)
 315  315                          debug_enter("pcplusmp: APIC Error interrupt received");
 316  316  #endif /* DEBUG */
 317  317                  if (apic_panic_on_apic_error)
 318  318                          cmn_err(CE_PANIC,
 319  319                              "APIC Error interrupt on CPU %d. Status = %x",
 320  320                              psm_get_cpu_id(), error);
 321  321                  else {
 322  322                          if ((error & ~APIC_CS_ERRORS) == 0) {
 323  323                                  /* cksum error only */
 324  324                                  apic_error |= APIC_ERR_APIC_ERROR;
 325  325                                  apic_apic_error |= error;
 326  326                                  apic_num_apic_errors++;
 327  327                                  apic_num_cksum_errors++;
 328  328                          } else {
 329  329                                  /*
 330  330                                   * prom_printf is the best shot we have of
 331  331                                   * something which is problem free from
 332  332                                   * high level/NMI type of interrupts
 333  333                                   */
 334  334                                  prom_printf("APIC Error interrupt on CPU %d. "
 335  335                                      "Status 0 = %x, Status 1 = %x\n",
 336  336                                      psm_get_cpu_id(), error0, error1);
 337  337                                  apic_error |= APIC_ERR_APIC_ERROR;
 338  338                                  apic_apic_error |= error;
 339  339                                  apic_num_apic_errors++;
 340  340                                  for (i = 0; i < apic_error_display_delay; i++) {
 341  341                                          tenmicrosec();
 342  342                                  }
 343  343                                  /*
 344  344                                   * provide more delay next time limited to
 345  345                                   * roughly 1 clock tick time
 346  346                                   */
 347  347                                  if (apic_error_display_delay < 500)
 348  348                                          apic_error_display_delay *= 2;
 349  349                          }
 350  350                  }
 351  351                  lock_clear(&apic_error_lock);
 352  352                  return (DDI_INTR_CLAIMED);
 353  353          } else {
 354  354                  lock_clear(&apic_error_lock);
 355  355                  return (DDI_INTR_UNCLAIMED);
 356  356          }
 357  357  }
 358  358  
 359  359  /*
 360  360   * Turn off the mask bit in the performance counter Local Vector Table entry.
 361  361   */
 362  362  void
 363  363  apic_cpcovf_mask_clear(void)
 364  364  {
 365  365          apic_reg_ops->apic_write(APIC_PCINT_VECT,
 366  366              (apic_reg_ops->apic_read(APIC_PCINT_VECT) & ~APIC_LVT_MASK));
 367  367  }
 368  368  
 369  369  /*ARGSUSED*/
 370  370  static int
 371  371  apic_cmci_enable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
 372  372  {
 373  373          apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect);
 374  374          return (0);
 375  375  }
 376  376  
 377  377  /*ARGSUSED*/
 378  378  static int
 379  379  apic_cmci_disable(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
 380  380  {
 381  381          apic_reg_ops->apic_write(APIC_CMCI_VECT, apic_cmci_vect | AV_MASK);
 382  382          return (0);
 383  383  }
 384  384  
 385  385  /*ARGSUSED*/
 386  386  int
 387  387  cmci_cpu_setup(cpu_setup_t what, int cpuid, void *arg)
 388  388  {
 389  389          cpuset_t        cpu_set;
 390  390  
 391  391          CPUSET_ONLY(cpu_set, cpuid);
 392  392  
 393  393          switch (what) {
 394  394                  case CPU_ON:
 395  395                          xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set),
 396  396                              (xc_func_t)apic_cmci_enable);
 397  397                          break;
 398  398  
 399  399                  case CPU_OFF:
 400  400                          xc_call(NULL, NULL, NULL, CPUSET2BV(cpu_set),
 401  401                              (xc_func_t)apic_cmci_disable);
 402  402                          break;
 403  403  
 404  404                  default:
 405  405                          break;
 406  406          }
 407  407  
 408  408          return (0);
 409  409  }
 410  410  
 411  411  static void
 412  412  apic_disable_local_apic(void)
 413  413  {
 414  414          apic_reg_ops->apic_write_task_reg(APIC_MASK_ALL);
 415  415          apic_reg_ops->apic_write(APIC_LOCAL_TIMER, AV_MASK);
 416  416  
 417  417          /* local intr reg 0 */
 418  418          apic_reg_ops->apic_write(APIC_INT_VECT0, AV_MASK);
 419  419  
 420  420          /* disable NMI */
 421  421          apic_reg_ops->apic_write(APIC_INT_VECT1, AV_MASK);
 422  422  
 423  423          /* and error interrupt */
 424  424          apic_reg_ops->apic_write(APIC_ERR_VECT, AV_MASK);
 425  425  
 426  426          /* and perf counter intr */
 427  427          apic_reg_ops->apic_write(APIC_PCINT_VECT, AV_MASK);
 428  428  
 429  429          apic_reg_ops->apic_write(APIC_SPUR_INT_REG, APIC_SPUR_INTR);
 430  430  }
 431  431  
 432  432  static void
 433  433  apic_cpu_send_SIPI(processorid_t cpun, boolean_t start)
 434  434  {
 435  435          int             loop_count;
 436  436          uint32_t        vector;
 437  437          uint_t          apicid;
 438  438          ulong_t         iflag;
 439  439  
 440  440          apicid =  apic_cpus[cpun].aci_local_id;
 441  441  
 442  442          /*
 443  443           * Interrupts on current CPU will be disabled during the
 444  444           * steps in order to avoid unwanted side effects from
 445  445           * executing interrupt handlers on a problematic BIOS.
 446  446           */
 447  447          iflag = intr_clear();
 448  448  
 449  449          if (start) {
 450  450                  outb(CMOS_ADDR, SSB);
 451  451                  outb(CMOS_DATA, BIOS_SHUTDOWN);
 452  452          }
 453  453  
 454  454          /*
 455  455           * According to X2APIC specification in section '2.3.5.1' of
 456  456           * Interrupt Command Register Semantics, the semantics of
 457  457           * programming the Interrupt Command Register to dispatch an interrupt
 458  458           * is simplified. A single MSR write to the 64-bit ICR is required
 459  459           * for dispatching an interrupt. Specifically, with the 64-bit MSR
 460  460           * interface to ICR, system software is not required to check the
 461  461           * status of the delivery status bit prior to writing to the ICR
 462  462           * to send an IPI. With the removal of the Delivery Status bit,
 463  463           * system software no longer has a reason to read the ICR. It remains
 464  464           * readable only to aid in debugging.
 465  465           */
 466  466  #ifdef  DEBUG
 467  467          APIC_AV_PENDING_SET();
 468  468  #else
 469  469          if (apic_mode == LOCAL_APIC) {
 470  470                  APIC_AV_PENDING_SET();
 471  471          }
 472  472  #endif /* DEBUG */
 473  473  
 474  474          /* for integrated - make sure there is one INIT IPI in buffer */
 475  475          /* for external - it will wake up the cpu */
 476  476          apic_reg_ops->apic_write_int_cmd(apicid, AV_ASSERT | AV_RESET);
 477  477  
 478  478          /* If only 1 CPU is installed, PENDING bit will not go low */
 479  479          for (loop_count = apic_sipi_max_loop_count; loop_count; loop_count--) {
 480  480                  if (apic_mode == LOCAL_APIC &&
 481  481                      apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING)
 482  482                          apic_ret();
 483  483                  else
 484  484                          break;
 485  485          }
 486  486  
 487  487          apic_reg_ops->apic_write_int_cmd(apicid, AV_DEASSERT | AV_RESET);
 488  488          drv_usecwait(20000);            /* 20 milli sec */
 489  489  
 490  490          if (apic_cpus[cpun].aci_local_ver >= APIC_INTEGRATED_VERS) {
 491  491                  /* integrated apic */
 492  492  
 493  493                  vector = (rm_platter_pa >> MMU_PAGESHIFT) &
 494  494                      (APIC_VECTOR_MASK | APIC_IPL_MASK);
 495  495  
 496  496                  /* to offset the INIT IPI queue up in the buffer */
 497  497                  apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
 498  498                  drv_usecwait(200);              /* 20 micro sec */
 499  499  
 500  500                  /*
 501  501                   * send the second SIPI (Startup IPI) as recommended by Intel
 502  502                   * software development manual.
 503  503                   */
 504  504                  apic_reg_ops->apic_write_int_cmd(apicid, vector | AV_STARTUP);
 505  505                  drv_usecwait(200);      /* 20 micro sec */
 506  506          }
 507  507  
 508  508          intr_restore(iflag);
 509  509  }
 510  510  
 511  511  /*ARGSUSED1*/
 512  512  int
 513  513  apic_cpu_start(processorid_t cpun, caddr_t arg)
 514  514  {
 515  515          ASSERT(MUTEX_HELD(&cpu_lock));
 516  516  
 517  517          if (!apic_cpu_in_range(cpun)) {
 518  518                  return (EINVAL);
 519  519          }
 520  520  
 521  521          /*
 522  522           * Switch to apic_common_send_ipi for safety during starting other CPUs.
 523  523           */
 524  524          if (apic_mode == LOCAL_X2APIC) {
 525  525                  apic_switch_ipi_callback(B_TRUE);
 526  526          }
 527  527  
 528  528          apic_cmos_ssb_set = 1;
 529  529          apic_cpu_send_SIPI(cpun, B_TRUE);
 530  530  
 531  531          return (0);
 532  532  }
 533  533  
 534  534  /*
 535  535   * Put CPU into halted state with interrupts disabled.
 536  536   */
 537  537  /*ARGSUSED1*/
 538  538  int
 539  539  apic_cpu_stop(processorid_t cpun, caddr_t arg)
 540  540  {
 541  541          int             rc;
 542  542          cpu_t           *cp;
 543  543          extern cpuset_t cpu_ready_set;
 544  544          extern void cpu_idle_intercept_cpu(cpu_t *cp);
 545  545  
 546  546          ASSERT(MUTEX_HELD(&cpu_lock));
 547  547  
 548  548          if (!apic_cpu_in_range(cpun)) {
 549  549                  return (EINVAL);
 550  550          }
 551  551          if (apic_cpus[cpun].aci_local_ver < APIC_INTEGRATED_VERS) {
 552  552                  return (ENOTSUP);
 553  553          }
 554  554  
 555  555          cp = cpu_get(cpun);
 556  556          ASSERT(cp != NULL);
 557  557          ASSERT((cp->cpu_flags & CPU_OFFLINE) != 0);
 558  558          ASSERT((cp->cpu_flags & CPU_QUIESCED) != 0);
 559  559          ASSERT((cp->cpu_flags & CPU_ENABLE) == 0);
 560  560  
 561  561          /* Clear CPU_READY flag to disable cross calls. */
 562  562          cp->cpu_flags &= ~CPU_READY;
 563  563          CPUSET_ATOMIC_DEL(cpu_ready_set, cpun);
 564  564          rc = xc_flush_cpu(cp);
 565  565          if (rc != 0) {
 566  566                  CPUSET_ATOMIC_ADD(cpu_ready_set, cpun);
 567  567                  cp->cpu_flags |= CPU_READY;
 568  568                  return (rc);
 569  569          }
 570  570  
 571  571          /* Intercept target CPU at a safe point before powering it off. */
 572  572          cpu_idle_intercept_cpu(cp);
 573  573  
 574  574          apic_cpu_send_SIPI(cpun, B_FALSE);
 575  575          cp->cpu_flags &= ~CPU_RUNNING;
 576  576  
 577  577          return (0);
 578  578  }
 579  579  
 580  580  int
 581  581  apic_cpu_ops(psm_cpu_request_t *reqp)
 582  582  {
 583  583          if (reqp == NULL) {
 584  584                  return (EINVAL);
 585  585          }
 586  586  
 587  587          switch (reqp->pcr_cmd) {
 588  588          case PSM_CPU_ADD:
 589  589                  return (apic_cpu_add(reqp));
 590  590  
 591  591          case PSM_CPU_REMOVE:
 592  592                  return (apic_cpu_remove(reqp));
 593  593  
 594  594          case PSM_CPU_STOP:
 595  595                  return (apic_cpu_stop(reqp->req.cpu_stop.cpuid,
 596  596                      reqp->req.cpu_stop.ctx));
 597  597  
 598  598          default:
 599  599                  return (ENOTSUP);
 600  600          }
 601  601  }
 602  602  
 603  603  #ifdef  DEBUG
 604  604  int     apic_break_on_cpu = 9;
 605  605  int     apic_stretch_interrupts = 0;
 606  606  int     apic_stretch_ISR = 1 << 3;      /* IPL of 3 matches nothing now */
 607  607  #endif /* DEBUG */
 608  608  
 609  609  /*
 610  610   * generates an interprocessor interrupt to another CPU. Any changes made to
 611  611   * this routine must be accompanied by similar changes to
 612  612   * apic_common_send_ipi().
 613  613   */
 614  614  void
 615  615  apic_send_ipi(int cpun, int ipl)
 616  616  {
 617  617          int vector;
 618  618          ulong_t flag;
 619  619  
 620  620          vector = apic_resv_vector[ipl];
 621  621  
 622  622          ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
 623  623  
 624  624          flag = intr_clear();
 625  625  
 626  626          APIC_AV_PENDING_SET();
 627  627  
 628  628          apic_reg_ops->apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
 629  629              vector);
 630  630  
 631  631          intr_restore(flag);
 632  632  }
 633  633  
 634  634  
 635  635  /*ARGSUSED*/
 636  636  void
 637  637  apic_set_idlecpu(processorid_t cpun)
 638  638  {
 639  639  }
 640  640  
 641  641  /*ARGSUSED*/
 642  642  void
 643  643  apic_unset_idlecpu(processorid_t cpun)
 644  644  {
 645  645  }
 646  646  
 647  647  
 648  648  void
 649  649  apic_ret()
 650  650  {
 651  651  }
 652  652  
 653  653  /*
 654  654   * If apic_coarse_time == 1, then apic_gettime() is used instead of
 655  655   * apic_gethrtime().  This is used for performance instead of accuracy.
 656  656   */
 657  657  
 658  658  hrtime_t
 659  659  apic_gettime()
 660  660  {
 661  661          int old_hrtime_stamp;
 662  662          hrtime_t temp;
 663  663  
 664  664          /*
 665  665           * In one-shot mode, we do not keep time, so if anyone
 666  666           * calls psm_gettime() directly, we vector over to
 667  667           * gethrtime().
 668  668           * one-shot mode MUST NOT be enabled if this psm is the source of
 669  669           * hrtime.
 670  670           */
 671  671  
 672  672          if (apic_oneshot)
 673  673                  return (gethrtime());
 674  674  
 675  675  
 676  676  gettime_again:
 677  677          while ((old_hrtime_stamp = apic_hrtime_stamp) & 1)
 678  678                  apic_ret();
 679  679  
 680  680          temp = apic_nsec_since_boot;
 681  681  
 682  682          if (apic_hrtime_stamp != old_hrtime_stamp) {    /* got an interrupt */
 683  683                  goto gettime_again;
 684  684          }
 685  685          return (temp);
 686  686  }
 687  687  
 688  688  /*
 689  689   * Here we return the number of nanoseconds since booting.  Note every
 690  690   * clock interrupt increments apic_nsec_since_boot by the appropriate
 691  691   * amount.
 692  692   */
 693  693  hrtime_t
 694  694  apic_gethrtime(void)
 695  695  {
 696  696          int curr_timeval, countval, elapsed_ticks;
 697  697          int old_hrtime_stamp, status;
 698  698          hrtime_t temp;
 699  699          uint32_t cpun;
 700  700          ulong_t oflags;
 701  701  
 702  702          /*
 703  703           * In one-shot mode, we do not keep time, so if anyone
 704  704           * calls psm_gethrtime() directly, we vector over to
 705  705           * gethrtime().
 706  706           * one-shot mode MUST NOT be enabled if this psm is the source of
 707  707           * hrtime.
 708  708           */
 709  709  
 710  710          if (apic_oneshot)
 711  711                  return (gethrtime());
 712  712  
 713  713          oflags = intr_clear();  /* prevent migration */
 714  714  
 715  715          cpun = apic_reg_ops->apic_read(APIC_LID_REG);
 716  716          if (apic_mode == LOCAL_APIC)
 717  717                  cpun >>= APIC_ID_BIT_OFFSET;
 718  718  
 719  719          lock_set(&apic_gethrtime_lock);
 720  720  
 721  721  gethrtime_again:
 722  722          while ((old_hrtime_stamp = apic_hrtime_stamp) & 1)
 723  723                  apic_ret();
 724  724  
 725  725          /*
 726  726           * Check to see which CPU we are on.  Note the time is kept on
 727  727           * the local APIC of CPU 0.  If on CPU 0, simply read the current
 728  728           * counter.  If on another CPU, issue a remote read command to CPU 0.
 729  729           */
 730  730          if (cpun == apic_cpus[0].aci_local_id) {
 731  731                  countval = apic_reg_ops->apic_read(APIC_CURR_COUNT);
 732  732          } else {
 733  733  #ifdef  DEBUG
 734  734                  APIC_AV_PENDING_SET();
 735  735  #else
 736  736                  if (apic_mode == LOCAL_APIC)
 737  737                          APIC_AV_PENDING_SET();
 738  738  #endif /* DEBUG */
 739  739  
 740  740                  apic_reg_ops->apic_write_int_cmd(
 741  741                      apic_cpus[0].aci_local_id, APIC_CURR_ADD | AV_REMOTE);
 742  742  
 743  743                  while ((status = apic_reg_ops->apic_read(APIC_INT_CMD1))
 744  744                      & AV_READ_PENDING) {
 745  745                          apic_ret();
 746  746                  }
 747  747  
 748  748                  if (status & AV_REMOTE_STATUS)  /* 1 = valid */
 749  749                          countval = apic_reg_ops->apic_read(APIC_REMOTE_READ);
 750  750                  else {  /* 0 = invalid */
 751  751                          apic_remote_hrterr++;
 752  752                          /*
 753  753                           * return last hrtime right now, will need more
 754  754                           * testing if change to retry
 755  755                           */
 756  756                          temp = apic_last_hrtime;
 757  757  
 758  758                          lock_clear(&apic_gethrtime_lock);
 759  759  
 760  760                          intr_restore(oflags);
 761  761  
 762  762                          return (temp);
 763  763                  }
 764  764          }
 765  765          if (countval > last_count_read)
 766  766                  countval = 0;
 767  767          else
 768  768                  last_count_read = countval;
 769  769  
 770  770          elapsed_ticks = apic_hertz_count - countval;
 771  771  
 772  772          curr_timeval = APIC_TICKS_TO_NSECS(elapsed_ticks);
 773  773          temp = apic_nsec_since_boot + curr_timeval;
 774  774  
 775  775          if (apic_hrtime_stamp != old_hrtime_stamp) {    /* got an interrupt */
 776  776                  /* we might have clobbered last_count_read. Restore it */
 777  777                  last_count_read = apic_hertz_count;
 778  778                  goto gethrtime_again;
 779  779          }
 780  780  
 781  781          if (temp < apic_last_hrtime) {
 782  782                  /* return last hrtime if error occurs */
 783  783                  apic_hrtime_error++;
 784  784                  temp = apic_last_hrtime;
 785  785          }
 786  786          else
 787  787                  apic_last_hrtime = temp;
 788  788  
 789  789          lock_clear(&apic_gethrtime_lock);
 790  790          intr_restore(oflags);
 791  791  
 792  792          return (temp);
 793  793  }
 794  794  
 795  795  /* apic NMI handler */
 796  796  /*ARGSUSED*/
 797  797  void
 798  798  apic_nmi_intr(caddr_t arg, struct regs *rp)
 799  799  {
 800  800          if (apic_shutdown_processors) {
 801  801                  apic_disable_local_apic();
 802  802                  return;
 803  803          }
 804  804  
 805  805          apic_error |= APIC_ERR_NMI;
 806  806  
 807  807          if (!lock_try(&apic_nmi_lock))
 808  808                  return;
 809  809          apic_num_nmis++;
 810  810  
 811  811          if (apic_kmdb_on_nmi && psm_debugger()) {
 812  812                  debug_enter("NMI received: entering kmdb\n");
 813  813          } else if (apic_panic_on_nmi) {
 814  814                  /* Keep panic from entering kmdb. */
 815  815                  nopanicdebug = 1;
 816  816                  panic("NMI received\n");
 817  817          } else {
 818  818                  /*
 819  819                   * prom_printf is the best shot we have of something which is
 820  820                   * problem free from high level/NMI type of interrupts
 821  821                   */
 822  822                  prom_printf("NMI received\n");
 823  823          }
 824  824  
 825  825          lock_clear(&apic_nmi_lock);
 826  826  }
 827  827  
 828  828  processorid_t
 829  829  apic_get_next_processorid(processorid_t cpu_id)
 830  830  {
 831  831  
 832  832          int i;
 833  833  
 834  834          if (cpu_id == -1)
 835  835                  return ((processorid_t)0);
 836  836  
 837  837          for (i = cpu_id + 1; i < NCPU; i++) {
 838  838                  if (apic_cpu_in_range(i))
 839  839                          return (i);
 840  840          }
  
    | ↓ open down ↓ | 840 lines elided | ↑ open up ↑ | 
 841  841  
 842  842          return ((processorid_t)-1);
 843  843  }
 844  844  
 845  845  int
 846  846  apic_cpu_add(psm_cpu_request_t *reqp)
 847  847  {
 848  848          int i, rv = 0;
 849  849          ulong_t iflag;
 850  850          boolean_t first = B_TRUE;
 851      -        uchar_t localver;
      851 +        uchar_t localver = 0;
 852  852          uint32_t localid, procid;
 853  853          processorid_t cpuid = (processorid_t)-1;
 854  854          mach_cpu_add_arg_t *ap;
 855  855  
 856  856          ASSERT(reqp != NULL);
 857  857          reqp->req.cpu_add.cpuid = (processorid_t)-1;
 858  858  
 859  859          /* Check whether CPU hotplug is supported. */
 860  860          if (!plat_dr_support_cpu() || apic_max_nproc == -1) {
 861  861                  return (ENOTSUP);
 862  862          }
 863  863  
 864  864          ap = (mach_cpu_add_arg_t *)reqp->req.cpu_add.argp;
 865  865          switch (ap->type) {
 866  866          case MACH_CPU_ARG_LOCAL_APIC:
 867  867                  localid = ap->arg.apic.apic_id;
 868  868                  procid = ap->arg.apic.proc_id;
 869  869                  if (localid >= 255 || procid > 255) {
 870  870                          cmn_err(CE_WARN,
 871  871                              "!apic: apicid(%u) or procid(%u) is invalid.",
 872  872                              localid, procid);
 873  873                          return (EINVAL);
 874  874                  }
 875  875                  break;
 876  876  
 877  877          case MACH_CPU_ARG_LOCAL_X2APIC:
 878  878                  localid = ap->arg.apic.apic_id;
 879  879                  procid = ap->arg.apic.proc_id;
 880  880                  if (localid >= UINT32_MAX) {
 881  881                          cmn_err(CE_WARN,
 882  882                              "!apic: x2apicid(%u) is invalid.", localid);
 883  883                          return (EINVAL);
 884  884                  } else if (localid >= 255 && apic_mode == LOCAL_APIC) {
 885  885                          cmn_err(CE_WARN, "!apic: system is in APIC mode, "
 886  886                              "can't support x2APIC processor.");
 887  887                          return (ENOTSUP);
 888  888                  }
 889  889                  break;
 890  890  
 891  891          default:
 892  892                  cmn_err(CE_WARN,
 893  893                      "!apic: unknown argument type %d to apic_cpu_add().",
 894  894                      ap->type);
 895  895                  return (EINVAL);
 896  896          }
 897  897  
 898  898          /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */
 899  899          iflag = intr_clear();
 900  900          lock_set(&apic_ioapic_lock);
 901  901  
 902  902          /* Check whether local APIC id already exists. */
 903  903          for (i = 0; i < apic_nproc; i++) {
 904  904                  if (!CPU_IN_SET(apic_cpumask, i))
 905  905                          continue;
 906  906                  if (apic_cpus[i].aci_local_id == localid) {
 907  907                          lock_clear(&apic_ioapic_lock);
 908  908                          intr_restore(iflag);
 909  909                          cmn_err(CE_WARN,
 910  910                              "!apic: local apic id %u already exists.",
 911  911                              localid);
 912  912                          return (EEXIST);
 913  913                  } else if (apic_cpus[i].aci_processor_id == procid) {
 914  914                          lock_clear(&apic_ioapic_lock);
 915  915                          intr_restore(iflag);
 916  916                          cmn_err(CE_WARN,
 917  917                              "!apic: processor id %u already exists.",
 918  918                              (int)procid);
 919  919                          return (EEXIST);
 920  920                  }
 921  921  
 922  922                  /*
 923  923                   * There's no local APIC version number available in MADT table,
 924  924                   * so assume that all CPUs are homogeneous and use local APIC
 925  925                   * version number of the first existing CPU.
 926  926                   */
 927  927                  if (first) {
 928  928                          first = B_FALSE;
 929  929                          localver = apic_cpus[i].aci_local_ver;
 930  930                  }
 931  931          }
 932  932          ASSERT(first == B_FALSE);
 933  933  
 934  934          /*
 935  935           * Try to assign the same cpuid if APIC id exists in the dirty cache.
 936  936           */
 937  937          for (i = 0; i < apic_max_nproc; i++) {
 938  938                  if (CPU_IN_SET(apic_cpumask, i)) {
 939  939                          ASSERT((apic_cpus[i].aci_status & APIC_CPU_FREE) == 0);
 940  940                          continue;
 941  941                  }
 942  942                  ASSERT(apic_cpus[i].aci_status & APIC_CPU_FREE);
 943  943                  if ((apic_cpus[i].aci_status & APIC_CPU_DIRTY) &&
 944  944                      apic_cpus[i].aci_local_id == localid &&
 945  945                      apic_cpus[i].aci_processor_id == procid) {
 946  946                          cpuid = i;
 947  947                          break;
 948  948                  }
 949  949          }
 950  950  
 951  951          /* Avoid the dirty cache and allocate fresh slot if possible. */
 952  952          if (cpuid == (processorid_t)-1) {
 953  953                  for (i = 0; i < apic_max_nproc; i++) {
 954  954                          if ((apic_cpus[i].aci_status & APIC_CPU_FREE) &&
 955  955                              (apic_cpus[i].aci_status & APIC_CPU_DIRTY) == 0) {
 956  956                                  cpuid = i;
 957  957                                  break;
 958  958                          }
 959  959                  }
 960  960          }
 961  961  
 962  962          /* Try to find any free slot as last resort. */
 963  963          if (cpuid == (processorid_t)-1) {
 964  964                  for (i = 0; i < apic_max_nproc; i++) {
 965  965                          if (apic_cpus[i].aci_status & APIC_CPU_FREE) {
 966  966                                  cpuid = i;
 967  967                                  break;
 968  968                          }
 969  969                  }
 970  970          }
 971  971  
 972  972          if (cpuid == (processorid_t)-1) {
 973  973                  lock_clear(&apic_ioapic_lock);
 974  974                  intr_restore(iflag);
 975  975                  cmn_err(CE_NOTE,
 976  976                      "!apic: failed to allocate cpu id for processor %u.",
 977  977                      procid);
 978  978                  rv = EAGAIN;
 979  979          } else if (ACPI_FAILURE(acpica_map_cpu(cpuid, procid))) {
 980  980                  lock_clear(&apic_ioapic_lock);
 981  981                  intr_restore(iflag);
 982  982                  cmn_err(CE_NOTE,
 983  983                      "!apic: failed to build mapping for processor %u.",
 984  984                      procid);
 985  985                  rv = EBUSY;
 986  986          } else {
 987  987                  ASSERT(cpuid >= 0 && cpuid < NCPU);
 988  988                  ASSERT(cpuid < apic_max_nproc && cpuid < max_ncpus);
 989  989                  bzero(&apic_cpus[cpuid], sizeof (apic_cpus[0]));
 990  990                  apic_cpus[cpuid].aci_processor_id = procid;
 991  991                  apic_cpus[cpuid].aci_local_id = localid;
 992  992                  apic_cpus[cpuid].aci_local_ver = localver;
 993  993                  CPUSET_ATOMIC_ADD(apic_cpumask, cpuid);
 994  994                  if (cpuid >= apic_nproc) {
 995  995                          apic_nproc = cpuid + 1;
 996  996                  }
 997  997                  lock_clear(&apic_ioapic_lock);
 998  998                  intr_restore(iflag);
 999  999                  reqp->req.cpu_add.cpuid = cpuid;
1000 1000          }
1001 1001  
1002 1002          return (rv);
1003 1003  }
1004 1004  
1005 1005  int
1006 1006  apic_cpu_remove(psm_cpu_request_t *reqp)
1007 1007  {
1008 1008          int i;
1009 1009          ulong_t iflag;
1010 1010          processorid_t cpuid;
1011 1011  
1012 1012          /* Check whether CPU hotplug is supported. */
1013 1013          if (!plat_dr_support_cpu() || apic_max_nproc == -1) {
1014 1014                  return (ENOTSUP);
1015 1015          }
1016 1016  
1017 1017          cpuid = reqp->req.cpu_remove.cpuid;
1018 1018  
1019 1019          /* Use apic_ioapic_lock to sync with apic_get_next_bind_cpu. */
1020 1020          iflag = intr_clear();
1021 1021          lock_set(&apic_ioapic_lock);
1022 1022  
1023 1023          if (!apic_cpu_in_range(cpuid)) {
1024 1024                  lock_clear(&apic_ioapic_lock);
1025 1025                  intr_restore(iflag);
1026 1026                  cmn_err(CE_WARN,
1027 1027                      "!apic: cpuid %d doesn't exist in apic_cpus array.",
1028 1028                      cpuid);
1029 1029                  return (ENODEV);
1030 1030          }
1031 1031          ASSERT((apic_cpus[cpuid].aci_status & APIC_CPU_FREE) == 0);
1032 1032  
1033 1033          if (ACPI_FAILURE(acpica_unmap_cpu(cpuid))) {
1034 1034                  lock_clear(&apic_ioapic_lock);
1035 1035                  intr_restore(iflag);
1036 1036                  return (ENOENT);
1037 1037          }
1038 1038  
1039 1039          if (cpuid == apic_nproc - 1) {
1040 1040                  /*
1041 1041                   * We are removing the highest numbered cpuid so we need to
1042 1042                   * find the next highest cpuid as the new value for apic_nproc.
1043 1043                   */
1044 1044                  for (i = apic_nproc; i > 0; i--) {
1045 1045                          if (CPU_IN_SET(apic_cpumask, i - 1)) {
1046 1046                                  apic_nproc = i;
1047 1047                                  break;
1048 1048                          }
1049 1049                  }
1050 1050                  /* at least one CPU left */
1051 1051                  ASSERT(i > 0);
1052 1052          }
1053 1053          CPUSET_ATOMIC_DEL(apic_cpumask, cpuid);
1054 1054          /* mark slot as free and keep it in the dirty cache */
1055 1055          apic_cpus[cpuid].aci_status = APIC_CPU_FREE | APIC_CPU_DIRTY;
1056 1056  
1057 1057          lock_clear(&apic_ioapic_lock);
1058 1058          intr_restore(iflag);
1059 1059  
1060 1060          return (0);
1061 1061  }
1062 1062  
1063 1063  /*
1064 1064   * Return the number of APIC clock ticks elapsed for 8245 to decrement
1065 1065   * (APIC_TIME_COUNT + pit_ticks_adj) ticks.
1066 1066   */
1067 1067  uint_t
1068 1068  apic_calibrate(volatile uint32_t *addr, uint16_t *pit_ticks_adj)
1069 1069  {
1070 1070          uint8_t         pit_tick_lo;
1071 1071          uint16_t        pit_tick, target_pit_tick;
1072 1072          uint32_t        start_apic_tick, end_apic_tick;
1073 1073          ulong_t         iflag;
1074 1074          uint32_t        reg;
1075 1075  
1076 1076          reg = addr + APIC_CURR_COUNT - apicadr;
1077 1077  
1078 1078          iflag = intr_clear();
1079 1079  
1080 1080          do {
1081 1081                  pit_tick_lo = inb(PITCTR0_PORT);
1082 1082                  pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
1083 1083          } while (pit_tick < APIC_TIME_MIN ||
1084 1084              pit_tick_lo <= APIC_LB_MIN || pit_tick_lo >= APIC_LB_MAX);
1085 1085  
1086 1086          /*
1087 1087           * Wait for the 8254 to decrement by 5 ticks to ensure
1088 1088           * we didn't start in the middle of a tick.
1089 1089           * Compare with 0x10 for the wrap around case.
1090 1090           */
1091 1091          target_pit_tick = pit_tick - 5;
1092 1092          do {
1093 1093                  pit_tick_lo = inb(PITCTR0_PORT);
1094 1094                  pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
1095 1095          } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10);
1096 1096  
1097 1097          start_apic_tick = apic_reg_ops->apic_read(reg);
1098 1098  
1099 1099          /*
1100 1100           * Wait for the 8254 to decrement by
1101 1101           * (APIC_TIME_COUNT + pit_ticks_adj) ticks
1102 1102           */
1103 1103          target_pit_tick = pit_tick - APIC_TIME_COUNT;
1104 1104          do {
1105 1105                  pit_tick_lo = inb(PITCTR0_PORT);
1106 1106                  pit_tick = (inb(PITCTR0_PORT) << 8) | pit_tick_lo;
1107 1107          } while (pit_tick > target_pit_tick || pit_tick_lo < 0x10);
1108 1108  
1109 1109          end_apic_tick = apic_reg_ops->apic_read(reg);
1110 1110  
1111 1111          *pit_ticks_adj = target_pit_tick - pit_tick;
1112 1112  
1113 1113          intr_restore(iflag);
1114 1114  
1115 1115          return (start_apic_tick - end_apic_tick);
1116 1116  }
1117 1117  
1118 1118  /*
1119 1119   * Initialise the APIC timer on the local APIC of CPU 0 to the desired
1120 1120   * frequency.  Note at this stage in the boot sequence, the boot processor
1121 1121   * is the only active processor.
1122 1122   * hertz value of 0 indicates a one-shot mode request.  In this case
1123 1123   * the function returns the resolution (in nanoseconds) for the hardware
1124 1124   * timer interrupt.  If one-shot mode capability is not available,
1125 1125   * the return value will be 0. apic_enable_oneshot is a global switch
1126 1126   * for disabling the functionality.
1127 1127   * A non-zero positive value for hertz indicates a periodic mode request.
1128 1128   * In this case the hardware will be programmed to generate clock interrupts
1129 1129   * at hertz frequency and returns the resolution of interrupts in
1130 1130   * nanosecond.
1131 1131   */
1132 1132  
1133 1133  int
1134 1134  apic_clkinit(int hertz)
1135 1135  {
1136 1136          int             ret;
1137 1137  
1138 1138          apic_int_busy_mark = (apic_int_busy_mark *
1139 1139              apic_sample_factor_redistribution) / 100;
1140 1140          apic_int_free_mark = (apic_int_free_mark *
1141 1141              apic_sample_factor_redistribution) / 100;
1142 1142          apic_diff_for_redistribution = (apic_diff_for_redistribution *
1143 1143              apic_sample_factor_redistribution) / 100;
1144 1144  
1145 1145          ret = apic_timer_init(hertz);
1146 1146          return (ret);
1147 1147  
1148 1148  }
1149 1149  
1150 1150  /*
1151 1151   * apic_preshutdown:
1152 1152   * Called early in shutdown whilst we can still access filesystems to do
1153 1153   * things like loading modules which will be required to complete shutdown
1154 1154   * after filesystems are all unmounted.
1155 1155   */
1156 1156  void
1157 1157  apic_preshutdown(int cmd, int fcn)
1158 1158  {
1159 1159          APIC_VERBOSE_POWEROFF(("apic_preshutdown(%d,%d); m=%d a=%d\n",
1160 1160              cmd, fcn, apic_poweroff_method, apic_enable_acpi));
1161 1161  }
1162 1162  
1163 1163  void
1164 1164  apic_shutdown(int cmd, int fcn)
1165 1165  {
1166 1166          int restarts, attempts;
1167 1167          int i;
1168 1168          uchar_t byte;
1169 1169          ulong_t iflag;
1170 1170  
1171 1171          hpet_acpi_fini();
1172 1172  
1173 1173          /* Send NMI to all CPUs except self to do per processor shutdown */
1174 1174          iflag = intr_clear();
1175 1175  #ifdef  DEBUG
1176 1176          APIC_AV_PENDING_SET();
1177 1177  #else
1178 1178          if (apic_mode == LOCAL_APIC)
1179 1179                  APIC_AV_PENDING_SET();
1180 1180  #endif /* DEBUG */
1181 1181          apic_shutdown_processors = 1;
1182 1182          apic_reg_ops->apic_write(APIC_INT_CMD1,
1183 1183              AV_NMI | AV_LEVEL | AV_SH_ALL_EXCSELF);
1184 1184  
1185 1185          /* restore cmos shutdown byte before reboot */
1186 1186          if (apic_cmos_ssb_set) {
1187 1187                  outb(CMOS_ADDR, SSB);
1188 1188                  outb(CMOS_DATA, 0);
1189 1189          }
1190 1190  
1191 1191          ioapic_disable_redirection();
1192 1192  
1193 1193          /*      disable apic mode if imcr present       */
1194 1194          if (apic_imcrp) {
1195 1195                  outb(APIC_IMCR_P1, (uchar_t)APIC_IMCR_SELECT);
1196 1196                  outb(APIC_IMCR_P2, (uchar_t)APIC_IMCR_PIC);
1197 1197          }
1198 1198  
1199 1199          apic_disable_local_apic();
1200 1200  
1201 1201          intr_restore(iflag);
1202 1202  
1203 1203          /* remainder of function is for shutdown cases only */
1204 1204          if (cmd != A_SHUTDOWN)
1205 1205                  return;
1206 1206  
1207 1207          /*
1208 1208           * Switch system back into Legacy-Mode if using ACPI and
1209 1209           * not powering-off.  Some BIOSes need to remain in ACPI-mode
1210 1210           * for power-off to succeed (Dell Dimension 4600)
1211 1211           * Do not disable ACPI while doing fastreboot
1212 1212           */
1213 1213          if (apic_enable_acpi && fcn != AD_POWEROFF && fcn != AD_FASTREBOOT)
1214 1214                  (void) AcpiDisable();
1215 1215  
1216 1216          if (fcn == AD_FASTREBOOT) {
1217 1217                  apic_reg_ops->apic_write(APIC_INT_CMD1,
1218 1218                      AV_ASSERT | AV_RESET | AV_SH_ALL_EXCSELF);
1219 1219          }
1220 1220  
1221 1221          /* remainder of function is for shutdown+poweroff case only */
1222 1222          if (fcn != AD_POWEROFF)
1223 1223                  return;
1224 1224  
1225 1225          switch (apic_poweroff_method) {
1226 1226                  case APIC_POWEROFF_VIA_RTC:
1227 1227  
1228 1228                          /* select the extended NVRAM bank in the RTC */
1229 1229                          outb(CMOS_ADDR, RTC_REGA);
1230 1230                          byte = inb(CMOS_DATA);
1231 1231                          outb(CMOS_DATA, (byte | EXT_BANK));
1232 1232  
1233 1233                          outb(CMOS_ADDR, PFR_REG);
1234 1234  
1235 1235                          /* for Predator must toggle the PAB bit */
1236 1236                          byte = inb(CMOS_DATA);
1237 1237  
1238 1238                          /*
1239 1239                           * clear power active bar, wakeup alarm and
1240 1240                           * kickstart
1241 1241                           */
1242 1242                          byte &= ~(PAB_CBIT | WF_FLAG | KS_FLAG);
1243 1243                          outb(CMOS_DATA, byte);
1244 1244  
1245 1245                          /* delay before next write */
1246 1246                          drv_usecwait(1000);
1247 1247  
1248 1248                          /* for S40 the following would suffice */
1249 1249                          byte = inb(CMOS_DATA);
1250 1250  
1251 1251                          /* power active bar control bit */
1252 1252                          byte |= PAB_CBIT;
1253 1253                          outb(CMOS_DATA, byte);
1254 1254  
1255 1255                          break;
1256 1256  
1257 1257                  case APIC_POWEROFF_VIA_ASPEN_BMC:
1258 1258                          restarts = 0;
1259 1259  restart_aspen_bmc:
1260 1260                          if (++restarts == 3)
1261 1261                                  break;
1262 1262                          attempts = 0;
1263 1263                          do {
1264 1264                                  byte = inb(MISMIC_FLAG_REGISTER);
1265 1265                                  byte &= MISMIC_BUSY_MASK;
1266 1266                                  if (byte != 0) {
1267 1267                                          drv_usecwait(1000);
1268 1268                                          if (attempts >= 3)
1269 1269                                                  goto restart_aspen_bmc;
1270 1270                                          ++attempts;
1271 1271                                  }
1272 1272                          } while (byte != 0);
1273 1273                          outb(MISMIC_CNTL_REGISTER, CC_SMS_GET_STATUS);
1274 1274                          byte = inb(MISMIC_FLAG_REGISTER);
1275 1275                          byte |= 0x1;
1276 1276                          outb(MISMIC_FLAG_REGISTER, byte);
1277 1277                          i = 0;
1278 1278                          for (; i < (sizeof (aspen_bmc)/sizeof (aspen_bmc[0]));
1279 1279                              i++) {
1280 1280                                  attempts = 0;
1281 1281                                  do {
1282 1282                                          byte = inb(MISMIC_FLAG_REGISTER);
1283 1283                                          byte &= MISMIC_BUSY_MASK;
1284 1284                                          if (byte != 0) {
1285 1285                                                  drv_usecwait(1000);
1286 1286                                                  if (attempts >= 3)
1287 1287                                                          goto restart_aspen_bmc;
1288 1288                                                  ++attempts;
1289 1289                                          }
1290 1290                                  } while (byte != 0);
1291 1291                                  outb(MISMIC_CNTL_REGISTER, aspen_bmc[i].cntl);
1292 1292                                  outb(MISMIC_DATA_REGISTER, aspen_bmc[i].data);
1293 1293                                  byte = inb(MISMIC_FLAG_REGISTER);
1294 1294                                  byte |= 0x1;
1295 1295                                  outb(MISMIC_FLAG_REGISTER, byte);
1296 1296                          }
1297 1297                          break;
1298 1298  
1299 1299                  case APIC_POWEROFF_VIA_SITKA_BMC:
1300 1300                          restarts = 0;
1301 1301  restart_sitka_bmc:
1302 1302                          if (++restarts == 3)
1303 1303                                  break;
1304 1304                          attempts = 0;
1305 1305                          do {
1306 1306                                  byte = inb(SMS_STATUS_REGISTER);
1307 1307                                  byte &= SMS_STATE_MASK;
1308 1308                                  if ((byte == SMS_READ_STATE) ||
1309 1309                                      (byte == SMS_WRITE_STATE)) {
1310 1310                                          drv_usecwait(1000);
1311 1311                                          if (attempts >= 3)
1312 1312                                                  goto restart_sitka_bmc;
1313 1313                                          ++attempts;
1314 1314                                  }
1315 1315                          } while ((byte == SMS_READ_STATE) ||
1316 1316                              (byte == SMS_WRITE_STATE));
1317 1317                          outb(SMS_COMMAND_REGISTER, SMS_GET_STATUS);
1318 1318                          i = 0;
1319 1319                          for (; i < (sizeof (sitka_bmc)/sizeof (sitka_bmc[0]));
1320 1320                              i++) {
1321 1321                                  attempts = 0;
1322 1322                                  do {
1323 1323                                          byte = inb(SMS_STATUS_REGISTER);
1324 1324                                          byte &= SMS_IBF_MASK;
1325 1325                                          if (byte != 0) {
1326 1326                                                  drv_usecwait(1000);
1327 1327                                                  if (attempts >= 3)
1328 1328                                                          goto restart_sitka_bmc;
1329 1329                                                  ++attempts;
1330 1330                                          }
1331 1331                                  } while (byte != 0);
1332 1332                                  outb(sitka_bmc[i].port, sitka_bmc[i].data);
1333 1333                          }
1334 1334                          break;
1335 1335  
1336 1336                  case APIC_POWEROFF_NONE:
1337 1337  
1338 1338                          /* If no APIC direct method, we will try using ACPI */
1339 1339                          if (apic_enable_acpi) {
1340 1340                                  if (acpi_poweroff() == 1)
1341 1341                                          return;
1342 1342                          } else
1343 1343                                  return;
1344 1344  
1345 1345                          break;
1346 1346          }
1347 1347          /*
1348 1348           * Wait a limited time here for power to go off.
1349 1349           * If the power does not go off, then there was a
1350 1350           * problem and we should continue to the halt which
1351 1351           * prints a message for the user to press a key to
1352 1352           * reboot.
1353 1353           */
1354 1354          drv_usecwait(7000000); /* wait seven seconds */
1355 1355  
1356 1356  }
1357 1357  
1358 1358  cyclic_id_t apic_cyclic_id;
1359 1359  
1360 1360  /*
1361 1361   * The following functions are in the platform specific file so that they
1362 1362   * can be different functions depending on whether we are running on
1363 1363   * bare metal or a hypervisor.
1364 1364   */
1365 1365  
1366 1366  /*
1367 1367   * map an apic for memory-mapped access
1368 1368   */
1369 1369  uint32_t *
1370 1370  mapin_apic(uint32_t addr, size_t len, int flags)
1371 1371  {
1372 1372          return ((void *)psm_map_phys(addr, len, flags));
1373 1373  }
1374 1374  
1375 1375  uint32_t *
1376 1376  mapin_ioapic(uint32_t addr, size_t len, int flags)
1377 1377  {
1378 1378          return (mapin_apic(addr, len, flags));
1379 1379  }
1380 1380  
1381 1381  /*
1382 1382   * unmap an apic
1383 1383   */
1384 1384  void
1385 1385  mapout_apic(caddr_t addr, size_t len)
1386 1386  {
1387 1387          psm_unmap_phys(addr, len);
1388 1388  }
1389 1389  
1390 1390  void
1391 1391  mapout_ioapic(caddr_t addr, size_t len)
1392 1392  {
1393 1393          mapout_apic(addr, len);
1394 1394  }
1395 1395  
1396 1396  uint32_t
1397 1397  ioapic_read(int ioapic_ix, uint32_t reg)
1398 1398  {
1399 1399          volatile uint32_t *ioapic;
1400 1400  
1401 1401          ioapic = apicioadr[ioapic_ix];
1402 1402          ioapic[APIC_IO_REG] = reg;
1403 1403          return (ioapic[APIC_IO_DATA]);
1404 1404  }
1405 1405  
1406 1406  void
1407 1407  ioapic_write(int ioapic_ix, uint32_t reg, uint32_t value)
1408 1408  {
1409 1409          volatile uint32_t *ioapic;
1410 1410  
1411 1411          ioapic = apicioadr[ioapic_ix];
1412 1412          ioapic[APIC_IO_REG] = reg;
1413 1413          ioapic[APIC_IO_DATA] = value;
1414 1414  }
1415 1415  
1416 1416  void
1417 1417  ioapic_write_eoi(int ioapic_ix, uint32_t value)
1418 1418  {
1419 1419          volatile uint32_t *ioapic;
1420 1420  
1421 1421          ioapic = apicioadr[ioapic_ix];
1422 1422          ioapic[APIC_IO_EOI] = value;
1423 1423  }
1424 1424  
1425 1425  /*
1426 1426   * Round-robin algorithm to find the next CPU with interrupts enabled.
1427 1427   * It can't share the same static variable apic_next_bind_cpu with
1428 1428   * apic_get_next_bind_cpu(), since that will cause all interrupts to be
1429 1429   * bound to CPU1 at boot time.  During boot, only CPU0 is online with
1430 1430   * interrupts enabled when apic_get_next_bind_cpu() and apic_find_cpu()
1431 1431   * are called.  However, the pcplusmp driver assumes that there will be
1432 1432   * boot_ncpus CPUs configured eventually so it tries to distribute all
1433 1433   * interrupts among CPU0 - CPU[boot_ncpus - 1].  Thus to prevent all
1434 1434   * interrupts being targetted at CPU1, we need to use a dedicated static
1435 1435   * variable for find_next_cpu() instead of sharing apic_next_bind_cpu.
1436 1436   */
1437 1437  
1438 1438  processorid_t
1439 1439  apic_find_cpu(int flag)
1440 1440  {
1441 1441          int i;
1442 1442          static processorid_t acid = 0;
1443 1443  
1444 1444          /* Find the first CPU with the passed-in flag set */
1445 1445          for (i = 0; i < apic_nproc; i++) {
1446 1446                  if (++acid >= apic_nproc) {
1447 1447                          acid = 0;
1448 1448                  }
1449 1449                  if (apic_cpu_in_range(acid) &&
1450 1450                      (apic_cpus[acid].aci_status & flag)) {
1451 1451                          break;
1452 1452                  }
1453 1453          }
1454 1454  
1455 1455          ASSERT((apic_cpus[acid].aci_status & flag) != 0);
1456 1456          return (acid);
1457 1457  }
1458 1458  
1459 1459  /*
1460 1460   * Switch between safe and x2APIC IPI sending method.
1461 1461   * CPU may power on in xapic mode or x2apic mode. If CPU needs to send IPI to
1462 1462   * other CPUs before entering x2APIC mode, it still needs to xAPIC method.
1463 1463   * Before sending StartIPI to target CPU, psm_send_ipi will be changed to
1464 1464   * apic_common_send_ipi, which detects current local APIC mode and use right
1465 1465   * method to send IPI. If some CPUs fail to start up, apic_poweron_cnt
1466 1466   * won't return to zero, so apic_common_send_ipi will always be used.
1467 1467   * psm_send_ipi can't be simply changed back to x2apic_send_ipi if some CPUs
1468 1468   * failed to start up because those failed CPUs may recover itself later at
1469 1469   * unpredictable time.
1470 1470   */
1471 1471  void
1472 1472  apic_switch_ipi_callback(boolean_t enter)
1473 1473  {
1474 1474          ulong_t iflag;
1475 1475          struct psm_ops *pops = psmops;
1476 1476  
1477 1477          iflag = intr_clear();
1478 1478          lock_set(&apic_mode_switch_lock);
1479 1479          if (enter) {
1480 1480                  ASSERT(apic_poweron_cnt >= 0);
1481 1481                  if (apic_poweron_cnt == 0) {
1482 1482                          pops->psm_send_ipi = apic_common_send_ipi;
1483 1483                          send_dirintf = pops->psm_send_ipi;
1484 1484                  }
1485 1485                  apic_poweron_cnt++;
1486 1486          } else {
1487 1487                  ASSERT(apic_poweron_cnt > 0);
1488 1488                  apic_poweron_cnt--;
1489 1489                  if (apic_poweron_cnt == 0) {
1490 1490                          pops->psm_send_ipi = x2apic_send_ipi;
1491 1491                          send_dirintf = pops->psm_send_ipi;
1492 1492                  }
1493 1493          }
1494 1494          lock_clear(&apic_mode_switch_lock);
1495 1495          intr_restore(iflag);
1496 1496  }
1497 1497  
1498 1498  void
1499 1499  apic_intrmap_init(int apic_mode)
1500 1500  {
1501 1501          int suppress_brdcst_eoi = 0;
1502 1502  
1503 1503          /*
1504 1504           * Intel Software Developer's Manual 3A, 10.12.7:
1505 1505           *
1506 1506           * Routing of device interrupts to local APIC units operating in
1507 1507           * x2APIC mode requires use of the interrupt-remapping architecture
1508 1508           * specified in the Intel Virtualization Technology for Directed
1509 1509           * I/O, Revision 1.3.  Because of this, BIOS must enumerate support
1510 1510           * for and software must enable this interrupt remapping with
1511 1511           * Extended Interrupt Mode Enabled before it enabling x2APIC mode in
1512 1512           * the local APIC units.
1513 1513           *
1514 1514           *
1515 1515           * In other words, to use the APIC in x2APIC mode, we need interrupt
1516 1516           * remapping.  Since we don't start up the IOMMU by default, we
1517 1517           * won't be able to do any interrupt remapping and therefore have to
1518 1518           * use the APIC in traditional 'local APIC' mode with memory mapped
1519 1519           * I/O.
1520 1520           */
1521 1521  
1522 1522          if (psm_vt_ops != NULL) {
1523 1523                  if (((apic_intrmap_ops_t *)psm_vt_ops)->
1524 1524                      apic_intrmap_init(apic_mode) == DDI_SUCCESS) {
1525 1525  
1526 1526                          apic_vt_ops = psm_vt_ops;
1527 1527  
1528 1528                          /*
1529 1529                           * We leverage the interrupt remapping engine to
1530 1530                           * suppress broadcast EOI; thus we must send the
1531 1531                           * directed EOI with the directed-EOI handler.
1532 1532                           */
1533 1533                          if (apic_directed_EOI_supported() == 0) {
1534 1534                                  suppress_brdcst_eoi = 1;
1535 1535                          }
1536 1536  
1537 1537                          apic_vt_ops->apic_intrmap_enable(suppress_brdcst_eoi);
1538 1538  
1539 1539                          if (apic_detect_x2apic()) {
1540 1540                                  apic_enable_x2apic();
1541 1541                          }
1542 1542  
1543 1543                          if (apic_directed_EOI_supported() == 0) {
1544 1544                                  apic_set_directed_EOI_handler();
1545 1545                          }
1546 1546                  }
1547 1547          }
1548 1548  }
1549 1549  
1550 1550  /*ARGSUSED*/
1551 1551  static void
1552 1552  apic_record_ioapic_rdt(void *intrmap_private, ioapic_rdt_t *irdt)
1553 1553  {
1554 1554          irdt->ir_hi <<= APIC_ID_BIT_OFFSET;
1555 1555  }
1556 1556  
1557 1557  /*ARGSUSED*/
1558 1558  static void
1559 1559  apic_record_msi(void *intrmap_private, msi_regs_t *mregs)
1560 1560  {
1561 1561          mregs->mr_addr = MSI_ADDR_HDR |
1562 1562              (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) |
1563 1563              (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) |
1564 1564              (mregs->mr_addr << MSI_ADDR_DEST_SHIFT);
1565 1565          mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) |
1566 1566              mregs->mr_data;
1567 1567  }
1568 1568  
1569 1569  /*
1570 1570   * Functions from apic_introp.c
1571 1571   *
1572 1572   * Those functions are used by apic_intr_ops().
1573 1573   */
1574 1574  
1575 1575  /*
1576 1576   * MSI support flag:
1577 1577   * reflects whether MSI is supported at APIC level
1578 1578   * it can also be patched through /etc/system
1579 1579   *
1580 1580   *  0 = default value - don't know and need to call apic_check_msi_support()
1581 1581   *      to find out then set it accordingly
1582 1582   *  1 = supported
1583 1583   * -1 = not supported
1584 1584   */
1585 1585  int     apic_support_msi = 0;
1586 1586  
1587 1587  /* Multiple vector support for MSI-X */
1588 1588  int     apic_msix_enable = 1;
1589 1589  
1590 1590  /* Multiple vector support for MSI */
1591 1591  int     apic_multi_msi_enable = 1;
1592 1592  
1593 1593  /*
1594 1594   * Check whether the system supports MSI.
1595 1595   *
1596 1596   * MSI is required for PCI-E and for PCI versions later than 2.2, so if we find
1597 1597   * a PCI-E bus or we find a PCI bus whose version we know is >= 2.2, then we
1598 1598   * return PSM_SUCCESS to indicate this system supports MSI.
1599 1599   *
1600 1600   * (Currently the only way we check whether a given PCI bus supports >= 2.2 is
1601 1601   * by detecting if we are running inside the KVM hypervisor, which guarantees
1602 1602   * this version number.)
1603 1603   */
1604 1604  int
1605 1605  apic_check_msi_support()
1606 1606  {
1607 1607          dev_info_t *cdip;
1608 1608          char dev_type[16];
1609 1609          int dev_len;
1610 1610  
1611 1611          DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support:\n"));
1612 1612  
1613 1613          /*
1614 1614           * check whether the first level children of root_node have
1615 1615           * PCI-E or PCI capability.
1616 1616           */
1617 1617          for (cdip = ddi_get_child(ddi_root_node()); cdip != NULL;
1618 1618              cdip = ddi_get_next_sibling(cdip)) {
1619 1619  
1620 1620                  DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: cdip: 0x%p,"
1621 1621                      " driver: %s, binding: %s, nodename: %s\n", (void *)cdip,
1622 1622                      ddi_driver_name(cdip), ddi_binding_name(cdip),
1623 1623                      ddi_node_name(cdip)));
1624 1624                  dev_len = sizeof (dev_type);
1625 1625                  if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
1626 1626                      "device_type", (caddr_t)dev_type, &dev_len)
1627 1627                      != DDI_PROP_SUCCESS)
1628 1628                          continue;
1629 1629                  if (strcmp(dev_type, "pciex") == 0)
1630 1630                          return (PSM_SUCCESS);
1631 1631                  if (strcmp(dev_type, "pci") == 0 && get_hwenv() == HW_KVM)
1632 1632                          return (PSM_SUCCESS);
1633 1633          }
1634 1634  
1635 1635          /* MSI is not supported on this system */
1636 1636          DDI_INTR_IMPLDBG((CE_CONT, "apic_check_msi_support: no 'pciex' "
1637 1637              "device_type found\n"));
1638 1638          return (PSM_FAILURE);
1639 1639  }
1640 1640  
1641 1641  /*
1642 1642   * apic_pci_msi_unconfigure:
1643 1643   *
1644 1644   * This and next two interfaces are copied from pci_intr_lib.c
1645 1645   * Do ensure that these two files stay in sync.
1646 1646   * These needed to be copied over here to avoid a deadlock situation on
1647 1647   * certain mp systems that use MSI interrupts.
1648 1648   *
1649 1649   * IMPORTANT regards next three interfaces:
1650 1650   * i) are called only for MSI/X interrupts.
1651 1651   * ii) called with interrupts disabled, and must not block
1652 1652   */
1653 1653  void
1654 1654  apic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum)
1655 1655  {
1656 1656          ushort_t                msi_ctrl;
1657 1657          int                     cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip);
1658 1658          ddi_acc_handle_t        handle = i_ddi_get_pci_config_handle(rdip);
1659 1659  
1660 1660          ASSERT((handle != NULL) && (cap_ptr != 0));
1661 1661  
1662 1662          if (type == DDI_INTR_TYPE_MSI) {
1663 1663                  msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
1664 1664                  msi_ctrl &= (~PCI_MSI_MME_MASK);
1665 1665                  pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
1666 1666                  pci_config_put32(handle, cap_ptr + PCI_MSI_ADDR_OFFSET, 0);
1667 1667  
1668 1668                  if (msi_ctrl &  PCI_MSI_64BIT_MASK) {
1669 1669                          pci_config_put16(handle,
1670 1670                              cap_ptr + PCI_MSI_64BIT_DATA, 0);
1671 1671                          pci_config_put32(handle,
1672 1672                              cap_ptr + PCI_MSI_ADDR_OFFSET + 4, 0);
1673 1673                  } else {
1674 1674                          pci_config_put16(handle,
1675 1675                              cap_ptr + PCI_MSI_32BIT_DATA, 0);
1676 1676                  }
1677 1677  
1678 1678          } else if (type == DDI_INTR_TYPE_MSIX) {
1679 1679                  uintptr_t       off;
1680 1680                  uint32_t        mask;
1681 1681                  ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
1682 1682  
1683 1683                  ASSERT(msix_p != NULL);
1684 1684  
1685 1685                  /* Offset into "inum"th entry in the MSI-X table & mask it */
1686 1686                  off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
1687 1687                      PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
1688 1688  
1689 1689                  mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off);
1690 1690  
1691 1691                  ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask | 1));
1692 1692  
1693 1693                  /* Offset into the "inum"th entry in the MSI-X table */
1694 1694                  off = (uintptr_t)msix_p->msix_tbl_addr +
1695 1695                      (inum * PCI_MSIX_VECTOR_SIZE);
1696 1696  
1697 1697                  /* Reset the "data" and "addr" bits */
1698 1698                  ddi_put32(msix_p->msix_tbl_hdl,
1699 1699                      (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
1700 1700                  ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, 0);
1701 1701          }
1702 1702  }
1703 1703  
1704 1704  /*
1705 1705   * apic_pci_msi_disable_mode:
1706 1706   */
1707 1707  void
1708 1708  apic_pci_msi_disable_mode(dev_info_t *rdip, int type)
1709 1709  {
1710 1710          ushort_t                msi_ctrl;
1711 1711          int                     cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip);
1712 1712          ddi_acc_handle_t        handle = i_ddi_get_pci_config_handle(rdip);
1713 1713  
1714 1714          ASSERT((handle != NULL) && (cap_ptr != 0));
1715 1715  
1716 1716          if (type == DDI_INTR_TYPE_MSI) {
1717 1717                  msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL);
1718 1718                  if (!(msi_ctrl & PCI_MSI_ENABLE_BIT))
1719 1719                          return;
1720 1720  
1721 1721                  msi_ctrl &= ~PCI_MSI_ENABLE_BIT;        /* MSI disable */
1722 1722                  pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl);
1723 1723  
1724 1724          } else if (type == DDI_INTR_TYPE_MSIX) {
1725 1725                  msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL);
1726 1726                  if (msi_ctrl & PCI_MSIX_ENABLE_BIT) {
1727 1727                          msi_ctrl &= ~PCI_MSIX_ENABLE_BIT;
1728 1728                          pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL,
1729 1729                              msi_ctrl);
1730 1730                  }
1731 1731          }
1732 1732  }
1733 1733  
1734 1734  uint32_t
1735 1735  apic_get_localapicid(uint32_t cpuid)
1736 1736  {
1737 1737          ASSERT(cpuid < apic_nproc && apic_cpus != NULL);
1738 1738  
1739 1739          return (apic_cpus[cpuid].aci_local_id);
1740 1740  }
1741 1741  
1742 1742  uchar_t
1743 1743  apic_get_ioapicid(uchar_t ioapicindex)
1744 1744  {
1745 1745          ASSERT(ioapicindex < MAX_IO_APIC);
1746 1746  
1747 1747          return (apic_io_id[ioapicindex]);
1748 1748  }
  
    | ↓ open down ↓ | 887 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX