diff options
author | K. Y. Srinivasan <kys@microsoft.com> | 2018-05-16 17:53:32 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-05-19 07:23:17 -0400 |
commit | 366f03b0cf90ef55f063d4a54cf62b0ac9b6da9d (patch) | |
tree | c08ee5d23e472443c023f3d07587a2c84cd79f07 | |
parent | 68bb7bfb7985df2bd15c2dc975cb68b7a901488a (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.c | 42 | ||||
-rw-r--r-- | arch/x86/hyperv/mmu.c | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/hyperv-tlfs.h | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 33 |
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 | */ |
96 | static 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 | |||
125 | ipi_mask_ex_done: | ||
126 | local_irq_restore(flags); | ||
127 | return ((ret == 0) ? true : false); | ||
128 | } | ||
129 | |||
96 | static bool __send_ipi_mask(const struct cpumask *mask, int vector) | 130 | static 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) | |||
193 | void __init hv_apic_init(void) | 230 | void __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 | ||
371 | enum HV_GENERIC_SET_FORMAT { | 372 | enum 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 | ||
725 | struct hv_vpset { | ||
726 | u64 format; | ||
727 | u64 valid_bank_mask; | ||
728 | u64 bank_contents[]; | ||
729 | }; | ||
730 | |||
731 | struct 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 | ||
262 | static 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 | |||
262 | void __init hyperv_init(void); | 295 | void __init hyperv_init(void); |
263 | void hyperv_setup_mmu_ops(void); | 296 | void hyperv_setup_mmu_ops(void); |
264 | void hyper_alloc_mmu(void); | 297 | void hyper_alloc_mmu(void); |