Skip to content

Commit 2a106ee

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 <sunilmut@microsoft.com>
1 parent dbcb218 commit 2a106ee

4 files changed

Lines changed: 72 additions & 33 deletions

File tree

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;
@@ -89,23 +114,35 @@ static int __init hyperv_init(void)
89114
{
90115
int i;
91116

117+
/*
118+
* Allocate the per-CPU state for the hypercall input arg.
119+
* If this allocation fails, we will not be able to setup
120+
* (per-CPU) hypercall input page and thus this failure is
121+
* fatal on Hyper-V.
122+
*/
123+
hyperv_pcpu_input_arg = alloc_percpu(void *);
124+
if (unlikely(!hyperv_pcpu_input_arg))
125+
return -ENOMEM;
126+
92127
/* Allocate and initialize percpu VP index array */
93128
hv_max_vp_index = num_possible_cpus();
94129
hv_vp_index = kmalloc_array(hv_max_vp_index, sizeof(*hv_vp_index),
95130
GFP_KERNEL);
96131
if (!hv_vp_index) {
97132
hv_max_vp_index = 0;
133+
free_percpu(hyperv_pcpu_input_arg);
98134
return -ENOMEM;
99135
}
100136

101137
for (i = 0; i < hv_max_vp_index; i++)
102138
hv_vp_index[i] = VP_INVAL;
103139

104140
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/hyperv_init:online",
105-
hv_cpu_init, NULL) < 0) {
141+
hv_cpu_init, hv_cpu_die) < 0) {
106142
hv_max_vp_index = 0;
107143
kfree(hv_vp_index);
108144
hv_vp_index = NULL;
145+
free_percpu(hyperv_pcpu_input_arg);
109146
return -EINVAL;
110147
}
111148

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)