]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'x86/urgent' into x86/hyperv
authorThomas Gleixner <tglx@linutronix.de>
Fri, 6 Jul 2018 10:35:56 +0000 (12:35 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 6 Jul 2018 10:35:56 +0000 (12:35 +0200)
Integrate the upstream bug fix to resolve the resulting conflict in
__send_ipi_mask().

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1  2 
arch/x86/hyperv/hv_apic.c
arch/x86/include/asm/mshyperv.h

index 657a2b8c738a541c052ef971a1f0c9d656c55721,40233836565118f4fb60239ded1fc09aabe34cf1..0c3c9f8fee77bbeaf2db91072b32b3c70d9205ee
@@@ -31,8 -31,6 +31,8 @@@
  #include <asm/mshyperv.h>
  #include <asm/apic.h>
  
 +#include <asm/trace/hyperv.h>
 +
  static struct apic orig_apic;
  
  static u64 hv_apic_icr_read(void)
@@@ -101,9 -99,6 +101,9 @@@ static bool __send_ipi_mask_ex(const st
        int nr_bank = 0;
        int ret = 1;
  
 +      if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
 +              return false;
 +
        local_irq_save(flags);
        arg = (struct ipi_arg_ex **)this_cpu_ptr(hyperv_pcpu_input_arg);
  
                ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K;
                nr_bank = cpumask_to_vpset(&(ipi_arg->vp_set), mask);
        }
+       if (nr_bank < 0)
+               goto ipi_mask_ex_done;
        if (!nr_bank)
                ipi_arg->vp_set.format = HV_GENERIC_SET_ALL;
  
@@@ -133,10 -130,10 +135,10 @@@ ipi_mask_ex_done
  static bool __send_ipi_mask(const struct cpumask *mask, int vector)
  {
        int cur_cpu, vcpu;
 -      struct ipi_arg_non_ex **arg;
 -      struct ipi_arg_non_ex *ipi_arg;
 +      struct ipi_arg_non_ex ipi_arg;
        int ret = 1;
 -      unsigned long flags;
 +
 +      trace_hyperv_send_ipi_mask(mask, vector);
  
        if (cpumask_empty(mask))
                return true;
        if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
                return false;
  
 -      if ((ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
 -              return __send_ipi_mask_ex(mask, vector);
 -
 -      local_irq_save(flags);
 -      arg = (struct ipi_arg_non_ex **)this_cpu_ptr(hyperv_pcpu_input_arg);
 -
 -      ipi_arg = *arg;
 -      if (unlikely(!ipi_arg))
 -              goto ipi_mask_done;
 -
 -      ipi_arg->vector = vector;
 -      ipi_arg->reserved = 0;
 -      ipi_arg->cpu_mask = 0;
 +      /*
 +       * From the supplied CPU set we need to figure out if we can get away
 +       * with cheaper HVCALL_SEND_IPI hypercall. This is possible when the
 +       * highest VP number in the set is < 64. As VP numbers are usually in
 +       * ascending order and match Linux CPU ids, here is an optimization:
 +       * we check the VP number for the highest bit in the supplied set first
 +       * so we can quickly find out if using HVCALL_SEND_IPI_EX hypercall is
 +       * a must. We will also check all VP numbers when walking the supplied
 +       * CPU set to remain correct in all cases.
 +       */
 +      if (hv_cpu_number_to_vp_number(cpumask_last(mask)) >= 64)
 +              goto do_ex_hypercall;
 +
 +      ipi_arg.vector = vector;
 +      ipi_arg.cpu_mask = 0;
  
        for_each_cpu(cur_cpu, mask) {
                vcpu = hv_cpu_number_to_vp_number(cur_cpu);
 -                      goto ipi_mask_done;
+               if (vcpu == VP_INVAL)
++                      return true;
                /*
                 * This particular version of the IPI hypercall can
                 * only target upto 64 CPUs.
                 */
                if (vcpu >= 64)
 -                      goto ipi_mask_done;
 +                      goto do_ex_hypercall;
  
 -              __set_bit(vcpu, (unsigned long *)&ipi_arg->cpu_mask);
 +              __set_bit(vcpu, (unsigned long *)&ipi_arg.cpu_mask);
        }
  
 -      ret = hv_do_hypercall(HVCALL_SEND_IPI, ipi_arg, NULL);
 -
 -ipi_mask_done:
 -      local_irq_restore(flags);
 +      ret = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector,
 +                                   ipi_arg.cpu_mask);
        return ((ret == 0) ? true : false);
 +
 +do_ex_hypercall:
 +      return __send_ipi_mask_ex(mask, vector);
  }
  
  static bool __send_ipi_one(int cpu, int vector)
@@@ -236,7 -233,10 +241,7 @@@ static void hv_send_ipi_self(int vector
  void __init hv_apic_init(void)
  {
        if (ms_hyperv.hints & HV_X64_CLUSTER_IPI_RECOMMENDED) {
 -              if ((ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
 -                      pr_info("Hyper-V: Using ext hypercalls for IPI\n");
 -              else
 -                      pr_info("Hyper-V: Using IPI hypercalls\n");
 +              pr_info("Hyper-V: Using IPI hypercalls\n");
                /*
                 * Set the IPI entry points.
                 */
index da25642940d31b491bcc0d60674cd3ba378acf2e,5a7375ed5f7cd80ca9925f05d422a9090e3602be..19886fef1dfc2c5c747ef4798048318c7214bd43
@@@ -9,6 -9,8 +9,8 @@@
  #include <asm/hyperv-tlfs.h>
  #include <asm/nospec-branch.h>
  
+ #define VP_INVAL      U32_MAX
  struct ms_hyperv_info {
        u32 features;
        u32 misc_features;
@@@ -20,7 -22,6 +22,6 @@@
  
  extern struct ms_hyperv_info ms_hyperv;
  
  /*
   * Generate the guest ID.
   */
@@@ -193,40 -194,6 +194,40 @@@ static inline u64 hv_do_fast_hypercall8
                return hv_status;
  }
  
 +/* Fast hypercall with 16 bytes of input */
 +static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
 +{
 +      u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
 +
 +#ifdef CONFIG_X86_64
 +      {
 +              __asm__ __volatile__("mov %4, %%r8\n"
 +                                   CALL_NOSPEC
 +                                   : "=a" (hv_status), ASM_CALL_CONSTRAINT,
 +                                     "+c" (control), "+d" (input1)
 +                                   : "r" (input2),
 +                                     THUNK_TARGET(hv_hypercall_pg)
 +                                   : "cc", "r8", "r9", "r10", "r11");
 +      }
 +#else
 +      {
 +              u32 input1_hi = upper_32_bits(input1);
 +              u32 input1_lo = lower_32_bits(input1);
 +              u32 input2_hi = upper_32_bits(input2);
 +              u32 input2_lo = lower_32_bits(input2);
 +
 +              __asm__ __volatile__ (CALL_NOSPEC
 +                                    : "=A"(hv_status),
 +                                      "+c"(input1_lo), ASM_CALL_CONSTRAINT
 +                                    : "A" (control), "b" (input1_hi),
 +                                      "D"(input2_hi), "S"(input2_lo),
 +                                      THUNK_TARGET(hv_hypercall_pg)
 +                                    : "cc");
 +      }
 +#endif
 +              return hv_status;
 +}
 +
  /*
   * Rep hypercalls. Callers of this functions are supposed to ensure that
   * rep_count and varhead_size comply with Hyper-V hypercall definition.
@@@ -315,6 -282,8 +316,8 @@@ static inline int cpumask_to_vpset(stru
         */
        for_each_cpu(cpu, cpus) {
                vcpu = hv_cpu_number_to_vp_number(cpu);
+               if (vcpu == VP_INVAL)
+                       return -1;
                vcpu_bank = vcpu / 64;
                vcpu_offset = vcpu % 64;
                __set_bit(vcpu_offset, (unsigned long *)