aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2018-05-16 17:53:32 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-05-19 07:23:17 -0400
commit366f03b0cf90ef55f063d4a54cf62b0ac9b6da9d (patch)
treec08ee5d23e472443c023f3d07587a2c84cd79f07
parent68bb7bfb7985df2bd15c2dc975cb68b7a901488a (diff)
X86/Hyper-V: Enhanced IPI enlightenment
Support enhanced IPI enlightenments (to target more than 64 CPUs). Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Cc: olaf@aepfle.de Cc: sthemmin@microsoft.com Cc: gregkh@linuxfoundation.org Cc: jasowang@redhat.com Cc: Michael.H.Kelley@microsoft.com Cc: hpa@zytor.com Cc: apw@canonical.com Cc: devel@linuxdriverproject.org Cc: vkuznets@redhat.com Link: https://lkml.kernel.org/r/20180516215334.6547-3-kys@linuxonhyperv.com
-rw-r--r--arch/x86/hyperv/hv_apic.c42
-rw-r--r--arch/x86/hyperv/mmu.c2
-rw-r--r--arch/x86/include/asm/hyperv-tlfs.h15
-rw-r--r--arch/x86/include/asm/mshyperv.h33
4 files changed, 89 insertions, 3 deletions
diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c
index 3e0de61f1a7c..192b6ad6a361 100644
--- a/arch/x86/hyperv/hv_apic.c
+++ b/arch/x86/hyperv/hv_apic.c
@@ -93,6 +93,40 @@ static void hv_apic_eoi_write(u32 reg, u32 val)
93/* 93/*
94 * IPI implementation on Hyper-V. 94 * IPI implementation on Hyper-V.
95 */ 95 */
96static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector)
97{
98 struct ipi_arg_ex **arg;
99 struct ipi_arg_ex *ipi_arg;
100 unsigned long flags;
101 int nr_bank = 0;
102 int ret = 1;
103
104 local_irq_save(flags);
105 arg = (struct ipi_arg_ex **)this_cpu_ptr(hyperv_pcpu_input_arg);
106
107 ipi_arg = *arg;
108 if (unlikely(!ipi_arg))
109 goto ipi_mask_ex_done;
110
111 ipi_arg->vector = vector;
112 ipi_arg->reserved = 0;
113 ipi_arg->vp_set.valid_bank_mask = 0;
114
115 if (!cpumask_equal(mask, cpu_present_mask)) {
116 ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K;
117 nr_bank = cpumask_to_vpset(&(ipi_arg->vp_set), mask);
118 }
119 if (!nr_bank)
120 ipi_arg->vp_set.format = HV_GENERIC_SET_ALL;
121
122 ret = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank,
123 ipi_arg, NULL);
124
125ipi_mask_ex_done:
126 local_irq_restore(flags);
127 return ((ret == 0) ? true : false);
128}
129
96static bool __send_ipi_mask(const struct cpumask *mask, int vector) 130static bool __send_ipi_mask(const struct cpumask *mask, int vector)
97{ 131{
98 int cur_cpu, vcpu; 132 int cur_cpu, vcpu;
@@ -110,6 +144,9 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector)
110 if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR)) 144 if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
111 return false; 145 return false;
112 146
147 if ((ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
148 return __send_ipi_mask_ex(mask, vector);
149
113 local_irq_save(flags); 150 local_irq_save(flags);
114 arg = (struct ipi_arg_non_ex **)this_cpu_ptr(hyperv_pcpu_input_arg); 151 arg = (struct ipi_arg_non_ex **)this_cpu_ptr(hyperv_pcpu_input_arg);
115 152
@@ -193,7 +230,10 @@ static void hv_send_ipi_self(int vector)
193void __init hv_apic_init(void) 230void __init hv_apic_init(void)
194{ 231{
195 if (ms_hyperv.hints & HV_X64_CLUSTER_IPI_RECOMMENDED) { 232 if (ms_hyperv.hints & HV_X64_CLUSTER_IPI_RECOMMENDED) {
196 pr_info("Hyper-V: Using IPI hypercalls\n"); 233 if ((ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
234 pr_info("Hyper-V: Using ext hypercalls for IPI\n");
235 else
236 pr_info("Hyper-V: Using IPI hypercalls\n");
197 /* 237 /*
198 * Set the IPI entry points. 238 * Set the IPI entry points.
199 */ 239 */
diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c
index 56c9ebac946f..adee39a7a3f2 100644
--- a/arch/x86/hyperv/mmu.c
+++ b/arch/x86/hyperv/mmu.c
@@ -239,7 +239,7 @@ static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
239 flush->hv_vp_set.valid_bank_mask = 0; 239 flush->hv_vp_set.valid_bank_mask = 0;
240 240
241 if (!cpumask_equal(cpus, cpu_present_mask)) { 241 if (!cpumask_equal(cpus, cpu_present_mask)) {
242 flush->hv_vp_set.format = HV_GENERIC_SET_SPARCE_4K; 242 flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
243 nr_bank = cpumask_to_vp_set(flush, cpus); 243 nr_bank = cpumask_to_vp_set(flush, cpus);
244 } 244 }
245 245
diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h
index 332e786d4deb..3bfa92c2793c 100644
--- a/arch/x86/include/asm/hyperv-tlfs.h
+++ b/arch/x86/include/asm/hyperv-tlfs.h
@@ -344,6 +344,7 @@ struct hv_tsc_emulation_status {
344#define HVCALL_SEND_IPI 0x000b 344#define HVCALL_SEND_IPI 0x000b
345#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013 345#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013
346#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014 346#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014
347#define HVCALL_SEND_IPI_EX 0x0015
347#define HVCALL_POST_MESSAGE 0x005c 348#define HVCALL_POST_MESSAGE 0x005c
348#define HVCALL_SIGNAL_EVENT 0x005d 349#define HVCALL_SIGNAL_EVENT 0x005d
349 350
@@ -369,7 +370,7 @@ struct hv_tsc_emulation_status {
369#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3) 370#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3)
370 371
371enum HV_GENERIC_SET_FORMAT { 372enum HV_GENERIC_SET_FORMAT {
372 HV_GENERIC_SET_SPARCE_4K, 373 HV_GENERIC_SET_SPARSE_4K,
373 HV_GENERIC_SET_ALL, 374 HV_GENERIC_SET_ALL,
374}; 375};
375 376
@@ -721,4 +722,16 @@ struct ipi_arg_non_ex {
721 u64 cpu_mask; 722 u64 cpu_mask;
722}; 723};
723 724
725struct hv_vpset {
726 u64 format;
727 u64 valid_bank_mask;
728 u64 bank_contents[];
729};
730
731struct ipi_arg_ex {
732 u32 vector;
733 u32 reserved;
734 struct hv_vpset vp_set;
735};
736
724#endif 737#endif
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index 1eff91599c2b..0ee82519957b 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -259,6 +259,39 @@ static inline int hv_cpu_number_to_vp_number(int cpu_number)
259 return hv_vp_index[cpu_number]; 259 return hv_vp_index[cpu_number];
260} 260}
261 261
262static inline int cpumask_to_vpset(struct hv_vpset *vpset,
263 const struct cpumask *cpus)
264{
265 int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
266
267 /* valid_bank_mask can represent up to 64 banks */
268 if (hv_max_vp_index / 64 >= 64)
269 return 0;
270
271 /*
272 * Clear all banks up to the maximum possible bank as hv_flush_pcpu_ex
273 * structs are not cleared between calls, we risk flushing unneeded
274 * vCPUs otherwise.
275 */
276 for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++)
277 vpset->bank_contents[vcpu_bank] = 0;
278
279 /*
280 * Some banks may end up being empty but this is acceptable.
281 */
282 for_each_cpu(cpu, cpus) {
283 vcpu = hv_cpu_number_to_vp_number(cpu);
284 vcpu_bank = vcpu / 64;
285 vcpu_offset = vcpu % 64;
286 __set_bit(vcpu_offset, (unsigned long *)
287 &vpset->bank_contents[vcpu_bank]);
288 if (vcpu_bank >= nr_bank)
289 nr_bank = vcpu_bank + 1;
290 }
291 vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
292 return nr_bank;
293}
294
262void __init hyperv_init(void); 295void __init hyperv_init(void);
263void hyperv_setup_mmu_ops(void); 296void hyperv_setup_mmu_ops(void);
264void hyper_alloc_mmu(void); 297void hyper_alloc_mmu(void);