18c582c7cSDexuan Cui /*- 293b4e111SSepherosa Ziehau * Copyright (c) 2016-2017 Microsoft Corp. 38c582c7cSDexuan Cui * All rights reserved. 48c582c7cSDexuan Cui * 58c582c7cSDexuan Cui * Redistribution and use in source and binary forms, with or without 68c582c7cSDexuan Cui * modification, are permitted provided that the following conditions 78c582c7cSDexuan Cui * are met: 88c582c7cSDexuan Cui * 1. Redistributions of source code must retain the above copyright 98c582c7cSDexuan Cui * notice, this list of conditions and the following disclaimer. 108c582c7cSDexuan Cui * 2. Redistributions in binary form must reproduce the above copyright 118c582c7cSDexuan Cui * notice, this list of conditions and the following disclaimer in the 128c582c7cSDexuan Cui * documentation and/or other materials provided with the distribution. 138c582c7cSDexuan Cui * 148c582c7cSDexuan Cui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158c582c7cSDexuan Cui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168c582c7cSDexuan Cui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178c582c7cSDexuan Cui * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188c582c7cSDexuan Cui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198c582c7cSDexuan Cui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208c582c7cSDexuan Cui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218c582c7cSDexuan Cui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228c582c7cSDexuan Cui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238c582c7cSDexuan Cui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248c582c7cSDexuan Cui * SUCH DAMAGE. 258c582c7cSDexuan Cui */ 268c582c7cSDexuan Cui 278c582c7cSDexuan Cui #include <sys/cdefs.h> 28cdb316eeSDexuan Cui #ifdef NEW_PCIB 296e5b082cSWei Hu #include "opt_acpi.h" 30cdb316eeSDexuan Cui 318c582c7cSDexuan Cui #include <sys/param.h> 328c582c7cSDexuan Cui #include <sys/systm.h> 338c582c7cSDexuan Cui #include <sys/types.h> 348c582c7cSDexuan Cui #include <sys/malloc.h> 358c582c7cSDexuan Cui #include <sys/module.h> 368c582c7cSDexuan Cui #include <sys/kernel.h> 378c582c7cSDexuan Cui #include <sys/queue.h> 388c582c7cSDexuan Cui #include <sys/lock.h> 398c582c7cSDexuan Cui #include <sys/sx.h> 408c582c7cSDexuan Cui #include <sys/smp.h> 418c582c7cSDexuan Cui #include <sys/sysctl.h> 428c582c7cSDexuan Cui #include <sys/bus.h> 438c582c7cSDexuan Cui #include <sys/rman.h> 448c582c7cSDexuan Cui #include <sys/mutex.h> 458c582c7cSDexuan Cui #include <sys/errno.h> 468c582c7cSDexuan Cui 478c582c7cSDexuan Cui #include <vm/vm.h> 488c582c7cSDexuan Cui #include <vm/vm_param.h> 498c582c7cSDexuan Cui #include <vm/vm_kern.h> 508c582c7cSDexuan Cui #include <vm/pmap.h> 518c582c7cSDexuan Cui 526e5b082cSWei Hu #if defined(__aarch64__) 536e5b082cSWei Hu #include <arm64/include/intr.h> 546e5b082cSWei Hu #endif 558c582c7cSDexuan Cui #include <machine/atomic.h> 568c582c7cSDexuan Cui #include <machine/bus.h> 578c582c7cSDexuan Cui #include <machine/frame.h> 588c582c7cSDexuan Cui #include <machine/pci_cfgreg.h> 598c582c7cSDexuan Cui #include <machine/resource.h> 608c582c7cSDexuan Cui 618c582c7cSDexuan Cui #include <sys/pciio.h> 628c582c7cSDexuan Cui #include <dev/pci/pcireg.h> 638c582c7cSDexuan Cui #include <dev/pci/pcivar.h> 648c582c7cSDexuan Cui #include <dev/pci/pci_private.h> 658c582c7cSDexuan Cui #include <dev/pci/pcib_private.h> 668c582c7cSDexuan Cui #include "pcib_if.h" 676e5b082cSWei Hu #if defined(__i386__) || defined(__amd64__) 688c582c7cSDexuan Cui #include <machine/intr_machdep.h> 698c582c7cSDexuan Cui #include <x86/apicreg.h> 70999174baSWei Hu #include <x86/apicvar.h> 716e5b082cSWei Hu #endif 726e5b082cSWei Hu #if defined(__aarch64__) 736e5b082cSWei Hu #include <contrib/dev/acpica/include/acpi.h> 746e5b082cSWei Hu #include <contrib/dev/acpica/include/accommon.h> 756e5b082cSWei Hu #include <dev/acpica/acpivar.h> 766e5b082cSWei Hu #include <dev/acpica/acpi_pcibvar.h> 776e5b082cSWei Hu #endif 788c582c7cSDexuan Cui #include <dev/hyperv/include/hyperv.h> 798c582c7cSDexuan Cui #include <dev/hyperv/include/vmbus_xact.h> 808c582c7cSDexuan Cui #include <dev/hyperv/vmbus/vmbus_reg.h> 818c582c7cSDexuan Cui #include <dev/hyperv/vmbus/vmbus_chanvar.h> 828c582c7cSDexuan Cui 838c582c7cSDexuan Cui #include "vmbus_if.h" 848c582c7cSDexuan Cui 858c582c7cSDexuan Cui struct completion { 868c582c7cSDexuan Cui unsigned int done; 878c582c7cSDexuan Cui struct mtx lock; 888c582c7cSDexuan Cui }; 898c582c7cSDexuan Cui 908c582c7cSDexuan Cui static void 918c582c7cSDexuan Cui init_completion(struct completion *c) 928c582c7cSDexuan Cui { 938c582c7cSDexuan Cui memset(c, 0, sizeof(*c)); 948c582c7cSDexuan Cui mtx_init(&c->lock, "hvcmpl", NULL, MTX_DEF); 958c582c7cSDexuan Cui c->done = 0; 968c582c7cSDexuan Cui } 97ea11861eSWei Hu static void 98ea11861eSWei Hu reinit_completion(struct completion *c) 99ea11861eSWei Hu { 100ea11861eSWei Hu c->done = 0; 101ea11861eSWei Hu } 1028c582c7cSDexuan Cui static void 1038c582c7cSDexuan Cui free_completion(struct completion *c) 1048c582c7cSDexuan Cui { 1058c582c7cSDexuan Cui mtx_destroy(&c->lock); 1068c582c7cSDexuan Cui } 1078c582c7cSDexuan Cui 1088c582c7cSDexuan Cui static void 1098c582c7cSDexuan Cui complete(struct completion *c) 1108c582c7cSDexuan Cui { 1118c582c7cSDexuan Cui mtx_lock(&c->lock); 1128c582c7cSDexuan Cui c->done++; 1138c582c7cSDexuan Cui mtx_unlock(&c->lock); 1148c582c7cSDexuan Cui wakeup(c); 1158c582c7cSDexuan Cui } 1168c582c7cSDexuan Cui 1178c582c7cSDexuan Cui static void 1188c582c7cSDexuan Cui wait_for_completion(struct completion *c) 1198c582c7cSDexuan Cui { 1208c582c7cSDexuan Cui mtx_lock(&c->lock); 1218c582c7cSDexuan Cui while (c->done == 0) 1228c582c7cSDexuan Cui mtx_sleep(c, &c->lock, 0, "hvwfc", 0); 1238c582c7cSDexuan Cui c->done--; 1248c582c7cSDexuan Cui mtx_unlock(&c->lock); 1258c582c7cSDexuan Cui } 1268c582c7cSDexuan Cui 12775c2786cSWei Hu /* 12875c2786cSWei Hu * Return: 0 if completed, a non-zero value if timed out. 12975c2786cSWei Hu */ 13075c2786cSWei Hu static int 13175c2786cSWei Hu wait_for_completion_timeout(struct completion *c, int timeout) 13275c2786cSWei Hu { 13375c2786cSWei Hu int ret; 13475c2786cSWei Hu 13575c2786cSWei Hu mtx_lock(&c->lock); 13675c2786cSWei Hu 13775c2786cSWei Hu if (c->done == 0) 13875c2786cSWei Hu mtx_sleep(c, &c->lock, 0, "hvwfc", timeout); 13975c2786cSWei Hu 14075c2786cSWei Hu if (c->done > 0) { 14175c2786cSWei Hu c->done--; 14275c2786cSWei Hu ret = 0; 14375c2786cSWei Hu } else { 14475c2786cSWei Hu ret = 1; 14575c2786cSWei Hu } 14675c2786cSWei Hu 14775c2786cSWei Hu mtx_unlock(&c->lock); 14875c2786cSWei Hu 14975c2786cSWei Hu return (ret); 15075c2786cSWei Hu } 15175c2786cSWei Hu 152ea11861eSWei Hu #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 1536e5b082cSWei Hu #define PCI_MAKE_VERSION(major, minor) ((uint32_t)(((major) << 16) | (minor))) 1548c582c7cSDexuan Cui 155ea11861eSWei Hu enum pci_protocol_version_t { 1568c582c7cSDexuan Cui PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1), 157ea11861eSWei Hu PCI_PROTOCOL_VERSION_1_4 = PCI_MAKE_VERSION(1, 4), 158ea11861eSWei Hu }; 159ea11861eSWei Hu 160ea11861eSWei Hu static enum pci_protocol_version_t pci_protocol_versions[] = { 161ea11861eSWei Hu PCI_PROTOCOL_VERSION_1_4, 162ea11861eSWei Hu PCI_PROTOCOL_VERSION_1_1, 1638c582c7cSDexuan Cui }; 1648c582c7cSDexuan Cui 1658c582c7cSDexuan Cui #define PCI_CONFIG_MMIO_LENGTH 0x2000 1668c582c7cSDexuan Cui #define CFG_PAGE_OFFSET 0x1000 1678c582c7cSDexuan Cui #define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET) 1688c582c7cSDexuan Cui 1698c582c7cSDexuan Cui /* 1708c582c7cSDexuan Cui * Message Types 1718c582c7cSDexuan Cui */ 1728c582c7cSDexuan Cui 1738c582c7cSDexuan Cui enum pci_message_type { 1748c582c7cSDexuan Cui /* 1758c582c7cSDexuan Cui * Version 1.1 1768c582c7cSDexuan Cui */ 1778c582c7cSDexuan Cui PCI_MESSAGE_BASE = 0x42490000, 1788c582c7cSDexuan Cui PCI_BUS_RELATIONS = PCI_MESSAGE_BASE + 0, 1798c582c7cSDexuan Cui PCI_QUERY_BUS_RELATIONS = PCI_MESSAGE_BASE + 1, 1808c582c7cSDexuan Cui PCI_POWER_STATE_CHANGE = PCI_MESSAGE_BASE + 4, 1818c582c7cSDexuan Cui PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5, 1828c582c7cSDexuan Cui PCI_QUERY_RESOURCE_RESOURCES = PCI_MESSAGE_BASE + 6, 1838c582c7cSDexuan Cui PCI_BUS_D0ENTRY = PCI_MESSAGE_BASE + 7, 1848c582c7cSDexuan Cui PCI_BUS_D0EXIT = PCI_MESSAGE_BASE + 8, 1858c582c7cSDexuan Cui PCI_READ_BLOCK = PCI_MESSAGE_BASE + 9, 1868c582c7cSDexuan Cui PCI_WRITE_BLOCK = PCI_MESSAGE_BASE + 0xA, 1878c582c7cSDexuan Cui PCI_EJECT = PCI_MESSAGE_BASE + 0xB, 1888c582c7cSDexuan Cui PCI_QUERY_STOP = PCI_MESSAGE_BASE + 0xC, 1898c582c7cSDexuan Cui PCI_REENABLE = PCI_MESSAGE_BASE + 0xD, 1908c582c7cSDexuan Cui PCI_QUERY_STOP_FAILED = PCI_MESSAGE_BASE + 0xE, 1918c582c7cSDexuan Cui PCI_EJECTION_COMPLETE = PCI_MESSAGE_BASE + 0xF, 1928c582c7cSDexuan Cui PCI_RESOURCES_ASSIGNED = PCI_MESSAGE_BASE + 0x10, 1938c582c7cSDexuan Cui PCI_RESOURCES_RELEASED = PCI_MESSAGE_BASE + 0x11, 1948c582c7cSDexuan Cui PCI_INVALIDATE_BLOCK = PCI_MESSAGE_BASE + 0x12, 1958c582c7cSDexuan Cui PCI_QUERY_PROTOCOL_VERSION = PCI_MESSAGE_BASE + 0x13, 1968c582c7cSDexuan Cui PCI_CREATE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x14, 1978c582c7cSDexuan Cui PCI_DELETE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x15, 1986e5b082cSWei Hu PCI_RESOURCES_ASSIGNED2 = PCI_MESSAGE_BASE + 0x16, 1996e5b082cSWei Hu PCI_CREATE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x17, 2006e5b082cSWei Hu PCI_DELETE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x18, /* unused */ 2016e5b082cSWei Hu PCI_BUS_RELATIONS2 = PCI_MESSAGE_BASE + 0x19, 2026e5b082cSWei Hu PCI_RESOURCES_ASSIGNED3 = PCI_MESSAGE_BASE + 0x1A, 2036e5b082cSWei Hu PCI_CREATE_INTERRUPT_MESSAGE3 = PCI_MESSAGE_BASE + 0x1B, 2048c582c7cSDexuan Cui PCI_MESSAGE_MAXIMUM 2058c582c7cSDexuan Cui }; 2068c582c7cSDexuan Cui 207ea11861eSWei Hu #define STATUS_REVISION_MISMATCH 0xC0000059 208ea11861eSWei Hu 2098c582c7cSDexuan Cui /* 2108c582c7cSDexuan Cui * Structures defining the virtual PCI Express protocol. 2118c582c7cSDexuan Cui */ 2128c582c7cSDexuan Cui 2138c582c7cSDexuan Cui union pci_version { 2148c582c7cSDexuan Cui struct { 2158c582c7cSDexuan Cui uint16_t minor_version; 2168c582c7cSDexuan Cui uint16_t major_version; 2178c582c7cSDexuan Cui } parts; 2188c582c7cSDexuan Cui uint32_t version; 2198c582c7cSDexuan Cui } __packed; 2208c582c7cSDexuan Cui 2218c582c7cSDexuan Cui /* 2228c582c7cSDexuan Cui * This representation is the one used in Windows, which is 2238c582c7cSDexuan Cui * what is expected when sending this back and forth with 2248c582c7cSDexuan Cui * the Hyper-V parent partition. 2258c582c7cSDexuan Cui */ 2268c582c7cSDexuan Cui union win_slot_encoding { 2278c582c7cSDexuan Cui struct { 2288c582c7cSDexuan Cui uint32_t slot:5; 2298c582c7cSDexuan Cui uint32_t func:3; 2308c582c7cSDexuan Cui uint32_t reserved:24; 2318c582c7cSDexuan Cui } bits; 2328c582c7cSDexuan Cui uint32_t val; 2338c582c7cSDexuan Cui } __packed; 2348c582c7cSDexuan Cui 2358c582c7cSDexuan Cui struct pci_func_desc { 2368c582c7cSDexuan Cui uint16_t v_id; /* vendor ID */ 2378c582c7cSDexuan Cui uint16_t d_id; /* device ID */ 2388c582c7cSDexuan Cui uint8_t rev; 2398c582c7cSDexuan Cui uint8_t prog_intf; 2408c582c7cSDexuan Cui uint8_t subclass; 2418c582c7cSDexuan Cui uint8_t base_class; 2428c582c7cSDexuan Cui uint32_t subsystem_id; 2438c582c7cSDexuan Cui union win_slot_encoding wslot; 2448c582c7cSDexuan Cui uint32_t ser; /* serial number */ 2458c582c7cSDexuan Cui } __packed; 2468c582c7cSDexuan Cui 2476e5b082cSWei Hu struct pci_func_desc2 { 2486e5b082cSWei Hu uint16_t v_id; /* vendor ID */ 2496e5b082cSWei Hu uint16_t d_id; /* device ID */ 2506e5b082cSWei Hu uint8_t rev; 2516e5b082cSWei Hu uint8_t prog_intf; 2526e5b082cSWei Hu uint8_t subclass; 2536e5b082cSWei Hu uint8_t base_class; 2546e5b082cSWei Hu uint32_t subsystem_id; 2556e5b082cSWei Hu union win_slot_encoding wslot; 2566e5b082cSWei Hu uint32_t ser; /* serial number */ 2576e5b082cSWei Hu uint32_t flags; 2586e5b082cSWei Hu uint16_t virtual_numa_node; 2596e5b082cSWei Hu uint16_t reserved; 2606e5b082cSWei Hu } __packed; 2616e5b082cSWei Hu 2626e5b082cSWei Hu 2638c582c7cSDexuan Cui struct hv_msi_desc { 2648c582c7cSDexuan Cui uint8_t vector; 2658c582c7cSDexuan Cui uint8_t delivery_mode; 2668c582c7cSDexuan Cui uint16_t vector_count; 2678c582c7cSDexuan Cui uint32_t reserved; 2688c582c7cSDexuan Cui uint64_t cpu_mask; 2698c582c7cSDexuan Cui } __packed; 2708c582c7cSDexuan Cui 2716e5b082cSWei Hu struct hv_msi_desc3 { 2726e5b082cSWei Hu uint32_t vector; 2736e5b082cSWei Hu uint8_t delivery_mode; 2746e5b082cSWei Hu uint8_t reserved; 2756e5b082cSWei Hu uint16_t vector_count; 2766e5b082cSWei Hu uint16_t processor_count; 2776e5b082cSWei Hu uint16_t processor_array[32]; 2786e5b082cSWei Hu } __packed; 2796e5b082cSWei Hu 2808c582c7cSDexuan Cui struct tran_int_desc { 2818c582c7cSDexuan Cui uint16_t reserved; 2828c582c7cSDexuan Cui uint16_t vector_count; 2838c582c7cSDexuan Cui uint32_t data; 2848c582c7cSDexuan Cui uint64_t address; 2858c582c7cSDexuan Cui } __packed; 2868c582c7cSDexuan Cui 2878c582c7cSDexuan Cui struct pci_message { 2888c582c7cSDexuan Cui uint32_t type; 2898c582c7cSDexuan Cui } __packed; 2908c582c7cSDexuan Cui 2918c582c7cSDexuan Cui struct pci_child_message { 2928c582c7cSDexuan Cui struct pci_message message_type; 2938c582c7cSDexuan Cui union win_slot_encoding wslot; 2948c582c7cSDexuan Cui } __packed; 2958c582c7cSDexuan Cui 2968c582c7cSDexuan Cui struct pci_incoming_message { 2978c582c7cSDexuan Cui struct vmbus_chanpkt_hdr hdr; 2988c582c7cSDexuan Cui struct pci_message message_type; 2998c582c7cSDexuan Cui } __packed; 3008c582c7cSDexuan Cui 3018c582c7cSDexuan Cui struct pci_response { 3028c582c7cSDexuan Cui struct vmbus_chanpkt_hdr hdr; 3038c582c7cSDexuan Cui int32_t status; /* negative values are failures */ 3048c582c7cSDexuan Cui } __packed; 3058c582c7cSDexuan Cui 3068c582c7cSDexuan Cui struct pci_packet { 3078c582c7cSDexuan Cui void (*completion_func)(void *context, struct pci_response *resp, 3088c582c7cSDexuan Cui int resp_packet_size); 3098c582c7cSDexuan Cui void *compl_ctxt; 3108c582c7cSDexuan Cui 3118c582c7cSDexuan Cui struct pci_message message[0]; 3128c582c7cSDexuan Cui }; 3138c582c7cSDexuan Cui 3148c582c7cSDexuan Cui /* 3158c582c7cSDexuan Cui * Specific message types supporting the PCI protocol. 3168c582c7cSDexuan Cui */ 3178c582c7cSDexuan Cui 3188c582c7cSDexuan Cui struct pci_version_request { 3198c582c7cSDexuan Cui struct pci_message message_type; 3208c582c7cSDexuan Cui uint32_t protocol_version; 3218c582c7cSDexuan Cui uint32_t reservedz:31; 3228c582c7cSDexuan Cui } __packed; 3238c582c7cSDexuan Cui 3248c582c7cSDexuan Cui struct pci_bus_d0_entry { 3258c582c7cSDexuan Cui struct pci_message message_type; 3268c582c7cSDexuan Cui uint32_t reserved; 3278c582c7cSDexuan Cui uint64_t mmio_base; 3288c582c7cSDexuan Cui } __packed; 3298c582c7cSDexuan Cui 3308c582c7cSDexuan Cui struct pci_bus_relations { 3318c582c7cSDexuan Cui struct pci_incoming_message incoming; 3328c582c7cSDexuan Cui uint32_t device_count; 3338c582c7cSDexuan Cui struct pci_func_desc func[0]; 3348c582c7cSDexuan Cui } __packed; 3358c582c7cSDexuan Cui 3366e5b082cSWei Hu struct pci_bus_relations2 { 3376e5b082cSWei Hu struct pci_incoming_message incoming; 3386e5b082cSWei Hu uint32_t device_count; 3396e5b082cSWei Hu struct pci_func_desc2 func[0]; 3406e5b082cSWei Hu } __packed; 3416e5b082cSWei Hu 3428c582c7cSDexuan Cui #define MAX_NUM_BARS (PCIR_MAX_BAR_0 + 1) 3438c582c7cSDexuan Cui struct pci_q_res_req_response { 3448c582c7cSDexuan Cui struct vmbus_chanpkt_hdr hdr; 3458c582c7cSDexuan Cui int32_t status; /* negative values are failures */ 3468c582c7cSDexuan Cui uint32_t probed_bar[MAX_NUM_BARS]; 3478c582c7cSDexuan Cui } __packed; 3488c582c7cSDexuan Cui 3498c582c7cSDexuan Cui struct pci_resources_assigned { 3508c582c7cSDexuan Cui struct pci_message message_type; 3518c582c7cSDexuan Cui union win_slot_encoding wslot; 3528c582c7cSDexuan Cui uint8_t memory_range[0x14][MAX_NUM_BARS]; /* unused here */ 3538c582c7cSDexuan Cui uint32_t msi_descriptors; 3548c582c7cSDexuan Cui uint32_t reserved[4]; 3558c582c7cSDexuan Cui } __packed; 3568c582c7cSDexuan Cui 3576e5b082cSWei Hu struct pci_resources_assigned2 { 3586e5b082cSWei Hu struct pci_message message_type; 3596e5b082cSWei Hu union win_slot_encoding wslot; 3606e5b082cSWei Hu uint8_t memory_range[0x14][6]; /* not used here */ 3616e5b082cSWei Hu uint32_t msi_descriptor_count; 3626e5b082cSWei Hu uint8_t reserved[70]; 3636e5b082cSWei Hu } __packed; 3646e5b082cSWei Hu 3658c582c7cSDexuan Cui struct pci_create_interrupt { 3668c582c7cSDexuan Cui struct pci_message message_type; 3678c582c7cSDexuan Cui union win_slot_encoding wslot; 3688c582c7cSDexuan Cui struct hv_msi_desc int_desc; 3698c582c7cSDexuan Cui } __packed; 3708c582c7cSDexuan Cui 3716e5b082cSWei Hu struct pci_create_interrupt3 { 3726e5b082cSWei Hu struct pci_message message_type; 3736e5b082cSWei Hu union win_slot_encoding wslot; 3746e5b082cSWei Hu struct hv_msi_desc3 int_desc; 3756e5b082cSWei Hu } __packed; 3766e5b082cSWei Hu 3778c582c7cSDexuan Cui struct pci_create_int_response { 3788c582c7cSDexuan Cui struct pci_response response; 3798c582c7cSDexuan Cui uint32_t reserved; 3808c582c7cSDexuan Cui struct tran_int_desc int_desc; 3818c582c7cSDexuan Cui } __packed; 3828c582c7cSDexuan Cui 3838c582c7cSDexuan Cui struct pci_delete_interrupt { 3848c582c7cSDexuan Cui struct pci_message message_type; 3858c582c7cSDexuan Cui union win_slot_encoding wslot; 3868c582c7cSDexuan Cui struct tran_int_desc int_desc; 3878c582c7cSDexuan Cui } __packed; 3888c582c7cSDexuan Cui 3898c582c7cSDexuan Cui struct pci_dev_incoming { 3908c582c7cSDexuan Cui struct pci_incoming_message incoming; 3918c582c7cSDexuan Cui union win_slot_encoding wslot; 3928c582c7cSDexuan Cui } __packed; 3938c582c7cSDexuan Cui 3948c582c7cSDexuan Cui struct pci_eject_response { 3958c582c7cSDexuan Cui struct pci_message message_type; 3968c582c7cSDexuan Cui union win_slot_encoding wslot; 3978c582c7cSDexuan Cui uint32_t status; 3988c582c7cSDexuan Cui } __packed; 3998c582c7cSDexuan Cui 4008c582c7cSDexuan Cui /* 4018c582c7cSDexuan Cui * Driver specific state. 4028c582c7cSDexuan Cui */ 4038c582c7cSDexuan Cui 4048c582c7cSDexuan Cui enum hv_pcibus_state { 4058c582c7cSDexuan Cui hv_pcibus_init = 0, 4068c582c7cSDexuan Cui hv_pcibus_installed, 4078c582c7cSDexuan Cui }; 4088c582c7cSDexuan Cui 4098c582c7cSDexuan Cui struct hv_pcibus { 4108c582c7cSDexuan Cui device_t pcib; 4118c582c7cSDexuan Cui device_t pci_bus; 4128c582c7cSDexuan Cui struct vmbus_pcib_softc *sc; 4138c582c7cSDexuan Cui 4148c582c7cSDexuan Cui uint16_t pci_domain; 4158c582c7cSDexuan Cui 4168c582c7cSDexuan Cui enum hv_pcibus_state state; 4178c582c7cSDexuan Cui 4188c582c7cSDexuan Cui struct resource *cfg_res; 4198c582c7cSDexuan Cui 4208c582c7cSDexuan Cui struct completion query_completion, *query_comp; 4218c582c7cSDexuan Cui 4228c582c7cSDexuan Cui struct mtx config_lock; /* Avoid two threads writing index page */ 4238c582c7cSDexuan Cui struct mtx device_list_lock; /* Protect lists below */ 4246e5b082cSWei Hu uint32_t protocol_version; 4258c582c7cSDexuan Cui TAILQ_HEAD(, hv_pci_dev) children; 4268c582c7cSDexuan Cui TAILQ_HEAD(, hv_dr_state) dr_list; 4278c582c7cSDexuan Cui 4288c582c7cSDexuan Cui volatile int detaching; 4298c582c7cSDexuan Cui }; 4308c582c7cSDexuan Cui 4316e5b082cSWei Hu struct hv_pcidev_desc { 4326e5b082cSWei Hu uint16_t v_id; /* vendor ID */ 4336e5b082cSWei Hu uint16_t d_id; /* device ID */ 4346e5b082cSWei Hu uint8_t rev; 4356e5b082cSWei Hu uint8_t prog_intf; 4366e5b082cSWei Hu uint8_t subclass; 4376e5b082cSWei Hu uint8_t base_class; 4386e5b082cSWei Hu uint32_t subsystem_id; 4396e5b082cSWei Hu union win_slot_encoding wslot; 4406e5b082cSWei Hu uint32_t ser; /* serial number */ 4416e5b082cSWei Hu uint32_t flags; 4426e5b082cSWei Hu uint16_t virtual_numa_node; 4436e5b082cSWei Hu } __packed; 4446e5b082cSWei Hu 4458c582c7cSDexuan Cui struct hv_pci_dev { 4468c582c7cSDexuan Cui TAILQ_ENTRY(hv_pci_dev) link; 4478c582c7cSDexuan Cui 448ea11861eSWei Hu struct hv_pcidev_desc desc; 4498c582c7cSDexuan Cui 4508c582c7cSDexuan Cui bool reported_missing; 4518c582c7cSDexuan Cui 4528c582c7cSDexuan Cui struct hv_pcibus *hbus; 4538c582c7cSDexuan Cui struct task eject_task; 4548c582c7cSDexuan Cui 4558c582c7cSDexuan Cui TAILQ_HEAD(, hv_irq_desc) irq_desc_list; 4568c582c7cSDexuan Cui 4578c582c7cSDexuan Cui /* 4588c582c7cSDexuan Cui * What would be observed if one wrote 0xFFFFFFFF to a BAR and then 4598c582c7cSDexuan Cui * read it back, for each of the BAR offsets within config space. 4608c582c7cSDexuan Cui */ 4618c582c7cSDexuan Cui uint32_t probed_bar[MAX_NUM_BARS]; 4628c582c7cSDexuan Cui }; 4638c582c7cSDexuan Cui 4648c582c7cSDexuan Cui /* 4658c582c7cSDexuan Cui * Tracks "Device Relations" messages from the host, which must be both 4668c582c7cSDexuan Cui * processed in order. 4678c582c7cSDexuan Cui */ 4688c582c7cSDexuan Cui struct hv_dr_work { 4698c582c7cSDexuan Cui struct task task; 4708c582c7cSDexuan Cui struct hv_pcibus *bus; 4718c582c7cSDexuan Cui }; 4728c582c7cSDexuan Cui 4738c582c7cSDexuan Cui struct hv_dr_state { 4748c582c7cSDexuan Cui TAILQ_ENTRY(hv_dr_state) link; 4758c582c7cSDexuan Cui uint32_t device_count; 476ea11861eSWei Hu struct hv_pcidev_desc func[0]; 4778c582c7cSDexuan Cui }; 4788c582c7cSDexuan Cui 4798c582c7cSDexuan Cui struct hv_irq_desc { 4808c582c7cSDexuan Cui TAILQ_ENTRY(hv_irq_desc) link; 4818c582c7cSDexuan Cui struct tran_int_desc desc; 4828c582c7cSDexuan Cui int irq; 4838c582c7cSDexuan Cui }; 4848c582c7cSDexuan Cui 4858c582c7cSDexuan Cui #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 4868c582c7cSDexuan Cui #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) 4878c582c7cSDexuan Cui #define PCI_FUNC(devfn) ((devfn) & 0x07) 4888c582c7cSDexuan Cui 4898c582c7cSDexuan Cui static uint32_t 4908c582c7cSDexuan Cui devfn_to_wslot(unsigned int devfn) 4918c582c7cSDexuan Cui { 4928c582c7cSDexuan Cui union win_slot_encoding wslot; 4938c582c7cSDexuan Cui 4948c582c7cSDexuan Cui wslot.val = 0; 4958c582c7cSDexuan Cui wslot.bits.slot = PCI_SLOT(devfn); 4968c582c7cSDexuan Cui wslot.bits.func = PCI_FUNC(devfn); 4978c582c7cSDexuan Cui 4988c582c7cSDexuan Cui return (wslot.val); 4998c582c7cSDexuan Cui } 5008c582c7cSDexuan Cui 5018c582c7cSDexuan Cui static unsigned int 5028c582c7cSDexuan Cui wslot_to_devfn(uint32_t wslot) 5038c582c7cSDexuan Cui { 5048c582c7cSDexuan Cui union win_slot_encoding encoding; 5058c582c7cSDexuan Cui unsigned int slot; 5068c582c7cSDexuan Cui unsigned int func; 5078c582c7cSDexuan Cui 5088c582c7cSDexuan Cui encoding.val = wslot; 5098c582c7cSDexuan Cui 5108c582c7cSDexuan Cui slot = encoding.bits.slot; 5118c582c7cSDexuan Cui func = encoding.bits.func; 5128c582c7cSDexuan Cui 5138c582c7cSDexuan Cui return (PCI_DEVFN(slot, func)); 5148c582c7cSDexuan Cui } 5158c582c7cSDexuan Cui 5168c582c7cSDexuan Cui struct vmbus_pcib_softc { 5178c582c7cSDexuan Cui struct vmbus_channel *chan; 5188c582c7cSDexuan Cui void *rx_buf; 5198c582c7cSDexuan Cui 5208c582c7cSDexuan Cui struct taskqueue *taskq; 5218c582c7cSDexuan Cui 5228c582c7cSDexuan Cui struct hv_pcibus *hbus; 5238c582c7cSDexuan Cui }; 5248c582c7cSDexuan Cui 5258c582c7cSDexuan Cui /* {44C4F61D-4444-4400-9D52-802E27EDE19F} */ 5268c582c7cSDexuan Cui static const struct hyperv_guid g_pass_through_dev_type = { 5278c582c7cSDexuan Cui .hv_guid = {0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44, 5288c582c7cSDexuan Cui 0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F} 5298c582c7cSDexuan Cui }; 5308c582c7cSDexuan Cui 5318c582c7cSDexuan Cui struct hv_pci_compl { 5328c582c7cSDexuan Cui struct completion host_event; 5338c582c7cSDexuan Cui int32_t completion_status; 5348c582c7cSDexuan Cui }; 5358c582c7cSDexuan Cui 5368c582c7cSDexuan Cui struct q_res_req_compl { 5378c582c7cSDexuan Cui struct completion host_event; 5388c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 5398c582c7cSDexuan Cui }; 5408c582c7cSDexuan Cui 5418c582c7cSDexuan Cui struct compose_comp_ctxt { 5428c582c7cSDexuan Cui struct hv_pci_compl comp_pkt; 5438c582c7cSDexuan Cui struct tran_int_desc int_desc; 5448c582c7cSDexuan Cui }; 5458c582c7cSDexuan Cui 54675c2786cSWei Hu /* 54775c2786cSWei Hu * It is possible the device is revoked during initialization. 54875c2786cSWei Hu * Check if this happens during wait. 54975c2786cSWei Hu * Return: 0 if response arrived, ENODEV if device revoked. 55075c2786cSWei Hu */ 55175c2786cSWei Hu static int 55275c2786cSWei Hu wait_for_response(struct hv_pcibus *hbus, struct completion *c) 55375c2786cSWei Hu { 55475c2786cSWei Hu do { 55575c2786cSWei Hu if (vmbus_chan_is_revoked(hbus->sc->chan)) { 55675c2786cSWei Hu device_printf(hbus->pcib, 55775c2786cSWei Hu "The device is revoked.\n"); 55875c2786cSWei Hu return (ENODEV); 55975c2786cSWei Hu } 56075c2786cSWei Hu } while (wait_for_completion_timeout(c, hz /10) != 0); 56175c2786cSWei Hu 56275c2786cSWei Hu return 0; 56375c2786cSWei Hu } 56475c2786cSWei Hu 5658c582c7cSDexuan Cui static void 5668c582c7cSDexuan Cui hv_pci_generic_compl(void *context, struct pci_response *resp, 5678c582c7cSDexuan Cui int resp_packet_size) 5688c582c7cSDexuan Cui { 5698c582c7cSDexuan Cui struct hv_pci_compl *comp_pkt = context; 5708c582c7cSDexuan Cui 5718c582c7cSDexuan Cui if (resp_packet_size >= sizeof(struct pci_response)) 5728c582c7cSDexuan Cui comp_pkt->completion_status = resp->status; 5738c582c7cSDexuan Cui else 5748c582c7cSDexuan Cui comp_pkt->completion_status = -1; 5758c582c7cSDexuan Cui 5768c582c7cSDexuan Cui complete(&comp_pkt->host_event); 5778c582c7cSDexuan Cui } 5788c582c7cSDexuan Cui 5798c582c7cSDexuan Cui static void 5808c582c7cSDexuan Cui q_resource_requirements(void *context, struct pci_response *resp, 5818c582c7cSDexuan Cui int resp_packet_size) 5828c582c7cSDexuan Cui { 5838c582c7cSDexuan Cui struct q_res_req_compl *completion = context; 5848c582c7cSDexuan Cui struct pci_q_res_req_response *q_res_req = 5858c582c7cSDexuan Cui (struct pci_q_res_req_response *)resp; 5868c582c7cSDexuan Cui int i; 5878c582c7cSDexuan Cui 5888c582c7cSDexuan Cui if (resp->status < 0) { 5898c582c7cSDexuan Cui printf("vmbus_pcib: failed to query resource requirements\n"); 5908c582c7cSDexuan Cui } else { 5918c582c7cSDexuan Cui for (i = 0; i < MAX_NUM_BARS; i++) 5928c582c7cSDexuan Cui completion->hpdev->probed_bar[i] = 5938c582c7cSDexuan Cui q_res_req->probed_bar[i]; 5948c582c7cSDexuan Cui } 5958c582c7cSDexuan Cui 5968c582c7cSDexuan Cui complete(&completion->host_event); 5978c582c7cSDexuan Cui } 5988c582c7cSDexuan Cui 5998c582c7cSDexuan Cui static void 6008c582c7cSDexuan Cui hv_pci_compose_compl(void *context, struct pci_response *resp, 6018c582c7cSDexuan Cui int resp_packet_size) 6028c582c7cSDexuan Cui { 6038c582c7cSDexuan Cui struct compose_comp_ctxt *comp_pkt = context; 6048c582c7cSDexuan Cui struct pci_create_int_response *int_resp = 6058c582c7cSDexuan Cui (struct pci_create_int_response *)resp; 6068c582c7cSDexuan Cui 6078c582c7cSDexuan Cui comp_pkt->comp_pkt.completion_status = resp->status; 6088c582c7cSDexuan Cui comp_pkt->int_desc = int_resp->int_desc; 6098c582c7cSDexuan Cui complete(&comp_pkt->comp_pkt.host_event); 6108c582c7cSDexuan Cui } 6118c582c7cSDexuan Cui 6128c582c7cSDexuan Cui static void 6138c582c7cSDexuan Cui hv_int_desc_free(struct hv_pci_dev *hpdev, struct hv_irq_desc *hid) 6148c582c7cSDexuan Cui { 6158c582c7cSDexuan Cui struct pci_delete_interrupt *int_pkt; 6168c582c7cSDexuan Cui struct { 6178c582c7cSDexuan Cui struct pci_packet pkt; 6188c582c7cSDexuan Cui uint8_t buffer[sizeof(struct pci_delete_interrupt)]; 6198c582c7cSDexuan Cui } ctxt; 6208c582c7cSDexuan Cui 6218c582c7cSDexuan Cui memset(&ctxt, 0, sizeof(ctxt)); 6228c582c7cSDexuan Cui int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message; 6238c582c7cSDexuan Cui int_pkt->message_type.type = PCI_DELETE_INTERRUPT_MESSAGE; 6248c582c7cSDexuan Cui int_pkt->wslot.val = hpdev->desc.wslot.val; 6258c582c7cSDexuan Cui int_pkt->int_desc = hid->desc; 6268c582c7cSDexuan Cui 6278c582c7cSDexuan Cui vmbus_chan_send(hpdev->hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 6288c582c7cSDexuan Cui int_pkt, sizeof(*int_pkt), 0); 6298c582c7cSDexuan Cui 6308c582c7cSDexuan Cui free(hid, M_DEVBUF); 6318c582c7cSDexuan Cui } 6328c582c7cSDexuan Cui 6338c582c7cSDexuan Cui static void 6348c582c7cSDexuan Cui hv_pci_delete_device(struct hv_pci_dev *hpdev) 6358c582c7cSDexuan Cui { 6368c582c7cSDexuan Cui struct hv_pcibus *hbus = hpdev->hbus; 6378c582c7cSDexuan Cui struct hv_irq_desc *hid, *tmp_hid; 6388c582c7cSDexuan Cui device_t pci_dev; 6398c582c7cSDexuan Cui int devfn; 6408c582c7cSDexuan Cui 6418c582c7cSDexuan Cui devfn = wslot_to_devfn(hpdev->desc.wslot.val); 6428c582c7cSDexuan Cui 643c6df6f53SWarner Losh bus_topo_lock(); 6448c582c7cSDexuan Cui 6458c582c7cSDexuan Cui pci_dev = pci_find_dbsf(hbus->pci_domain, 6468c582c7cSDexuan Cui 0, PCI_SLOT(devfn), PCI_FUNC(devfn)); 6478c582c7cSDexuan Cui if (pci_dev) 6488c582c7cSDexuan Cui device_delete_child(hbus->pci_bus, pci_dev); 6498c582c7cSDexuan Cui 650c6df6f53SWarner Losh bus_topo_unlock(); 6518c582c7cSDexuan Cui 6528c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 6538c582c7cSDexuan Cui TAILQ_REMOVE(&hbus->children, hpdev, link); 6548c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 6558c582c7cSDexuan Cui 6568c582c7cSDexuan Cui TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid) 6578c582c7cSDexuan Cui hv_int_desc_free(hpdev, hid); 6588c582c7cSDexuan Cui 6598c582c7cSDexuan Cui free(hpdev, M_DEVBUF); 6608c582c7cSDexuan Cui } 6618c582c7cSDexuan Cui 6628c582c7cSDexuan Cui static struct hv_pci_dev * 663ea11861eSWei Hu new_pcichild_device(struct hv_pcibus *hbus, struct hv_pcidev_desc *desc) 6648c582c7cSDexuan Cui { 6658c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 6668c582c7cSDexuan Cui struct pci_child_message *res_req; 6678c582c7cSDexuan Cui struct q_res_req_compl comp_pkt; 6688c582c7cSDexuan Cui struct { 6698c582c7cSDexuan Cui struct pci_packet pkt; 6708c582c7cSDexuan Cui uint8_t buffer[sizeof(struct pci_child_message)]; 6718c582c7cSDexuan Cui } ctxt; 6728c582c7cSDexuan Cui int ret; 6738c582c7cSDexuan Cui 6748c582c7cSDexuan Cui hpdev = malloc(sizeof(*hpdev), M_DEVBUF, M_WAITOK | M_ZERO); 6758c582c7cSDexuan Cui hpdev->hbus = hbus; 6768c582c7cSDexuan Cui 6778c582c7cSDexuan Cui TAILQ_INIT(&hpdev->irq_desc_list); 6788c582c7cSDexuan Cui 6798c582c7cSDexuan Cui init_completion(&comp_pkt.host_event); 6808c582c7cSDexuan Cui comp_pkt.hpdev = hpdev; 6818c582c7cSDexuan Cui 6828c582c7cSDexuan Cui ctxt.pkt.compl_ctxt = &comp_pkt; 6838c582c7cSDexuan Cui ctxt.pkt.completion_func = q_resource_requirements; 6848c582c7cSDexuan Cui 6858c582c7cSDexuan Cui res_req = (struct pci_child_message *)&ctxt.pkt.message; 6868c582c7cSDexuan Cui res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS; 6878c582c7cSDexuan Cui res_req->wslot.val = desc->wslot.val; 6888c582c7cSDexuan Cui 6898c582c7cSDexuan Cui ret = vmbus_chan_send(hbus->sc->chan, 6908c582c7cSDexuan Cui VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 691aaf13123SDimitry Andric res_req, sizeof(*res_req), (uint64_t)(uintptr_t)&ctxt.pkt); 6928c582c7cSDexuan Cui if (ret) 6938c582c7cSDexuan Cui goto err; 6948c582c7cSDexuan Cui 69575c2786cSWei Hu if (wait_for_response(hbus, &comp_pkt.host_event)) 69675c2786cSWei Hu goto err; 69775c2786cSWei Hu 6988c582c7cSDexuan Cui free_completion(&comp_pkt.host_event); 6998c582c7cSDexuan Cui 7008c582c7cSDexuan Cui hpdev->desc = *desc; 7018c582c7cSDexuan Cui 7028c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 7036944b2e6SDexuan Cui if (TAILQ_EMPTY(&hbus->children)) 7046944b2e6SDexuan Cui hbus->pci_domain = desc->ser & 0xFFFF; 7058c582c7cSDexuan Cui TAILQ_INSERT_TAIL(&hbus->children, hpdev, link); 7068c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 7078c582c7cSDexuan Cui return (hpdev); 7088c582c7cSDexuan Cui err: 7098c582c7cSDexuan Cui free_completion(&comp_pkt.host_event); 7108c582c7cSDexuan Cui free(hpdev, M_DEVBUF); 7118c582c7cSDexuan Cui return (NULL); 7128c582c7cSDexuan Cui } 7138c582c7cSDexuan Cui 7148c582c7cSDexuan Cui static int 7158c582c7cSDexuan Cui pci_rescan(device_t dev) 7168c582c7cSDexuan Cui { 7178c582c7cSDexuan Cui return (BUS_RESCAN(dev)); 7188c582c7cSDexuan Cui } 7198c582c7cSDexuan Cui 7208c582c7cSDexuan Cui static void 7218c582c7cSDexuan Cui pci_devices_present_work(void *arg, int pending __unused) 7228c582c7cSDexuan Cui { 7238c582c7cSDexuan Cui struct hv_dr_work *dr_wrk = arg; 7248c582c7cSDexuan Cui struct hv_dr_state *dr = NULL; 7258c582c7cSDexuan Cui struct hv_pcibus *hbus; 7268c582c7cSDexuan Cui uint32_t child_no; 7278c582c7cSDexuan Cui bool found; 728ea11861eSWei Hu struct hv_pcidev_desc *new_desc; 7298c582c7cSDexuan Cui struct hv_pci_dev *hpdev, *tmp_hpdev; 7308c582c7cSDexuan Cui struct completion *query_comp; 7318c582c7cSDexuan Cui bool need_rescan = false; 7328c582c7cSDexuan Cui 7338c582c7cSDexuan Cui hbus = dr_wrk->bus; 7348c582c7cSDexuan Cui free(dr_wrk, M_DEVBUF); 7358c582c7cSDexuan Cui 7368c582c7cSDexuan Cui /* Pull this off the queue and process it if it was the last one. */ 7378c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 7388c582c7cSDexuan Cui while (!TAILQ_EMPTY(&hbus->dr_list)) { 7398c582c7cSDexuan Cui dr = TAILQ_FIRST(&hbus->dr_list); 7408c582c7cSDexuan Cui TAILQ_REMOVE(&hbus->dr_list, dr, link); 7418c582c7cSDexuan Cui 7428c582c7cSDexuan Cui /* Throw this away if the list still has stuff in it. */ 7438c582c7cSDexuan Cui if (!TAILQ_EMPTY(&hbus->dr_list)) { 7448c582c7cSDexuan Cui free(dr, M_DEVBUF); 7458c582c7cSDexuan Cui continue; 7468c582c7cSDexuan Cui } 7478c582c7cSDexuan Cui } 7488c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 7498c582c7cSDexuan Cui 7508c582c7cSDexuan Cui if (!dr) 7518c582c7cSDexuan Cui return; 7528c582c7cSDexuan Cui 7538c582c7cSDexuan Cui /* First, mark all existing children as reported missing. */ 7548c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 7558c582c7cSDexuan Cui TAILQ_FOREACH(hpdev, &hbus->children, link) 7568c582c7cSDexuan Cui hpdev->reported_missing = true; 7578c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 7588c582c7cSDexuan Cui 7598c582c7cSDexuan Cui /* Next, add back any reported devices. */ 7608c582c7cSDexuan Cui for (child_no = 0; child_no < dr->device_count; child_no++) { 7618c582c7cSDexuan Cui found = false; 7628c582c7cSDexuan Cui new_desc = &dr->func[child_no]; 7638c582c7cSDexuan Cui 7648c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 7658c582c7cSDexuan Cui TAILQ_FOREACH(hpdev, &hbus->children, link) { 7668c582c7cSDexuan Cui if ((hpdev->desc.wslot.val == 7678c582c7cSDexuan Cui new_desc->wslot.val) && 7688c582c7cSDexuan Cui (hpdev->desc.v_id == new_desc->v_id) && 7698c582c7cSDexuan Cui (hpdev->desc.d_id == new_desc->d_id) && 7708c582c7cSDexuan Cui (hpdev->desc.ser == new_desc->ser)) { 7718c582c7cSDexuan Cui hpdev->reported_missing = false; 7728c582c7cSDexuan Cui found = true; 7738c582c7cSDexuan Cui break; 7748c582c7cSDexuan Cui } 7758c582c7cSDexuan Cui } 7768c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 7778c582c7cSDexuan Cui 7788c582c7cSDexuan Cui if (!found) { 7798c582c7cSDexuan Cui if (!need_rescan) 7808c582c7cSDexuan Cui need_rescan = true; 7818c582c7cSDexuan Cui 7828c582c7cSDexuan Cui hpdev = new_pcichild_device(hbus, new_desc); 7838c582c7cSDexuan Cui if (!hpdev) 7848c582c7cSDexuan Cui printf("vmbus_pcib: failed to add a child\n"); 7858c582c7cSDexuan Cui } 7868c582c7cSDexuan Cui } 7878c582c7cSDexuan Cui 7888c582c7cSDexuan Cui /* Remove missing device(s), if any */ 7898c582c7cSDexuan Cui TAILQ_FOREACH_SAFE(hpdev, &hbus->children, link, tmp_hpdev) { 7908c582c7cSDexuan Cui if (hpdev->reported_missing) 7918c582c7cSDexuan Cui hv_pci_delete_device(hpdev); 7928c582c7cSDexuan Cui } 7938c582c7cSDexuan Cui 7948c582c7cSDexuan Cui /* Rescan the bus to find any new device, if necessary. */ 7958c582c7cSDexuan Cui if (hbus->state == hv_pcibus_installed && need_rescan) 7968c582c7cSDexuan Cui pci_rescan(hbus->pci_bus); 7978c582c7cSDexuan Cui 7988c582c7cSDexuan Cui /* Wake up hv_pci_query_relations(), if it's waiting. */ 7998c582c7cSDexuan Cui query_comp = hbus->query_comp; 8008c582c7cSDexuan Cui if (query_comp) { 8018c582c7cSDexuan Cui hbus->query_comp = NULL; 8028c582c7cSDexuan Cui complete(query_comp); 8038c582c7cSDexuan Cui } 8048c582c7cSDexuan Cui 8058c582c7cSDexuan Cui free(dr, M_DEVBUF); 8068c582c7cSDexuan Cui } 8078c582c7cSDexuan Cui 8088c582c7cSDexuan Cui static struct hv_pci_dev * 8098c582c7cSDexuan Cui get_pcichild_wslot(struct hv_pcibus *hbus, uint32_t wslot) 8108c582c7cSDexuan Cui { 8118c582c7cSDexuan Cui struct hv_pci_dev *hpdev, *ret = NULL; 8128c582c7cSDexuan Cui 8138c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 8148c582c7cSDexuan Cui TAILQ_FOREACH(hpdev, &hbus->children, link) { 8158c582c7cSDexuan Cui if (hpdev->desc.wslot.val == wslot) { 8168c582c7cSDexuan Cui ret = hpdev; 8178c582c7cSDexuan Cui break; 8188c582c7cSDexuan Cui } 8198c582c7cSDexuan Cui } 8208c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 8218c582c7cSDexuan Cui 8228c582c7cSDexuan Cui return (ret); 8238c582c7cSDexuan Cui } 8248c582c7cSDexuan Cui 8258c582c7cSDexuan Cui static void 8268c582c7cSDexuan Cui hv_pci_devices_present(struct hv_pcibus *hbus, 8278c582c7cSDexuan Cui struct pci_bus_relations *relations) 8288c582c7cSDexuan Cui { 8298c582c7cSDexuan Cui struct hv_dr_state *dr; 8308c582c7cSDexuan Cui struct hv_dr_work *dr_wrk; 8318c582c7cSDexuan Cui unsigned long dr_size; 8328c582c7cSDexuan Cui 8338c582c7cSDexuan Cui if (hbus->detaching && relations->device_count > 0) 8348c582c7cSDexuan Cui return; 8358c582c7cSDexuan Cui 8368c582c7cSDexuan Cui dr_size = offsetof(struct hv_dr_state, func) + 8378c582c7cSDexuan Cui (sizeof(struct pci_func_desc) * relations->device_count); 8388c582c7cSDexuan Cui dr = malloc(dr_size, M_DEVBUF, M_WAITOK | M_ZERO); 8398c582c7cSDexuan Cui 8408c582c7cSDexuan Cui dr->device_count = relations->device_count; 8418c582c7cSDexuan Cui if (dr->device_count != 0) 8428c582c7cSDexuan Cui memcpy(dr->func, relations->func, 843ea11861eSWei Hu sizeof(struct hv_pcidev_desc) * dr->device_count); 844ea11861eSWei Hu 845ea11861eSWei Hu mtx_lock(&hbus->device_list_lock); 846ea11861eSWei Hu TAILQ_INSERT_TAIL(&hbus->dr_list, dr, link); 847ea11861eSWei Hu mtx_unlock(&hbus->device_list_lock); 848ea11861eSWei Hu 849ea11861eSWei Hu dr_wrk = malloc(sizeof(*dr_wrk), M_DEVBUF, M_WAITOK | M_ZERO); 850ea11861eSWei Hu dr_wrk->bus = hbus; 851ea11861eSWei Hu TASK_INIT(&dr_wrk->task, 0, pci_devices_present_work, dr_wrk); 852ea11861eSWei Hu taskqueue_enqueue(hbus->sc->taskq, &dr_wrk->task); 853ea11861eSWei Hu } 854ea11861eSWei Hu 855ea11861eSWei Hu static void 856ea11861eSWei Hu hv_pci_devices_present2(struct hv_pcibus *hbus, 857ea11861eSWei Hu struct pci_bus_relations2 *relations) 858ea11861eSWei Hu { 859ea11861eSWei Hu struct hv_dr_state *dr; 860ea11861eSWei Hu struct hv_dr_work *dr_wrk; 861ea11861eSWei Hu unsigned long dr_size; 862ea11861eSWei Hu 863ea11861eSWei Hu if (hbus->detaching && relations->device_count > 0) 864ea11861eSWei Hu return; 865ea11861eSWei Hu 866ea11861eSWei Hu dr_size = offsetof(struct hv_dr_state, func) + 867ea11861eSWei Hu (sizeof(struct pci_func_desc2) * relations->device_count); 868ea11861eSWei Hu dr = malloc(dr_size, M_DEVBUF, M_WAITOK | M_ZERO); 869ea11861eSWei Hu 870ea11861eSWei Hu dr->device_count = relations->device_count; 871ea11861eSWei Hu if (dr->device_count != 0) 872ea11861eSWei Hu memcpy(dr->func, relations->func, 873ea11861eSWei Hu sizeof(struct pci_func_desc2) * dr->device_count); 8748c582c7cSDexuan Cui 8758c582c7cSDexuan Cui mtx_lock(&hbus->device_list_lock); 8768c582c7cSDexuan Cui TAILQ_INSERT_TAIL(&hbus->dr_list, dr, link); 8778c582c7cSDexuan Cui mtx_unlock(&hbus->device_list_lock); 8788c582c7cSDexuan Cui 8798c582c7cSDexuan Cui dr_wrk = malloc(sizeof(*dr_wrk), M_DEVBUF, M_WAITOK | M_ZERO); 8808c582c7cSDexuan Cui dr_wrk->bus = hbus; 8818c582c7cSDexuan Cui TASK_INIT(&dr_wrk->task, 0, pci_devices_present_work, dr_wrk); 8828c582c7cSDexuan Cui taskqueue_enqueue(hbus->sc->taskq, &dr_wrk->task); 8838c582c7cSDexuan Cui } 8848c582c7cSDexuan Cui 8858c582c7cSDexuan Cui static void 8868c582c7cSDexuan Cui hv_eject_device_work(void *arg, int pending __unused) 8878c582c7cSDexuan Cui { 8888c582c7cSDexuan Cui struct hv_pci_dev *hpdev = arg; 8898c582c7cSDexuan Cui union win_slot_encoding wslot = hpdev->desc.wslot; 8908c582c7cSDexuan Cui struct hv_pcibus *hbus = hpdev->hbus; 8918c582c7cSDexuan Cui struct pci_eject_response *eject_pkt; 8928c582c7cSDexuan Cui struct { 8938c582c7cSDexuan Cui struct pci_packet pkt; 8948c582c7cSDexuan Cui uint8_t buffer[sizeof(struct pci_eject_response)]; 8958c582c7cSDexuan Cui } ctxt; 8968c582c7cSDexuan Cui 8978c582c7cSDexuan Cui hv_pci_delete_device(hpdev); 8988c582c7cSDexuan Cui 8998c582c7cSDexuan Cui memset(&ctxt, 0, sizeof(ctxt)); 9008c582c7cSDexuan Cui eject_pkt = (struct pci_eject_response *)&ctxt.pkt.message; 9018c582c7cSDexuan Cui eject_pkt->message_type.type = PCI_EJECTION_COMPLETE; 9028c582c7cSDexuan Cui eject_pkt->wslot.val = wslot.val; 9038c582c7cSDexuan Cui vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 9048c582c7cSDexuan Cui eject_pkt, sizeof(*eject_pkt), 0); 9058c582c7cSDexuan Cui } 9068c582c7cSDexuan Cui 9078c582c7cSDexuan Cui static void 9088c582c7cSDexuan Cui hv_pci_eject_device(struct hv_pci_dev *hpdev) 9098c582c7cSDexuan Cui { 9108c582c7cSDexuan Cui struct hv_pcibus *hbus = hpdev->hbus; 9118c582c7cSDexuan Cui struct taskqueue *taskq; 9128c582c7cSDexuan Cui 9138c582c7cSDexuan Cui if (hbus->detaching) 9148c582c7cSDexuan Cui return; 9158c582c7cSDexuan Cui 9168c582c7cSDexuan Cui /* 9178c582c7cSDexuan Cui * Push this task into the same taskqueue on which 9188c582c7cSDexuan Cui * vmbus_pcib_attach() runs, so we're sure this task can't run 9198c582c7cSDexuan Cui * concurrently with vmbus_pcib_attach(). 9208c582c7cSDexuan Cui */ 9218c582c7cSDexuan Cui TASK_INIT(&hpdev->eject_task, 0, hv_eject_device_work, hpdev); 9228c582c7cSDexuan Cui taskq = vmbus_chan_mgmt_tq(hbus->sc->chan); 9238c582c7cSDexuan Cui taskqueue_enqueue(taskq, &hpdev->eject_task); 9248c582c7cSDexuan Cui } 9258c582c7cSDexuan Cui 9268c582c7cSDexuan Cui #define PCIB_PACKET_SIZE 0x100 9278c582c7cSDexuan Cui 9288c582c7cSDexuan Cui static void 9298c582c7cSDexuan Cui vmbus_pcib_on_channel_callback(struct vmbus_channel *chan, void *arg) 9308c582c7cSDexuan Cui { 9318c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = arg; 9328c582c7cSDexuan Cui struct hv_pcibus *hbus = sc->hbus; 9338c582c7cSDexuan Cui 9348c582c7cSDexuan Cui void *buffer; 9358c582c7cSDexuan Cui int bufferlen = PCIB_PACKET_SIZE; 9368c582c7cSDexuan Cui 9378c582c7cSDexuan Cui struct pci_packet *comp_packet; 9388c582c7cSDexuan Cui struct pci_response *response; 9398c582c7cSDexuan Cui struct pci_incoming_message *new_msg; 9408c582c7cSDexuan Cui struct pci_bus_relations *bus_rel; 941ea11861eSWei Hu struct pci_bus_relations2 *bus_rel2; 9428c582c7cSDexuan Cui struct pci_dev_incoming *dev_msg; 9438c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 9448c582c7cSDexuan Cui 9458c582c7cSDexuan Cui buffer = sc->rx_buf; 9468c582c7cSDexuan Cui do { 9478c582c7cSDexuan Cui struct vmbus_chanpkt_hdr *pkt = buffer; 9488c582c7cSDexuan Cui uint32_t bytes_rxed; 9498c582c7cSDexuan Cui int ret; 9508c582c7cSDexuan Cui 9518c582c7cSDexuan Cui bytes_rxed = bufferlen; 9528c582c7cSDexuan Cui ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); 9538c582c7cSDexuan Cui 9548c582c7cSDexuan Cui if (ret == ENOBUFS) { 9558c582c7cSDexuan Cui /* Handle large packet */ 9568c582c7cSDexuan Cui if (bufferlen > PCIB_PACKET_SIZE) { 9578c582c7cSDexuan Cui free(buffer, M_DEVBUF); 9588c582c7cSDexuan Cui buffer = NULL; 9598c582c7cSDexuan Cui } 9608c582c7cSDexuan Cui 9618c582c7cSDexuan Cui /* alloc new buffer */ 962ea11861eSWei Hu buffer = 963ea11861eSWei Hu malloc(bytes_rxed, M_DEVBUF, M_WAITOK | M_ZERO); 9648c582c7cSDexuan Cui bufferlen = bytes_rxed; 9658c582c7cSDexuan Cui 9668c582c7cSDexuan Cui continue; 9678c582c7cSDexuan Cui } 9688c582c7cSDexuan Cui 9698c582c7cSDexuan Cui if (ret != 0) { 9708c582c7cSDexuan Cui /* ignore EIO or EAGAIN */ 9718c582c7cSDexuan Cui break; 9728c582c7cSDexuan Cui } 9738c582c7cSDexuan Cui 9748c582c7cSDexuan Cui if (bytes_rxed <= sizeof(struct pci_response)) 9758c582c7cSDexuan Cui continue; 9768c582c7cSDexuan Cui 9778c582c7cSDexuan Cui switch (pkt->cph_type) { 9788c582c7cSDexuan Cui case VMBUS_CHANPKT_TYPE_COMP: 979aaf13123SDimitry Andric comp_packet = 980aaf13123SDimitry Andric (struct pci_packet *)(uintptr_t)pkt->cph_xactid; 9818c582c7cSDexuan Cui response = (struct pci_response *)pkt; 9828c582c7cSDexuan Cui comp_packet->completion_func(comp_packet->compl_ctxt, 9838c582c7cSDexuan Cui response, bytes_rxed); 9848c582c7cSDexuan Cui break; 9858c582c7cSDexuan Cui case VMBUS_CHANPKT_TYPE_INBAND: 9868c582c7cSDexuan Cui new_msg = (struct pci_incoming_message *)buffer; 9878c582c7cSDexuan Cui 9888c582c7cSDexuan Cui switch (new_msg->message_type.type) { 9898c582c7cSDexuan Cui case PCI_BUS_RELATIONS: 9908c582c7cSDexuan Cui bus_rel = (struct pci_bus_relations *)buffer; 9918c582c7cSDexuan Cui 9928c582c7cSDexuan Cui if (bus_rel->device_count == 0) 9938c582c7cSDexuan Cui break; 9948c582c7cSDexuan Cui 9958c582c7cSDexuan Cui if (bytes_rxed < 9968c582c7cSDexuan Cui offsetof(struct pci_bus_relations, func) + 9978c582c7cSDexuan Cui (sizeof(struct pci_func_desc) * 9988c582c7cSDexuan Cui (bus_rel->device_count))) 9998c582c7cSDexuan Cui break; 10008c582c7cSDexuan Cui 10018c582c7cSDexuan Cui hv_pci_devices_present(hbus, bus_rel); 10028c582c7cSDexuan Cui break; 10038c582c7cSDexuan Cui 1004ea11861eSWei Hu case PCI_BUS_RELATIONS2: 1005ea11861eSWei Hu bus_rel2 = (struct pci_bus_relations2 *)buffer; 1006ea11861eSWei Hu 1007ea11861eSWei Hu if (bus_rel2->device_count == 0) 1008ea11861eSWei Hu break; 1009ea11861eSWei Hu 1010ea11861eSWei Hu if (bytes_rxed < 1011ea11861eSWei Hu offsetof(struct pci_bus_relations2, func) + 1012ea11861eSWei Hu (sizeof(struct pci_func_desc2) * 1013ea11861eSWei Hu (bus_rel2->device_count))) 1014ea11861eSWei Hu break; 1015ea11861eSWei Hu 1016ea11861eSWei Hu hv_pci_devices_present2(hbus, bus_rel2); 1017ea11861eSWei Hu 10188c582c7cSDexuan Cui case PCI_EJECT: 10198c582c7cSDexuan Cui dev_msg = (struct pci_dev_incoming *)buffer; 10208c582c7cSDexuan Cui hpdev = get_pcichild_wslot(hbus, 10218c582c7cSDexuan Cui dev_msg->wslot.val); 10228c582c7cSDexuan Cui 10238c582c7cSDexuan Cui if (hpdev) 10248c582c7cSDexuan Cui hv_pci_eject_device(hpdev); 10258c582c7cSDexuan Cui 10268c582c7cSDexuan Cui break; 10278c582c7cSDexuan Cui default: 10288c582c7cSDexuan Cui printf("vmbus_pcib: Unknown msg type 0x%x\n", 10298c582c7cSDexuan Cui new_msg->message_type.type); 10308c582c7cSDexuan Cui break; 10318c582c7cSDexuan Cui } 10328c582c7cSDexuan Cui break; 10338c582c7cSDexuan Cui default: 10348c582c7cSDexuan Cui printf("vmbus_pcib: Unknown VMBus msg type %hd\n", 10358c582c7cSDexuan Cui pkt->cph_type); 10368c582c7cSDexuan Cui break; 10378c582c7cSDexuan Cui } 10388c582c7cSDexuan Cui } while (1); 10398c582c7cSDexuan Cui 10408c582c7cSDexuan Cui if (bufferlen > PCIB_PACKET_SIZE) 10418c582c7cSDexuan Cui free(buffer, M_DEVBUF); 10428c582c7cSDexuan Cui } 10438c582c7cSDexuan Cui 10448c582c7cSDexuan Cui static int 1045ea11861eSWei Hu hv_pci_protocol_negotiation(struct hv_pcibus *hbus, 1046ea11861eSWei Hu enum pci_protocol_version_t version[], 1047ea11861eSWei Hu int num_version) 10488c582c7cSDexuan Cui { 10498c582c7cSDexuan Cui struct pci_version_request *version_req; 10508c582c7cSDexuan Cui struct hv_pci_compl comp_pkt; 10518c582c7cSDexuan Cui struct { 10528c582c7cSDexuan Cui struct pci_packet pkt; 10538c582c7cSDexuan Cui uint8_t buffer[sizeof(struct pci_version_request)]; 10548c582c7cSDexuan Cui } ctxt; 10558c582c7cSDexuan Cui int ret; 1056ea11861eSWei Hu int i; 10578c582c7cSDexuan Cui 10588c582c7cSDexuan Cui init_completion(&comp_pkt.host_event); 10598c582c7cSDexuan Cui 10608c582c7cSDexuan Cui ctxt.pkt.completion_func = hv_pci_generic_compl; 10618c582c7cSDexuan Cui ctxt.pkt.compl_ctxt = &comp_pkt; 10628c582c7cSDexuan Cui version_req = (struct pci_version_request *)&ctxt.pkt.message; 10638c582c7cSDexuan Cui version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION; 10648c582c7cSDexuan Cui 1065ea11861eSWei Hu for(i=0; i< num_version; i++) { 1066ea11861eSWei Hu version_req->protocol_version = version[i]; 1067ea11861eSWei Hu ret = vmbus_chan_send(hbus->sc->chan, 1068ea11861eSWei Hu VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 1069ea11861eSWei Hu version_req, sizeof(*version_req), 1070aaf13123SDimitry Andric (uint64_t)(uintptr_t)&ctxt.pkt); 107175c2786cSWei Hu if (!ret) 107275c2786cSWei Hu ret = wait_for_response(hbus, &comp_pkt.host_event); 10738c582c7cSDexuan Cui 107475c2786cSWei Hu if (ret) { 107575c2786cSWei Hu device_printf(hbus->pcib, 107675c2786cSWei Hu "vmbus_pcib failed to request version: %d\n", 107775c2786cSWei Hu ret); 107875c2786cSWei Hu goto out; 107975c2786cSWei Hu } 10808c582c7cSDexuan Cui 1081ea11861eSWei Hu if (comp_pkt.completion_status >= 0) { 1082ea11861eSWei Hu hbus->protocol_version = version[i]; 1083ea11861eSWei Hu device_printf(hbus->pcib, 1084ea11861eSWei Hu "PCI VMBus using version 0x%x\n", 1085ea11861eSWei Hu hbus->protocol_version); 1086ea11861eSWei Hu ret = 0; 1087ea11861eSWei Hu goto out; 1088ea11861eSWei Hu } 1089ea11861eSWei Hu 1090ea11861eSWei Hu if (comp_pkt.completion_status != STATUS_REVISION_MISMATCH) { 10918c582c7cSDexuan Cui device_printf(hbus->pcib, 10928c582c7cSDexuan Cui "vmbus_pcib version negotiation failed: %x\n", 10938c582c7cSDexuan Cui comp_pkt.completion_status); 10948c582c7cSDexuan Cui ret = EPROTO; 1095ea11861eSWei Hu goto out; 10968c582c7cSDexuan Cui } 1097ea11861eSWei Hu reinit_completion(&comp_pkt.host_event); 1098ea11861eSWei Hu } 1099ea11861eSWei Hu 1100ea11861eSWei Hu device_printf(hbus->pcib, 1101ea11861eSWei Hu "PCI pass-trhpugh VSP failed to find supported version\n"); 11028c582c7cSDexuan Cui out: 11038c582c7cSDexuan Cui free_completion(&comp_pkt.host_event); 11048c582c7cSDexuan Cui return (ret); 11058c582c7cSDexuan Cui } 11068c582c7cSDexuan Cui 11078c582c7cSDexuan Cui /* Ask the host to send along the list of child devices */ 11088c582c7cSDexuan Cui static int 11098c582c7cSDexuan Cui hv_pci_query_relations(struct hv_pcibus *hbus) 11108c582c7cSDexuan Cui { 11118c582c7cSDexuan Cui struct pci_message message; 11128c582c7cSDexuan Cui int ret; 11138c582c7cSDexuan Cui 11148c582c7cSDexuan Cui message.type = PCI_QUERY_BUS_RELATIONS; 11158c582c7cSDexuan Cui ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 11168c582c7cSDexuan Cui &message, sizeof(message), 0); 11178c582c7cSDexuan Cui return (ret); 11188c582c7cSDexuan Cui } 11198c582c7cSDexuan Cui 11208c582c7cSDexuan Cui static int 11218c582c7cSDexuan Cui hv_pci_enter_d0(struct hv_pcibus *hbus) 11228c582c7cSDexuan Cui { 11238c582c7cSDexuan Cui struct pci_bus_d0_entry *d0_entry; 11248c582c7cSDexuan Cui struct hv_pci_compl comp_pkt; 11258c582c7cSDexuan Cui struct { 11268c582c7cSDexuan Cui struct pci_packet pkt; 11278c582c7cSDexuan Cui uint8_t buffer[sizeof(struct pci_bus_d0_entry)]; 11288c582c7cSDexuan Cui } ctxt; 11298c582c7cSDexuan Cui int ret; 11308c582c7cSDexuan Cui 11318c582c7cSDexuan Cui /* 11328c582c7cSDexuan Cui * Tell the host that the bus is ready to use, and moved into the 11338c582c7cSDexuan Cui * powered-on state. This includes telling the host which region 11348c582c7cSDexuan Cui * of memory-mapped I/O space has been chosen for configuration space 11358c582c7cSDexuan Cui * access. 11368c582c7cSDexuan Cui */ 11378c582c7cSDexuan Cui init_completion(&comp_pkt.host_event); 11388c582c7cSDexuan Cui 11398c582c7cSDexuan Cui ctxt.pkt.completion_func = hv_pci_generic_compl; 11408c582c7cSDexuan Cui ctxt.pkt.compl_ctxt = &comp_pkt; 11418c582c7cSDexuan Cui 11428c582c7cSDexuan Cui d0_entry = (struct pci_bus_d0_entry *)&ctxt.pkt.message; 11438c582c7cSDexuan Cui memset(d0_entry, 0, sizeof(*d0_entry)); 11448c582c7cSDexuan Cui d0_entry->message_type.type = PCI_BUS_D0ENTRY; 11458c582c7cSDexuan Cui d0_entry->mmio_base = rman_get_start(hbus->cfg_res); 11468c582c7cSDexuan Cui 11478c582c7cSDexuan Cui ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 11488c582c7cSDexuan Cui VMBUS_CHANPKT_FLAG_RC, d0_entry, sizeof(*d0_entry), 1149aaf13123SDimitry Andric (uint64_t)(uintptr_t)&ctxt.pkt); 115075c2786cSWei Hu if (!ret) 115175c2786cSWei Hu ret = wait_for_response(hbus, &comp_pkt.host_event); 115275c2786cSWei Hu 11538c582c7cSDexuan Cui if (ret) 11548c582c7cSDexuan Cui goto out; 11558c582c7cSDexuan Cui 11568c582c7cSDexuan Cui if (comp_pkt.completion_status < 0) { 11578c582c7cSDexuan Cui device_printf(hbus->pcib, "vmbus_pcib failed to enable D0\n"); 11588c582c7cSDexuan Cui ret = EPROTO; 11598c582c7cSDexuan Cui } else { 11608c582c7cSDexuan Cui ret = 0; 11618c582c7cSDexuan Cui } 11628c582c7cSDexuan Cui 11638c582c7cSDexuan Cui out: 11648c582c7cSDexuan Cui free_completion(&comp_pkt.host_event); 11658c582c7cSDexuan Cui return (ret); 11668c582c7cSDexuan Cui } 11678c582c7cSDexuan Cui 11688c582c7cSDexuan Cui /* 11698c582c7cSDexuan Cui * It looks this is only needed by Windows VM, but let's send the message too 11708c582c7cSDexuan Cui * just to make the host happy. 11718c582c7cSDexuan Cui */ 11728c582c7cSDexuan Cui static int 11738c582c7cSDexuan Cui hv_send_resources_allocated(struct hv_pcibus *hbus) 11748c582c7cSDexuan Cui { 11758c582c7cSDexuan Cui struct pci_resources_assigned *res_assigned; 1176ea11861eSWei Hu struct pci_resources_assigned2 *res_assigned2; 11778c582c7cSDexuan Cui struct hv_pci_compl comp_pkt; 11788c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 11798c582c7cSDexuan Cui struct pci_packet *pkt; 11808c582c7cSDexuan Cui uint32_t wslot; 11818c582c7cSDexuan Cui int ret = 0; 1182ea11861eSWei Hu size_t size_res; 11838c582c7cSDexuan Cui 1184ea11861eSWei Hu size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_4) 1185ea11861eSWei Hu ? sizeof(*res_assigned) : sizeof(*res_assigned2); 1186ea11861eSWei Hu pkt = malloc(sizeof(*pkt) + size_res, 11878c582c7cSDexuan Cui M_DEVBUF, M_WAITOK | M_ZERO); 11888c582c7cSDexuan Cui 11898c582c7cSDexuan Cui for (wslot = 0; wslot < 256; wslot++) { 11908c582c7cSDexuan Cui hpdev = get_pcichild_wslot(hbus, wslot); 11918c582c7cSDexuan Cui if (!hpdev) 11928c582c7cSDexuan Cui continue; 11938c582c7cSDexuan Cui 11948c582c7cSDexuan Cui init_completion(&comp_pkt.host_event); 11958c582c7cSDexuan Cui 1196ea11861eSWei Hu memset(pkt, 0, sizeof(*pkt) + size_res); 11978c582c7cSDexuan Cui pkt->completion_func = hv_pci_generic_compl; 11988c582c7cSDexuan Cui pkt->compl_ctxt = &comp_pkt; 11998c582c7cSDexuan Cui 1200ea11861eSWei Hu if (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_4) { 1201ea11861eSWei Hu res_assigned = 1202ea11861eSWei Hu (struct pci_resources_assigned *)&pkt->message; 1203ea11861eSWei Hu res_assigned->message_type.type = 1204ea11861eSWei Hu PCI_RESOURCES_ASSIGNED; 12058c582c7cSDexuan Cui res_assigned->wslot.val = hpdev->desc.wslot.val; 1206ea11861eSWei Hu } else { 1207ea11861eSWei Hu res_assigned2 = 1208ea11861eSWei Hu (struct pci_resources_assigned2 *)&pkt->message; 1209ea11861eSWei Hu res_assigned2->message_type.type = 1210ea11861eSWei Hu PCI_RESOURCES_ASSIGNED2; 1211ea11861eSWei Hu res_assigned2->wslot.val = hpdev->desc.wslot.val; 1212ea11861eSWei Hu } 12138c582c7cSDexuan Cui 12148c582c7cSDexuan Cui ret = vmbus_chan_send(hbus->sc->chan, 12158c582c7cSDexuan Cui VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 1216ea11861eSWei Hu &pkt->message, size_res, 1217aaf13123SDimitry Andric (uint64_t)(uintptr_t)pkt); 121875c2786cSWei Hu if (!ret) 121975c2786cSWei Hu ret = wait_for_response(hbus, &comp_pkt.host_event); 12208c582c7cSDexuan Cui 12218c582c7cSDexuan Cui free_completion(&comp_pkt.host_event); 12228c582c7cSDexuan Cui 122375c2786cSWei Hu if (ret) 122475c2786cSWei Hu break; 122575c2786cSWei Hu 12268c582c7cSDexuan Cui if (comp_pkt.completion_status < 0) { 12278c582c7cSDexuan Cui ret = EPROTO; 12288c582c7cSDexuan Cui device_printf(hbus->pcib, 12298c582c7cSDexuan Cui "failed to send PCI_RESOURCES_ASSIGNED\n"); 12308c582c7cSDexuan Cui break; 12318c582c7cSDexuan Cui } 12328c582c7cSDexuan Cui } 12338c582c7cSDexuan Cui 12348c582c7cSDexuan Cui free(pkt, M_DEVBUF); 12358c582c7cSDexuan Cui return (ret); 12368c582c7cSDexuan Cui } 12378c582c7cSDexuan Cui 12388c582c7cSDexuan Cui static int 12398c582c7cSDexuan Cui hv_send_resources_released(struct hv_pcibus *hbus) 12408c582c7cSDexuan Cui { 12418c582c7cSDexuan Cui struct pci_child_message pkt; 12428c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 12438c582c7cSDexuan Cui uint32_t wslot; 12448c582c7cSDexuan Cui int ret; 12458c582c7cSDexuan Cui 12468c582c7cSDexuan Cui for (wslot = 0; wslot < 256; wslot++) { 12478c582c7cSDexuan Cui hpdev = get_pcichild_wslot(hbus, wslot); 12488c582c7cSDexuan Cui if (!hpdev) 12498c582c7cSDexuan Cui continue; 12508c582c7cSDexuan Cui 12518c582c7cSDexuan Cui pkt.message_type.type = PCI_RESOURCES_RELEASED; 12528c582c7cSDexuan Cui pkt.wslot.val = hpdev->desc.wslot.val; 12538c582c7cSDexuan Cui 12548c582c7cSDexuan Cui ret = vmbus_chan_send(hbus->sc->chan, 12558c582c7cSDexuan Cui VMBUS_CHANPKT_TYPE_INBAND, 0, &pkt, sizeof(pkt), 0); 12568c582c7cSDexuan Cui if (ret) 12578c582c7cSDexuan Cui return (ret); 12588c582c7cSDexuan Cui } 12598c582c7cSDexuan Cui 12608c582c7cSDexuan Cui return (0); 12618c582c7cSDexuan Cui } 12628c582c7cSDexuan Cui 12638c582c7cSDexuan Cui #define hv_cfg_read(x, s) \ 12648c582c7cSDexuan Cui static inline uint##x##_t hv_cfg_read_##s(struct hv_pcibus *bus, \ 12658c582c7cSDexuan Cui bus_size_t offset) \ 12668c582c7cSDexuan Cui { \ 12678c582c7cSDexuan Cui return (bus_read_##s(bus->cfg_res, offset)); \ 12688c582c7cSDexuan Cui } 12698c582c7cSDexuan Cui 12708c582c7cSDexuan Cui #define hv_cfg_write(x, s) \ 12718c582c7cSDexuan Cui static inline void hv_cfg_write_##s(struct hv_pcibus *bus, \ 12728c582c7cSDexuan Cui bus_size_t offset, uint##x##_t val) \ 12738c582c7cSDexuan Cui { \ 12748c582c7cSDexuan Cui return (bus_write_##s(bus->cfg_res, offset, val)); \ 12758c582c7cSDexuan Cui } 12768c582c7cSDexuan Cui 12778c582c7cSDexuan Cui hv_cfg_read(8, 1) 12788c582c7cSDexuan Cui hv_cfg_read(16, 2) 12798c582c7cSDexuan Cui hv_cfg_read(32, 4) 12808c582c7cSDexuan Cui 12818c582c7cSDexuan Cui hv_cfg_write(8, 1) 12828c582c7cSDexuan Cui hv_cfg_write(16, 2) 12838c582c7cSDexuan Cui hv_cfg_write(32, 4) 12848c582c7cSDexuan Cui 12858c582c7cSDexuan Cui static void 12868c582c7cSDexuan Cui _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, int size, 12878c582c7cSDexuan Cui uint32_t *val) 12888c582c7cSDexuan Cui { 12898c582c7cSDexuan Cui struct hv_pcibus *hbus = hpdev->hbus; 12908c582c7cSDexuan Cui bus_size_t addr = CFG_PAGE_OFFSET + where; 12918c582c7cSDexuan Cui 12928c582c7cSDexuan Cui /* 12938c582c7cSDexuan Cui * If the attempt is to read the IDs or the ROM BAR, simulate that. 12948c582c7cSDexuan Cui */ 12958c582c7cSDexuan Cui if (where + size <= PCIR_COMMAND) { 12968c582c7cSDexuan Cui memcpy(val, ((uint8_t *)&hpdev->desc.v_id) + where, size); 12978c582c7cSDexuan Cui } else if (where >= PCIR_REVID && where + size <= 12988c582c7cSDexuan Cui PCIR_CACHELNSZ) { 12998c582c7cSDexuan Cui memcpy(val, ((uint8_t *)&hpdev->desc.rev) + where - 13008c582c7cSDexuan Cui PCIR_REVID, size); 13018c582c7cSDexuan Cui } else if (where >= PCIR_SUBVEND_0 && where + size <= 13028c582c7cSDexuan Cui PCIR_BIOS) { 13038c582c7cSDexuan Cui memcpy(val, (uint8_t *)&hpdev->desc.subsystem_id + where - 13048c582c7cSDexuan Cui PCIR_SUBVEND_0, size); 13058c582c7cSDexuan Cui } else if (where >= PCIR_BIOS && where + size <= 13068c582c7cSDexuan Cui PCIR_CAP_PTR) { 13078c582c7cSDexuan Cui /* ROM BARs are unimplemented */ 13088c582c7cSDexuan Cui *val = 0; 13098c582c7cSDexuan Cui } else if ((where >= PCIR_INTLINE && where + size <= 13108c582c7cSDexuan Cui PCIR_INTPIN) ||(where == PCIR_INTPIN && size == 1)) { 13118c582c7cSDexuan Cui /* 13128c582c7cSDexuan Cui * Interrupt Line and Interrupt PIN are hard-wired to zero 13138c582c7cSDexuan Cui * because this front-end only supports message-signaled 13148c582c7cSDexuan Cui * interrupts. 13158c582c7cSDexuan Cui */ 13168c582c7cSDexuan Cui *val = 0; 13178c582c7cSDexuan Cui } else if (where + size <= CFG_PAGE_SIZE) { 13188c582c7cSDexuan Cui mtx_lock(&hbus->config_lock); 13198c582c7cSDexuan Cui 13208c582c7cSDexuan Cui /* Choose the function to be read. */ 13218c582c7cSDexuan Cui hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val); 13228c582c7cSDexuan Cui 13238c582c7cSDexuan Cui /* Make sure the function was chosen before we start reading.*/ 13248c582c7cSDexuan Cui mb(); 13258c582c7cSDexuan Cui 13268c582c7cSDexuan Cui /* Read from that function's config space. */ 13278c582c7cSDexuan Cui switch (size) { 13288c582c7cSDexuan Cui case 1: 13298c582c7cSDexuan Cui *((uint8_t *)val) = hv_cfg_read_1(hbus, addr); 13308c582c7cSDexuan Cui break; 13318c582c7cSDexuan Cui case 2: 13328c582c7cSDexuan Cui *((uint16_t *)val) = hv_cfg_read_2(hbus, addr); 13338c582c7cSDexuan Cui break; 13348c582c7cSDexuan Cui default: 13358c582c7cSDexuan Cui *((uint32_t *)val) = hv_cfg_read_4(hbus, addr); 13368c582c7cSDexuan Cui break; 13378c582c7cSDexuan Cui } 13388c582c7cSDexuan Cui /* 13398c582c7cSDexuan Cui * Make sure the write was done before we release the lock, 13408c582c7cSDexuan Cui * allowing consecutive reads/writes. 13418c582c7cSDexuan Cui */ 13428c582c7cSDexuan Cui mb(); 13438c582c7cSDexuan Cui 13448c582c7cSDexuan Cui mtx_unlock(&hbus->config_lock); 13458c582c7cSDexuan Cui } else { 13468c582c7cSDexuan Cui /* Invalid config read: it's unlikely to reach here. */ 13478c582c7cSDexuan Cui memset(val, 0, size); 13488c582c7cSDexuan Cui } 13498c582c7cSDexuan Cui } 13508c582c7cSDexuan Cui 13518c582c7cSDexuan Cui static void 13528c582c7cSDexuan Cui _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size, 13538c582c7cSDexuan Cui uint32_t val) 13548c582c7cSDexuan Cui { 13558c582c7cSDexuan Cui struct hv_pcibus *hbus = hpdev->hbus; 13568c582c7cSDexuan Cui bus_size_t addr = CFG_PAGE_OFFSET + where; 13578c582c7cSDexuan Cui 13588c582c7cSDexuan Cui /* SSIDs and ROM BARs are read-only */ 13598c582c7cSDexuan Cui if (where >= PCIR_SUBVEND_0 && where + size <= PCIR_CAP_PTR) 13608c582c7cSDexuan Cui return; 13618c582c7cSDexuan Cui 13628c582c7cSDexuan Cui if (where >= PCIR_COMMAND && where + size <= CFG_PAGE_SIZE) { 13638c582c7cSDexuan Cui mtx_lock(&hbus->config_lock); 13648c582c7cSDexuan Cui 13658c582c7cSDexuan Cui /* Choose the function to be written. */ 13668c582c7cSDexuan Cui hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val); 13678c582c7cSDexuan Cui 13688c582c7cSDexuan Cui /* Make sure the function was chosen before we start writing.*/ 13698c582c7cSDexuan Cui wmb(); 13708c582c7cSDexuan Cui 13718c582c7cSDexuan Cui /* Write to that function's config space. */ 13728c582c7cSDexuan Cui switch (size) { 13738c582c7cSDexuan Cui case 1: 13748c582c7cSDexuan Cui hv_cfg_write_1(hbus, addr, (uint8_t)val); 13758c582c7cSDexuan Cui break; 13768c582c7cSDexuan Cui case 2: 13778c582c7cSDexuan Cui hv_cfg_write_2(hbus, addr, (uint16_t)val); 13788c582c7cSDexuan Cui break; 13798c582c7cSDexuan Cui default: 13808c582c7cSDexuan Cui hv_cfg_write_4(hbus, addr, (uint32_t)val); 13818c582c7cSDexuan Cui break; 13828c582c7cSDexuan Cui } 13838c582c7cSDexuan Cui 13848c582c7cSDexuan Cui /* 13858c582c7cSDexuan Cui * Make sure the write was done before we release the lock, 13868c582c7cSDexuan Cui * allowing consecutive reads/writes. 13878c582c7cSDexuan Cui */ 13888c582c7cSDexuan Cui mb(); 13898c582c7cSDexuan Cui 13908c582c7cSDexuan Cui mtx_unlock(&hbus->config_lock); 13918c582c7cSDexuan Cui } else { 13928c582c7cSDexuan Cui /* Invalid config write: it's unlikely to reach here. */ 13938c582c7cSDexuan Cui return; 13948c582c7cSDexuan Cui } 13958c582c7cSDexuan Cui } 13968c582c7cSDexuan Cui 139775412a52SWei Hu /* 139875412a52SWei Hu * The vPCI in some Hyper-V releases do not initialize the last 4 139975412a52SWei Hu * bit of BAR registers. This could result weird problems causing PCI 140075412a52SWei Hu * code fail to configure BAR correctly. 140175412a52SWei Hu * 140275412a52SWei Hu * Just write all 1's to those BARs whose probed values are not zero. 140375412a52SWei Hu * This seems to make the Hyper-V vPCI and pci_write_bar() to cooperate 140475412a52SWei Hu * correctly. 140575412a52SWei Hu */ 140675412a52SWei Hu 140775412a52SWei Hu static void 140875412a52SWei Hu vmbus_pcib_prepopulate_bars(struct hv_pcibus *hbus) 140975412a52SWei Hu { 141075412a52SWei Hu struct hv_pci_dev *hpdev; 141175412a52SWei Hu int i; 141275412a52SWei Hu 141375412a52SWei Hu mtx_lock(&hbus->device_list_lock); 141475412a52SWei Hu TAILQ_FOREACH(hpdev, &hbus->children, link) { 141575412a52SWei Hu for (i = 0; i < 6; i++) { 141675412a52SWei Hu /* Ignore empty bar */ 141775412a52SWei Hu if (hpdev->probed_bar[i] == 0) 141875412a52SWei Hu continue; 141975412a52SWei Hu 142075412a52SWei Hu uint32_t bar_val = 0; 142175412a52SWei Hu 142275412a52SWei Hu _hv_pcifront_read_config(hpdev, PCIR_BAR(i), 142375412a52SWei Hu 4, &bar_val); 142475412a52SWei Hu 142575412a52SWei Hu if (hpdev->probed_bar[i] != bar_val) { 142675412a52SWei Hu if (bootverbose) 142775412a52SWei Hu printf("vmbus_pcib: initialize bar %d " 142875412a52SWei Hu "by writing all 1s\n", i); 142975412a52SWei Hu 143075412a52SWei Hu _hv_pcifront_write_config(hpdev, PCIR_BAR(i), 143175412a52SWei Hu 4, 0xffffffff); 14325473dee7SWei Hu 14335473dee7SWei Hu /* Now write the original value back */ 14345473dee7SWei Hu _hv_pcifront_write_config(hpdev, PCIR_BAR(i), 14355473dee7SWei Hu 4, bar_val); 143675412a52SWei Hu } 143775412a52SWei Hu } 143875412a52SWei Hu } 143975412a52SWei Hu mtx_unlock(&hbus->device_list_lock); 144075412a52SWei Hu } 144175412a52SWei Hu 14428c582c7cSDexuan Cui static void 14438c582c7cSDexuan Cui vmbus_pcib_set_detaching(void *arg, int pending __unused) 14448c582c7cSDexuan Cui { 14458c582c7cSDexuan Cui struct hv_pcibus *hbus = arg; 14468c582c7cSDexuan Cui 14478c582c7cSDexuan Cui atomic_set_int(&hbus->detaching, 1); 14488c582c7cSDexuan Cui } 14498c582c7cSDexuan Cui 14508c582c7cSDexuan Cui static void 14518c582c7cSDexuan Cui vmbus_pcib_pre_detach(struct hv_pcibus *hbus) 14528c582c7cSDexuan Cui { 14538c582c7cSDexuan Cui struct task task; 14548c582c7cSDexuan Cui 14558c582c7cSDexuan Cui TASK_INIT(&task, 0, vmbus_pcib_set_detaching, hbus); 14568c582c7cSDexuan Cui 14578c582c7cSDexuan Cui /* 14588c582c7cSDexuan Cui * Make sure the channel callback won't push any possible new 14598c582c7cSDexuan Cui * PCI_BUS_RELATIONS and PCI_EJECT tasks to sc->taskq. 14608c582c7cSDexuan Cui */ 14618c582c7cSDexuan Cui vmbus_chan_run_task(hbus->sc->chan, &task); 14628c582c7cSDexuan Cui 14638c582c7cSDexuan Cui taskqueue_drain_all(hbus->sc->taskq); 14648c582c7cSDexuan Cui } 14658c582c7cSDexuan Cui 14668c582c7cSDexuan Cui 14678c582c7cSDexuan Cui /* 14688c582c7cSDexuan Cui * Standard probe entry point. 14698c582c7cSDexuan Cui * 14708c582c7cSDexuan Cui */ 14718c582c7cSDexuan Cui static int 14728c582c7cSDexuan Cui vmbus_pcib_probe(device_t dev) 14738c582c7cSDexuan Cui { 14748c582c7cSDexuan Cui if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 14758c582c7cSDexuan Cui &g_pass_through_dev_type) == 0) { 14768c582c7cSDexuan Cui device_set_desc(dev, "Hyper-V PCI Express Pass Through"); 14778c582c7cSDexuan Cui return (BUS_PROBE_DEFAULT); 14788c582c7cSDexuan Cui } 14798c582c7cSDexuan Cui return (ENXIO); 14808c582c7cSDexuan Cui } 14818c582c7cSDexuan Cui 14828c582c7cSDexuan Cui /* 14838c582c7cSDexuan Cui * Standard attach entry point. 14848c582c7cSDexuan Cui * 14858c582c7cSDexuan Cui */ 14868c582c7cSDexuan Cui static int 14878c582c7cSDexuan Cui vmbus_pcib_attach(device_t dev) 14888c582c7cSDexuan Cui { 14898c582c7cSDexuan Cui const int pci_ring_size = (4 * PAGE_SIZE); 14908c582c7cSDexuan Cui const struct hyperv_guid *inst_guid; 14918c582c7cSDexuan Cui struct vmbus_channel *channel; 14928c582c7cSDexuan Cui struct vmbus_pcib_softc *sc; 14938c582c7cSDexuan Cui struct hv_pcibus *hbus; 14948c582c7cSDexuan Cui int rid = 0; 14958c582c7cSDexuan Cui int ret; 14968c582c7cSDexuan Cui 14978c582c7cSDexuan Cui hbus = malloc(sizeof(*hbus), M_DEVBUF, M_WAITOK | M_ZERO); 14988c582c7cSDexuan Cui hbus->pcib = dev; 14998c582c7cSDexuan Cui 15008c582c7cSDexuan Cui channel = vmbus_get_channel(dev); 15018c582c7cSDexuan Cui inst_guid = vmbus_chan_guid_inst(channel); 15028c582c7cSDexuan Cui hbus->pci_domain = inst_guid->hv_guid[9] | 15038c582c7cSDexuan Cui (inst_guid->hv_guid[8] << 8); 15048c582c7cSDexuan Cui 15058c582c7cSDexuan Cui mtx_init(&hbus->config_lock, "hbcfg", NULL, MTX_DEF); 15068c582c7cSDexuan Cui mtx_init(&hbus->device_list_lock, "hbdl", NULL, MTX_DEF); 15078c582c7cSDexuan Cui TAILQ_INIT(&hbus->children); 15088c582c7cSDexuan Cui TAILQ_INIT(&hbus->dr_list); 15098c582c7cSDexuan Cui 15108c582c7cSDexuan Cui hbus->cfg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 15118c582c7cSDexuan Cui 0, RM_MAX_END, PCI_CONFIG_MMIO_LENGTH, 15128c582c7cSDexuan Cui RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE)); 15138c582c7cSDexuan Cui 15148c582c7cSDexuan Cui if (!hbus->cfg_res) { 15158c582c7cSDexuan Cui device_printf(dev, "failed to get resource for cfg window\n"); 15168c582c7cSDexuan Cui ret = ENXIO; 15178c582c7cSDexuan Cui goto free_bus; 15188c582c7cSDexuan Cui } 15198c582c7cSDexuan Cui 15208c582c7cSDexuan Cui sc = device_get_softc(dev); 15218c582c7cSDexuan Cui sc->chan = channel; 15228c582c7cSDexuan Cui sc->rx_buf = malloc(PCIB_PACKET_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); 15238c582c7cSDexuan Cui sc->hbus = hbus; 15248c582c7cSDexuan Cui 15258c582c7cSDexuan Cui /* 15268c582c7cSDexuan Cui * The taskq is used to handle PCI_BUS_RELATIONS and PCI_EJECT 15278c582c7cSDexuan Cui * messages. NB: we can't handle the messages in the channel callback 15288c582c7cSDexuan Cui * directly, because the message handlers need to send new messages 15298c582c7cSDexuan Cui * to the host and waits for the host's completion messages, which 15308c582c7cSDexuan Cui * must also be handled by the channel callback. 15318c582c7cSDexuan Cui */ 15328c582c7cSDexuan Cui sc->taskq = taskqueue_create("vmbus_pcib_tq", M_WAITOK, 15338c582c7cSDexuan Cui taskqueue_thread_enqueue, &sc->taskq); 15348c582c7cSDexuan Cui taskqueue_start_threads(&sc->taskq, 1, PI_NET, "vmbus_pcib_tq"); 15358c582c7cSDexuan Cui 15368c582c7cSDexuan Cui hbus->sc = sc; 15378c582c7cSDexuan Cui 15388c582c7cSDexuan Cui init_completion(&hbus->query_completion); 15398c582c7cSDexuan Cui hbus->query_comp = &hbus->query_completion; 15408c582c7cSDexuan Cui 15418c582c7cSDexuan Cui ret = vmbus_chan_open(sc->chan, pci_ring_size, pci_ring_size, 15428c582c7cSDexuan Cui NULL, 0, vmbus_pcib_on_channel_callback, sc); 15438c582c7cSDexuan Cui if (ret) 15448c582c7cSDexuan Cui goto free_res; 15458c582c7cSDexuan Cui 1546ea11861eSWei Hu ret = hv_pci_protocol_negotiation(hbus, pci_protocol_versions, 1547ea11861eSWei Hu ARRAY_SIZE(pci_protocol_versions)); 15488c582c7cSDexuan Cui if (ret) 15498c582c7cSDexuan Cui goto vmbus_close; 15508c582c7cSDexuan Cui 15518c582c7cSDexuan Cui ret = hv_pci_query_relations(hbus); 155275c2786cSWei Hu if (!ret) 155375c2786cSWei Hu ret = wait_for_response(hbus, hbus->query_comp); 155475c2786cSWei Hu 15558c582c7cSDexuan Cui if (ret) 15568c582c7cSDexuan Cui goto vmbus_close; 15578c582c7cSDexuan Cui 15588c582c7cSDexuan Cui ret = hv_pci_enter_d0(hbus); 15598c582c7cSDexuan Cui if (ret) 15608c582c7cSDexuan Cui goto vmbus_close; 15618c582c7cSDexuan Cui 15628c582c7cSDexuan Cui ret = hv_send_resources_allocated(hbus); 15638c582c7cSDexuan Cui if (ret) 15648c582c7cSDexuan Cui goto vmbus_close; 15658c582c7cSDexuan Cui 156675412a52SWei Hu vmbus_pcib_prepopulate_bars(hbus); 156775412a52SWei Hu 15688c582c7cSDexuan Cui hbus->pci_bus = device_add_child(dev, "pci", -1); 15698c582c7cSDexuan Cui if (!hbus->pci_bus) { 15708c582c7cSDexuan Cui device_printf(dev, "failed to create pci bus\n"); 15718c582c7cSDexuan Cui ret = ENXIO; 15728c582c7cSDexuan Cui goto vmbus_close; 15738c582c7cSDexuan Cui } 15748c582c7cSDexuan Cui 15758c582c7cSDexuan Cui bus_generic_attach(dev); 15768c582c7cSDexuan Cui 15778c582c7cSDexuan Cui hbus->state = hv_pcibus_installed; 15788c582c7cSDexuan Cui 15798c582c7cSDexuan Cui return (0); 15808c582c7cSDexuan Cui 15818c582c7cSDexuan Cui vmbus_close: 15828c582c7cSDexuan Cui vmbus_pcib_pre_detach(hbus); 15838c582c7cSDexuan Cui vmbus_chan_close(sc->chan); 15848c582c7cSDexuan Cui free_res: 15858c582c7cSDexuan Cui taskqueue_free(sc->taskq); 15868c582c7cSDexuan Cui free_completion(&hbus->query_completion); 15878c582c7cSDexuan Cui free(sc->rx_buf, M_DEVBUF); 15888c582c7cSDexuan Cui bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res); 15898c582c7cSDexuan Cui free_bus: 15908c582c7cSDexuan Cui mtx_destroy(&hbus->device_list_lock); 15918c582c7cSDexuan Cui mtx_destroy(&hbus->config_lock); 15928c582c7cSDexuan Cui free(hbus, M_DEVBUF); 15938c582c7cSDexuan Cui return (ret); 15948c582c7cSDexuan Cui } 15958c582c7cSDexuan Cui 15968c582c7cSDexuan Cui /* 15978c582c7cSDexuan Cui * Standard detach entry point 15988c582c7cSDexuan Cui */ 15998c582c7cSDexuan Cui static int 16008c582c7cSDexuan Cui vmbus_pcib_detach(device_t dev) 16018c582c7cSDexuan Cui { 16028c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 16038c582c7cSDexuan Cui struct hv_pcibus *hbus = sc->hbus; 16048c582c7cSDexuan Cui struct pci_message teardown_packet; 16058c582c7cSDexuan Cui struct pci_bus_relations relations; 16068c582c7cSDexuan Cui int ret; 16078c582c7cSDexuan Cui 16088c582c7cSDexuan Cui vmbus_pcib_pre_detach(hbus); 16098c582c7cSDexuan Cui 16108c582c7cSDexuan Cui if (hbus->state == hv_pcibus_installed) 16118c582c7cSDexuan Cui bus_generic_detach(dev); 16128c582c7cSDexuan Cui 16138c582c7cSDexuan Cui /* Delete any children which might still exist. */ 16148c582c7cSDexuan Cui memset(&relations, 0, sizeof(relations)); 16158c582c7cSDexuan Cui hv_pci_devices_present(hbus, &relations); 16168c582c7cSDexuan Cui 16178c582c7cSDexuan Cui ret = hv_send_resources_released(hbus); 16188c582c7cSDexuan Cui if (ret) 16198c582c7cSDexuan Cui device_printf(dev, "failed to send PCI_RESOURCES_RELEASED\n"); 16208c582c7cSDexuan Cui 16218c582c7cSDexuan Cui teardown_packet.type = PCI_BUS_D0EXIT; 16228c582c7cSDexuan Cui ret = vmbus_chan_send(sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 16238c582c7cSDexuan Cui &teardown_packet, sizeof(struct pci_message), 0); 16248c582c7cSDexuan Cui if (ret) 16258c582c7cSDexuan Cui device_printf(dev, "failed to send PCI_BUS_D0EXIT\n"); 16268c582c7cSDexuan Cui 16278c582c7cSDexuan Cui taskqueue_drain_all(hbus->sc->taskq); 16288c582c7cSDexuan Cui vmbus_chan_close(sc->chan); 16298c582c7cSDexuan Cui taskqueue_free(sc->taskq); 16308c582c7cSDexuan Cui 16318c582c7cSDexuan Cui free_completion(&hbus->query_completion); 16328c582c7cSDexuan Cui free(sc->rx_buf, M_DEVBUF); 16338c582c7cSDexuan Cui bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res); 16348c582c7cSDexuan Cui 16358c582c7cSDexuan Cui mtx_destroy(&hbus->device_list_lock); 16368c582c7cSDexuan Cui mtx_destroy(&hbus->config_lock); 16378c582c7cSDexuan Cui free(hbus, M_DEVBUF); 16388c582c7cSDexuan Cui 16398c582c7cSDexuan Cui return (0); 16408c582c7cSDexuan Cui } 16418c582c7cSDexuan Cui 16428c582c7cSDexuan Cui static int 16438c582c7cSDexuan Cui vmbus_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *val) 16448c582c7cSDexuan Cui { 16458c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 16468c582c7cSDexuan Cui 16478c582c7cSDexuan Cui switch (which) { 16488c582c7cSDexuan Cui case PCIB_IVAR_DOMAIN: 16498c582c7cSDexuan Cui *val = sc->hbus->pci_domain; 16508c582c7cSDexuan Cui return (0); 16518c582c7cSDexuan Cui 16528c582c7cSDexuan Cui case PCIB_IVAR_BUS: 16538c582c7cSDexuan Cui /* There is only bus 0. */ 16548c582c7cSDexuan Cui *val = 0; 16558c582c7cSDexuan Cui return (0); 16568c582c7cSDexuan Cui } 16578c582c7cSDexuan Cui return (ENOENT); 16588c582c7cSDexuan Cui } 16598c582c7cSDexuan Cui 16608c582c7cSDexuan Cui static int 16618c582c7cSDexuan Cui vmbus_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t val) 16628c582c7cSDexuan Cui { 16638c582c7cSDexuan Cui return (ENOENT); 16648c582c7cSDexuan Cui } 16658c582c7cSDexuan Cui 16668c582c7cSDexuan Cui static struct resource * 16678c582c7cSDexuan Cui vmbus_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 16688c582c7cSDexuan Cui rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 16698c582c7cSDexuan Cui { 16708c582c7cSDexuan Cui unsigned int bar_no; 16718c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 16728c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 16738c582c7cSDexuan Cui struct resource *res; 16748c582c7cSDexuan Cui unsigned int devfn; 16758c582c7cSDexuan Cui 16768c582c7cSDexuan Cui if (type == PCI_RES_BUS) 16778c582c7cSDexuan Cui return (pci_domain_alloc_bus(sc->hbus->pci_domain, child, rid, 16788c582c7cSDexuan Cui start, end, count, flags)); 16798c582c7cSDexuan Cui 16808c582c7cSDexuan Cui /* Devices with port I/O BAR are not supported. */ 16818c582c7cSDexuan Cui if (type == SYS_RES_IOPORT) 16828c582c7cSDexuan Cui return (NULL); 16838c582c7cSDexuan Cui 16848c582c7cSDexuan Cui if (type == SYS_RES_MEMORY) { 16858c582c7cSDexuan Cui devfn = PCI_DEVFN(pci_get_slot(child), 16868c582c7cSDexuan Cui pci_get_function(child)); 16878c582c7cSDexuan Cui hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 16888c582c7cSDexuan Cui if (!hpdev) 16898c582c7cSDexuan Cui return (NULL); 16908c582c7cSDexuan Cui 16918c582c7cSDexuan Cui bar_no = PCI_RID2BAR(*rid); 16928c582c7cSDexuan Cui if (bar_no >= MAX_NUM_BARS) 16938c582c7cSDexuan Cui return (NULL); 16948c582c7cSDexuan Cui 16958c582c7cSDexuan Cui /* Make sure a 32-bit BAR gets a 32-bit address */ 16968c582c7cSDexuan Cui if (!(hpdev->probed_bar[bar_no] & PCIM_BAR_MEM_64)) 16978c582c7cSDexuan Cui end = ulmin(end, 0xFFFFFFFF); 16988c582c7cSDexuan Cui } 16998c582c7cSDexuan Cui 17008c582c7cSDexuan Cui res = bus_generic_alloc_resource(dev, child, type, rid, 17018c582c7cSDexuan Cui start, end, count, flags); 17028c582c7cSDexuan Cui /* 17038c582c7cSDexuan Cui * If this is a request for a specific range, assume it is 17048c582c7cSDexuan Cui * correct and pass it up to the parent. 17058c582c7cSDexuan Cui */ 17068c582c7cSDexuan Cui if (res == NULL && start + count - 1 == end) 17078c582c7cSDexuan Cui res = bus_generic_alloc_resource(dev, child, type, rid, 17088c582c7cSDexuan Cui start, end, count, flags); 17094196186dSLi-Wen Hsu if (res == NULL) 17104196186dSLi-Wen Hsu device_printf(dev, "vmbus_pcib_alloc_resource failed\n"); 17114196186dSLi-Wen Hsu 17128c582c7cSDexuan Cui return (res); 17138c582c7cSDexuan Cui } 17148c582c7cSDexuan Cui 17158c582c7cSDexuan Cui static int 1716fef01f04SJohn Baldwin vmbus_pcib_adjust_resource(device_t dev, device_t child, 17179c4effb1SJohn Baldwin struct resource *r, rman_res_t start, rman_res_t end) 17189c4effb1SJohn Baldwin { 17199c4effb1SJohn Baldwin struct vmbus_pcib_softc *sc = device_get_softc(dev); 17209c4effb1SJohn Baldwin 1721fef01f04SJohn Baldwin if (rman_get_type(r) == PCI_RES_BUS) 17229c4effb1SJohn Baldwin return (pci_domain_adjust_bus(sc->hbus->pci_domain, child, r, 17239c4effb1SJohn Baldwin start, end)); 1724fef01f04SJohn Baldwin return (bus_generic_adjust_resource(dev, child, r, start, end)); 17259c4effb1SJohn Baldwin } 17269c4effb1SJohn Baldwin 17279c4effb1SJohn Baldwin static int 17288c582c7cSDexuan Cui vmbus_pcib_release_resource(device_t dev, device_t child, int type, int rid, 17298c582c7cSDexuan Cui struct resource *r) 17308c582c7cSDexuan Cui { 17318c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 17328c582c7cSDexuan Cui 17338c582c7cSDexuan Cui if (type == PCI_RES_BUS) 17348c582c7cSDexuan Cui return (pci_domain_release_bus(sc->hbus->pci_domain, child, 17358c582c7cSDexuan Cui rid, r)); 17368c582c7cSDexuan Cui 17378c582c7cSDexuan Cui if (type == SYS_RES_IOPORT) 17388c582c7cSDexuan Cui return (EINVAL); 17398c582c7cSDexuan Cui 17408c582c7cSDexuan Cui return (bus_generic_release_resource(dev, child, type, rid, r)); 17418c582c7cSDexuan Cui } 17428c582c7cSDexuan Cui 17438c582c7cSDexuan Cui static int 1744*2baed46eSJohn Baldwin vmbus_pcib_activate_resource(device_t dev, device_t child, struct resource *r) 17459c4effb1SJohn Baldwin { 17469c4effb1SJohn Baldwin struct vmbus_pcib_softc *sc = device_get_softc(dev); 17479c4effb1SJohn Baldwin 1748*2baed46eSJohn Baldwin if (rman_get_type(r) == PCI_RES_BUS) 17499c4effb1SJohn Baldwin return (pci_domain_activate_bus(sc->hbus->pci_domain, child, 1750*2baed46eSJohn Baldwin r)); 1751*2baed46eSJohn Baldwin return (bus_generic_activate_resource(dev, child, r)); 17529c4effb1SJohn Baldwin } 17539c4effb1SJohn Baldwin 17549c4effb1SJohn Baldwin static int 1755*2baed46eSJohn Baldwin vmbus_pcib_deactivate_resource(device_t dev, device_t child, struct resource *r) 17569c4effb1SJohn Baldwin { 17579c4effb1SJohn Baldwin struct vmbus_pcib_softc *sc = device_get_softc(dev); 17589c4effb1SJohn Baldwin 1759*2baed46eSJohn Baldwin if (rman_get_type(r) == PCI_RES_BUS) 17609c4effb1SJohn Baldwin return (pci_domain_deactivate_bus(sc->hbus->pci_domain, child, 1761*2baed46eSJohn Baldwin r)); 1762*2baed46eSJohn Baldwin return (bus_generic_deactivate_resource(dev, child, r)); 17639c4effb1SJohn Baldwin } 17649c4effb1SJohn Baldwin 17659c4effb1SJohn Baldwin static int 17668c582c7cSDexuan Cui vmbus_pcib_get_cpus(device_t pcib, device_t dev, enum cpu_sets op, 17678c582c7cSDexuan Cui size_t setsize, cpuset_t *cpuset) 17688c582c7cSDexuan Cui { 17698c582c7cSDexuan Cui return (bus_get_cpus(pcib, op, setsize, cpuset)); 17708c582c7cSDexuan Cui } 17718c582c7cSDexuan Cui 17728c582c7cSDexuan Cui static uint32_t 17738c582c7cSDexuan Cui vmbus_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 17748c582c7cSDexuan Cui u_int reg, int bytes) 17758c582c7cSDexuan Cui { 17768c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 17778c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 17788c582c7cSDexuan Cui unsigned int devfn = PCI_DEVFN(slot, func); 17798c582c7cSDexuan Cui uint32_t data = 0; 17808c582c7cSDexuan Cui 17818c582c7cSDexuan Cui KASSERT(bus == 0, ("bus should be 0, but is %u", bus)); 17828c582c7cSDexuan Cui 17838c582c7cSDexuan Cui hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 17848c582c7cSDexuan Cui if (!hpdev) 17858c582c7cSDexuan Cui return (~0); 17868c582c7cSDexuan Cui 17878c582c7cSDexuan Cui _hv_pcifront_read_config(hpdev, reg, bytes, &data); 17888c582c7cSDexuan Cui 17898c582c7cSDexuan Cui return (data); 17908c582c7cSDexuan Cui } 17918c582c7cSDexuan Cui 17928c582c7cSDexuan Cui static void 17938c582c7cSDexuan Cui vmbus_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 17948c582c7cSDexuan Cui u_int reg, uint32_t data, int bytes) 17958c582c7cSDexuan Cui { 17968c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(dev); 17978c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 17988c582c7cSDexuan Cui unsigned int devfn = PCI_DEVFN(slot, func); 17998c582c7cSDexuan Cui 18008c582c7cSDexuan Cui KASSERT(bus == 0, ("bus should be 0, but is %u", bus)); 18018c582c7cSDexuan Cui 18028c582c7cSDexuan Cui hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 18038c582c7cSDexuan Cui if (!hpdev) 18048c582c7cSDexuan Cui return; 18058c582c7cSDexuan Cui 18068c582c7cSDexuan Cui _hv_pcifront_write_config(hpdev, reg, bytes, data); 18078c582c7cSDexuan Cui } 18088c582c7cSDexuan Cui 18098c582c7cSDexuan Cui static int 18108c582c7cSDexuan Cui vmbus_pcib_route_intr(device_t pcib, device_t dev, int pin) 18118c582c7cSDexuan Cui { 18128c582c7cSDexuan Cui /* We only support MSI/MSI-X and don't support INTx interrupt. */ 18138c582c7cSDexuan Cui return (PCI_INVALID_IRQ); 18148c582c7cSDexuan Cui } 18158c582c7cSDexuan Cui 18168c582c7cSDexuan Cui static int 18178c582c7cSDexuan Cui vmbus_pcib_alloc_msi(device_t pcib, device_t dev, int count, 18188c582c7cSDexuan Cui int maxcount, int *irqs) 18198c582c7cSDexuan Cui { 1820ea11861eSWei Hu #if defined(__amd64__) || defined(__i386__) 18218c582c7cSDexuan Cui return (PCIB_ALLOC_MSI(device_get_parent(pcib), dev, count, maxcount, 18228c582c7cSDexuan Cui irqs)); 1823ea11861eSWei Hu #endif 1824ea11861eSWei Hu #if defined(__aarch64__) 1825ea11861eSWei Hu return (intr_alloc_msi(pcib, dev, ACPI_MSI_XREF, count, maxcount, 1826ea11861eSWei Hu irqs)); 1827ea11861eSWei Hu #endif 18288c582c7cSDexuan Cui } 18298c582c7cSDexuan Cui 18308c582c7cSDexuan Cui static int 18318c582c7cSDexuan Cui vmbus_pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 18328c582c7cSDexuan Cui { 1833ea11861eSWei Hu #if defined(__amd64__) || defined(__i386__) 18348c582c7cSDexuan Cui return (PCIB_RELEASE_MSI(device_get_parent(pcib), dev, count, irqs)); 1835ea11861eSWei Hu #endif 1836ea11861eSWei Hu #if defined(__aarch64__) 1837ea11861eSWei Hu return(intr_release_msi(pcib, dev, ACPI_MSI_XREF, count, irqs)); 1838ea11861eSWei Hu #endif 18398c582c7cSDexuan Cui } 18408c582c7cSDexuan Cui 18418c582c7cSDexuan Cui static int 18428c582c7cSDexuan Cui vmbus_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 18438c582c7cSDexuan Cui { 1844ea11861eSWei Hu #if defined(__aarch64__) 1845ea11861eSWei Hu int ret; 1846ea11861eSWei Hu #if defined(INTRNG) 1847ea11861eSWei Hu ret = intr_alloc_msix(pcib, dev, ACPI_MSI_XREF, irq); 1848ea11861eSWei Hu return ret; 1849ea11861eSWei Hu #else 1850ea11861eSWei Hu return (ENXIO); 1851ea11861eSWei Hu #endif 1852ea11861eSWei Hu #else 18538c582c7cSDexuan Cui return (PCIB_ALLOC_MSIX(device_get_parent(pcib), dev, irq)); 1854ea11861eSWei Hu #endif /* __aarch64__ */ 18558c582c7cSDexuan Cui } 18568c582c7cSDexuan Cui 18578c582c7cSDexuan Cui static int 18588c582c7cSDexuan Cui vmbus_pcib_release_msix(device_t pcib, device_t dev, int irq) 18598c582c7cSDexuan Cui { 1860ea11861eSWei Hu #if defined(__aarch64__) 1861ea11861eSWei Hu return (intr_release_msix(pcib, dev, ACPI_MSI_XREF, irq)); 1862ea11861eSWei Hu #else 18638c582c7cSDexuan Cui return (PCIB_RELEASE_MSIX(device_get_parent(pcib), dev, irq)); 1864ea11861eSWei Hu #endif /* __aarch64__ */ 18658c582c7cSDexuan Cui } 18668c582c7cSDexuan Cui 1867ea11861eSWei Hu #if defined(__aarch64__) 1868ea11861eSWei Hu #define MSI_INTEL_ADDR_DEST 0x00000000 1869ea11861eSWei Hu #define MSI_INTEL_DATA_DELFIXED 0x0 1870ea11861eSWei Hu #endif 1871ea11861eSWei Hu #if defined(__amd64__) || defined(__i386__) 18728c582c7cSDexuan Cui #define MSI_INTEL_ADDR_DEST 0x000ff000 18738c582c7cSDexuan Cui #define MSI_INTEL_DATA_INTVEC IOART_INTVEC /* Interrupt vector. */ 18748c582c7cSDexuan Cui #define MSI_INTEL_DATA_DELFIXED IOART_DELFIXED 1875ea11861eSWei Hu #endif 18768c582c7cSDexuan Cui 18778c582c7cSDexuan Cui static int 18788c582c7cSDexuan Cui vmbus_pcib_map_msi(device_t pcib, device_t child, int irq, 18798c582c7cSDexuan Cui uint64_t *addr, uint32_t *data) 18808c582c7cSDexuan Cui { 18818c582c7cSDexuan Cui unsigned int devfn; 18828c582c7cSDexuan Cui struct hv_pci_dev *hpdev; 18838c582c7cSDexuan Cui 18848c582c7cSDexuan Cui uint64_t v_addr; 18858c582c7cSDexuan Cui uint32_t v_data; 18868c582c7cSDexuan Cui struct hv_irq_desc *hid, *tmp_hid; 18878c582c7cSDexuan Cui unsigned int cpu, vcpu_id; 18888c582c7cSDexuan Cui unsigned int vector; 18898c582c7cSDexuan Cui 18908c582c7cSDexuan Cui struct vmbus_pcib_softc *sc = device_get_softc(pcib); 18918c582c7cSDexuan Cui struct compose_comp_ctxt comp; 18928c582c7cSDexuan Cui struct { 18938c582c7cSDexuan Cui struct pci_packet pkt; 1894ea11861eSWei Hu union { 1895ea11861eSWei Hu struct pci_create_interrupt v1; 1896ea11861eSWei Hu struct pci_create_interrupt3 v3; 1897ea11861eSWei Hu }int_pkts; 18988c582c7cSDexuan Cui } ctxt; 18998c582c7cSDexuan Cui int ret; 1900ea11861eSWei Hu uint32_t size; 19018c582c7cSDexuan Cui 19028c582c7cSDexuan Cui devfn = PCI_DEVFN(pci_get_slot(child), pci_get_function(child)); 19038c582c7cSDexuan Cui hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 19048c582c7cSDexuan Cui if (!hpdev) 19058c582c7cSDexuan Cui return (ENOENT); 1906ea11861eSWei Hu #if defined(__aarch64__) 1907ea11861eSWei Hu ret = intr_map_msi(pcib, child, ACPI_MSI_XREF, irq, 1908ea11861eSWei Hu &v_addr, &v_data); 1909ea11861eSWei Hu #else 19108c582c7cSDexuan Cui ret = PCIB_MAP_MSI(device_get_parent(pcib), child, irq, 19118c582c7cSDexuan Cui &v_addr, &v_data); 1912ea11861eSWei Hu #endif 19138c582c7cSDexuan Cui if (ret) 19148c582c7cSDexuan Cui return (ret); 19158c582c7cSDexuan Cui 19168c582c7cSDexuan Cui TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid) { 19178c582c7cSDexuan Cui if (hid->irq == irq) { 19188c582c7cSDexuan Cui TAILQ_REMOVE(&hpdev->irq_desc_list, hid, link); 19198c582c7cSDexuan Cui hv_int_desc_free(hpdev, hid); 19208c582c7cSDexuan Cui break; 19218c582c7cSDexuan Cui } 19228c582c7cSDexuan Cui } 19238c582c7cSDexuan Cui 1924ea11861eSWei Hu #if defined(__aarch64__) 1925ea11861eSWei Hu cpu = 0; 1926ea11861eSWei Hu vcpu_id = VMBUS_GET_VCPU_ID(device_get_parent(pcib), pcib, cpu); 1927ea11861eSWei Hu vector = v_data; 1928ea11861eSWei Hu #else 1929999174baSWei Hu cpu = apic_cpuid((v_addr & MSI_INTEL_ADDR_DEST) >> 12); 19308c582c7cSDexuan Cui vcpu_id = VMBUS_GET_VCPU_ID(device_get_parent(pcib), pcib, cpu); 19318c582c7cSDexuan Cui vector = v_data & MSI_INTEL_DATA_INTVEC; 1932ea11861eSWei Hu #endif 19338c582c7cSDexuan Cui 1934999174baSWei Hu if (hpdev->hbus->protocol_version < PCI_PROTOCOL_VERSION_1_4 && 1935999174baSWei Hu vcpu_id > 63) { 1936999174baSWei Hu /* We only support vcpu_id < 64 before vPCI version 1.4 */ 1937999174baSWei Hu device_printf(pcib, 1938999174baSWei Hu "Error: " 1939999174baSWei Hu "vcpu_id %u overflowed on PCI VMBus version 0x%x\n", 1940999174baSWei Hu vcpu_id, hpdev->hbus->protocol_version); 1941999174baSWei Hu return (ENODEV); 1942999174baSWei Hu } 1943999174baSWei Hu 19448c582c7cSDexuan Cui init_completion(&comp.comp_pkt.host_event); 19458c582c7cSDexuan Cui 19468c582c7cSDexuan Cui memset(&ctxt, 0, sizeof(ctxt)); 19478c582c7cSDexuan Cui ctxt.pkt.completion_func = hv_pci_compose_compl; 19488c582c7cSDexuan Cui ctxt.pkt.compl_ctxt = ∁ 1949ea11861eSWei Hu switch (hpdev->hbus->protocol_version) { 1950ea11861eSWei Hu case PCI_PROTOCOL_VERSION_1_1: 1951ea11861eSWei Hu ctxt.int_pkts.v1.message_type.type = 1952ea11861eSWei Hu PCI_CREATE_INTERRUPT_MESSAGE; 1953ea11861eSWei Hu ctxt.int_pkts.v1.wslot.val = hpdev->desc.wslot.val; 1954ea11861eSWei Hu ctxt.int_pkts.v1.int_desc.vector = vector; 1955ea11861eSWei Hu ctxt.int_pkts.v1.int_desc.vector_count = 1; 1956ea11861eSWei Hu ctxt.int_pkts.v1.int_desc.delivery_mode = 1957ea11861eSWei Hu MSI_INTEL_DATA_DELFIXED; 1958ea11861eSWei Hu ctxt.int_pkts.v1.int_desc.cpu_mask = 1ULL << vcpu_id; 1959ea11861eSWei Hu size = sizeof(ctxt.int_pkts.v1); 1960ea11861eSWei Hu break; 19618c582c7cSDexuan Cui 1962ea11861eSWei Hu case PCI_PROTOCOL_VERSION_1_4: 1963ea11861eSWei Hu ctxt.int_pkts.v3.message_type.type = 1964ea11861eSWei Hu PCI_CREATE_INTERRUPT_MESSAGE3; 1965ea11861eSWei Hu ctxt.int_pkts.v3.wslot.val = hpdev->desc.wslot.val; 1966ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.vector = vector; 1967ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.vector_count = 1; 1968ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.reserved = 0; 1969ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.delivery_mode = 1970ea11861eSWei Hu MSI_INTEL_DATA_DELFIXED; 1971ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.processor_count = 1; 1972ea11861eSWei Hu ctxt.int_pkts.v3.int_desc.processor_array[0] = vcpu_id; 1973ea11861eSWei Hu size = sizeof(ctxt.int_pkts.v3); 1974ea11861eSWei Hu break; 1975ea11861eSWei Hu } 19768c582c7cSDexuan Cui ret = vmbus_chan_send(sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 1977ea11861eSWei Hu VMBUS_CHANPKT_FLAG_RC, &ctxt.int_pkts, size, 1978aaf13123SDimitry Andric (uint64_t)(uintptr_t)&ctxt.pkt); 19798c582c7cSDexuan Cui if (ret) { 19808c582c7cSDexuan Cui free_completion(&comp.comp_pkt.host_event); 19818c582c7cSDexuan Cui return (ret); 19828c582c7cSDexuan Cui } 19838c582c7cSDexuan Cui 19848c582c7cSDexuan Cui wait_for_completion(&comp.comp_pkt.host_event); 19858c582c7cSDexuan Cui free_completion(&comp.comp_pkt.host_event); 19868c582c7cSDexuan Cui 1987ea11861eSWei Hu if (comp.comp_pkt.completion_status < 0) { 1988ea11861eSWei Hu device_printf(pcib, 1989ea11861eSWei Hu "vmbus_pcib_map_msi completion_status %d\n", 1990ea11861eSWei Hu comp.comp_pkt.completion_status); 19918c582c7cSDexuan Cui return (EPROTO); 1992ea11861eSWei Hu } 19938c582c7cSDexuan Cui 19948c582c7cSDexuan Cui *addr = comp.int_desc.address; 19958c582c7cSDexuan Cui *data = comp.int_desc.data; 19968c582c7cSDexuan Cui 19978c582c7cSDexuan Cui hid = malloc(sizeof(struct hv_irq_desc), M_DEVBUF, M_WAITOK | M_ZERO); 19988c582c7cSDexuan Cui hid->irq = irq; 19998c582c7cSDexuan Cui hid->desc = comp.int_desc; 20008c582c7cSDexuan Cui TAILQ_INSERT_TAIL(&hpdev->irq_desc_list, hid, link); 20018c582c7cSDexuan Cui 20028c582c7cSDexuan Cui return (0); 20038c582c7cSDexuan Cui } 20048c582c7cSDexuan Cui 20058c582c7cSDexuan Cui static device_method_t vmbus_pcib_methods[] = { 20068c582c7cSDexuan Cui /* Device interface */ 20078c582c7cSDexuan Cui DEVMETHOD(device_probe, vmbus_pcib_probe), 20088c582c7cSDexuan Cui DEVMETHOD(device_attach, vmbus_pcib_attach), 20098c582c7cSDexuan Cui DEVMETHOD(device_detach, vmbus_pcib_detach), 20108c582c7cSDexuan Cui DEVMETHOD(device_shutdown, bus_generic_shutdown), 20118c582c7cSDexuan Cui DEVMETHOD(device_suspend, bus_generic_suspend), 20128c582c7cSDexuan Cui DEVMETHOD(device_resume, bus_generic_resume), 20138c582c7cSDexuan Cui 20148c582c7cSDexuan Cui /* Bus interface */ 20158c582c7cSDexuan Cui DEVMETHOD(bus_read_ivar, vmbus_pcib_read_ivar), 20168c582c7cSDexuan Cui DEVMETHOD(bus_write_ivar, vmbus_pcib_write_ivar), 20178c582c7cSDexuan Cui DEVMETHOD(bus_alloc_resource, vmbus_pcib_alloc_resource), 20189c4effb1SJohn Baldwin DEVMETHOD(bus_adjust_resource, vmbus_pcib_adjust_resource), 20198c582c7cSDexuan Cui DEVMETHOD(bus_release_resource, vmbus_pcib_release_resource), 20209c4effb1SJohn Baldwin DEVMETHOD(bus_activate_resource, vmbus_pcib_activate_resource), 20219c4effb1SJohn Baldwin DEVMETHOD(bus_deactivate_resource, vmbus_pcib_deactivate_resource), 20228c582c7cSDexuan Cui DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 20238c582c7cSDexuan Cui DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 20248c582c7cSDexuan Cui DEVMETHOD(bus_get_cpus, vmbus_pcib_get_cpus), 20258c582c7cSDexuan Cui 20268c582c7cSDexuan Cui /* pcib interface */ 20278c582c7cSDexuan Cui DEVMETHOD(pcib_maxslots, pcib_maxslots), 20288c582c7cSDexuan Cui DEVMETHOD(pcib_read_config, vmbus_pcib_read_config), 20298c582c7cSDexuan Cui DEVMETHOD(pcib_write_config, vmbus_pcib_write_config), 20308c582c7cSDexuan Cui DEVMETHOD(pcib_route_interrupt, vmbus_pcib_route_intr), 20318c582c7cSDexuan Cui DEVMETHOD(pcib_alloc_msi, vmbus_pcib_alloc_msi), 20328c582c7cSDexuan Cui DEVMETHOD(pcib_release_msi, vmbus_pcib_release_msi), 20338c582c7cSDexuan Cui DEVMETHOD(pcib_alloc_msix, vmbus_pcib_alloc_msix), 20348c582c7cSDexuan Cui DEVMETHOD(pcib_release_msix, vmbus_pcib_release_msix), 20358c582c7cSDexuan Cui DEVMETHOD(pcib_map_msi, vmbus_pcib_map_msi), 203628586889SWarner Losh DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), 20378c582c7cSDexuan Cui 20388c582c7cSDexuan Cui DEVMETHOD_END 20398c582c7cSDexuan Cui }; 20408c582c7cSDexuan Cui 20418c582c7cSDexuan Cui DEFINE_CLASS_0(pcib, vmbus_pcib_driver, vmbus_pcib_methods, 20428c582c7cSDexuan Cui sizeof(struct vmbus_pcib_softc)); 2043c1cef544SJohn Baldwin DRIVER_MODULE(vmbus_pcib, vmbus, vmbus_pcib_driver, 0, 0); 20448c582c7cSDexuan Cui MODULE_DEPEND(vmbus_pcib, vmbus, 1, 1, 1); 20458c582c7cSDexuan Cui MODULE_DEPEND(vmbus_pcib, pci, 1, 1, 1); 2046cdb316eeSDexuan Cui 2047cdb316eeSDexuan Cui #endif /* NEW_PCIB */ 2048