|
35 | 35 | #include <linux/kernel.h> |
36 | 36 | #include <linux/syscore_ops.h> |
37 | 37 | #include <linux/dma-map-ops.h> |
| 38 | +#include <linux/pci.h> |
38 | 39 | #include <clocksource/hyperv_timer.h> |
39 | 40 | #include "hyperv_vmbus.h" |
40 | 41 |
|
@@ -2262,26 +2263,43 @@ static int vmbus_acpi_remove(struct acpi_device *device) |
2262 | 2263 |
|
2263 | 2264 | static void vmbus_reserve_fb(void) |
2264 | 2265 | { |
2265 | | - int size; |
| 2266 | + resource_size_t start = 0, size; |
| 2267 | + struct pci_dev *pdev; |
| 2268 | + |
| 2269 | + if (efi_enabled(EFI_BOOT)) { |
| 2270 | + /* Gen2 VM: get FB base from EFI framebuffer */ |
| 2271 | + start = screen_info.lfb_base; |
| 2272 | + size = max_t(__u32, screen_info.lfb_size, 0x800000); |
| 2273 | + } else { |
| 2274 | + /* Gen1 VM: get FB base from PCI */ |
| 2275 | + pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, |
| 2276 | + PCI_DEVICE_ID_HYPERV_VIDEO, NULL); |
| 2277 | + if (!pdev) |
| 2278 | + return; |
| 2279 | + |
| 2280 | + if (pdev->resource[0].flags & IORESOURCE_MEM) { |
| 2281 | + start = pci_resource_start(pdev, 0); |
| 2282 | + size = pci_resource_len(pdev, 0); |
| 2283 | + } |
| 2284 | + |
| 2285 | + /* |
| 2286 | + * Release the PCI device so hyperv_drm or hyperv_fb driver can |
| 2287 | + * grab it later. |
| 2288 | + */ |
| 2289 | + pci_dev_put(pdev); |
| 2290 | + } |
| 2291 | + |
| 2292 | + if (!start) |
| 2293 | + return; |
| 2294 | + |
2266 | 2295 | /* |
2267 | 2296 | * Make a claim for the frame buffer in the resource tree under the |
2268 | 2297 | * first node, which will be the one below 4GB. The length seems to |
2269 | 2298 | * be underreported, particularly in a Generation 1 VM. So start out |
2270 | 2299 | * reserving a larger area and make it smaller until it succeeds. |
2271 | 2300 | */ |
2272 | | - |
2273 | | - if (screen_info.lfb_base) { |
2274 | | - if (efi_enabled(EFI_BOOT)) |
2275 | | - size = max_t(__u32, screen_info.lfb_size, 0x800000); |
2276 | | - else |
2277 | | - size = max_t(__u32, screen_info.lfb_size, 0x4000000); |
2278 | | - |
2279 | | - for (; !fb_mmio && (size >= 0x100000); size >>= 1) { |
2280 | | - fb_mmio = __request_region(hyperv_mmio, |
2281 | | - screen_info.lfb_base, size, |
2282 | | - fb_mmio_name, 0); |
2283 | | - } |
2284 | | - } |
| 2301 | + for (; !fb_mmio && (size >= 0x100000); size >>= 1) |
| 2302 | + fb_mmio = __request_region(hyperv_mmio, start, size, fb_mmio_name, 0); |
2285 | 2303 | } |
2286 | 2304 |
|
2287 | 2305 | /** |
@@ -2313,7 +2331,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, |
2313 | 2331 | bool fb_overlap_ok) |
2314 | 2332 | { |
2315 | 2333 | struct resource *iter, *shadow; |
2316 | | - resource_size_t range_min, range_max, start; |
| 2334 | + resource_size_t range_min, range_max, start, end; |
2317 | 2335 | const char *dev_n = dev_name(&device_obj->device); |
2318 | 2336 | int retval; |
2319 | 2337 |
|
@@ -2348,6 +2366,14 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, |
2348 | 2366 | range_max = iter->end; |
2349 | 2367 | start = (range_min + align - 1) & ~(align - 1); |
2350 | 2368 | for (; start + size - 1 <= range_max; start += align) { |
| 2369 | + end = start + size - 1; |
| 2370 | + |
| 2371 | + /* Skip the whole fb_mmio region if not fb_overlap_ok */ |
| 2372 | + if (!fb_overlap_ok && fb_mmio && |
| 2373 | + (((start >= fb_mmio->start) && (start <= fb_mmio->end)) || |
| 2374 | + ((end >= fb_mmio->start) && (end <= fb_mmio->end)))) |
| 2375 | + continue; |
| 2376 | + |
2351 | 2377 | shadow = __request_region(iter, start, size, NULL, |
2352 | 2378 | IORESOURCE_BUSY); |
2353 | 2379 | if (!shadow) |
|
0 commit comments