aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/hyperv/vmbus/vmbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hyperv/vmbus/vmbus.c')
-rw-r--r--sys/dev/hyperv/vmbus/vmbus.c57
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;