diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2014-02-26 05:51:24 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-28 18:31:39 -0500 |
commit | 9069fd54960304a7c941909cbccdf8df9c42b488 (patch) | |
tree | 74179cf285290436141b88f5727c27fb6de1cf53 | |
parent | 2da19688f4776437597c1e217d27f74ffaecd52a (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.c | 86 |
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 | ||
213 | struct hvfb_par { | 214 | struct 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 */ |
628 | static int hvfb_getmem(struct fb_info *info) | 630 | static 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 | ||
667 | err3: | 697 | err3: |
668 | iounmap(fb_virt); | 698 | iounmap(fb_virt); |
669 | err2: | 699 | err2: |
670 | release_mem_region(fb_phys, screen_fb_size); | 700 | release_resource(&par->mem); |
671 | err1: | 701 | err1: |
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 */ |
677 | static void hvfb_putmem(struct fb_info *info) | 709 | static 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 | ||