mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 23:41:35 -04:00
x86/hyperv: Skip LP/VP creation on kexec
After a kexec the logical processors and virtual processors already exist in the hypervisor because they were created by the previous kernel. Attempting to add them again causes either a BUG_ON or corrupted VP state leading to MCEs in the new kernel. Add hv_lp_exists() to probe whether an LP is already present by calling HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME. When it succeeds the LP exists and we skip the add-LP and create-VP loops entirely. Also add hv_call_notify_all_processors_started() which informs the hypervisor that all processors are online. This is required after adding LPs (fresh boot) and is a no-op on kexec since we skip that path. Co-developed-by: Anirudh Rayabharam <anrayabh@linux.microsoft.com> Signed-off-by: Anirudh Rayabharam <anrayabh@linux.microsoft.com> Co-developed-by: Stanislav Kinsburskii <stanislav.kinsburskii@gmail.com> Signed-off-by: Stanislav Kinsburskii <stanislav.kinsburskii@gmail.com> Co-developed-by: Mukesh Rathor <mrathor@linux.microsoft.com> Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com> Signed-off-by: Jork Loeser <jloeser@linux.microsoft.com> Reviewed-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
This commit is contained in:
@@ -429,6 +429,10 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* If AP LPs exist, we are in a kexec'd kernel and VPs already exist */
|
||||
if (num_present_cpus() == 1 || hv_lp_exists(1))
|
||||
return;
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
@@ -436,6 +440,9 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
ret = hv_call_notify_all_processors_started();
|
||||
WARN_ON(ret);
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
@@ -239,3 +239,50 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_call_create_vp);
|
||||
|
||||
int hv_call_notify_all_processors_started(void)
|
||||
{
|
||||
struct hv_input_notify_partition_event *input;
|
||||
u64 status;
|
||||
unsigned long irq_flags;
|
||||
int ret = 0;
|
||||
|
||||
local_irq_save(irq_flags);
|
||||
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
|
||||
memset(input, 0, sizeof(*input));
|
||||
input->event = HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED;
|
||||
status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT,
|
||||
input, NULL);
|
||||
local_irq_restore(irq_flags);
|
||||
|
||||
if (!hv_result_success(status)) {
|
||||
hv_status_err(status, "\n");
|
||||
ret = hv_result_to_errno(status);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hv_lp_exists(u32 lp_index)
|
||||
{
|
||||
struct hv_input_get_logical_processor_run_time *input;
|
||||
struct hv_output_get_logical_processor_run_time *output;
|
||||
unsigned long flags;
|
||||
u64 status;
|
||||
|
||||
local_irq_save(flags);
|
||||
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
|
||||
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
|
||||
|
||||
input->lp_index = lp_index;
|
||||
status = hv_do_hypercall(HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME,
|
||||
input, output);
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (!hv_result_success(status) &&
|
||||
hv_result(status) != HV_STATUS_INVALID_LP_INDEX) {
|
||||
hv_status_err(status, "\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
return hv_result_success(status);
|
||||
}
|
||||
|
||||
@@ -347,6 +347,8 @@ bool hv_result_needs_memory(u64 status);
|
||||
int hv_deposit_memory_node(int node, u64 partition_id, u64 status);
|
||||
int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
|
||||
int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
|
||||
int hv_call_notify_all_processors_started(void);
|
||||
bool hv_lp_exists(u32 lp_index);
|
||||
int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);
|
||||
|
||||
#else /* CONFIG_MSHV_ROOT */
|
||||
@@ -366,6 +368,14 @@ static inline int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int hv_call_notify_all_processors_started(void)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline bool hv_lp_exists(u32 lp_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -435,6 +435,7 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
|
||||
/* HV_CALL_CODE */
|
||||
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
|
||||
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
|
||||
#define HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME 0x0004
|
||||
#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008
|
||||
#define HVCALL_SEND_IPI 0x000b
|
||||
#define HVCALL_ENABLE_VP_VTL 0x000f
|
||||
|
||||
@@ -362,6 +362,7 @@ union hv_partition_event_input {
|
||||
|
||||
enum hv_partition_event {
|
||||
HV_PARTITION_EVENT_ROOT_CRASHDUMP = 2,
|
||||
HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED = 4,
|
||||
};
|
||||
|
||||
struct hv_input_notify_partition_event {
|
||||
@@ -369,6 +370,17 @@ struct hv_input_notify_partition_event {
|
||||
union hv_partition_event_input input;
|
||||
} __packed;
|
||||
|
||||
struct hv_input_get_logical_processor_run_time {
|
||||
u32 lp_index;
|
||||
} __packed;
|
||||
|
||||
struct hv_output_get_logical_processor_run_time {
|
||||
u64 global_time;
|
||||
u64 local_run_time;
|
||||
u64 rsvdz0;
|
||||
u64 hypervisor_time;
|
||||
} __packed;
|
||||
|
||||
struct hv_lp_startup_status {
|
||||
u64 hv_status;
|
||||
u64 substatus1;
|
||||
|
||||
Reference in New Issue
Block a user