Print this page
6062 Workaround broken KVM handling of directed EOIs
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>

  27  */
  28 
  29 #include <sys/cpuvar.h>
  30 #include <sys/psm.h>
  31 #include <sys/archsystm.h>
  32 #include <sys/apic.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/ddi_impldefs.h>
  35 #include <sys/mach_intr.h>
  36 #include <sys/sysmacros.h>
  37 #include <sys/trap.h>
  38 #include <sys/x86_archext.h>
  39 #include <sys/privregs.h>
  40 #include <sys/psm_common.h>
  41 
  42 /* Function prototypes of local apic and X2APIC */
  43 static uint64_t local_apic_read(uint32_t reg);
  44 static void local_apic_write(uint32_t reg, uint64_t value);
  45 static int get_local_apic_pri(void);
  46 static void local_apic_write_task_reg(uint64_t value);


  49 static void local_x2apic_write(uint32_t msr, uint64_t value);
  50 static int get_local_x2apic_pri(void);
  51 static void local_x2apic_write_task_reg(uint64_t value);
  52 static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
  53 
  54 /*
  55  * According to the X2APIC specification:
  56  *
  57  *   xAPIC global enable    X2APIC enable         Description
  58  *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
  59  * -----------------------------------------------------------
  60  *      0                       0       APIC is disabled
  61  *      0                       1       Invalid
  62  *      1                       0       APIC is enabled in xAPIC mode
  63  *      1                       1       APIC is enabled in X2APIC mode
  64  * -----------------------------------------------------------
  65  */
  66 int     x2apic_enable = 1;
  67 apic_mode_t apic_mode = LOCAL_APIC;     /* Default mode is Local APIC */
  68 



  69 /* Uses MMIO (Memory Mapped IO) */
  70 static apic_reg_ops_t local_apic_regs_ops = {
  71         local_apic_read,
  72         local_apic_write,
  73         get_local_apic_pri,
  74         local_apic_write_task_reg,
  75         local_apic_write_int_cmd,
  76         apic_send_EOI,
  77 };
  78 
  79 /* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
  80 static apic_reg_ops_t x2apic_regs_ops = {
  81         local_x2apic_read,
  82         local_x2apic_write,
  83         get_local_x2apic_pri,
  84         local_x2apic_write_task_reg,
  85         local_x2apic_write_int_cmd,
  86         apic_send_EOI,
  87 };
  88 


 277 
 278         apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
 279 
 280         if ((apic_base_msr & bit) == bit)
 281                 return (LOCAL_X2APIC);
 282         else
 283                 return (LOCAL_APIC);
 284 }
 285 
 286 void
 287 apic_set_directed_EOI_handler()
 288 {
 289         apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
 290 }
 291 
 292 int
 293 apic_directed_EOI_supported()
 294 {
 295         uint32_t ver;
 296 



































 297         ver = apic_reg_ops->apic_read(APIC_VERS_REG);
 298         if (ver & APIC_DIRECTED_EOI_BIT)
 299                 return (1);
 300 
 301         return (0);
 302 }
 303 
 304 /*
 305  * Change apic_reg_ops depending upon the apic_mode.
 306  */
 307 void
 308 apic_change_ops()
 309 {
 310         if (apic_mode == LOCAL_APIC)
 311                 apic_reg_ops = &local_apic_regs_ops;
 312         else if (apic_mode == LOCAL_X2APIC)
 313                 apic_reg_ops = &x2apic_regs_ops;
 314 }
 315 
 316 /*




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  27  * Copyright (c) 2014 by Delphix. All rights reserved.
  28  */
  29 
  30 #include <sys/cpuvar.h>
  31 #include <sys/psm.h>
  32 #include <sys/archsystm.h>
  33 #include <sys/apic.h>
  34 #include <sys/sunddi.h>
  35 #include <sys/ddi_impldefs.h>
  36 #include <sys/mach_intr.h>
  37 #include <sys/sysmacros.h>
  38 #include <sys/trap.h>
  39 #include <sys/x86_archext.h>
  40 #include <sys/privregs.h>
  41 #include <sys/psm_common.h>
  42 
  43 /* Function prototypes of local apic and X2APIC */
  44 static uint64_t local_apic_read(uint32_t reg);
  45 static void local_apic_write(uint32_t reg, uint64_t value);
  46 static int get_local_apic_pri(void);
  47 static void local_apic_write_task_reg(uint64_t value);


  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 
  55 /*
  56  * According to the X2APIC specification:
  57  *
  58  *   xAPIC global enable    X2APIC enable         Description
  59  *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
  60  * -----------------------------------------------------------
  61  *      0                       0       APIC is disabled
  62  *      0                       1       Invalid
  63  *      1                       0       APIC is enabled in xAPIC mode
  64  *      1                       1       APIC is enabled in X2APIC mode
  65  * -----------------------------------------------------------
  66  */
  67 int     x2apic_enable = 1;
  68 apic_mode_t apic_mode = LOCAL_APIC;     /* Default mode is Local APIC */
  69 
  70 /* See apic_directed_EOI_supported().  Currently 3-state variable. */
  71 volatile int apic_directed_eoi_state = 2;
  72 
  73 /* Uses MMIO (Memory Mapped IO) */
  74 static apic_reg_ops_t local_apic_regs_ops = {
  75         local_apic_read,
  76         local_apic_write,
  77         get_local_apic_pri,
  78         local_apic_write_task_reg,
  79         local_apic_write_int_cmd,
  80         apic_send_EOI,
  81 };
  82 
  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 


 281 
 282         apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
 283 
 284         if ((apic_base_msr & bit) == bit)
 285                 return (LOCAL_X2APIC);
 286         else
 287                 return (LOCAL_APIC);
 288 }
 289 
 290 void
 291 apic_set_directed_EOI_handler()
 292 {
 293         apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
 294 }
 295 
 296 int
 297 apic_directed_EOI_supported()
 298 {
 299         uint32_t ver;
 300 
 301         /*
 302          * There are some known issues with some versions of Linux KVM and QEMU
 303          * where by directed EOIs do not properly function and instead get
 304          * coalesced at the hypervisor, causing the host not to see interrupts.
 305          * Thus, when the platform is KVM, we would like to disable it by
 306          * default, but keep it available otherwise.
 307          *
 308          * We use a three-state variable (apic_directed_eoi_state) to determine
 309          * how we handle directed EOI.
 310          *
 311          * 0 --> Don't do directed EOI at all.
 312          * 1 --> Do directed EOI if available, no matter the HW environment.
 313          * 2 --> Don't do directed EOI on KVM, but do it otherwise if available.
 314          *
 315          * If some grinning weirdo put something else in there, treat it as '2'
 316          * (i.e. the current default).
 317          *
 318          * Note, at this time illumos KVM does not identify as KVM. If it does,
 319          * we'll need to do some work to determine if it should be caught by
 320          * this or if it should show up as its own value of platform_type.
 321          */
 322         switch (apic_directed_eoi_state) {
 323         case 0:
 324                 /* Don't do it at all. */
 325                 return (0);
 326         case 1:
 327                 break;
 328         case 2:
 329         default:
 330                 /* Only do it if we aren't on KVM. */
 331                 if (get_hwenv() == HW_KVM)
 332                         return (0);
 333                 /* FALLTHRU */
 334         }
 335 
 336         ver = apic_reg_ops->apic_read(APIC_VERS_REG);
 337         if (ver & APIC_DIRECTED_EOI_BIT)
 338                 return (1);
 339 
 340         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 /*