Commit 0fed89a9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'hyperv-fixes-signed-20250311' of...

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 memory
parents 0b46b049 73fe9073
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −2
Original line number Diff line number Diff line
@@ -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))
+2 −0
Original line number Diff line number Diff line
@@ -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);
}

+13 −0
Original line number Diff line number Diff line
@@ -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);

+34 −18
Original line number Diff line number Diff line
@@ -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 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
}

/* 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)