Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137788387
D8409.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D8409.diff
View Options
Index: head/sys/dev/hyperv/vmbus/vmbus.c
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus.c
+++ head/sys/dev/hyperv/vmbus/vmbus.c
@@ -44,10 +44,13 @@
#include <sys/systm.h>
#include <sys/taskqueue.h>
+#include <machine/bus.h>
#include <machine/intr_machdep.h>
+#include <machine/resource.h>
#include <x86/include/apicvar.h>
#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/vmbus_xact.h>
@@ -58,6 +61,7 @@
#include <dev/hyperv/vmbus/vmbus_chanvar.h>
#include "acpi_if.h"
+#include "pcib_if.h"
#include "vmbus_if.h"
#define VMBUS_GPADL_START 0xe1e10
@@ -74,6 +78,20 @@
uintptr_t *);
static int vmbus_child_pnpinfo_str(device_t, device_t,
char *, size_t);
+static struct resource *vmbus_alloc_resource(device_t dev,
+ device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end,
+ rman_res_t count, u_int flags);
+static int vmbus_alloc_msi(device_t bus, device_t dev,
+ int count, int maxcount, int *irqs);
+static int vmbus_release_msi(device_t bus, device_t dev,
+ int count, int *irqs);
+static int vmbus_alloc_msix(device_t bus, device_t dev,
+ int *irq);
+static int vmbus_release_msix(device_t bus, device_t dev,
+ int irq);
+static int vmbus_map_msi(device_t bus, device_t dev,
+ int irq, uint64_t *addr, uint32_t *data);
static uint32_t vmbus_get_version_method(device_t, device_t);
static int vmbus_probe_guid_method(device_t, device_t,
const struct hyperv_guid *);
@@ -133,6 +151,22 @@
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, vmbus_read_ivar),
DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str),
+ DEVMETHOD(bus_alloc_resource, vmbus_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+#if __FreeBSD_version >= 1100000
+ DEVMETHOD(bus_get_cpus, bus_generic_get_cpus),
+#endif
+
+ /* pcib interface */
+ DEVMETHOD(pcib_alloc_msi, vmbus_alloc_msi),
+ DEVMETHOD(pcib_release_msi, vmbus_release_msi),
+ DEVMETHOD(pcib_alloc_msix, vmbus_alloc_msix),
+ DEVMETHOD(pcib_release_msix, vmbus_release_msix),
+ DEVMETHOD(pcib_map_msi, vmbus_map_msi),
/* Vmbus interface */
DEVMETHOD(vmbus_get_version, vmbus_get_version_method),
@@ -975,6 +1009,69 @@
return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
}
+/*
+ * We need the function to make sure the MMIO resource is allocated from the
+ * ranges found in _CRS.
+ *
+ * For the release function, we can use bus_generic_release_resource().
+ */
+static struct resource *
+vmbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct vmbus_softc *sc = device_get_softc(dev);
+ device_t parent = device_get_parent(dev);
+ struct resource *res;
+
+ if (type != SYS_RES_MEMORY)
+ res = BUS_ALLOC_RESOURCE(parent, child, type, rid, start,
+ end, count, flags);
+ else
+ res = pcib_host_res_alloc(&sc->vmbus_mmio_res, child, type,
+ rid, start, end, count, flags);
+
+ return (res);
+}
+
+static device_t
+get_nexus(device_t vmbus)
+{
+ device_t acpi = device_get_parent(vmbus);
+ device_t nexus = device_get_parent(acpi);
+ return (nexus);
+}
+
+static int
+vmbus_alloc_msi(device_t bus, device_t dev, int count, int maxcount, int *irqs)
+{
+ return (PCIB_ALLOC_MSI(get_nexus(bus), dev, count, maxcount, irqs));
+}
+
+static int
+vmbus_release_msi(device_t bus, device_t dev, int count, int *irqs)
+{
+ return (PCIB_RELEASE_MSI(get_nexus(bus), dev, count, irqs));
+}
+
+static int
+vmbus_alloc_msix(device_t bus, device_t dev, int *irq)
+{
+ return (PCIB_ALLOC_MSIX(get_nexus(bus), dev, irq));
+}
+
+static int
+vmbus_release_msix(device_t bus, device_t dev, int irq)
+{
+ return (PCIB_RELEASE_MSIX(get_nexus(bus), dev, irq));
+}
+
+static int
+vmbus_map_msi(device_t bus, device_t dev, int irq, uint64_t *addr,
+ uint32_t *data)
+{
+ return (PCIB_MAP_MSI(get_nexus(bus), dev, irq, addr, data));
+}
+
static uint32_t
vmbus_get_version_method(device_t bus, device_t dev)
{
@@ -1002,6 +1099,138 @@
return (VMBUS_PCPU_GET(sc, vcpuid, cpu));
}
+#define VTPM_BASE_ADDR 0xfed40000
+#define FOUR_GB (1ULL << 32)
+
+enum parse_pass { parse_64, parse_32 };
+
+struct parse_context {
+ device_t vmbus_dev;
+ enum parse_pass pass;
+};
+
+static ACPI_STATUS
+parse_crs(ACPI_RESOURCE *res, void *ctx)
+{
+ const struct parse_context *pc = ctx;
+ device_t vmbus_dev = pc->vmbus_dev;
+
+ struct vmbus_softc *sc = device_get_softc(vmbus_dev);
+ UINT64 start, end;
+
+ switch (res->Type) {
+ case ACPI_RESOURCE_TYPE_ADDRESS32:
+ start = res->Data.Address32.Address.Minimum;
+ end = res->Data.Address32.Address.Maximum;
+ break;
+
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ start = res->Data.Address64.Address.Minimum;
+ end = res->Data.Address64.Address.Maximum;
+ break;
+
+ default:
+ /* Unused types. */
+ return (AE_OK);
+ }
+
+ /*
+ * We don't use <1MB addresses.
+ */
+ if (end < 0x100000)
+ return (AE_OK);
+
+ /* Don't conflict with vTPM. */
+ if (end >= VTPM_BASE_ADDR && start < VTPM_BASE_ADDR)
+ end = VTPM_BASE_ADDR - 1;
+
+ if ((pc->pass == parse_32 && start < FOUR_GB) ||
+ (pc->pass == parse_64 && start >= FOUR_GB))
+ pcib_host_res_decodes(&sc->vmbus_mmio_res, SYS_RES_MEMORY,
+ start, end, 0);
+
+ return (AE_OK);
+}
+
+static void
+vmbus_get_crs(device_t dev, device_t vmbus_dev, enum parse_pass pass)
+{
+ struct parse_context pc;
+ ACPI_STATUS status;
+
+ if (bootverbose)
+ device_printf(dev, "walking _CRS, pass=%d\n", pass);
+
+ pc.vmbus_dev = vmbus_dev;
+ pc.pass = pass;
+ status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+ parse_crs, &pc);
+
+ if (bootverbose && ACPI_FAILURE(status))
+ device_printf(dev, "_CRS: not found, pass=%d\n", pass);
+}
+
+static void
+vmbus_get_mmio_res_pass(device_t dev, enum parse_pass pass)
+{
+ device_t acpi0, pcib0 = NULL;
+ device_t *children;
+ int i, count;
+
+ /* Try to find _CRS on VMBus device */
+ vmbus_get_crs(dev, dev, pass);
+
+ /* Try to find _CRS on VMBus device's parent */
+ acpi0 = device_get_parent(dev);
+ vmbus_get_crs(acpi0, dev, pass);
+
+ /* Try to locate pcib0 and find _CRS on it */
+ if (device_get_children(acpi0, &children, &count) != 0)
+ return;
+
+ for (i = 0; i < count; i++) {
+ if (!device_is_attached(children[i]))
+ continue;
+
+ if (strcmp("pcib0", device_get_nameunit(children[i])))
+ continue;
+
+ pcib0 = children[i];
+ break;
+ }
+
+ if (pcib0)
+ vmbus_get_crs(pcib0, dev, pass);
+
+ free(children, M_TEMP);
+}
+
+static void
+vmbus_get_mmio_res(device_t dev)
+{
+ struct vmbus_softc *sc = device_get_softc(dev);
+ /*
+ * We walk the resources twice to make sure that: in the resource
+ * list, the 32-bit resources appear behind the 64-bit resources.
+ * NB: resource_list_add() uses INSERT_TAIL. This way, when we
+ * iterate through the list to find a range for a 64-bit BAR in
+ * vmbus_alloc_resource(), we can make sure we try to use >4GB
+ * ranges first.
+ */
+ pcib_host_res_init(dev, &sc->vmbus_mmio_res);
+
+ vmbus_get_mmio_res_pass(dev, parse_64);
+ vmbus_get_mmio_res_pass(dev, parse_32);
+}
+
+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);
+}
+
static int
vmbus_probe(device_t dev)
{
@@ -1038,6 +1267,9 @@
if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
return (0);
+
+ vmbus_get_mmio_res(sc->vmbus_dev);
+
sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
sc->vmbus_gpadl = VMBUS_GPADL_START;
@@ -1184,6 +1416,8 @@
mtx_destroy(&sc->vmbus_prichan_lock);
mtx_destroy(&sc->vmbus_chan_lock);
+ vmbus_free_mmio_res(dev);
+
return (0);
}
Index: head/sys/dev/hyperv/vmbus/vmbus_var.h
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_var.h
+++ head/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -31,8 +31,11 @@
#include <sys/param.h>
#include <sys/taskqueue.h>
+#include <sys/rman.h>
#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
/*
* NOTE: DO NOT CHANGE THIS.
@@ -77,6 +80,10 @@
struct task message_task; /* message task */
} __aligned(CACHE_LINE_SIZE);
+#if __FreeBSD_version < 1100000
+typedef u_long rman_res_t;
+#endif
+
struct vmbus_softc {
void (*vmbus_event_proc)(struct vmbus_softc *, int);
u_long *vmbus_tx_evtflags;
@@ -120,6 +127,9 @@
/* Complete channel list */
struct mtx vmbus_chan_lock;
TAILQ_HEAD(, vmbus_channel) vmbus_chans;
+
+ /* The list of usable MMIO ranges for PCIe pass-through */
+ struct pcib_host_resources vmbus_mmio_res;
};
#define VMBUS_FLAG_ATTACHED 0x0001 /* vmbus was attached */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 26, 8:59 PM (15 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26226181
Default Alt Text
D8409.diff (8 KB)
Attached To
Mode
D8409: hyperv/vmbus: add new vmbus methods to support PCIe pass-through
Attached
Detach File
Event Timeline
Log In to Comment