hyperv-fixes for v7.1-rc8
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEIbPD0id6easf0xsudhRwX5BBoF4FAmomTIwTHHdlaS5saXVA a2VybmVsLm9yZwAKCRB2FHBfkEGgXqyECADL9eYwEkfwQDB+CmyemmINo/wvOfGu u6husKyGqs3eBe7sPtERarHtN8UlQMGLMVd2CR8QqtD+P9yZjSnNX54ljtweEdIr eAijVHEFmw1e1Lo/lGOv8eldNP3FuUGopz6rkfuQ2S+6xZ9MHIYda5MCZ3I0rbOe Mq+aB17Qhvqp+O4+zfk5wDh9OJ1Wa5c0U0xfKx51SX4qf1KDL7AUIz0Cyy7P8h5q u7MDYFaE4U9d8M5GbRQUGyHr6W0YQuMMUW5Ip04OsQXRKyMR5W20dFtiwoqI4UbF loWUakk4RkC9tEMs6WeLSvqrLgKqbqfDOScYB8OPEUlh5CRMhYp7uhkA =fcaL -----END PGP SIGNATURE----- Merge tag 'hyperv-fixes-signed-20260607' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux Pull hyperv fixes from Wei Liu: - MSHV driver fixes from various people (Anirudh Rayabharam, Can Peng, Dexuan Cui, Michael Kelley, Jork Loeser, Wei Liu) - Hyper-V user space tools fixes (Thorsten Blum) - Allow VMBus to be unloaded after frame buffer is flushed (Michael Kelley) * tag 'hyperv-fixes-signed-20260607' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: mshv: support 1G hugepages by passing them as 2M-aligned chunks Drivers: hv: vmbus: Improve the logic of reserving fb_mmio on Gen2 VMs mshv: use kmalloc_array in mshv_root_scheduler_init mshv: Add conditional VMBus dependency hyperv: Clean up and fix the guest ID comment in hvgdk.h drm/hyperv: During panic do VMBus unload after frame buffer is flushed Drivers: hv: vmbus: Provide option to skip VMBus unload on panic mshv: unmap debugfs stats pages on kexec mshv: clean up SynIC state on kexec for L1VH mshv: limit SynIC management to MSHV-owned resources hv: utils: replace deprecated strcpy with strscpy in kvp_register hv: utils: handle and propagate errors in kvp_register mshv: add a missing padding field
This commit is contained in:
commit
e92a762877
15 changed files with 206 additions and 111 deletions
|
|
@ -150,6 +150,10 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
|
|||
goto err_free_mmio;
|
||||
}
|
||||
|
||||
/* If DRM panic path is stubbed out VMBus code must do the unload */
|
||||
if (IS_ENABLED(CONFIG_DRM_PANIC))
|
||||
vmbus_set_skip_unload(true);
|
||||
|
||||
drm_client_setup(dev, NULL);
|
||||
|
||||
return 0;
|
||||
|
|
@ -169,6 +173,7 @@ static void hyperv_vmbus_remove(struct hv_device *hdev)
|
|||
struct drm_device *dev = hv_get_drvdata(hdev);
|
||||
struct hyperv_drm_device *hv = to_hv(dev);
|
||||
|
||||
vmbus_set_skip_unload(false);
|
||||
drm_dev_unplug(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
vmbus_close(hdev->channel);
|
||||
|
|
|
|||
|
|
@ -212,15 +212,16 @@ static void hyperv_plane_panic_flush(struct drm_plane *plane)
|
|||
struct hyperv_drm_device *hv = to_hv(plane->dev);
|
||||
struct drm_rect rect;
|
||||
|
||||
if (!plane->state || !plane->state->fb)
|
||||
return;
|
||||
if (plane->state && plane->state->fb) {
|
||||
rect.x1 = 0;
|
||||
rect.y1 = 0;
|
||||
rect.x2 = plane->state->fb->width;
|
||||
rect.y2 = plane->state->fb->height;
|
||||
|
||||
rect.x1 = 0;
|
||||
rect.y1 = 0;
|
||||
rect.x2 = plane->state->fb->width;
|
||||
rect.y2 = plane->state->fb->height;
|
||||
hyperv_update_dirt(hv->hdev, &rect);
|
||||
}
|
||||
|
||||
hyperv_update_dirt(hv->hdev, &rect);
|
||||
vmbus_initiate_unload(true);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs hyperv_plane_helper_funcs = {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ config MSHV_ROOT
|
|||
# e.g. When withdrawing memory, the hypervisor gives back 4k pages in
|
||||
# no particular order, making it impossible to reassemble larger pages
|
||||
depends on PAGE_SIZE_4KB
|
||||
depends on HYPERV_VMBUS if HYPERV_VMBUS
|
||||
select EVENTFD
|
||||
select VIRT_XFER_TO_GUEST_WORK
|
||||
select HMM_MIRROR
|
||||
|
|
|
|||
|
|
@ -952,6 +952,7 @@ void vmbus_initiate_unload(bool crash)
|
|||
else
|
||||
vmbus_wait_for_unload();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_initiate_unload);
|
||||
|
||||
static void vmbus_setup_channel_state(struct vmbus_channel *channel,
|
||||
struct vmbus_channel_offer_channel *offer)
|
||||
|
|
|
|||
|
|
@ -272,6 +272,9 @@ void hv_synic_free(void)
|
|||
/*
|
||||
* hv_hyp_synic_enable_regs - Initialize the Synthetic Interrupt Controller
|
||||
* with the hypervisor.
|
||||
*
|
||||
* Note: When MSHV is present, mshv_synic_cpu_init() intializes further
|
||||
* registers later.
|
||||
*/
|
||||
void hv_hyp_synic_enable_regs(unsigned int cpu)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/connector.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/string.h>
|
||||
#include <hyperv/hvhdk.h>
|
||||
|
||||
#include "hyperv_vmbus.h"
|
||||
|
|
@ -93,7 +94,7 @@ static void kvp_send_key(struct work_struct *dummy);
|
|||
static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
|
||||
static void kvp_timeout_func(struct work_struct *dummy);
|
||||
static void kvp_host_handshake_func(struct work_struct *dummy);
|
||||
static void kvp_register(int);
|
||||
static int kvp_register(int);
|
||||
|
||||
static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
|
||||
static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
|
||||
|
|
@ -127,24 +128,23 @@ static void kvp_register_done(void)
|
|||
hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
kvp_register(int reg_value)
|
||||
{
|
||||
|
||||
struct hv_kvp_msg *kvp_msg;
|
||||
char *version;
|
||||
int ret;
|
||||
|
||||
kvp_msg = kzalloc_obj(*kvp_msg);
|
||||
if (!kvp_msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (kvp_msg) {
|
||||
version = kvp_msg->body.kvp_register.version;
|
||||
kvp_msg->kvp_hdr.operation = reg_value;
|
||||
strcpy(version, HV_DRV_VERSION);
|
||||
kvp_msg->kvp_hdr.operation = reg_value;
|
||||
strscpy(kvp_msg->body.kvp_register.version, HV_DRV_VERSION);
|
||||
|
||||
hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
|
||||
kvp_register_done);
|
||||
kfree(kvp_msg);
|
||||
}
|
||||
ret = hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
|
||||
kvp_register_done);
|
||||
kfree(kvp_msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvp_timeout_func(struct work_struct *dummy)
|
||||
|
|
@ -186,9 +186,8 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
|
|||
*/
|
||||
pr_debug("KVP: userspace daemon ver. %d connected\n",
|
||||
msg->kvp_hdr.operation);
|
||||
kvp_register(dm_reg_value);
|
||||
|
||||
return 0;
|
||||
return kvp_register(dm_reg_value);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -441,7 +441,6 @@ void hv_vss_deinit(void);
|
|||
int hv_vss_pre_suspend(void);
|
||||
int hv_vss_pre_resume(void);
|
||||
void hv_vss_onchannelcallback(void *context);
|
||||
void vmbus_initiate_unload(bool crash);
|
||||
|
||||
static inline void hv_poll_channel(struct vmbus_channel *channel,
|
||||
void (*cb)(void *))
|
||||
|
|
|
|||
|
|
@ -674,8 +674,10 @@ int __init mshv_debugfs_init(void)
|
|||
|
||||
mshv_debugfs = debugfs_create_dir("mshv", NULL);
|
||||
if (IS_ERR(mshv_debugfs)) {
|
||||
err = PTR_ERR(mshv_debugfs);
|
||||
mshv_debugfs = NULL;
|
||||
pr_err("%s: failed to create debugfs directory\n", __func__);
|
||||
return PTR_ERR(mshv_debugfs);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hv_root_partition()) {
|
||||
|
|
@ -710,6 +712,9 @@ remove_mshv_dir:
|
|||
|
||||
void mshv_debugfs_exit(void)
|
||||
{
|
||||
if (!mshv_debugfs)
|
||||
return;
|
||||
|
||||
mshv_debugfs_parent_partition_remove();
|
||||
|
||||
if (hv_root_partition()) {
|
||||
|
|
|
|||
|
|
@ -29,29 +29,27 @@
|
|||
* Uses huge page stride if the backing page is huge and the guest mapping
|
||||
* is properly aligned; otherwise falls back to single page stride.
|
||||
*
|
||||
* Return: Stride in pages, or -EINVAL if page order is unsupported.
|
||||
* Return: Stride in pages.
|
||||
*/
|
||||
static int mshv_chunk_stride(struct page *page,
|
||||
u64 gfn, u64 page_count)
|
||||
static unsigned int mshv_chunk_stride(struct page *page, u64 gfn,
|
||||
u64 page_count)
|
||||
{
|
||||
unsigned int page_order;
|
||||
unsigned int page_order = folio_order(page_folio(page));
|
||||
|
||||
/*
|
||||
* Use single page stride by default. For huge page stride, the
|
||||
* page must be compound and point to the head of the compound
|
||||
* page, and both gfn and page_count must be huge-page aligned.
|
||||
* folio order must be at least PMD_ORDER, the page's PFN must be
|
||||
* 2M-aligned (so that a 2M-aligned tail page of a larger folio is
|
||||
* acceptable), and both gfn and page_count must be 2M-aligned.
|
||||
*/
|
||||
if (!PageCompound(page) || !PageHead(page) ||
|
||||
if (page_order < PMD_ORDER ||
|
||||
!IS_ALIGNED(page_to_pfn(page), PTRS_PER_PMD) ||
|
||||
!IS_ALIGNED(gfn, PTRS_PER_PMD) ||
|
||||
!IS_ALIGNED(page_count, PTRS_PER_PMD))
|
||||
return 1;
|
||||
|
||||
page_order = folio_order(page_folio(page));
|
||||
/* The hypervisor only supports 2M huge page */
|
||||
if (page_order != PMD_ORDER)
|
||||
return -EINVAL;
|
||||
|
||||
return 1 << page_order;
|
||||
/* Use 2M stride always i.e. process 1G folios as 2M chunks */
|
||||
return 1 << PMD_ORDER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,15 +84,14 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region,
|
|||
u64 gfn = region->start_gfn + page_offset;
|
||||
u64 count;
|
||||
struct page *page;
|
||||
int stride, ret;
|
||||
unsigned int stride;
|
||||
int ret;
|
||||
|
||||
page = region->mreg_pages[page_offset];
|
||||
if (!page)
|
||||
return -EINVAL;
|
||||
|
||||
stride = mshv_chunk_stride(page, gfn, page_count);
|
||||
if (stride < 0)
|
||||
return stride;
|
||||
|
||||
/* Start at stride since the first stride is validated */
|
||||
for (count = stride; count < page_count; count += stride) {
|
||||
|
|
|
|||
|
|
@ -2241,7 +2241,7 @@ static int mshv_root_scheduler_init(unsigned int cpu)
|
|||
outputarg = (void **)this_cpu_ptr(root_scheduler_output);
|
||||
|
||||
/* Allocate two consecutive pages. One for input, one for output. */
|
||||
p = kmalloc(2 * HV_HYP_PAGE_SIZE, GFP_KERNEL);
|
||||
p = kmalloc_array(2, HV_HYP_PAGE_SIZE, GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <linux/acpi.h>
|
||||
|
|
@ -456,46 +457,75 @@ static int mshv_synic_cpu_init(unsigned int cpu)
|
|||
union hv_synic_siefp siefp;
|
||||
union hv_synic_sirbp sirbp;
|
||||
union hv_synic_sint sint;
|
||||
union hv_synic_scontrol sctrl;
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
|
||||
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
|
||||
struct hv_synic_event_flags_page **event_flags_page =
|
||||
&spages->synic_event_flags_page;
|
||||
struct hv_synic_event_ring_page **event_ring_page =
|
||||
&spages->synic_event_ring_page;
|
||||
/*
|
||||
* VMBus owns SIMP/SIEFP/SCONTROL when it is active.
|
||||
* See hv_hyp_synic_enable_regs() for that initialization.
|
||||
*/
|
||||
bool vmbus_active = hv_vmbus_exists();
|
||||
|
||||
/* Setup the Synic's message page */
|
||||
/*
|
||||
* Map the SYNIC message page. When VMBus is not active the
|
||||
* hypervisor pre-provisions the SIMP GPA but may not set
|
||||
* simp_enabled — enable it here.
|
||||
*/
|
||||
simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP);
|
||||
simp.simp_enabled = true;
|
||||
if (!vmbus_active) {
|
||||
simp.simp_enabled = true;
|
||||
hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
|
||||
}
|
||||
*msg_page = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
|
||||
HV_HYP_PAGE_SIZE,
|
||||
MEMREMAP_WB);
|
||||
|
||||
if (!(*msg_page))
|
||||
return -EFAULT;
|
||||
goto cleanup_simp;
|
||||
|
||||
hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
|
||||
|
||||
/* Setup the Synic's event flags page */
|
||||
/*
|
||||
* Map the event flags page. Same as SIMP: enable when
|
||||
* VMBus is not active, already enabled by VMBus otherwise.
|
||||
*/
|
||||
siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP);
|
||||
siefp.siefp_enabled = true;
|
||||
*event_flags_page = memremap(siefp.base_siefp_gpa << PAGE_SHIFT,
|
||||
PAGE_SIZE, MEMREMAP_WB);
|
||||
if (!vmbus_active) {
|
||||
siefp.siefp_enabled = true;
|
||||
hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
|
||||
}
|
||||
*event_flags_page = memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT,
|
||||
HV_HYP_PAGE_SIZE, MEMREMAP_WB);
|
||||
|
||||
if (!(*event_flags_page))
|
||||
goto cleanup;
|
||||
|
||||
hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
|
||||
goto cleanup_siefp;
|
||||
|
||||
/* Setup the Synic's event ring page */
|
||||
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
|
||||
|
||||
if (hv_root_partition()) {
|
||||
*event_ring_page = memremap(sirbp.base_sirbp_gpa << HV_HYP_PAGE_SHIFT,
|
||||
HV_HYP_PAGE_SIZE, MEMREMAP_WB);
|
||||
|
||||
if (!(*event_ring_page))
|
||||
goto cleanup_siefp;
|
||||
} else {
|
||||
/*
|
||||
* On L1VH the hypervisor does not provide a SIRBP page.
|
||||
* Allocate one and program its GPA into the MSR.
|
||||
*/
|
||||
*event_ring_page = (struct hv_synic_event_ring_page *)
|
||||
get_zeroed_page(GFP_KERNEL);
|
||||
|
||||
if (!(*event_ring_page))
|
||||
goto cleanup_siefp;
|
||||
|
||||
sirbp.base_sirbp_gpa = virt_to_phys(*event_ring_page)
|
||||
>> HV_HYP_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
sirbp.sirbp_enabled = true;
|
||||
*event_ring_page = memremap(sirbp.base_sirbp_gpa << PAGE_SHIFT,
|
||||
PAGE_SIZE, MEMREMAP_WB);
|
||||
|
||||
if (!(*event_ring_page))
|
||||
goto cleanup;
|
||||
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
|
||||
if (mshv_sint_irq != -1)
|
||||
|
|
@ -518,28 +548,30 @@ static int mshv_synic_cpu_init(unsigned int cpu)
|
|||
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
|
||||
sint.as_uint64);
|
||||
|
||||
/* Enable global synic bit */
|
||||
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
|
||||
sctrl.enable = 1;
|
||||
hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
|
||||
/* When VMBus is active it already enabled SCONTROL. */
|
||||
if (!vmbus_active) {
|
||||
union hv_synic_scontrol sctrl;
|
||||
|
||||
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
|
||||
sctrl.enable = 1;
|
||||
hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (*event_ring_page) {
|
||||
sirbp.sirbp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
memunmap(*event_ring_page);
|
||||
}
|
||||
if (*event_flags_page) {
|
||||
cleanup_siefp:
|
||||
if (*event_flags_page)
|
||||
memunmap(*event_flags_page);
|
||||
if (!vmbus_active) {
|
||||
siefp.siefp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
|
||||
memunmap(*event_flags_page);
|
||||
}
|
||||
if (*msg_page) {
|
||||
cleanup_simp:
|
||||
if (*msg_page)
|
||||
memunmap(*msg_page);
|
||||
if (!vmbus_active) {
|
||||
simp.simp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
|
||||
memunmap(*msg_page);
|
||||
}
|
||||
|
||||
return -EFAULT;
|
||||
|
|
@ -548,16 +580,15 @@ cleanup:
|
|||
static int mshv_synic_cpu_exit(unsigned int cpu)
|
||||
{
|
||||
union hv_synic_sint sint;
|
||||
union hv_synic_simp simp;
|
||||
union hv_synic_siefp siefp;
|
||||
union hv_synic_sirbp sirbp;
|
||||
union hv_synic_scontrol sctrl;
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
|
||||
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
|
||||
struct hv_synic_event_flags_page **event_flags_page =
|
||||
&spages->synic_event_flags_page;
|
||||
struct hv_synic_event_ring_page **event_ring_page =
|
||||
&spages->synic_event_ring_page;
|
||||
/* VMBus owns SIMP/SIEFP/SCONTROL when it is active */
|
||||
bool vmbus_active = hv_vmbus_exists();
|
||||
|
||||
/* Disable the interrupt */
|
||||
sint.as_uint64 = hv_get_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX);
|
||||
|
|
@ -574,28 +605,47 @@ static int mshv_synic_cpu_exit(unsigned int cpu)
|
|||
if (mshv_sint_irq != -1)
|
||||
disable_percpu_irq(mshv_sint_irq);
|
||||
|
||||
/* Disable Synic's event ring page */
|
||||
/* Disable SYNIC event ring page owned by MSHV */
|
||||
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
|
||||
sirbp.sirbp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
memunmap(*event_ring_page);
|
||||
|
||||
/* Disable Synic's event flags page */
|
||||
siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP);
|
||||
siefp.siefp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
|
||||
if (hv_root_partition()) {
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
memunmap(*event_ring_page);
|
||||
} else {
|
||||
sirbp.base_sirbp_gpa = 0;
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
free_page((unsigned long)*event_ring_page);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release our mappings of the message and event flags pages.
|
||||
* When VMBus is not active, we enabled SIMP/SIEFP — disable
|
||||
* them. Otherwise VMBus owns the MSRs — leave them.
|
||||
*/
|
||||
memunmap(*event_flags_page);
|
||||
if (!vmbus_active) {
|
||||
union hv_synic_simp simp;
|
||||
union hv_synic_siefp siefp;
|
||||
|
||||
/* Disable Synic's message page */
|
||||
simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP);
|
||||
simp.simp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
|
||||
siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP);
|
||||
siefp.siefp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
|
||||
|
||||
simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP);
|
||||
simp.simp_enabled = false;
|
||||
hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
|
||||
}
|
||||
memunmap(*msg_page);
|
||||
|
||||
/* Disable global synic bit */
|
||||
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
|
||||
sctrl.enable = 0;
|
||||
hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
|
||||
/* When VMBus is active it owns SCONTROL — leave it. */
|
||||
if (!vmbus_active) {
|
||||
union hv_synic_scontrol sctrl;
|
||||
|
||||
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
|
||||
sctrl.enable = 0;
|
||||
hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -673,9 +723,7 @@ mshv_unregister_doorbell(u64 partition_id, int doorbell_portid)
|
|||
static int mshv_synic_reboot_notify(struct notifier_block *nb,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
if (!hv_root_partition())
|
||||
return 0;
|
||||
|
||||
mshv_debugfs_exit();
|
||||
cpuhp_remove_state(synic_cpuhp_online);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,19 +69,29 @@ bool vmbus_is_confidential(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_is_confidential);
|
||||
|
||||
static bool skip_vmbus_unload;
|
||||
|
||||
/*
|
||||
* Allow a VMBus framebuffer driver to specify that in the case of a panic,
|
||||
* it will do the VMbus unload operation once it has flushed any dirty
|
||||
* portions of the framebuffer to the Hyper-V host.
|
||||
*/
|
||||
void vmbus_set_skip_unload(bool skip)
|
||||
{
|
||||
skip_vmbus_unload = skip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_set_skip_unload);
|
||||
|
||||
/*
|
||||
* The panic notifier below is responsible solely for unloading the
|
||||
* vmbus connection, which is necessary in a panic event.
|
||||
*
|
||||
* Notice an intrincate relation of this notifier with Hyper-V
|
||||
* framebuffer panic notifier exists - we need vmbus connection alive
|
||||
* there in order to succeed, so we need to order both with each other
|
||||
* [see hvfb_on_panic()] - this is done using notifiers' priorities.
|
||||
*/
|
||||
static int hv_panic_vmbus_unload(struct notifier_block *nb, unsigned long val,
|
||||
void *args)
|
||||
{
|
||||
vmbus_initiate_unload(true);
|
||||
if (!skip_vmbus_unload)
|
||||
vmbus_initiate_unload(true);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
static struct notifier_block hyperv_panic_vmbus_unload_block = {
|
||||
|
|
@ -2317,8 +2327,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
|
|||
return AE_NO_MEMORY;
|
||||
|
||||
/* If this range overlaps the virtual TPM, truncate it. */
|
||||
if (end > VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS)
|
||||
end = VTPM_BASE_ADDRESS;
|
||||
if (end >= VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS)
|
||||
end = VTPM_BASE_ADDRESS - 1;
|
||||
|
||||
new_res->name = "hyperv mmio";
|
||||
new_res->flags = IORESOURCE_MEM;
|
||||
|
|
@ -2385,6 +2395,7 @@ static void vmbus_mmio_remove(void)
|
|||
static void __maybe_unused vmbus_reserve_fb(void)
|
||||
{
|
||||
resource_size_t start = 0, size;
|
||||
resource_size_t low_mmio_base;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if (efi_enabled(EFI_BOOT)) {
|
||||
|
|
@ -2392,6 +2403,24 @@ static void __maybe_unused vmbus_reserve_fb(void)
|
|||
if (IS_ENABLED(CONFIG_SYSFB)) {
|
||||
start = sysfb_primary_display.screen.lfb_base;
|
||||
size = max_t(__u32, sysfb_primary_display.screen.lfb_size, 0x800000);
|
||||
|
||||
low_mmio_base = hyperv_mmio->start;
|
||||
if (!low_mmio_base || upper_32_bits(low_mmio_base) ||
|
||||
(start && start < low_mmio_base)) {
|
||||
pr_warn("Unexpected low mmio base %pa\n", &low_mmio_base);
|
||||
} else {
|
||||
/*
|
||||
* If the kdump/kexec or CVM kernel's lfb_base
|
||||
* is 0, fall back to the low mmio base.
|
||||
*/
|
||||
if (!start)
|
||||
start = low_mmio_base;
|
||||
/*
|
||||
* Reserve half of the space below 4GB for high
|
||||
* resolutions, but cap the reservation to 128MB.
|
||||
*/
|
||||
size = min((SZ_4G - start) / 2, SZ_128M);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Gen1 VM: get FB base from PCI */
|
||||
|
|
@ -2412,8 +2441,10 @@ static void __maybe_unused vmbus_reserve_fb(void)
|
|||
pci_dev_put(pdev);
|
||||
}
|
||||
|
||||
if (!start)
|
||||
if (!start) {
|
||||
pr_warn("Unexpected framebuffer mmio base of zero\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a claim for the frame buffer in the resource tree under the
|
||||
|
|
@ -2423,6 +2454,8 @@ static void __maybe_unused vmbus_reserve_fb(void)
|
|||
*/
|
||||
for (; !fb_mmio && (size >= 0x100000); size >>= 1)
|
||||
fb_mmio = __request_region(hyperv_mmio, start, size, fb_mmio_name, 0);
|
||||
|
||||
pr_info("hv_mmio=%pR,%pR fb=%pR\n", hyperv_mmio, hyperv_mmio->sibling, fb_mmio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2897,7 +2930,8 @@ static void hv_crash_handler(struct pt_regs *regs)
|
|||
{
|
||||
int cpu;
|
||||
|
||||
vmbus_initiate_unload(true);
|
||||
if (!skip_vmbus_unload)
|
||||
vmbus_initiate_unload(true);
|
||||
/*
|
||||
* In crash handler we can't schedule synic cleanup for all CPUs,
|
||||
* doing the cleanup for current CPU only. This should be sufficient
|
||||
|
|
|
|||
|
|
@ -10,18 +10,12 @@
|
|||
|
||||
/*
|
||||
* The guest OS needs to register the guest ID with the hypervisor.
|
||||
* The guest ID is a 64 bit entity and the structure of this ID is
|
||||
* The guest ID is a 64-bit entity and the structure of this ID is
|
||||
* specified in the Hyper-V TLFS specification.
|
||||
*
|
||||
* While the current guideline does not specify how Linux guest ID(s)
|
||||
* need to be generated, our plan is to publish the guidelines for
|
||||
* Linux and other guest operating systems that currently are hosted
|
||||
* on Hyper-V. The implementation here conforms to this yet
|
||||
* unpublished guidelines.
|
||||
*
|
||||
* Bit(s)
|
||||
* 63 - Indicates if the OS is Open Source or not; 1 is Open Source
|
||||
* 62:56 - Os Type; Linux is 0x100
|
||||
* 62:56 - OS Type; Linux is 0x1
|
||||
* 55:48 - Distro specific identification
|
||||
* 47:16 - Linux kernel version number
|
||||
* 15:0 - Distro specific identification
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ struct hv_vp_register_page {
|
|||
|
||||
u64 registers[18];
|
||||
};
|
||||
u8 reserved[8];
|
||||
/* Volatile XMM registers (HV_X64_REGISTER_CLASS_XMM) */
|
||||
union {
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -1304,7 +1304,11 @@ static inline void *hv_get_drvdata(struct hv_device *dev)
|
|||
|
||||
struct device *hv_get_vmbus_root_device(void);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV_VMBUS)
|
||||
bool hv_vmbus_exists(void);
|
||||
#else
|
||||
static inline bool hv_vmbus_exists(void) { return false; }
|
||||
#endif
|
||||
|
||||
struct hv_ring_buffer_debug_info {
|
||||
u32 current_interrupt_mask;
|
||||
|
|
@ -1336,6 +1340,9 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
|
|||
bool fb_overlap_ok);
|
||||
void vmbus_free_mmio(resource_size_t start, resource_size_t size);
|
||||
|
||||
void vmbus_initiate_unload(bool crash);
|
||||
void vmbus_set_skip_unload(bool skip);
|
||||
|
||||
/*
|
||||
* GUID definitions of various offer types - services offered to the guest.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue