aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2014-02-26 05:51:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-28 18:31:39 -0500
commit9069fd54960304a7c941909cbccdf8df9c42b488 (patch)
tree74179cf285290436141b88f5727c27fb6de1cf53
parent2da19688f4776437597c1e217d27f74ffaecd52a (diff)
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: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Acked-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/video/hyperv_fb.c86
1 files changed, 60 insertions, 26 deletions
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
index 130708f96430..b7b3dd0ab675 100644
--- a/drivers/video/hyperv_fb.c
+++ b/drivers/video/hyperv_fb.c
@@ -42,6 +42,7 @@
42#include <linux/completion.h> 42#include <linux/completion.h>
43#include <linux/fb.h> 43#include <linux/fb.h>
44#include <linux/pci.h> 44#include <linux/pci.h>
45#include <linux/efi.h>
45 46
46#include <linux/hyperv.h> 47#include <linux/hyperv.h>
47 48
@@ -212,6 +213,7 @@ struct synthvid_msg {
212 213
213struct hvfb_par { 214struct hvfb_par {
214 struct fb_info *info; 215 struct fb_info *info;
216 struct resource mem;
215 bool fb_ready; /* fb device is ready */ 217 bool fb_ready; /* fb device is ready */
216 struct completion wait; 218 struct completion wait;
217 u32 synthvid_version; 219 u32 synthvid_version;
@@ -460,13 +462,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
460 goto error; 462 goto error;
461 } 463 }
462 464
463 if (par->synthvid_version == SYNTHVID_VERSION_WIN7) { 465 if (par->synthvid_version == SYNTHVID_VERSION_WIN7)
464 screen_depth = SYNTHVID_DEPTH_WIN7; 466 screen_depth = SYNTHVID_DEPTH_WIN7;
465 screen_fb_size = SYNTHVID_FB_SIZE_WIN7; 467 else
466 } else {
467 screen_depth = SYNTHVID_DEPTH_WIN8; 468 screen_depth = SYNTHVID_DEPTH_WIN8;
468 screen_fb_size = SYNTHVID_FB_SIZE_WIN8; 469
469 } 470 screen_fb_size = hdev->channel->offermsg.offer.
471 mmio_megabytes * 1024 * 1024;
470 472
471 return 0; 473 return 0;
472 474
@@ -627,26 +629,46 @@ static void hvfb_get_option(struct fb_info *info)
627/* Get framebuffer memory from Hyper-V video pci space */ 629/* Get framebuffer memory from Hyper-V video pci space */
628static int hvfb_getmem(struct fb_info *info) 630static int hvfb_getmem(struct fb_info *info)
629{ 631{
630 struct pci_dev *pdev; 632 struct hvfb_par *par = info->par;
631 ulong fb_phys; 633 struct pci_dev *pdev = NULL;
632 void __iomem *fb_virt; 634 void __iomem *fb_virt;
635 int gen2vm = efi_enabled(EFI_BOOT);
636 int ret;
633 637
634 pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, 638 par->mem.name = KBUILD_MODNAME;
639 par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
640 if (gen2vm) {
641 ret = allocate_resource(&hyperv_mmio, &par->mem,
642 screen_fb_size,
643 0, -1,
644 screen_fb_size,
645 NULL, NULL);
646 if (ret != 0) {
647 pr_err("Unable to allocate framebuffer memory\n");
648 return -ENODEV;
649 }
650 } else {
651 pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
635 PCI_DEVICE_ID_HYPERV_VIDEO, NULL); 652 PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
636 if (!pdev) { 653 if (!pdev) {
637 pr_err("Unable to find PCI Hyper-V video\n"); 654 pr_err("Unable to find PCI Hyper-V video\n");
638 return -ENODEV; 655 return -ENODEV;
639 } 656 }
640 657
641 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 658 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
642 pci_resource_len(pdev, 0) < screen_fb_size) 659 pci_resource_len(pdev, 0) < screen_fb_size)
643 goto err1; 660 goto err1;
644 661
645 fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1; 662 par->mem.end = pci_resource_end(pdev, 0);
646 if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME)) 663 par->mem.start = par->mem.end - screen_fb_size + 1;
647 goto err1; 664 ret = request_resource(&pdev->resource[0], &par->mem);
665 if (ret != 0) {
666 pr_err("Unable to request framebuffer memory\n");
667 goto err1;
668 }
669 }
648 670
649 fb_virt = ioremap(fb_phys, screen_fb_size); 671 fb_virt = ioremap(par->mem.start, screen_fb_size);
650 if (!fb_virt) 672 if (!fb_virt)
651 goto err2; 673 goto err2;
652 674
@@ -654,30 +676,42 @@ static int hvfb_getmem(struct fb_info *info)
654 if (!info->apertures) 676 if (!info->apertures)
655 goto err3; 677 goto err3;
656 678
657 info->apertures->ranges[0].base = pci_resource_start(pdev, 0); 679 if (gen2vm) {
658 info->apertures->ranges[0].size = pci_resource_len(pdev, 0); 680 info->apertures->ranges[0].base = screen_info.lfb_base;
659 info->fix.smem_start = fb_phys; 681 info->apertures->ranges[0].size = screen_info.lfb_size;
682 } else {
683 info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
684 info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
685 }
686
687 info->fix.smem_start = par->mem.start;
660 info->fix.smem_len = screen_fb_size; 688 info->fix.smem_len = screen_fb_size;
661 info->screen_base = fb_virt; 689 info->screen_base = fb_virt;
662 info->screen_size = screen_fb_size; 690 info->screen_size = screen_fb_size;
663 691
664 pci_dev_put(pdev); 692 if (!gen2vm)
693 pci_dev_put(pdev);
694
665 return 0; 695 return 0;
666 696
667err3: 697err3:
668 iounmap(fb_virt); 698 iounmap(fb_virt);
669err2: 699err2:
670 release_mem_region(fb_phys, screen_fb_size); 700 release_resource(&par->mem);
671err1: 701err1:
672 pci_dev_put(pdev); 702 if (!gen2vm)
703 pci_dev_put(pdev);
704
673 return -ENOMEM; 705 return -ENOMEM;
674} 706}
675 707
676/* Release the framebuffer */ 708/* Release the framebuffer */
677static void hvfb_putmem(struct fb_info *info) 709static void hvfb_putmem(struct fb_info *info)
678{ 710{
711 struct hvfb_par *par = info->par;
712
679 iounmap(info->screen_base); 713 iounmap(info->screen_base);
680 release_mem_region(info->fix.smem_start, screen_fb_size); 714 release_resource(&par->mem);
681} 715}
682 716
683 717