Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9069fd54 authored by Gerd Hoffmann's avatar Gerd Hoffmann Committed by Greg Kroah-Hartman
Browse files

hyperv-fb: add support for generation 2 virtual machines.



UEFI-based generation 2 virtual machines support vmbus devices only.
There is no pci bus.  Thus they use a different mechanism for the
graphics framebuffer:  Instead of using the vga pci bar a chunk of
memory muct be allocated from the hyperv mmio region declared using
APCI.  This patch implements support for it.

Based on a patch by Haiyang Zhang <haiyangz@microsoft.com>

Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Acked-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2da19688
Loading
Loading
Loading
Loading
+60 −26
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#include <linux/completion.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/efi.h>

#include <linux/hyperv.h>

@@ -212,6 +213,7 @@ struct synthvid_msg {

struct hvfb_par {
	struct fb_info *info;
	struct resource mem;
	bool fb_ready; /* fb device is ready */
	struct completion wait;
	u32 synthvid_version;
@@ -460,13 +462,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
		goto error;
	}

	if (par->synthvid_version == SYNTHVID_VERSION_WIN7) {
	if (par->synthvid_version == SYNTHVID_VERSION_WIN7)
		screen_depth = SYNTHVID_DEPTH_WIN7;
		screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
	} else {
	else
		screen_depth = SYNTHVID_DEPTH_WIN8;
		screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
	}

	screen_fb_size = hdev->channel->offermsg.offer.
				mmio_megabytes * 1024 * 1024;

	return 0;

@@ -627,10 +629,25 @@ static void hvfb_get_option(struct fb_info *info)
/* Get framebuffer memory from Hyper-V video pci space */
static int hvfb_getmem(struct fb_info *info)
{
	struct pci_dev *pdev;
	ulong fb_phys;
	struct hvfb_par *par = info->par;
	struct pci_dev *pdev  = NULL;
	void __iomem *fb_virt;
	int gen2vm = efi_enabled(EFI_BOOT);
	int ret;

	par->mem.name = KBUILD_MODNAME;
	par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
	if (gen2vm) {
		ret = allocate_resource(&hyperv_mmio, &par->mem,
					screen_fb_size,
					0, -1,
					screen_fb_size,
					NULL, NULL);
		if (ret != 0) {
			pr_err("Unable to allocate framebuffer memory\n");
			return -ENODEV;
		}
	} else {
		pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
			      PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
		if (!pdev) {
@@ -642,11 +659,16 @@ static int hvfb_getmem(struct fb_info *info)
		    pci_resource_len(pdev, 0) < screen_fb_size)
			goto err1;

	fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1;
	if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME))
		par->mem.end = pci_resource_end(pdev, 0);
		par->mem.start = par->mem.end - screen_fb_size + 1;
		ret = request_resource(&pdev->resource[0], &par->mem);
		if (ret != 0) {
			pr_err("Unable to request framebuffer memory\n");
			goto err1;
		}
	}

	fb_virt = ioremap(fb_phys, screen_fb_size);
	fb_virt = ioremap(par->mem.start, screen_fb_size);
	if (!fb_virt)
		goto err2;

@@ -654,30 +676,42 @@ static int hvfb_getmem(struct fb_info *info)
	if (!info->apertures)
		goto err3;

	if (gen2vm) {
		info->apertures->ranges[0].base = screen_info.lfb_base;
		info->apertures->ranges[0].size = screen_info.lfb_size;
	} else {
		info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
		info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
	info->fix.smem_start = fb_phys;
	}

	info->fix.smem_start = par->mem.start;
	info->fix.smem_len = screen_fb_size;
	info->screen_base = fb_virt;
	info->screen_size = screen_fb_size;

	if (!gen2vm)
		pci_dev_put(pdev);

	return 0;

err3:
	iounmap(fb_virt);
err2:
	release_mem_region(fb_phys, screen_fb_size);
	release_resource(&par->mem);
err1:
	if (!gen2vm)
		pci_dev_put(pdev);

	return -ENOMEM;
}

/* Release the framebuffer */
static void hvfb_putmem(struct fb_info *info)
{
	struct hvfb_par *par = info->par;

	iounmap(info->screen_base);
	release_mem_region(info->fix.smem_start, screen_fb_size);
	release_resource(&par->mem);
}