diff options
Diffstat (limited to 'sys/dev/hyperv/vmbus/vmbus.c')
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c index 9d4f5e77fa97..38e9cd7b4c26 100644 --- a/sys/dev/hyperv/vmbus/vmbus.c +++ b/sys/dev/hyperv/vmbus/vmbus.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/bus.h> #include <sys/kernel.h> +#include <sys/linker.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/module.h> @@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/intr_machdep.h> +#include <machine/metadata.h> #include <machine/md_var.h> #include <machine/resource.h> #include <x86/include/apicvar.h> @@ -1332,12 +1334,66 @@ vmbus_get_mmio_res(device_t dev) vmbus_get_mmio_res_pass(dev, parse_32); } +/* + * On Gen2 VMs, Hyper-V provides mmio space for framebuffer. + * This mmio address range is not useable for other PCI devices. + * Currently only efifb driver is using this range without reserving + * it from system. + * Therefore, vmbus driver reserves it before any other PCI device + * drivers start to request mmio addresses. + */ +static struct resource *hv_fb_res; + +static void +vmbus_fb_mmio_res(device_t dev) +{ + struct efi_fb *efifb; + caddr_t kmdp; + + struct vmbus_softc *sc = device_get_softc(dev); + int rid = 0; + + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + efifb = (struct efi_fb *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_EFI_FB); + if (efifb == NULL) { + if (bootverbose) + device_printf(dev, + "fb has no preloaded kernel efi information\n"); + /* We are on Gen1 VM, just return. */ + return; + } else { + if (bootverbose) + device_printf(dev, + "efifb: fb_addr: %#jx, size: %#jx, " + "actual size needed: 0x%x\n", + efifb->fb_addr, efifb->fb_size, + (int) efifb->fb_height * efifb->fb_width); + } + + hv_fb_res = pcib_host_res_alloc(&sc->vmbus_mmio_res, dev, + SYS_RES_MEMORY, &rid, + efifb->fb_addr, efifb->fb_addr + efifb->fb_size, efifb->fb_size, + RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE)); + + if (hv_fb_res && bootverbose) + device_printf(dev, + "successfully reserved memory for framebuffer " + "starting at %#jx, size %#jx\n", + efifb->fb_addr, efifb->fb_size); +} + static void vmbus_free_mmio_res(device_t dev) { struct vmbus_softc *sc = device_get_softc(dev); pcib_host_res_free(dev, &sc->vmbus_mmio_res); + + if (hv_fb_res) + hv_fb_res = NULL; } #endif /* NEW_PCIB */ @@ -1387,6 +1443,7 @@ vmbus_doattach(struct vmbus_softc *sc) #ifdef NEW_PCIB vmbus_get_mmio_res(sc->vmbus_dev); + vmbus_fb_mmio_res(sc->vmbus_dev); #endif sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; |