Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers:hv: Move MMIO range picking from hyper_fb to hv_vmbus

This patch deletes the logic from hyperv_fb which picked a range of MMIO space
for the frame buffer and adds new logic to hv_vmbus which picks ranges for
child drivers. The new logic isn't quite the same as the old, as it considers
more possible ranges.

Signed-off-by: Jake Oshins <jakeo@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jake Oshins and committed by
Greg Kroah-Hartman
35464483 7f163a6f

+110 -31
+84 -4
drivers/hv/vmbus_drv.c
··· 39 39 #include <asm/mshyperv.h> 40 40 #include <linux/notifier.h> 41 41 #include <linux/ptrace.h> 42 + #include <linux/screen_info.h> 42 43 #include <linux/kdebug.h> 43 44 #include "hyperv_vmbus.h" 44 45 ··· 104 103 }; 105 104 106 105 struct resource *hyperv_mmio; 107 - EXPORT_SYMBOL_GPL(hyperv_mmio); 108 106 109 107 static int vmbus_exists(void) 110 108 { ··· 891 891 } 892 892 893 893 /** 894 - * __vmbus_child_driver_register - Register a vmbus's driver 895 - * @drv: Pointer to driver structure you want to register 894 + * __vmbus_child_driver_register() - Register a vmbus's driver 895 + * @hv_driver: Pointer to driver structure you want to register 896 896 * @owner: owner module of the drv 897 897 * @mod_name: module name string 898 898 * ··· 924 924 925 925 /** 926 926 * vmbus_driver_unregister() - Unregister a vmbus's driver 927 - * @drv: Pointer to driver structure you want to un-register 927 + * @hv_driver: Pointer to driver structure you want to 928 + * un-register 928 929 * 929 930 * Un-register the given driver that was previous registered with a call to 930 931 * vmbus_driver_register() ··· 1104 1103 1105 1104 return 0; 1106 1105 } 1106 + 1107 + /** 1108 + * vmbus_allocate_mmio() - Pick a memory-mapped I/O range. 1109 + * @new: If successful, supplied a pointer to the 1110 + * allocated MMIO space. 1111 + * @device_obj: Identifies the caller 1112 + * @min: Minimum guest physical address of the 1113 + * allocation 1114 + * @max: Maximum guest physical address 1115 + * @size: Size of the range to be allocated 1116 + * @align: Alignment of the range to be allocated 1117 + * @fb_overlap_ok: Whether this allocation can be allowed 1118 + * to overlap the video frame buffer. 1119 + * 1120 + * This function walks the resources granted to VMBus by the 1121 + * _CRS object in the ACPI namespace underneath the parent 1122 + * "bridge" whether that's a root PCI bus in the Generation 1 1123 + * case or a Module Device in the Generation 2 case. It then 1124 + * attempts to allocate from the global MMIO pool in a way that 1125 + * matches the constraints supplied in these parameters and by 1126 + * that _CRS. 1127 + * 1128 + * Return: 0 on success, -errno on failure 1129 + */ 1130 + int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, 1131 + resource_size_t min, resource_size_t max, 1132 + resource_size_t size, resource_size_t align, 1133 + bool fb_overlap_ok) 1134 + { 1135 + struct resource *iter; 1136 + resource_size_t range_min, range_max, start, local_min, local_max; 1137 + const char *dev_n = dev_name(&device_obj->device); 1138 + u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1); 1139 + int i; 1140 + 1141 + for (iter = hyperv_mmio; iter; iter = iter->sibling) { 1142 + if ((iter->start >= max) || (iter->end <= min)) 1143 + continue; 1144 + 1145 + range_min = iter->start; 1146 + range_max = iter->end; 1147 + 1148 + /* If this range overlaps the frame buffer, split it into 1149 + two tries. */ 1150 + for (i = 0; i < 2; i++) { 1151 + local_min = range_min; 1152 + local_max = range_max; 1153 + if (fb_overlap_ok || (range_min >= fb_end) || 1154 + (range_max <= screen_info.lfb_base)) { 1155 + i++; 1156 + } else { 1157 + if ((range_min <= screen_info.lfb_base) && 1158 + (range_max >= screen_info.lfb_base)) { 1159 + /* 1160 + * The frame buffer is in this window, 1161 + * so trim this into the part that 1162 + * preceeds the frame buffer. 1163 + */ 1164 + local_max = screen_info.lfb_base - 1; 1165 + range_min = fb_end; 1166 + } else { 1167 + range_min = fb_end; 1168 + continue; 1169 + } 1170 + } 1171 + 1172 + start = (local_min + align - 1) & ~(align - 1); 1173 + for (; start + size - 1 <= local_max; start += align) { 1174 + *new = request_mem_region_exclusive(start, size, 1175 + dev_n); 1176 + if (*new) 1177 + return 0; 1178 + } 1179 + } 1180 + } 1181 + 1182 + return -ENXIO; 1183 + } 1184 + EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); 1107 1185 1108 1186 static int vmbus_acpi_add(struct acpi_device *device) 1109 1187 {
+21 -25
drivers/video/fbdev/hyperv_fb.c
··· 213 213 214 214 struct hvfb_par { 215 215 struct fb_info *info; 216 - struct resource mem; 216 + struct resource *mem; 217 217 bool fb_ready; /* fb device is ready */ 218 218 struct completion wait; 219 219 u32 synthvid_version; ··· 677 677 678 678 679 679 /* Get framebuffer memory from Hyper-V video pci space */ 680 - static int hvfb_getmem(struct fb_info *info) 680 + static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) 681 681 { 682 682 struct hvfb_par *par = info->par; 683 683 struct pci_dev *pdev = NULL; 684 684 void __iomem *fb_virt; 685 685 int gen2vm = efi_enabled(EFI_BOOT); 686 + resource_size_t pot_start, pot_end; 686 687 int ret; 687 688 688 - par->mem.name = KBUILD_MODNAME; 689 - par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; 690 689 if (gen2vm) { 691 - ret = allocate_resource(hyperv_mmio, &par->mem, 692 - screen_fb_size, 693 - 0, -1, 694 - screen_fb_size, 695 - NULL, NULL); 696 - if (ret != 0) { 697 - pr_err("Unable to allocate framebuffer memory\n"); 698 - return -ENODEV; 699 - } 690 + pot_start = 0; 691 + pot_end = -1; 700 692 } else { 701 693 pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, 702 694 PCI_DEVICE_ID_HYPERV_VIDEO, NULL); ··· 701 709 pci_resource_len(pdev, 0) < screen_fb_size) 702 710 goto err1; 703 711 704 - par->mem.end = pci_resource_end(pdev, 0); 705 - par->mem.start = par->mem.end - screen_fb_size + 1; 706 - ret = request_resource(&pdev->resource[0], &par->mem); 707 - if (ret != 0) { 708 - pr_err("Unable to request framebuffer memory\n"); 709 - goto err1; 710 - } 712 + pot_end = pci_resource_end(pdev, 0); 713 + pot_start = pot_end - screen_fb_size + 1; 711 714 } 712 715 713 - fb_virt = ioremap(par->mem.start, screen_fb_size); 716 + ret = vmbus_allocate_mmio(&par->mem, hdev, pot_start, pot_end, 717 + screen_fb_size, 0x100000, true); 718 + if (ret != 0) { 719 + pr_err("Unable to allocate framebuffer memory\n"); 720 + goto err1; 721 + } 722 + 723 + fb_virt = ioremap(par->mem->start, screen_fb_size); 714 724 if (!fb_virt) 715 725 goto err2; 716 726 ··· 730 736 info->apertures->ranges[0].size = pci_resource_len(pdev, 0); 731 737 } 732 738 733 - info->fix.smem_start = par->mem.start; 739 + info->fix.smem_start = par->mem->start; 734 740 info->fix.smem_len = screen_fb_size; 735 741 info->screen_base = fb_virt; 736 742 info->screen_size = screen_fb_size; ··· 743 749 err3: 744 750 iounmap(fb_virt); 745 751 err2: 746 - release_resource(&par->mem); 752 + release_mem_region(par->mem->start, screen_fb_size); 753 + par->mem = NULL; 747 754 err1: 748 755 if (!gen2vm) 749 756 pci_dev_put(pdev); ··· 758 763 struct hvfb_par *par = info->par; 759 764 760 765 iounmap(info->screen_base); 761 - release_resource(&par->mem); 766 + release_mem_region(par->mem->start, screen_fb_size); 767 + par->mem = NULL; 762 768 } 763 769 764 770 ··· 790 794 goto error1; 791 795 } 792 796 793 - ret = hvfb_getmem(info); 797 + ret = hvfb_getmem(hdev, info); 794 798 if (ret) { 795 799 pr_err("No memory for framebuffer\n"); 796 800 goto error2;
+5 -2
include/linux/hyperv.h
··· 977 977 const char *mod_name); 978 978 void vmbus_driver_unregister(struct hv_driver *hv_driver); 979 979 980 + int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, 981 + resource_size_t min, resource_size_t max, 982 + resource_size_t size, resource_size_t align, 983 + bool fb_overlap_ok); 984 + 980 985 /** 981 986 * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device 982 987 * ··· 1237 1232 int); 1238 1233 1239 1234 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); 1240 - 1241 - extern struct resource *hyperv_mmio; 1242 1235 1243 1236 /* 1244 1237 * Negotiated version with the Host.