Skip to content

Commit f5d8319

Browse files
committed
Hyper-V: arm64: Support for repetitive hypercall
This patch adds support for repetitive hyperv hypercall for arm64. This is already supported for x64. Its mostly bringing arm64 to the same level of support by unifying the common functionality. Signed-off-by: Sunil Muthuswamy <[email protected]> TAG_MSFT: wsl
1 parent 65dbae1 commit f5d8319

File tree

4 files changed

+73
-33
lines changed

4 files changed

+73
-33
lines changed

arch/arm64/hyperv/hv_core.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,21 @@ EXPORT_SYMBOL_GPL(hv_vp_index);
4040
u32 hv_max_vp_index;
4141
EXPORT_SYMBOL_GPL(hv_max_vp_index);
4242

43+
void __percpu **hyperv_pcpu_input_arg;
44+
EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg);
45+
4346
static int hv_cpu_init(unsigned int cpu)
4447
{
48+
void **input_arg;
49+
struct page *pg;
4550
u64 msr_vp_index;
4651

52+
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
53+
pg = alloc_page(GFP_KERNEL);
54+
if (unlikely(!pg))
55+
return -ENOMEM;
56+
*input_arg = page_address(pg);
57+
4758
msr_vp_index = hv_get_vpreg(HV_REGISTER_VPINDEX);
4859

4960
hv_vp_index[smp_processor_id()] = msr_vp_index;
@@ -54,6 +65,22 @@ static int hv_cpu_init(unsigned int cpu)
5465
return 0;
5566
}
5667

68+
static int hv_cpu_die(unsigned int cpu)
69+
{
70+
void **input_arg;
71+
void *input_pg;
72+
unsigned long flags;
73+
74+
local_irq_save(flags);
75+
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
76+
input_pg = *input_arg;
77+
*input_arg = NULL;
78+
local_irq_restore(flags);
79+
free_page((unsigned long)input_pg);
80+
81+
return 0;
82+
}
83+
5784
/*
5885
* Functions for allocating and freeing memory with size and
5986
* alignment HV_HYP_PAGE_SIZE. These functions are needed because
@@ -140,6 +167,16 @@ static int __init hyperv_init(struct acpi_table_header *table)
140167
pr_info("Hyper-V: Features 0x%x, hints 0x%x, misc 0x%x\n",
141168
ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
142169

170+
/*
171+
* Allocate the per-CPU state for the hypercall input arg.
172+
* If this allocation fails, we will not be able to setup
173+
* (per-CPU) hypercall input page and thus this failure is
174+
* fatal on Hyper-V.
175+
*/
176+
hyperv_pcpu_input_arg = alloc_percpu(void *);
177+
178+
BUG_ON(hyperv_pcpu_input_arg == NULL);
179+
143180
/*
144181
* If Hyper-V has crash notifications, set crash_kexec_post_notifiers
145182
* so that we will report the panic to Hyper-V before running kdump.
@@ -166,7 +203,7 @@ static int __init hyperv_init(struct acpi_table_header *table)
166203
hv_vp_index[i] = VP_INVAL;
167204

168205
cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
169-
"arm64/hyperv_init:online", hv_cpu_init, NULL);
206+
"arm64/hyperv_init:online", hv_cpu_init, hv_cpu_die);
170207
if (cpuhp < 0)
171208
goto free_vp_index;
172209

arch/arm64/include/asm/mshyperv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ extern void hv_set_vpreg(u32 reg, u64 value);
3535
extern u64 hv_get_vpreg(u32 reg);
3636
extern void hv_get_vpreg_128(u32 reg, struct hv_get_vp_registers_output *result);
3737

38+
extern void __percpu **hyperv_pcpu_input_arg;
39+
3840
/* Access various Hyper-V synthetic registers */
3941
static inline void hv_set_simp(u64 val)
4042
{

arch/x86/include/asm/mshyperv.h

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -184,38 +184,6 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
184184
return hv_status;
185185
}
186186

187-
/*
188-
* Rep hypercalls. Callers of this functions are supposed to ensure that
189-
* rep_count and varhead_size comply with Hyper-V hypercall definition.
190-
*/
191-
static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
192-
void *input, void *output)
193-
{
194-
u64 control = code;
195-
u64 status;
196-
u16 rep_comp;
197-
198-
control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
199-
control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
200-
201-
do {
202-
status = hv_do_hypercall(control, input, output);
203-
if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
204-
return status;
205-
206-
/* Bits 32-43 of status have 'Reps completed' data. */
207-
rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
208-
HV_HYPERCALL_REP_COMP_OFFSET;
209-
210-
control &= ~HV_HYPERCALL_REP_START_MASK;
211-
control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
212-
213-
touch_nmi_watchdog();
214-
} while (rep_comp < rep_count);
215-
216-
return status;
217-
}
218-
219187
extern struct hv_vp_assist_page **hv_vp_assist_page;
220188

221189
static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)

include/asm-generic/mshyperv.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/atomic.h>
2323
#include <linux/bitops.h>
2424
#include <linux/cpumask.h>
25+
#include <linux/nmi.h>
2526
#include <asm/ptrace.h>
2627
#include <asm/hyperv-tlfs.h>
2728

@@ -184,6 +185,38 @@ static inline void hyperv_cleanup(void) {}
184185
#if IS_ENABLED(CONFIG_HYPERV)
185186
extern int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void));
186187
extern void hv_remove_stimer0_irq(int irq);
188+
189+
/*
190+
* Rep hypercalls. Callers of this functions are supposed to ensure that
191+
* rep_count and varhead_size comply with Hyper-V hypercall definition.
192+
*/
193+
static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
194+
void *input, void *output)
195+
{
196+
u64 control = code;
197+
u64 status;
198+
u16 rep_comp;
199+
200+
control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
201+
control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
202+
203+
do {
204+
status = hv_do_hypercall(control, input, output);
205+
if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
206+
return status;
207+
208+
/* Bits 32-43 of status have 'Reps completed' data. */
209+
rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
210+
HV_HYPERCALL_REP_COMP_OFFSET;
211+
212+
control &= ~HV_HYPERCALL_REP_START_MASK;
213+
control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
214+
215+
touch_nmi_watchdog();
216+
} while (rep_comp < rep_count);
217+
218+
return status;
219+
}
187220
#endif
188221

189222
#endif

0 commit comments

Comments
 (0)