Skip to content

Commit 7db6f28

Browse files
sunilmuttyhicks
authored andcommitted
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]>
1 parent afa4d09 commit 7db6f28

File tree

4 files changed

+72
-33
lines changed

4 files changed

+72
-33
lines changed

arch/arm64/hyperv/mshyperv.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,37 @@ EXPORT_SYMBOL_GPL(hv_vp_index);
3232
u32 hv_max_vp_index;
3333
EXPORT_SYMBOL_GPL(hv_max_vp_index);
3434

35+
void __percpu **hyperv_pcpu_input_arg;
36+
EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg);
37+
3538
static int hv_cpu_init(unsigned int cpu)
3639
{
40+
void **input_arg;
41+
42+
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
43+
*input_arg = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
44+
if (unlikely(!*input_arg))
45+
return -ENOMEM;
3746
hv_vp_index[cpu] = hv_get_vpreg(HV_REGISTER_VP_INDEX);
3847
return 0;
3948
}
4049

50+
static int hv_cpu_die(unsigned int cpu)
51+
{
52+
void **input_arg;
53+
void *input;
54+
unsigned long flags;
55+
56+
local_irq_save(flags);
57+
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
58+
input = *input_arg;
59+
*input_arg = NULL;
60+
local_irq_restore(flags);
61+
kfree(input);
62+
63+
return 0;
64+
}
65+
4166
void __init hyperv_early_init(void)
4267
{
4368
struct hv_get_vp_registers_output result;
@@ -95,23 +120,35 @@ static int __init hyperv_init(void)
95120
if (!hyperv_initialized)
96121
return 0;
97122

123+
/*
124+
* Allocate the per-CPU state for the hypercall input arg.
125+
* If this allocation fails, we will not be able to setup
126+
* (per-CPU) hypercall input page and thus this failure is
127+
* fatal on Hyper-V.
128+
*/
129+
hyperv_pcpu_input_arg = alloc_percpu(void *);
130+
if (unlikely(!hyperv_pcpu_input_arg))
131+
return -ENOMEM;
132+
98133
/* Allocate and initialize percpu VP index array */
99134
hv_max_vp_index = num_possible_cpus();
100135
hv_vp_index = kmalloc_array(hv_max_vp_index, sizeof(*hv_vp_index),
101136
GFP_KERNEL);
102137
if (!hv_vp_index) {
103138
hv_max_vp_index = 0;
139+
free_percpu(hyperv_pcpu_input_arg);
104140
return -ENOMEM;
105141
}
106142

107143
for (i = 0; i < hv_max_vp_index; i++)
108144
hv_vp_index[i] = VP_INVAL;
109145

110146
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/hyperv_init:online",
111-
hv_cpu_init, NULL) < 0) {
147+
hv_cpu_init, hv_cpu_die) < 0) {
112148
hv_max_vp_index = 0;
113149
kfree(hv_vp_index);
114150
hv_vp_index = NULL;
151+
free_percpu(hyperv_pcpu_input_arg);
115152
return -EINVAL;
116153
}
117154

arch/arm64/include/asm/mshyperv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern u64 hv_do_hvc_fast_get(u64 control, u64 input1, u64 input2, u64 input3,
4141
extern void hv_set_vpreg(u32 reg, u64 value);
4242
extern u64 hv_get_vpreg(u32 reg);
4343
extern void hv_get_vpreg_128(u32 reg, struct hv_get_vp_registers_output *result);
44+
extern void __percpu **hyperv_pcpu_input_arg;
4445

4546
static inline void hv_set_register(unsigned int reg, u64 value)
4647
{

arch/x86/include/asm/mshyperv.h

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

143-
/*
144-
* Rep hypercalls. Callers of this functions are supposed to ensure that
145-
* rep_count and varhead_size comply with Hyper-V hypercall definition.
146-
*/
147-
static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
148-
void *input, void *output)
149-
{
150-
u64 control = code;
151-
u64 status;
152-
u16 rep_comp;
153-
154-
control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
155-
control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
156-
157-
do {
158-
status = hv_do_hypercall(control, input, output);
159-
if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
160-
return status;
161-
162-
/* Bits 32-43 of status have 'Reps completed' data. */
163-
rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
164-
HV_HYPERCALL_REP_COMP_OFFSET;
165-
166-
control &= ~HV_HYPERCALL_REP_START_MASK;
167-
control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
168-
169-
touch_nmi_watchdog();
170-
} while (rep_comp < rep_count);
171-
172-
return status;
173-
}
174-
175143
extern struct hv_vp_assist_page **hv_vp_assist_page;
176144

177145
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

@@ -168,6 +169,38 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset,
168169
return nr_bank;
169170
}
170171

172+
/*
173+
* Rep hypercalls. Callers of this functions are supposed to ensure that
174+
* rep_count and varhead_size comply with Hyper-V hypercall definition.
175+
*/
176+
static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
177+
void *input, void *output)
178+
{
179+
u64 control = code;
180+
u64 status;
181+
u16 rep_comp;
182+
183+
control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
184+
control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
185+
186+
do {
187+
status = hv_do_hypercall(control, input, output);
188+
if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
189+
return status;
190+
191+
/* Bits 32-43 of status have 'Reps completed' data. */
192+
rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
193+
HV_HYPERCALL_REP_COMP_OFFSET;
194+
195+
control &= ~HV_HYPERCALL_REP_START_MASK;
196+
control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
197+
198+
touch_nmi_watchdog();
199+
} while (rep_comp < rep_count);
200+
201+
return status;
202+
}
203+
171204
void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
172205
bool hv_is_hyperv_initialized(void);
173206
bool hv_is_hibernation_supported(void);

0 commit comments

Comments
 (0)