Skip to content

Commit afca4d9

Browse files
kelleymhliuw
authored andcommitted
Drivers: hv: Make portions of Hyper-V init code be arch neutral
The code to allocate and initialize the hv_vp_index array is architecture neutral. Similarly, the code to allocate and populate the hypercall input and output arg pages is architecture neutral. Move both sets of code out from arch/x86 and into utility functions in drivers/hv/hv_common.c that can be shared by Hyper-V initialization on ARM64. No functional changes. However, the allocation of the hypercall input and output arg pages is done differently so that the size is always the Hyper-V page size, even if not the same as the guest page size (such as with ARM64's 64K page size). Signed-off-by: Michael Kelley <mikelley@microsoft.com> Link: https://lore.kernel.org/r/1626287687-2045-2-git-send-email-mikelley@microsoft.com Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent c445535 commit afca4d9

5 files changed

Lines changed: 158 additions & 88 deletions

File tree

arch/x86/hyperv/hv_init.c

Lines changed: 10 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -39,48 +39,17 @@ EXPORT_SYMBOL_GPL(hv_hypercall_pg);
3939
/* Storage to save the hypercall page temporarily for hibernation */
4040
static void *hv_hypercall_pg_saved;
4141

42-
u32 *hv_vp_index;
43-
EXPORT_SYMBOL_GPL(hv_vp_index);
44-
4542
struct hv_vp_assist_page **hv_vp_assist_page;
4643
EXPORT_SYMBOL_GPL(hv_vp_assist_page);
4744

48-
void __percpu **hyperv_pcpu_input_arg;
49-
EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg);
50-
51-
void __percpu **hyperv_pcpu_output_arg;
52-
EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg);
53-
54-
u32 hv_max_vp_index;
55-
EXPORT_SYMBOL_GPL(hv_max_vp_index);
56-
5745
static int hv_cpu_init(unsigned int cpu)
5846
{
59-
u64 msr_vp_index;
6047
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
61-
void **input_arg;
62-
struct page *pg;
63-
64-
/* hv_cpu_init() can be called with IRQs disabled from hv_resume() */
65-
pg = alloc_pages(irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL, hv_root_partition ? 1 : 0);
66-
if (unlikely(!pg))
67-
return -ENOMEM;
68-
69-
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
70-
*input_arg = page_address(pg);
71-
if (hv_root_partition) {
72-
void **output_arg;
73-
74-
output_arg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
75-
*output_arg = page_address(pg + 1);
76-
}
77-
78-
msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX);
79-
80-
hv_vp_index[smp_processor_id()] = msr_vp_index;
48+
int ret;
8149

82-
if (msr_vp_index > hv_max_vp_index)
83-
hv_max_vp_index = msr_vp_index;
50+
ret = hv_common_cpu_init(cpu);
51+
if (ret)
52+
return ret;
8453

8554
if (!hv_vp_assist_page)
8655
return 0;
@@ -198,25 +167,8 @@ static int hv_cpu_die(unsigned int cpu)
198167
{
199168
struct hv_reenlightenment_control re_ctrl;
200169
unsigned int new_cpu;
201-
unsigned long flags;
202-
void **input_arg;
203-
void *pg;
204170

205-
local_irq_save(flags);
206-
input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
207-
pg = *input_arg;
208-
*input_arg = NULL;
209-
210-
if (hv_root_partition) {
211-
void **output_arg;
212-
213-
output_arg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
214-
*output_arg = NULL;
215-
}
216-
217-
local_irq_restore(flags);
218-
219-
free_pages((unsigned long)pg, hv_root_partition ? 1 : 0);
171+
hv_common_cpu_die(cpu);
220172

221173
if (hv_vp_assist_page && hv_vp_assist_page[cpu])
222174
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, 0);
@@ -368,7 +320,7 @@ void __init hyperv_init(void)
368320
{
369321
u64 guest_id, required_msrs;
370322
union hv_x64_msr_hypercall_contents hypercall_msr;
371-
int cpuhp, i;
323+
int cpuhp;
372324

373325
if (x86_hyper_type != X86_HYPER_MS_HYPERV)
374326
return;
@@ -380,36 +332,14 @@ void __init hyperv_init(void)
380332
if ((ms_hyperv.features & required_msrs) != required_msrs)
381333
return;
382334

383-
/*
384-
* Allocate the per-CPU state for the hypercall input arg.
385-
* If this allocation fails, we will not be able to setup
386-
* (per-CPU) hypercall input page and thus this failure is
387-
* fatal on Hyper-V.
388-
*/
389-
hyperv_pcpu_input_arg = alloc_percpu(void *);
390-
391-
BUG_ON(hyperv_pcpu_input_arg == NULL);
392-
393-
/* Allocate the per-CPU state for output arg for root */
394-
if (hv_root_partition) {
395-
hyperv_pcpu_output_arg = alloc_percpu(void *);
396-
BUG_ON(hyperv_pcpu_output_arg == NULL);
397-
}
398-
399-
/* Allocate percpu VP index */
400-
hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
401-
GFP_KERNEL);
402-
if (!hv_vp_index)
335+
if (hv_common_init())
403336
return;
404337

405-
for (i = 0; i < num_possible_cpus(); i++)
406-
hv_vp_index[i] = VP_INVAL;
407-
408338
hv_vp_assist_page = kcalloc(num_possible_cpus(),
409339
sizeof(*hv_vp_assist_page), GFP_KERNEL);
410340
if (!hv_vp_assist_page) {
411341
ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED;
412-
goto free_vp_index;
342+
goto common_free;
413343
}
414344

415345
cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
@@ -507,9 +437,8 @@ void __init hyperv_init(void)
507437
free_vp_assist_page:
508438
kfree(hv_vp_assist_page);
509439
hv_vp_assist_page = NULL;
510-
free_vp_index:
511-
kfree(hv_vp_index);
512-
hv_vp_index = NULL;
440+
common_free:
441+
hv_common_free();
513442
}
514443

515444
/*

arch/x86/include/asm/mshyperv.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ void hyperv_vector_handler(struct pt_regs *regs);
3636
extern int hyperv_init_cpuhp;
3737

3838
extern void *hv_hypercall_pg;
39-
extern void __percpu **hyperv_pcpu_input_arg;
40-
extern void __percpu **hyperv_pcpu_output_arg;
4139

4240
extern u64 hv_current_partition_id;
4341

@@ -170,8 +168,6 @@ int hyperv_fill_flush_guest_mapping_list(
170168
struct hv_guest_mapping_flush_list *flush,
171169
u64 start_gfn, u64 end_gfn);
172170

173-
extern bool hv_root_partition;
174-
175171
#ifdef CONFIG_X86_64
176172
void hv_apic_init(void);
177173
void __init hv_init_spinlocks(void);

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@
3636

3737
/* Is Linux running as the root partition? */
3838
bool hv_root_partition;
39-
EXPORT_SYMBOL_GPL(hv_root_partition);
40-
4139
struct ms_hyperv_info ms_hyperv;
42-
EXPORT_SYMBOL_GPL(ms_hyperv);
4340

4441
#if IS_ENABLED(CONFIG_HYPERV)
4542
static void (*vmbus_handler)(void);

drivers/hv/hv_common.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,147 @@
1515
#include <linux/types.h>
1616
#include <linux/export.h>
1717
#include <linux/bitfield.h>
18+
#include <linux/cpumask.h>
19+
#include <linux/slab.h>
1820
#include <asm/hyperv-tlfs.h>
1921
#include <asm/mshyperv.h>
2022

23+
/*
24+
* hv_root_partition and ms_hyperv are defined here with other Hyper-V
25+
* specific globals so they are shared across all architectures and are
26+
* built only when CONFIG_HYPERV is defined. But on x86,
27+
* ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not
28+
* defined, and it uses these two variables. So mark them as __weak
29+
* here, allowing for an overriding definition in the module containing
30+
* ms_hyperv_init_platform().
31+
*/
32+
bool __weak hv_root_partition;
33+
EXPORT_SYMBOL_GPL(hv_root_partition);
34+
35+
struct ms_hyperv_info __weak ms_hyperv;
36+
EXPORT_SYMBOL_GPL(ms_hyperv);
37+
38+
u32 *hv_vp_index;
39+
EXPORT_SYMBOL_GPL(hv_vp_index);
40+
41+
u32 hv_max_vp_index;
42+
EXPORT_SYMBOL_GPL(hv_max_vp_index);
43+
44+
void __percpu **hyperv_pcpu_input_arg;
45+
EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg);
46+
47+
void __percpu **hyperv_pcpu_output_arg;
48+
EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg);
49+
50+
/*
51+
* Hyper-V specific initialization and shutdown code that is
52+
* common across all architectures. Called from architecture
53+
* specific initialization functions.
54+
*/
55+
56+
void __init hv_common_free(void)
57+
{
58+
kfree(hv_vp_index);
59+
hv_vp_index = NULL;
60+
61+
free_percpu(hyperv_pcpu_output_arg);
62+
hyperv_pcpu_output_arg = NULL;
63+
64+
free_percpu(hyperv_pcpu_input_arg);
65+
hyperv_pcpu_input_arg = NULL;
66+
}
67+
68+
int __init hv_common_init(void)
69+
{
70+
int i;
71+
72+
/*
73+
* Allocate the per-CPU state for the hypercall input arg.
74+
* If this allocation fails, we will not be able to setup
75+
* (per-CPU) hypercall input page and thus this failure is
76+
* fatal on Hyper-V.
77+
*/
78+
hyperv_pcpu_input_arg = alloc_percpu(void *);
79+
BUG_ON(!hyperv_pcpu_input_arg);
80+
81+
/* Allocate the per-CPU state for output arg for root */
82+
if (hv_root_partition) {
83+
hyperv_pcpu_output_arg = alloc_percpu(void *);
84+
BUG_ON(!hyperv_pcpu_output_arg);
85+
}
86+
87+
hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
88+
GFP_KERNEL);
89+
if (!hv_vp_index) {
90+
hv_common_free();
91+
return -ENOMEM;
92+
}
93+
94+
for (i = 0; i < num_possible_cpus(); i++)
95+
hv_vp_index[i] = VP_INVAL;
96+
97+
return 0;
98+
}
99+
100+
/*
101+
* Hyper-V specific initialization and die code for
102+
* individual CPUs that is common across all architectures.
103+
* Called by the CPU hotplug mechanism.
104+
*/
105+
106+
int hv_common_cpu_init(unsigned int cpu)
107+
{
108+
void **inputarg, **outputarg;
109+
u64 msr_vp_index;
110+
gfp_t flags;
111+
int pgcount = hv_root_partition ? 2 : 1;
112+
113+
/* hv_cpu_init() can be called with IRQs disabled from hv_resume() */
114+
flags = irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL;
115+
116+
inputarg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
117+
*inputarg = kmalloc(pgcount * HV_HYP_PAGE_SIZE, flags);
118+
if (!(*inputarg))
119+
return -ENOMEM;
120+
121+
if (hv_root_partition) {
122+
outputarg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
123+
*outputarg = (char *)(*inputarg) + HV_HYP_PAGE_SIZE;
124+
}
125+
126+
msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX);
127+
128+
hv_vp_index[cpu] = msr_vp_index;
129+
130+
if (msr_vp_index > hv_max_vp_index)
131+
hv_max_vp_index = msr_vp_index;
132+
133+
return 0;
134+
}
135+
136+
int hv_common_cpu_die(unsigned int cpu)
137+
{
138+
unsigned long flags;
139+
void **inputarg, **outputarg;
140+
void *mem;
141+
142+
local_irq_save(flags);
143+
144+
inputarg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
145+
mem = *inputarg;
146+
*inputarg = NULL;
147+
148+
if (hv_root_partition) {
149+
outputarg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
150+
*outputarg = NULL;
151+
}
152+
153+
local_irq_restore(flags);
154+
155+
kfree(mem);
156+
157+
return 0;
158+
}
21159

22160
/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */
23161
bool hv_query_ext_cap(u64 cap_query)

include/asm-generic/mshyperv.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct ms_hyperv_info {
3939
};
4040
extern struct ms_hyperv_info ms_hyperv;
4141

42+
extern void __percpu **hyperv_pcpu_input_arg;
43+
extern void __percpu **hyperv_pcpu_output_arg;
44+
4245
extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);
4346
extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
4447

@@ -152,6 +155,8 @@ void hv_remove_crash_handler(void);
152155
extern int vmbus_interrupt;
153156
extern int vmbus_irq;
154157

158+
extern bool hv_root_partition;
159+
155160
#if IS_ENABLED(CONFIG_HYPERV)
156161
/*
157162
* Hypervisor's notion of virtual processor ID is different from
@@ -165,6 +170,11 @@ extern u32 hv_max_vp_index;
165170
/* Sentinel value for an uninitialized entry in hv_vp_index array */
166171
#define VP_INVAL U32_MAX
167172

173+
int __init hv_common_init(void);
174+
void __init hv_common_free(void);
175+
int hv_common_cpu_init(unsigned int cpu);
176+
int hv_common_cpu_die(unsigned int cpu);
177+
168178
void *hv_alloc_hyperv_page(void);
169179
void *hv_alloc_hyperv_zeroed_page(void);
170180
void hv_free_hyperv_page(unsigned long addr);

0 commit comments

Comments
 (0)