Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F138016396
D8409.id21878.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.id21878.diff
View Options
Index: sys/dev/hyperv/vmbus/vmbus.c
===================================================================
--- sys/dev/hyperv/vmbus/vmbus.c
+++ sys/dev/hyperv/vmbus/vmbus.c
@@ -44,10 +44,19 @@
#include <sys/systm.h>
#include <sys/taskqueue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
#include <machine/intr_machdep.h>
#include <x86/include/apicvar.h>
#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/vmbus_xact.h>
@@ -74,6 +83,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 +156,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),
@@ -974,6 +1013,85 @@
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)
+{
+ device_t parent = device_get_parent(dev);
+ int isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
+ struct vmbus_mmio_entry *entry;
+ struct vmbus_softc *sc;
+ struct resource *res;
+
+ if (type != SYS_RES_MEMORY)
+ return (BUS_ALLOC_RESOURCE(parent, child, type, rid, start,
+ end, count, flags));
+
+ sc = device_get_softc(dev);
+ TAILQ_FOREACH(entry, &sc->vmbus_mmio_list, link) {
+ if (isdefault ||
+ (start <= entry->end && end >= entry->start)) {
+ if (isdefault) {
+ start = entry->start;
+ end = entry->end;
+ }
+
+ res = BUS_ALLOC_RESOURCE(parent, child, type, rid,
+ MAX(start, entry->start), MIN(end, entry->end),
+ count, flags);
+ if (res != NULL)
+ return (res);
+ }
+ }
+
+ return NULL;
+}
+
+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)
{
@@ -1001,6 +1119,126 @@
return (VMBUS_PCPU_GET(chan->ch_vmbus, vcpuid, cpu));
}
+#define VTPM_BASE_ADDR 0xfed40000
+static ACPI_STATUS
+parse_crs(ACPI_RESOURCE *res, void *ctx)
+{
+ device_t vmbus_dev = ctx;
+ struct vmbus_softc *sc = device_get_softc(vmbus_dev);
+ UINT64 start, end;
+ struct vmbus_mmio_entry *e;
+
+ 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;
+
+ device_printf(vmbus_dev, "found _CRS [0x%lx, 0x%lx]\n", start, end);
+
+ e = malloc(sizeof(struct vmbus_mmio_entry), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+ e->start = start;
+ e->end = end;
+
+ /*
+ * Put the >4GB range(s) at the beginning of the list. This way, when
+ * we iterate through the list to try to find a range for a 64-bit
+ * BAR, i.e., vmbus_alloc_resource(), we can make sure we try to use
+ * >4GB range first.
+ */
+ if (e->start < (1ULL << 32))
+ TAILQ_INSERT_TAIL(&sc->vmbus_mmio_list, e, link);
+ else
+ TAILQ_INSERT_HEAD(&sc->vmbus_mmio_list, e, link);
+
+ return (AE_OK);
+}
+
+static void
+vmbus_get_crs(device_t dev, device_t vmbus_dev)
+{
+ ACPI_STATUS status;
+
+ if (bootverbose)
+ device_printf(dev, "walking _CRS\n");
+
+ status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+ parse_crs, vmbus_dev);
+
+ if (bootverbose && ACPI_FAILURE(status))
+ device_printf(dev, "_CRS: not found\n");
+}
+
+static void
+vmbus_get_mmio_list(device_t dev)
+{
+ struct vmbus_softc *sc = device_get_softc(dev);
+ device_t acpi0, pcib0 = NULL;
+ device_t *children;
+ int i, count;
+
+ TAILQ_INIT(&sc->vmbus_mmio_list);
+
+ /* Try to find _CRS on VMBus device */
+ vmbus_get_crs(dev, dev);
+
+ /* Try to find _CRS on VMBus device's parent */
+ acpi0 = device_get_parent(dev);
+ vmbus_get_crs(acpi0, dev);
+
+ /* 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;
+ }
+ free(children, M_TEMP);
+
+ if (pcib0)
+ vmbus_get_crs(pcib0, dev);
+}
+
+static void
+vmbus_free_mmio_list(device_t dev)
+{
+ struct vmbus_softc *sc = device_get_softc(dev);
+ struct vmbus_mmio_entry *e;
+
+ while ((e = TAILQ_FIRST(&sc->vmbus_mmio_list)) != NULL) {
+ TAILQ_REMOVE(&sc->vmbus_mmio_list, e, link);
+ free(e, M_DEVBUF);
+ }
+}
+
static int
vmbus_probe(device_t dev)
{
@@ -1037,6 +1275,9 @@
if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
return (0);
+
+ vmbus_get_mmio_list(sc->vmbus_dev);
+
sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
sc->vmbus_gpadl = VMBUS_GPADL_START;
@@ -1183,6 +1424,8 @@
mtx_destroy(&sc->vmbus_prichan_lock);
mtx_destroy(&sc->vmbus_chan_lock);
+ vmbus_free_mmio_list(dev);
+
return (0);
}
Index: sys/dev/hyperv/vmbus/vmbus_var.h
===================================================================
--- sys/dev/hyperv/vmbus/vmbus_var.h
+++ sys/dev/hyperv/vmbus/vmbus_var.h
@@ -77,6 +77,18 @@
struct task message_task; /* message task */
} __aligned(CACHE_LINE_SIZE);
+#if __FreeBSD_version < 1100000
+typedef u_long rman_res_t;
+#define RM_MAX_END (~(rman_res_t)0)
+#define RMAN_IS_DEFAULT_RANGE(s,e) ((s) == 0 && (e) == RM_MAX_END)
+#endif
+
+struct vmbus_mmio_entry {
+ TAILQ_ENTRY(vmbus_mmio_entry) link;
+ rman_res_t start;
+ rman_res_t end;
+};
+
struct vmbus_softc {
void (*vmbus_event_proc)(struct vmbus_softc *, int);
u_long *vmbus_tx_evtflags;
@@ -120,6 +132,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 */
+ TAILQ_HEAD(, vmbus_mmio_entry) vmbus_mmio_list;
};
#define VMBUS_FLAG_ATTACHED 0x0001 /* vmbus was attached */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 29, 4:38 AM (10 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26279264
Default Alt Text
D8409.id21878.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