hyperv-fixes for v6.14-rc7
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEIbPD0id6easf0xsudhRwX5BBoF4FAmfQqQgTHHdlaS5saXVA a2VybmVsLm9yZwAKCRB2FHBfkEGgXp65B/9kg3QLFvqe88XtisV2bdI1jkwuFrVD ibHAvmodYPqnWnecXl1TG+4x3gn5U6qA6niQcXl5uucsWoB3hdqG/oaJfw0gLnp5 +x6dsoY1olKVs0Y8/Tr4lzg73IBxz2w8IhvYZerbUx1g3l7cc79WLYkr6lS7hnlz szBEoPuVMRTZsblLuw80u8BZHLcVLDFFFZ+MRTtTqZwL7y2A5fMA5rcZpTngvoxP DEzaoU9iYMn37pC/8uaCjviR7n2UEFGLY4tVHDgrpRRtJvB14aEkhvM9k3v6ddpL +c5UhUKd+L+KKHMmSNVeJ2lstKXVgssJEDUrf+ZBwmoDk/0O7Wdrx2Dy =HkGK -----END PGP SIGNATURE----- Merge tag 'hyperv-fixes-signed-20250311' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux Pull hyperv fixes from Wei Liu: - Patches to fix Hyper-v framebuffer code (Michael Kelley and Saurabh Sengar) - Fix for Hyper-V output argument to hypercall that changes page visibility (Michael Kelley) - Fix for Hyper-V VTL mode (Naman Jain) * tag 'hyperv-fixes-signed-20250311' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: Drivers: hv: vmbus: Don't release fb_mmio resource in vmbus_free_mmio() x86/hyperv: Fix output argument to hypercall that changes page visibility fbdev: hyperv_fb: Allow graceful removal of framebuffer fbdev: hyperv_fb: Simplify hvfb_putmem fbdev: hyperv_fb: Fix hang in kdump kernel when on Hyper-V Gen 2 VMs drm/hyperv: Fix address space leak when Hyper-V DRM device is removed fbdev: hyperv_fb: iounmap() the correct memory when removing a device x86/hyperv/vtl: Stop kernel from probing VTL0 low memorypull/1170/head
commit
0fed89a961
|
|
@ -30,6 +30,7 @@ void __init hv_vtl_init_platform(void)
|
|||
x86_platform.realmode_init = x86_init_noop;
|
||||
x86_init.irqs.pre_vector_init = x86_init_noop;
|
||||
x86_init.timers.timer_init = x86_init_noop;
|
||||
x86_init.resources.probe_roms = x86_init_noop;
|
||||
|
||||
/* Avoid searching for BIOS MP tables */
|
||||
x86_init.mpparse.find_mptable = x86_init_noop;
|
||||
|
|
|
|||
|
|
@ -464,7 +464,6 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
|
|||
enum hv_mem_host_visibility visibility)
|
||||
{
|
||||
struct hv_gpa_range_for_visibility *input;
|
||||
u16 pages_processed;
|
||||
u64 hv_status;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -493,7 +492,7 @@ static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
|
|||
memcpy((void *)input->gpa_page_list, pfn, count * sizeof(*pfn));
|
||||
hv_status = hv_do_rep_hypercall(
|
||||
HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY, count,
|
||||
0, input, &pages_processed);
|
||||
0, input, NULL);
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (hv_result_success(hv_status))
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
|
|||
return 0;
|
||||
|
||||
err_free_mmio:
|
||||
iounmap(hv->vram);
|
||||
vmbus_free_mmio(hv->mem->start, hv->fb_size);
|
||||
err_vmbus_close:
|
||||
vmbus_close(hdev->channel);
|
||||
|
|
@ -172,6 +173,7 @@ static void hyperv_vmbus_remove(struct hv_device *hdev)
|
|||
vmbus_close(hdev->channel);
|
||||
hv_set_drvdata(hdev, NULL);
|
||||
|
||||
iounmap(hv->vram);
|
||||
vmbus_free_mmio(hv->mem->start, hv->fb_size);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2262,12 +2262,25 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size)
|
|||
struct resource *iter;
|
||||
|
||||
mutex_lock(&hyperv_mmio_lock);
|
||||
|
||||
/*
|
||||
* If all bytes of the MMIO range to be released are within the
|
||||
* special case fb_mmio shadow region, skip releasing the shadow
|
||||
* region since no corresponding __request_region() was done
|
||||
* in vmbus_allocate_mmio().
|
||||
*/
|
||||
if (fb_mmio && start >= fb_mmio->start &&
|
||||
(start + size - 1 <= fb_mmio->end))
|
||||
goto skip_shadow_release;
|
||||
|
||||
for (iter = hyperv_mmio; iter; iter = iter->sibling) {
|
||||
if ((iter->start >= start + size) || (iter->end <= start))
|
||||
continue;
|
||||
|
||||
__release_region(iter, start, size);
|
||||
}
|
||||
|
||||
skip_shadow_release:
|
||||
release_mem_region(start, size);
|
||||
mutex_unlock(&hyperv_mmio_lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -282,6 +282,8 @@ static uint screen_depth;
|
|||
static uint screen_fb_size;
|
||||
static uint dio_fb_size; /* FB size for deferred IO */
|
||||
|
||||
static void hvfb_putmem(struct fb_info *info);
|
||||
|
||||
/* Send message to Hyper-V host */
|
||||
static inline int synthvid_send(struct hv_device *hdev,
|
||||
struct synthvid_msg *msg)
|
||||
|
|
@ -862,6 +864,17 @@ static void hvfb_ops_damage_area(struct fb_info *info, u32 x, u32 y, u32 width,
|
|||
hvfb_ondemand_refresh_throttle(par, x, y, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
* fb_ops.fb_destroy is called by the last put_fb_info() call at the end
|
||||
* of unregister_framebuffer() or fb_release(). Do any cleanup related to
|
||||
* framebuffer here.
|
||||
*/
|
||||
static void hvfb_destroy(struct fb_info *info)
|
||||
{
|
||||
hvfb_putmem(info);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: GEN1 codepaths allocate from system or DMA-able memory. Fix the
|
||||
* driver to use the _SYSMEM_ or _DMAMEM_ helpers in these cases.
|
||||
|
|
@ -877,6 +890,7 @@ static const struct fb_ops hvfb_ops = {
|
|||
.fb_set_par = hvfb_set_par,
|
||||
.fb_setcolreg = hvfb_setcolreg,
|
||||
.fb_blank = hvfb_blank,
|
||||
.fb_destroy = hvfb_destroy,
|
||||
};
|
||||
|
||||
/* Get options from kernel paramenter "video=" */
|
||||
|
|
@ -952,7 +966,7 @@ static phys_addr_t hvfb_get_phymem(struct hv_device *hdev,
|
|||
}
|
||||
|
||||
/* Release contiguous physical memory */
|
||||
static void hvfb_release_phymem(struct hv_device *hdev,
|
||||
static void hvfb_release_phymem(struct device *device,
|
||||
phys_addr_t paddr, unsigned int size)
|
||||
{
|
||||
unsigned int order = get_order(size);
|
||||
|
|
@ -960,7 +974,7 @@ static void hvfb_release_phymem(struct hv_device *hdev,
|
|||
if (order <= MAX_PAGE_ORDER)
|
||||
__free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order);
|
||||
else
|
||||
dma_free_coherent(&hdev->device,
|
||||
dma_free_coherent(device,
|
||||
round_up(size, PAGE_SIZE),
|
||||
phys_to_virt(paddr),
|
||||
paddr);
|
||||
|
|
@ -989,6 +1003,7 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|||
|
||||
base = pci_resource_start(pdev, 0);
|
||||
size = pci_resource_len(pdev, 0);
|
||||
aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
|
||||
|
||||
/*
|
||||
* For Gen 1 VM, we can directly use the contiguous memory
|
||||
|
|
@ -1010,11 +1025,21 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|||
goto getmem_done;
|
||||
}
|
||||
pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
|
||||
} else {
|
||||
aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cannot use the contiguous physical memory.
|
||||
* Allocate mmio space for framebuffer.
|
||||
* Cannot use contiguous physical memory, so allocate MMIO space for
|
||||
* the framebuffer. At this point in the function, conflicting devices
|
||||
* that might have claimed the framebuffer MMIO space based on
|
||||
* screen_info.lfb_base must have already been removed so that
|
||||
* vmbus_allocate_mmio() does not allocate different MMIO space. If the
|
||||
* kdump image were to be loaded using kexec_file_load(), the
|
||||
* framebuffer location in the kdump image would be set from
|
||||
* screen_info.lfb_base at the time that kdump is enabled. If the
|
||||
* framebuffer has moved elsewhere, this could be the wrong location,
|
||||
* causing kdump to hang when efifb (for example) loads.
|
||||
*/
|
||||
dio_fb_size =
|
||||
screen_width * screen_height * screen_depth / 8;
|
||||
|
|
@ -1051,11 +1076,6 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|||
info->screen_size = dio_fb_size;
|
||||
|
||||
getmem_done:
|
||||
if (base && size)
|
||||
aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
|
||||
else
|
||||
aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
|
||||
|
||||
if (!gen2vm)
|
||||
pci_dev_put(pdev);
|
||||
|
||||
|
|
@ -1074,16 +1094,16 @@ err1:
|
|||
}
|
||||
|
||||
/* Release the framebuffer */
|
||||
static void hvfb_putmem(struct hv_device *hdev, struct fb_info *info)
|
||||
static void hvfb_putmem(struct fb_info *info)
|
||||
{
|
||||
struct hvfb_par *par = info->par;
|
||||
|
||||
if (par->need_docopy) {
|
||||
vfree(par->dio_vp);
|
||||
iounmap(info->screen_base);
|
||||
iounmap(par->mmio_vp);
|
||||
vmbus_free_mmio(par->mem->start, screen_fb_size);
|
||||
} else {
|
||||
hvfb_release_phymem(hdev, info->fix.smem_start,
|
||||
hvfb_release_phymem(info->device, info->fix.smem_start,
|
||||
screen_fb_size);
|
||||
}
|
||||
|
||||
|
|
@ -1172,7 +1192,7 @@ static int hvfb_probe(struct hv_device *hdev,
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = register_framebuffer(info);
|
||||
ret = devm_register_framebuffer(&hdev->device, info);
|
||||
if (ret) {
|
||||
pr_err("Unable to register framebuffer\n");
|
||||
goto error;
|
||||
|
|
@ -1197,7 +1217,7 @@ static int hvfb_probe(struct hv_device *hdev,
|
|||
|
||||
error:
|
||||
fb_deferred_io_cleanup(info);
|
||||
hvfb_putmem(hdev, info);
|
||||
hvfb_putmem(info);
|
||||
error2:
|
||||
vmbus_close(hdev->channel);
|
||||
error1:
|
||||
|
|
@ -1220,14 +1240,10 @@ static void hvfb_remove(struct hv_device *hdev)
|
|||
|
||||
fb_deferred_io_cleanup(info);
|
||||
|
||||
unregister_framebuffer(info);
|
||||
cancel_delayed_work_sync(&par->dwork);
|
||||
|
||||
vmbus_close(hdev->channel);
|
||||
hv_set_drvdata(hdev, NULL);
|
||||
|
||||
hvfb_putmem(hdev, info);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
static int hvfb_suspend(struct hv_device *hdev)
|
||||
|
|
|
|||
Loading…
Reference in New Issue