From owner-svn-src-head@freebsd.org Wed Nov 16 09:08:33 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id EBB16C41AF1; Wed, 16 Nov 2016 09:08:33 +0000 (UTC) (envelope-from dexuan@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C83915E6; Wed, 16 Nov 2016 09:08:33 +0000 (UTC) (envelope-from dexuan@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAG98XBa052229; Wed, 16 Nov 2016 09:08:33 GMT (envelope-from dexuan@FreeBSD.org) Received: (from dexuan@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAG98WjC052227; Wed, 16 Nov 2016 09:08:32 GMT (envelope-from dexuan@FreeBSD.org) Message-Id: <201611160908.uAG98WjC052227@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: dexuan set sender to dexuan@FreeBSD.org using -f From: Dexuan Cui Date: Wed, 16 Nov 2016 09:08:32 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308724 - head/sys/dev/hyperv/vmbus X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Nov 2016 09:08:34 -0000 Author: dexuan Date: Wed Nov 16 09:08:32 2016 New Revision: 308724 URL: https://svnweb.freebsd.org/changeset/base/308724 Log: hyperv/vmbus: add new vmbus methods to support PCIe pass-through The new methods will be used by the coming pcib driver. Reviewed by: sephe Approved by: sephe (mentor) MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8409 Modified: head/sys/dev/hyperv/vmbus/vmbus.c head/sys/dev/hyperv/vmbus/vmbus_var.h Modified: head/sys/dev/hyperv/vmbus/vmbus.c ============================================================================== --- head/sys/dev/hyperv/vmbus/vmbus.c Wed Nov 16 09:02:17 2016 (r308723) +++ head/sys/dev/hyperv/vmbus/vmbus.c Wed Nov 16 09:08:32 2016 (r308724) @@ -44,10 +44,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include +#include #include #include @@ -58,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include "acpi_if.h" +#include "pcib_if.h" #include "vmbus_if.h" #define VMBUS_GPADL_START 0xe1e10 @@ -74,6 +78,20 @@ static int vmbus_read_ivar(device_t, d 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 @@ static device_method_t vmbus_methods[] = 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 @@ vmbus_sysctl_version(SYSCTL_HANDLER_ARGS 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 @@ vmbus_get_vcpu_id_method(device_t bus, d 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 @@ vmbus_doattach(struct vmbus_softc *sc) 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 @@ vmbus_detach(device_t dev) mtx_destroy(&sc->vmbus_prichan_lock); mtx_destroy(&sc->vmbus_chan_lock); + vmbus_free_mmio_res(dev); + return (0); } Modified: head/sys/dev/hyperv/vmbus/vmbus_var.h ============================================================================== --- head/sys/dev/hyperv/vmbus/vmbus_var.h Wed Nov 16 09:02:17 2016 (r308723) +++ head/sys/dev/hyperv/vmbus/vmbus_var.h Wed Nov 16 09:08:32 2016 (r308724) @@ -31,8 +31,11 @@ #include #include +#include #include +#include +#include /* * NOTE: DO NOT CHANGE THIS. @@ -77,6 +80,10 @@ struct vmbus_pcpu_data { 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 @@ struct vmbus_softc { /* 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 */