1308725Sdexuan/*- 2324461Ssephe * Copyright (c) 2016-2017 Microsoft Corp. 3308725Sdexuan * All rights reserved. 4308725Sdexuan * 5308725Sdexuan * Redistribution and use in source and binary forms, with or without 6308725Sdexuan * modification, are permitted provided that the following conditions 7308725Sdexuan * are met: 8308725Sdexuan * 1. Redistributions of source code must retain the above copyright 9308725Sdexuan * notice, this list of conditions and the following disclaimer. 10308725Sdexuan * 2. Redistributions in binary form must reproduce the above copyright 11308725Sdexuan * notice, this list of conditions and the following disclaimer in the 12308725Sdexuan * documentation and/or other materials provided with the distribution. 13308725Sdexuan * 14308725Sdexuan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15308725Sdexuan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16308725Sdexuan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17308725Sdexuan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18308725Sdexuan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19308725Sdexuan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20308725Sdexuan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21308725Sdexuan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22308725Sdexuan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23308725Sdexuan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24308725Sdexuan * SUCH DAMAGE. 25308725Sdexuan */ 26308725Sdexuan 27308725Sdexuan#include <sys/cdefs.h> 28308725Sdexuan__FBSDID("$FreeBSD: stable/10/sys/dev/hyperv/pcib/vmbus_pcib.c 337959 2018-08-17 06:31:30Z dim $"); 29308725Sdexuan 30309313Sdexuan#ifdef NEW_PCIB 31309313Sdexuan 32308725Sdexuan#include <sys/param.h> 33308725Sdexuan#include <sys/systm.h> 34308725Sdexuan#include <sys/types.h> 35308725Sdexuan#include <sys/malloc.h> 36308725Sdexuan#include <sys/module.h> 37308725Sdexuan#include <sys/kernel.h> 38308725Sdexuan#include <sys/queue.h> 39308725Sdexuan#include <sys/lock.h> 40308725Sdexuan#include <sys/sx.h> 41308725Sdexuan#include <sys/smp.h> 42308725Sdexuan#include <sys/sysctl.h> 43308725Sdexuan#include <sys/bus.h> 44308725Sdexuan#include <sys/rman.h> 45308725Sdexuan#include <sys/mutex.h> 46308725Sdexuan#include <sys/errno.h> 47308725Sdexuan 48308725Sdexuan#include <vm/vm.h> 49308725Sdexuan#include <vm/vm_param.h> 50308725Sdexuan#include <vm/vm_kern.h> 51308725Sdexuan#include <vm/pmap.h> 52308725Sdexuan 53308725Sdexuan#include <machine/atomic.h> 54308725Sdexuan#include <machine/bus.h> 55308725Sdexuan#include <machine/frame.h> 56308725Sdexuan#include <machine/pci_cfgreg.h> 57308725Sdexuan#include <machine/resource.h> 58308725Sdexuan 59308725Sdexuan#include <sys/pciio.h> 60308725Sdexuan#include <dev/pci/pcireg.h> 61308725Sdexuan#include <dev/pci/pcivar.h> 62308725Sdexuan#include <dev/pci/pci_private.h> 63308725Sdexuan#include <dev/pci/pcib_private.h> 64308725Sdexuan#include "pcib_if.h" 65308725Sdexuan 66308725Sdexuan#include <machine/intr_machdep.h> 67308725Sdexuan#include <x86/apicreg.h> 68308725Sdexuan 69308725Sdexuan#include <dev/hyperv/include/hyperv.h> 70308725Sdexuan#include <dev/hyperv/include/hyperv_busdma.h> 71308725Sdexuan#include <dev/hyperv/include/vmbus_xact.h> 72308725Sdexuan#include <dev/hyperv/vmbus/vmbus_reg.h> 73308725Sdexuan#include <dev/hyperv/vmbus/vmbus_chanvar.h> 74308725Sdexuan 75308725Sdexuan#include "vmbus_if.h" 76308725Sdexuan 77308725Sdexuan#if __FreeBSD_version < 1100000 78308725Sdexuantypedef u_long rman_res_t; 79308725Sdexuan#define RM_MAX_END (~(rman_res_t)0) 80308725Sdexuan#endif 81308725Sdexuan 82308725Sdexuanstruct completion { 83308725Sdexuan unsigned int done; 84308725Sdexuan struct mtx lock; 85308725Sdexuan}; 86308725Sdexuan 87308725Sdexuanstatic void 88308725Sdexuaninit_completion(struct completion *c) 89308725Sdexuan{ 90308725Sdexuan memset(c, 0, sizeof(*c)); 91308725Sdexuan mtx_init(&c->lock, "hvcmpl", NULL, MTX_DEF); 92308725Sdexuan c->done = 0; 93308725Sdexuan} 94308725Sdexuan 95308725Sdexuanstatic void 96308725Sdexuanfree_completion(struct completion *c) 97308725Sdexuan{ 98308725Sdexuan mtx_destroy(&c->lock); 99308725Sdexuan} 100308725Sdexuan 101308725Sdexuanstatic void 102308725Sdexuancomplete(struct completion *c) 103308725Sdexuan{ 104308725Sdexuan mtx_lock(&c->lock); 105308725Sdexuan c->done++; 106308725Sdexuan mtx_unlock(&c->lock); 107308725Sdexuan wakeup(c); 108308725Sdexuan} 109308725Sdexuan 110308725Sdexuanstatic void 111308725Sdexuanwait_for_completion(struct completion *c) 112308725Sdexuan{ 113308725Sdexuan mtx_lock(&c->lock); 114308725Sdexuan while (c->done == 0) 115308725Sdexuan mtx_sleep(c, &c->lock, 0, "hvwfc", 0); 116308725Sdexuan c->done--; 117308725Sdexuan mtx_unlock(&c->lock); 118308725Sdexuan} 119308725Sdexuan 120308725Sdexuan#define PCI_MAKE_VERSION(major, minor) ((uint32_t)(((major) << 16) | (major))) 121308725Sdexuan 122308725Sdexuanenum { 123308725Sdexuan PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1), 124308725Sdexuan PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1 125308725Sdexuan}; 126308725Sdexuan 127308725Sdexuan#define PCI_CONFIG_MMIO_LENGTH 0x2000 128308725Sdexuan#define CFG_PAGE_OFFSET 0x1000 129308725Sdexuan#define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET) 130308725Sdexuan 131308725Sdexuan/* 132308725Sdexuan * Message Types 133308725Sdexuan */ 134308725Sdexuan 135308725Sdexuanenum pci_message_type { 136308725Sdexuan /* 137308725Sdexuan * Version 1.1 138308725Sdexuan */ 139308725Sdexuan PCI_MESSAGE_BASE = 0x42490000, 140308725Sdexuan PCI_BUS_RELATIONS = PCI_MESSAGE_BASE + 0, 141308725Sdexuan PCI_QUERY_BUS_RELATIONS = PCI_MESSAGE_BASE + 1, 142308725Sdexuan PCI_POWER_STATE_CHANGE = PCI_MESSAGE_BASE + 4, 143308725Sdexuan PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5, 144308725Sdexuan PCI_QUERY_RESOURCE_RESOURCES = PCI_MESSAGE_BASE + 6, 145308725Sdexuan PCI_BUS_D0ENTRY = PCI_MESSAGE_BASE + 7, 146308725Sdexuan PCI_BUS_D0EXIT = PCI_MESSAGE_BASE + 8, 147308725Sdexuan PCI_READ_BLOCK = PCI_MESSAGE_BASE + 9, 148308725Sdexuan PCI_WRITE_BLOCK = PCI_MESSAGE_BASE + 0xA, 149308725Sdexuan PCI_EJECT = PCI_MESSAGE_BASE + 0xB, 150308725Sdexuan PCI_QUERY_STOP = PCI_MESSAGE_BASE + 0xC, 151308725Sdexuan PCI_REENABLE = PCI_MESSAGE_BASE + 0xD, 152308725Sdexuan PCI_QUERY_STOP_FAILED = PCI_MESSAGE_BASE + 0xE, 153308725Sdexuan PCI_EJECTION_COMPLETE = PCI_MESSAGE_BASE + 0xF, 154308725Sdexuan PCI_RESOURCES_ASSIGNED = PCI_MESSAGE_BASE + 0x10, 155308725Sdexuan PCI_RESOURCES_RELEASED = PCI_MESSAGE_BASE + 0x11, 156308725Sdexuan PCI_INVALIDATE_BLOCK = PCI_MESSAGE_BASE + 0x12, 157308725Sdexuan PCI_QUERY_PROTOCOL_VERSION = PCI_MESSAGE_BASE + 0x13, 158308725Sdexuan PCI_CREATE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x14, 159308725Sdexuan PCI_DELETE_INTERRUPT_MESSAGE = PCI_MESSAGE_BASE + 0x15, 160308725Sdexuan PCI_MESSAGE_MAXIMUM 161308725Sdexuan}; 162308725Sdexuan 163308725Sdexuan/* 164308725Sdexuan * Structures defining the virtual PCI Express protocol. 165308725Sdexuan */ 166308725Sdexuan 167308725Sdexuanunion pci_version { 168308725Sdexuan struct { 169308725Sdexuan uint16_t minor_version; 170308725Sdexuan uint16_t major_version; 171308725Sdexuan } parts; 172308725Sdexuan uint32_t version; 173308725Sdexuan} __packed; 174308725Sdexuan 175308725Sdexuan/* 176308725Sdexuan * This representation is the one used in Windows, which is 177308725Sdexuan * what is expected when sending this back and forth with 178308725Sdexuan * the Hyper-V parent partition. 179308725Sdexuan */ 180308725Sdexuanunion win_slot_encoding { 181308725Sdexuan struct { 182308725Sdexuan uint32_t slot:5; 183308725Sdexuan uint32_t func:3; 184308725Sdexuan uint32_t reserved:24; 185308725Sdexuan } bits; 186308725Sdexuan uint32_t val; 187308725Sdexuan} __packed; 188308725Sdexuan 189308725Sdexuanstruct pci_func_desc { 190308725Sdexuan uint16_t v_id; /* vendor ID */ 191308725Sdexuan uint16_t d_id; /* device ID */ 192308725Sdexuan uint8_t rev; 193308725Sdexuan uint8_t prog_intf; 194308725Sdexuan uint8_t subclass; 195308725Sdexuan uint8_t base_class; 196308725Sdexuan uint32_t subsystem_id; 197308725Sdexuan union win_slot_encoding wslot; 198308725Sdexuan uint32_t ser; /* serial number */ 199308725Sdexuan} __packed; 200308725Sdexuan 201308725Sdexuanstruct hv_msi_desc { 202308725Sdexuan uint8_t vector; 203308725Sdexuan uint8_t delivery_mode; 204308725Sdexuan uint16_t vector_count; 205308725Sdexuan uint32_t reserved; 206308725Sdexuan uint64_t cpu_mask; 207308725Sdexuan} __packed; 208308725Sdexuan 209308725Sdexuanstruct tran_int_desc { 210308725Sdexuan uint16_t reserved; 211308725Sdexuan uint16_t vector_count; 212308725Sdexuan uint32_t data; 213308725Sdexuan uint64_t address; 214308725Sdexuan} __packed; 215308725Sdexuan 216308725Sdexuanstruct pci_message { 217308725Sdexuan uint32_t type; 218308725Sdexuan} __packed; 219308725Sdexuan 220308725Sdexuanstruct pci_child_message { 221308725Sdexuan struct pci_message message_type; 222308725Sdexuan union win_slot_encoding wslot; 223308725Sdexuan} __packed; 224308725Sdexuan 225308725Sdexuanstruct pci_incoming_message { 226308725Sdexuan struct vmbus_chanpkt_hdr hdr; 227308725Sdexuan struct pci_message message_type; 228308725Sdexuan} __packed; 229308725Sdexuan 230308725Sdexuanstruct pci_response { 231308725Sdexuan struct vmbus_chanpkt_hdr hdr; 232308725Sdexuan int32_t status; /* negative values are failures */ 233308725Sdexuan} __packed; 234308725Sdexuan 235308725Sdexuanstruct pci_packet { 236308725Sdexuan void (*completion_func)(void *context, struct pci_response *resp, 237308725Sdexuan int resp_packet_size); 238308725Sdexuan void *compl_ctxt; 239308725Sdexuan 240308725Sdexuan struct pci_message message[0]; 241308725Sdexuan}; 242308725Sdexuan 243308725Sdexuan/* 244308725Sdexuan * Specific message types supporting the PCI protocol. 245308725Sdexuan */ 246308725Sdexuan 247308725Sdexuanstruct pci_version_request { 248308725Sdexuan struct pci_message message_type; 249308725Sdexuan uint32_t protocol_version; 250308725Sdexuan uint32_t is_last_attempt:1; 251308725Sdexuan uint32_t reservedz:31; 252308725Sdexuan} __packed; 253308725Sdexuan 254308725Sdexuanstruct pci_bus_d0_entry { 255308725Sdexuan struct pci_message message_type; 256308725Sdexuan uint32_t reserved; 257308725Sdexuan uint64_t mmio_base; 258308725Sdexuan} __packed; 259308725Sdexuan 260308725Sdexuanstruct pci_bus_relations { 261308725Sdexuan struct pci_incoming_message incoming; 262308725Sdexuan uint32_t device_count; 263308725Sdexuan struct pci_func_desc func[0]; 264308725Sdexuan} __packed; 265308725Sdexuan 266308725Sdexuan#define MAX_NUM_BARS (PCIR_MAX_BAR_0 + 1) 267308725Sdexuanstruct pci_q_res_req_response { 268308725Sdexuan struct vmbus_chanpkt_hdr hdr; 269308725Sdexuan int32_t status; /* negative values are failures */ 270308725Sdexuan uint32_t probed_bar[MAX_NUM_BARS]; 271308725Sdexuan} __packed; 272308725Sdexuan 273308725Sdexuanstruct pci_resources_assigned { 274308725Sdexuan struct pci_message message_type; 275308725Sdexuan union win_slot_encoding wslot; 276308725Sdexuan uint8_t memory_range[0x14][MAX_NUM_BARS]; /* unused here */ 277308725Sdexuan uint32_t msi_descriptors; 278308725Sdexuan uint32_t reserved[4]; 279308725Sdexuan} __packed; 280308725Sdexuan 281308725Sdexuanstruct pci_create_interrupt { 282308725Sdexuan struct pci_message message_type; 283308725Sdexuan union win_slot_encoding wslot; 284308725Sdexuan struct hv_msi_desc int_desc; 285308725Sdexuan} __packed; 286308725Sdexuan 287308725Sdexuanstruct pci_create_int_response { 288308725Sdexuan struct pci_response response; 289308725Sdexuan uint32_t reserved; 290308725Sdexuan struct tran_int_desc int_desc; 291308725Sdexuan} __packed; 292308725Sdexuan 293308725Sdexuanstruct pci_delete_interrupt { 294308725Sdexuan struct pci_message message_type; 295308725Sdexuan union win_slot_encoding wslot; 296308725Sdexuan struct tran_int_desc int_desc; 297308725Sdexuan} __packed; 298308725Sdexuan 299308725Sdexuanstruct pci_dev_incoming { 300308725Sdexuan struct pci_incoming_message incoming; 301308725Sdexuan union win_slot_encoding wslot; 302308725Sdexuan} __packed; 303308725Sdexuan 304308725Sdexuanstruct pci_eject_response { 305308725Sdexuan struct pci_message message_type; 306308725Sdexuan union win_slot_encoding wslot; 307308725Sdexuan uint32_t status; 308308725Sdexuan} __packed; 309308725Sdexuan 310308725Sdexuan/* 311308725Sdexuan * Driver specific state. 312308725Sdexuan */ 313308725Sdexuan 314308725Sdexuanenum hv_pcibus_state { 315308725Sdexuan hv_pcibus_init = 0, 316308725Sdexuan hv_pcibus_installed, 317308725Sdexuan}; 318308725Sdexuan 319308725Sdexuanstruct hv_pcibus { 320308725Sdexuan device_t pcib; 321308725Sdexuan device_t pci_bus; 322308725Sdexuan struct vmbus_pcib_softc *sc; 323308725Sdexuan 324308725Sdexuan uint16_t pci_domain; 325308725Sdexuan 326308725Sdexuan enum hv_pcibus_state state; 327308725Sdexuan 328308725Sdexuan struct resource *cfg_res; 329308725Sdexuan 330308725Sdexuan struct completion query_completion, *query_comp; 331308725Sdexuan 332308725Sdexuan struct mtx config_lock; /* Avoid two threads writing index page */ 333308725Sdexuan struct mtx device_list_lock; /* Protect lists below */ 334308725Sdexuan TAILQ_HEAD(, hv_pci_dev) children; 335308725Sdexuan TAILQ_HEAD(, hv_dr_state) dr_list; 336308725Sdexuan 337308725Sdexuan volatile int detaching; 338308725Sdexuan}; 339308725Sdexuan 340308725Sdexuanstruct hv_pci_dev { 341308725Sdexuan TAILQ_ENTRY(hv_pci_dev) link; 342308725Sdexuan 343308725Sdexuan struct pci_func_desc desc; 344308725Sdexuan 345308725Sdexuan bool reported_missing; 346308725Sdexuan 347308725Sdexuan struct hv_pcibus *hbus; 348308725Sdexuan struct task eject_task; 349308725Sdexuan 350308725Sdexuan TAILQ_HEAD(, hv_irq_desc) irq_desc_list; 351308725Sdexuan 352308725Sdexuan /* 353308725Sdexuan * What would be observed if one wrote 0xFFFFFFFF to a BAR and then 354308725Sdexuan * read it back, for each of the BAR offsets within config space. 355308725Sdexuan */ 356308725Sdexuan uint32_t probed_bar[MAX_NUM_BARS]; 357308725Sdexuan}; 358308725Sdexuan 359308725Sdexuan/* 360308725Sdexuan * Tracks "Device Relations" messages from the host, which must be both 361308725Sdexuan * processed in order. 362308725Sdexuan */ 363308725Sdexuanstruct hv_dr_work { 364308725Sdexuan struct task task; 365308725Sdexuan struct hv_pcibus *bus; 366308725Sdexuan}; 367308725Sdexuan 368308725Sdexuanstruct hv_dr_state { 369308725Sdexuan TAILQ_ENTRY(hv_dr_state) link; 370308725Sdexuan uint32_t device_count; 371308725Sdexuan struct pci_func_desc func[0]; 372308725Sdexuan}; 373308725Sdexuan 374308725Sdexuanstruct hv_irq_desc { 375308725Sdexuan TAILQ_ENTRY(hv_irq_desc) link; 376308725Sdexuan struct tran_int_desc desc; 377308725Sdexuan int irq; 378308725Sdexuan}; 379308725Sdexuan 380308725Sdexuan#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 381308725Sdexuan#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) 382308725Sdexuan#define PCI_FUNC(devfn) ((devfn) & 0x07) 383308725Sdexuan 384308725Sdexuanstatic uint32_t 385308725Sdexuandevfn_to_wslot(unsigned int devfn) 386308725Sdexuan{ 387308725Sdexuan union win_slot_encoding wslot; 388308725Sdexuan 389308725Sdexuan wslot.val = 0; 390308725Sdexuan wslot.bits.slot = PCI_SLOT(devfn); 391308725Sdexuan wslot.bits.func = PCI_FUNC(devfn); 392308725Sdexuan 393308725Sdexuan return (wslot.val); 394308725Sdexuan} 395308725Sdexuan 396308725Sdexuanstatic unsigned int 397308725Sdexuanwslot_to_devfn(uint32_t wslot) 398308725Sdexuan{ 399308725Sdexuan union win_slot_encoding encoding; 400308725Sdexuan unsigned int slot; 401308725Sdexuan unsigned int func; 402308725Sdexuan 403308725Sdexuan encoding.val = wslot; 404308725Sdexuan 405308725Sdexuan slot = encoding.bits.slot; 406308725Sdexuan func = encoding.bits.func; 407308725Sdexuan 408308725Sdexuan return (PCI_DEVFN(slot, func)); 409308725Sdexuan} 410308725Sdexuan 411308725Sdexuanstruct vmbus_pcib_softc { 412308725Sdexuan struct vmbus_channel *chan; 413308725Sdexuan void *rx_buf; 414308725Sdexuan 415308725Sdexuan struct taskqueue *taskq; 416308725Sdexuan 417308725Sdexuan struct hv_pcibus *hbus; 418308725Sdexuan}; 419308725Sdexuan 420308725Sdexuan/* {44C4F61D-4444-4400-9D52-802E27EDE19F} */ 421308725Sdexuanstatic const struct hyperv_guid g_pass_through_dev_type = { 422308725Sdexuan .hv_guid = {0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44, 423308725Sdexuan 0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F} 424308725Sdexuan}; 425308725Sdexuan 426308725Sdexuanstruct hv_pci_compl { 427308725Sdexuan struct completion host_event; 428308725Sdexuan int32_t completion_status; 429308725Sdexuan}; 430308725Sdexuan 431308725Sdexuanstruct q_res_req_compl { 432308725Sdexuan struct completion host_event; 433308725Sdexuan struct hv_pci_dev *hpdev; 434308725Sdexuan}; 435308725Sdexuan 436308725Sdexuanstruct compose_comp_ctxt { 437308725Sdexuan struct hv_pci_compl comp_pkt; 438308725Sdexuan struct tran_int_desc int_desc; 439308725Sdexuan}; 440308725Sdexuan 441308725Sdexuanstatic void 442308725Sdexuanhv_pci_generic_compl(void *context, struct pci_response *resp, 443308725Sdexuan int resp_packet_size) 444308725Sdexuan{ 445308725Sdexuan struct hv_pci_compl *comp_pkt = context; 446308725Sdexuan 447308725Sdexuan if (resp_packet_size >= sizeof(struct pci_response)) 448308725Sdexuan comp_pkt->completion_status = resp->status; 449308725Sdexuan else 450308725Sdexuan comp_pkt->completion_status = -1; 451308725Sdexuan 452308725Sdexuan complete(&comp_pkt->host_event); 453308725Sdexuan} 454308725Sdexuan 455308725Sdexuanstatic void 456308725Sdexuanq_resource_requirements(void *context, struct pci_response *resp, 457308725Sdexuan int resp_packet_size) 458308725Sdexuan{ 459308725Sdexuan struct q_res_req_compl *completion = context; 460308725Sdexuan struct pci_q_res_req_response *q_res_req = 461308725Sdexuan (struct pci_q_res_req_response *)resp; 462308725Sdexuan int i; 463308725Sdexuan 464308725Sdexuan if (resp->status < 0) { 465308725Sdexuan printf("vmbus_pcib: failed to query resource requirements\n"); 466308725Sdexuan } else { 467308725Sdexuan for (i = 0; i < MAX_NUM_BARS; i++) 468308725Sdexuan completion->hpdev->probed_bar[i] = 469308725Sdexuan q_res_req->probed_bar[i]; 470308725Sdexuan } 471308725Sdexuan 472308725Sdexuan complete(&completion->host_event); 473308725Sdexuan} 474308725Sdexuan 475308725Sdexuanstatic void 476308725Sdexuanhv_pci_compose_compl(void *context, struct pci_response *resp, 477308725Sdexuan int resp_packet_size) 478308725Sdexuan{ 479308725Sdexuan struct compose_comp_ctxt *comp_pkt = context; 480308725Sdexuan struct pci_create_int_response *int_resp = 481308725Sdexuan (struct pci_create_int_response *)resp; 482308725Sdexuan 483308725Sdexuan comp_pkt->comp_pkt.completion_status = resp->status; 484308725Sdexuan comp_pkt->int_desc = int_resp->int_desc; 485308725Sdexuan complete(&comp_pkt->comp_pkt.host_event); 486308725Sdexuan} 487308725Sdexuan 488308725Sdexuanstatic void 489308725Sdexuanhv_int_desc_free(struct hv_pci_dev *hpdev, struct hv_irq_desc *hid) 490308725Sdexuan{ 491308725Sdexuan struct pci_delete_interrupt *int_pkt; 492308725Sdexuan struct { 493308725Sdexuan struct pci_packet pkt; 494308725Sdexuan uint8_t buffer[sizeof(struct pci_delete_interrupt)]; 495308725Sdexuan } ctxt; 496308725Sdexuan 497308725Sdexuan memset(&ctxt, 0, sizeof(ctxt)); 498308725Sdexuan int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message; 499308725Sdexuan int_pkt->message_type.type = PCI_DELETE_INTERRUPT_MESSAGE; 500308725Sdexuan int_pkt->wslot.val = hpdev->desc.wslot.val; 501308725Sdexuan int_pkt->int_desc = hid->desc; 502308725Sdexuan 503308725Sdexuan vmbus_chan_send(hpdev->hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 504308725Sdexuan int_pkt, sizeof(*int_pkt), 0); 505308725Sdexuan 506308725Sdexuan free(hid, M_DEVBUF); 507308725Sdexuan} 508308725Sdexuan 509308725Sdexuanstatic void 510308725Sdexuanhv_pci_delete_device(struct hv_pci_dev *hpdev) 511308725Sdexuan{ 512308725Sdexuan struct hv_pcibus *hbus = hpdev->hbus; 513308725Sdexuan struct hv_irq_desc *hid, *tmp_hid; 514308725Sdexuan device_t pci_dev; 515308725Sdexuan int devfn; 516308725Sdexuan 517308725Sdexuan devfn = wslot_to_devfn(hpdev->desc.wslot.val); 518308725Sdexuan 519308725Sdexuan mtx_lock(&Giant); 520308725Sdexuan 521308725Sdexuan pci_dev = pci_find_dbsf(hbus->pci_domain, 522308725Sdexuan 0, PCI_SLOT(devfn), PCI_FUNC(devfn)); 523308725Sdexuan if (pci_dev) 524308725Sdexuan device_delete_child(hbus->pci_bus, pci_dev); 525308725Sdexuan 526308725Sdexuan mtx_unlock(&Giant); 527308725Sdexuan 528308725Sdexuan mtx_lock(&hbus->device_list_lock); 529308725Sdexuan TAILQ_REMOVE(&hbus->children, hpdev, link); 530308725Sdexuan mtx_unlock(&hbus->device_list_lock); 531308725Sdexuan 532308725Sdexuan TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid) 533308725Sdexuan hv_int_desc_free(hpdev, hid); 534308725Sdexuan 535308725Sdexuan free(hpdev, M_DEVBUF); 536308725Sdexuan} 537308725Sdexuan 538308725Sdexuanstatic struct hv_pci_dev * 539308725Sdexuannew_pcichild_device(struct hv_pcibus *hbus, struct pci_func_desc *desc) 540308725Sdexuan{ 541308725Sdexuan struct hv_pci_dev *hpdev; 542308725Sdexuan struct pci_child_message *res_req; 543308725Sdexuan struct q_res_req_compl comp_pkt; 544308725Sdexuan struct { 545308725Sdexuan struct pci_packet pkt; 546308725Sdexuan uint8_t buffer[sizeof(struct pci_child_message)]; 547308725Sdexuan } ctxt; 548308725Sdexuan int ret; 549308725Sdexuan 550308725Sdexuan hpdev = malloc(sizeof(*hpdev), M_DEVBUF, M_WAITOK | M_ZERO); 551308725Sdexuan hpdev->hbus = hbus; 552308725Sdexuan 553308725Sdexuan TAILQ_INIT(&hpdev->irq_desc_list); 554308725Sdexuan 555308725Sdexuan init_completion(&comp_pkt.host_event); 556308725Sdexuan comp_pkt.hpdev = hpdev; 557308725Sdexuan 558308725Sdexuan ctxt.pkt.compl_ctxt = &comp_pkt; 559308725Sdexuan ctxt.pkt.completion_func = q_resource_requirements; 560308725Sdexuan 561308725Sdexuan res_req = (struct pci_child_message *)&ctxt.pkt.message; 562308725Sdexuan res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS; 563308725Sdexuan res_req->wslot.val = desc->wslot.val; 564308725Sdexuan 565308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, 566308725Sdexuan VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 567337959Sdim res_req, sizeof(*res_req), (uint64_t)(uintptr_t)&ctxt.pkt); 568308725Sdexuan if (ret) 569308725Sdexuan goto err; 570308725Sdexuan 571308725Sdexuan wait_for_completion(&comp_pkt.host_event); 572308725Sdexuan free_completion(&comp_pkt.host_event); 573308725Sdexuan 574308725Sdexuan hpdev->desc = *desc; 575308725Sdexuan 576308725Sdexuan mtx_lock(&hbus->device_list_lock); 577319941Sdexuan if (TAILQ_EMPTY(&hbus->children)) 578319941Sdexuan hbus->pci_domain = desc->ser & 0xFFFF; 579308725Sdexuan TAILQ_INSERT_TAIL(&hbus->children, hpdev, link); 580308725Sdexuan mtx_unlock(&hbus->device_list_lock); 581308725Sdexuan return (hpdev); 582308725Sdexuanerr: 583308725Sdexuan free_completion(&comp_pkt.host_event); 584308725Sdexuan free(hpdev, M_DEVBUF); 585308725Sdexuan return (NULL); 586308725Sdexuan} 587308725Sdexuan 588308725Sdexuan#if __FreeBSD_version < 1100000 589308725Sdexuan 590308725Sdexuan/* Old versions don't have BUS_RESCAN(). Let's copy it from FreeBSD 11. */ 591308725Sdexuan 592308725Sdexuanstatic struct pci_devinfo * 593308725Sdexuanpci_identify_function(device_t pcib, device_t dev, int domain, int busno, 594308725Sdexuan int slot, int func, size_t dinfo_size) 595308725Sdexuan{ 596308725Sdexuan struct pci_devinfo *dinfo; 597308725Sdexuan 598308725Sdexuan dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size); 599308725Sdexuan if (dinfo != NULL) 600308725Sdexuan pci_add_child(dev, dinfo); 601308725Sdexuan 602308725Sdexuan return (dinfo); 603308725Sdexuan} 604308725Sdexuan 605308725Sdexuanstatic int 606308725Sdexuanpci_rescan(device_t dev) 607308725Sdexuan{ 608308725Sdexuan#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w) 609308725Sdexuan device_t pcib = device_get_parent(dev); 610308725Sdexuan struct pci_softc *sc; 611308725Sdexuan device_t child, *devlist, *unchanged; 612308725Sdexuan int devcount, error, i, j, maxslots, oldcount; 613308725Sdexuan int busno, domain, s, f, pcifunchigh; 614308725Sdexuan uint8_t hdrtype; 615308725Sdexuan 616308725Sdexuan /* No need to check for ARI on a rescan. */ 617308725Sdexuan error = device_get_children(dev, &devlist, &devcount); 618308725Sdexuan if (error) 619308725Sdexuan return (error); 620308725Sdexuan if (devcount != 0) { 621308725Sdexuan unchanged = malloc(devcount * sizeof(device_t), M_TEMP, 622308725Sdexuan M_NOWAIT | M_ZERO); 623308725Sdexuan if (unchanged == NULL) { 624308725Sdexuan free(devlist, M_TEMP); 625308725Sdexuan return (ENOMEM); 626308725Sdexuan } 627308725Sdexuan } else 628308725Sdexuan unchanged = NULL; 629308725Sdexuan 630308725Sdexuan sc = device_get_softc(dev); 631308725Sdexuan domain = pcib_get_domain(dev); 632308725Sdexuan busno = pcib_get_bus(dev); 633308725Sdexuan maxslots = PCIB_MAXSLOTS(pcib); 634308725Sdexuan for (s = 0; s <= maxslots; s++) { 635308725Sdexuan /* If function 0 is not present, skip to the next slot. */ 636308725Sdexuan f = 0; 637308725Sdexuan if (REG(PCIR_VENDOR, 2) == 0xffff) 638308725Sdexuan continue; 639308725Sdexuan pcifunchigh = 0; 640308725Sdexuan hdrtype = REG(PCIR_HDRTYPE, 1); 641308725Sdexuan if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 642308725Sdexuan continue; 643308725Sdexuan if (hdrtype & PCIM_MFDEV) 644308725Sdexuan pcifunchigh = PCIB_MAXFUNCS(pcib); 645308725Sdexuan for (f = 0; f <= pcifunchigh; f++) { 646308725Sdexuan if (REG(PCIR_VENDOR, 2) == 0xffff) 647308725Sdexuan continue; 648308725Sdexuan 649308725Sdexuan /* 650308725Sdexuan * Found a valid function. Check if a 651308725Sdexuan * device_t for this device already exists. 652308725Sdexuan */ 653308725Sdexuan for (i = 0; i < devcount; i++) { 654308725Sdexuan child = devlist[i]; 655308725Sdexuan if (child == NULL) 656308725Sdexuan continue; 657308725Sdexuan if (pci_get_slot(child) == s && 658308725Sdexuan pci_get_function(child) == f) { 659308725Sdexuan unchanged[i] = child; 660308725Sdexuan goto next_func; 661308725Sdexuan } 662308725Sdexuan } 663308725Sdexuan 664308725Sdexuan pci_identify_function(pcib, dev, domain, busno, s, f, 665308725Sdexuan sizeof(struct pci_devinfo)); 666308725Sdexuan next_func:; 667308725Sdexuan } 668308725Sdexuan } 669308725Sdexuan 670308725Sdexuan /* Remove devices that are no longer present. */ 671308725Sdexuan for (i = 0; i < devcount; i++) { 672308725Sdexuan if (unchanged[i] != NULL) 673308725Sdexuan continue; 674308725Sdexuan device_delete_child(dev, devlist[i]); 675308725Sdexuan } 676308725Sdexuan 677308725Sdexuan free(devlist, M_TEMP); 678308725Sdexuan oldcount = devcount; 679308725Sdexuan 680308725Sdexuan /* Try to attach the devices just added. */ 681308725Sdexuan error = device_get_children(dev, &devlist, &devcount); 682308725Sdexuan if (error) { 683308725Sdexuan free(unchanged, M_TEMP); 684308725Sdexuan return (error); 685308725Sdexuan } 686308725Sdexuan 687308725Sdexuan for (i = 0; i < devcount; i++) { 688308725Sdexuan for (j = 0; j < oldcount; j++) { 689308725Sdexuan if (devlist[i] == unchanged[j]) 690308725Sdexuan goto next_device; 691308725Sdexuan } 692308725Sdexuan 693308725Sdexuan device_probe_and_attach(devlist[i]); 694308725Sdexuan next_device:; 695308725Sdexuan } 696308725Sdexuan 697308725Sdexuan free(unchanged, M_TEMP); 698308725Sdexuan free(devlist, M_TEMP); 699308725Sdexuan return (0); 700308725Sdexuan#undef REG 701308725Sdexuan} 702308725Sdexuan 703308725Sdexuan#else 704308725Sdexuan 705308725Sdexuanstatic int 706308725Sdexuanpci_rescan(device_t dev) 707308725Sdexuan{ 708308725Sdexuan return (BUS_RESCAN(dev)); 709308725Sdexuan} 710308725Sdexuan 711308725Sdexuan#endif 712308725Sdexuan 713308725Sdexuanstatic void 714308725Sdexuanpci_devices_present_work(void *arg, int pending __unused) 715308725Sdexuan{ 716308725Sdexuan struct hv_dr_work *dr_wrk = arg; 717308725Sdexuan struct hv_dr_state *dr = NULL; 718308725Sdexuan struct hv_pcibus *hbus; 719308725Sdexuan uint32_t child_no; 720308725Sdexuan bool found; 721308725Sdexuan struct pci_func_desc *new_desc; 722308725Sdexuan struct hv_pci_dev *hpdev, *tmp_hpdev; 723308725Sdexuan struct completion *query_comp; 724308725Sdexuan bool need_rescan = false; 725308725Sdexuan 726308725Sdexuan hbus = dr_wrk->bus; 727308725Sdexuan free(dr_wrk, M_DEVBUF); 728308725Sdexuan 729308725Sdexuan /* Pull this off the queue and process it if it was the last one. */ 730308725Sdexuan mtx_lock(&hbus->device_list_lock); 731308725Sdexuan while (!TAILQ_EMPTY(&hbus->dr_list)) { 732308725Sdexuan dr = TAILQ_FIRST(&hbus->dr_list); 733308725Sdexuan TAILQ_REMOVE(&hbus->dr_list, dr, link); 734308725Sdexuan 735308725Sdexuan /* Throw this away if the list still has stuff in it. */ 736308725Sdexuan if (!TAILQ_EMPTY(&hbus->dr_list)) { 737308725Sdexuan free(dr, M_DEVBUF); 738308725Sdexuan continue; 739308725Sdexuan } 740308725Sdexuan } 741308725Sdexuan mtx_unlock(&hbus->device_list_lock); 742308725Sdexuan 743308725Sdexuan if (!dr) 744308725Sdexuan return; 745308725Sdexuan 746308725Sdexuan /* First, mark all existing children as reported missing. */ 747308725Sdexuan mtx_lock(&hbus->device_list_lock); 748308725Sdexuan TAILQ_FOREACH(hpdev, &hbus->children, link) 749308725Sdexuan hpdev->reported_missing = true; 750308725Sdexuan mtx_unlock(&hbus->device_list_lock); 751308725Sdexuan 752308725Sdexuan /* Next, add back any reported devices. */ 753308725Sdexuan for (child_no = 0; child_no < dr->device_count; child_no++) { 754308725Sdexuan found = false; 755308725Sdexuan new_desc = &dr->func[child_no]; 756308725Sdexuan 757308725Sdexuan mtx_lock(&hbus->device_list_lock); 758308725Sdexuan TAILQ_FOREACH(hpdev, &hbus->children, link) { 759308725Sdexuan if ((hpdev->desc.wslot.val == 760308725Sdexuan new_desc->wslot.val) && 761308725Sdexuan (hpdev->desc.v_id == new_desc->v_id) && 762308725Sdexuan (hpdev->desc.d_id == new_desc->d_id) && 763308725Sdexuan (hpdev->desc.ser == new_desc->ser)) { 764308725Sdexuan hpdev->reported_missing = false; 765308725Sdexuan found = true; 766308725Sdexuan break; 767308725Sdexuan } 768308725Sdexuan } 769308725Sdexuan mtx_unlock(&hbus->device_list_lock); 770308725Sdexuan 771308725Sdexuan if (!found) { 772308725Sdexuan if (!need_rescan) 773308725Sdexuan need_rescan = true; 774308725Sdexuan 775308725Sdexuan hpdev = new_pcichild_device(hbus, new_desc); 776308725Sdexuan if (!hpdev) 777308725Sdexuan printf("vmbus_pcib: failed to add a child\n"); 778308725Sdexuan } 779308725Sdexuan } 780308725Sdexuan 781308725Sdexuan /* Remove missing device(s), if any */ 782308725Sdexuan TAILQ_FOREACH_SAFE(hpdev, &hbus->children, link, tmp_hpdev) { 783308725Sdexuan if (hpdev->reported_missing) 784308725Sdexuan hv_pci_delete_device(hpdev); 785308725Sdexuan } 786308725Sdexuan 787308725Sdexuan /* Rescan the bus to find any new device, if necessary. */ 788308725Sdexuan if (hbus->state == hv_pcibus_installed && need_rescan) 789308725Sdexuan pci_rescan(hbus->pci_bus); 790308725Sdexuan 791308725Sdexuan /* Wake up hv_pci_query_relations(), if it's waiting. */ 792308725Sdexuan query_comp = hbus->query_comp; 793308725Sdexuan if (query_comp) { 794308725Sdexuan hbus->query_comp = NULL; 795308725Sdexuan complete(query_comp); 796308725Sdexuan } 797308725Sdexuan 798308725Sdexuan free(dr, M_DEVBUF); 799308725Sdexuan} 800308725Sdexuan 801308725Sdexuanstatic struct hv_pci_dev * 802308725Sdexuanget_pcichild_wslot(struct hv_pcibus *hbus, uint32_t wslot) 803308725Sdexuan{ 804308725Sdexuan struct hv_pci_dev *hpdev, *ret = NULL; 805308725Sdexuan 806308725Sdexuan mtx_lock(&hbus->device_list_lock); 807308725Sdexuan TAILQ_FOREACH(hpdev, &hbus->children, link) { 808308725Sdexuan if (hpdev->desc.wslot.val == wslot) { 809308725Sdexuan ret = hpdev; 810308725Sdexuan break; 811308725Sdexuan } 812308725Sdexuan } 813308725Sdexuan mtx_unlock(&hbus->device_list_lock); 814308725Sdexuan 815308725Sdexuan return (ret); 816308725Sdexuan} 817308725Sdexuan 818308725Sdexuanstatic void 819308725Sdexuanhv_pci_devices_present(struct hv_pcibus *hbus, 820308725Sdexuan struct pci_bus_relations *relations) 821308725Sdexuan{ 822308725Sdexuan struct hv_dr_state *dr; 823308725Sdexuan struct hv_dr_work *dr_wrk; 824308725Sdexuan unsigned long dr_size; 825308725Sdexuan 826308725Sdexuan if (hbus->detaching && relations->device_count > 0) 827308725Sdexuan return; 828308725Sdexuan 829308725Sdexuan dr_size = offsetof(struct hv_dr_state, func) + 830308725Sdexuan (sizeof(struct pci_func_desc) * relations->device_count); 831308725Sdexuan dr = malloc(dr_size, M_DEVBUF, M_WAITOK | M_ZERO); 832308725Sdexuan 833308725Sdexuan dr->device_count = relations->device_count; 834308725Sdexuan if (dr->device_count != 0) 835308725Sdexuan memcpy(dr->func, relations->func, 836308725Sdexuan sizeof(struct pci_func_desc) * dr->device_count); 837308725Sdexuan 838308725Sdexuan mtx_lock(&hbus->device_list_lock); 839308725Sdexuan TAILQ_INSERT_TAIL(&hbus->dr_list, dr, link); 840308725Sdexuan mtx_unlock(&hbus->device_list_lock); 841308725Sdexuan 842308725Sdexuan dr_wrk = malloc(sizeof(*dr_wrk), M_DEVBUF, M_WAITOK | M_ZERO); 843308725Sdexuan dr_wrk->bus = hbus; 844308725Sdexuan TASK_INIT(&dr_wrk->task, 0, pci_devices_present_work, dr_wrk); 845308725Sdexuan taskqueue_enqueue(hbus->sc->taskq, &dr_wrk->task); 846308725Sdexuan} 847308725Sdexuan 848308725Sdexuanstatic void 849308725Sdexuanhv_eject_device_work(void *arg, int pending __unused) 850308725Sdexuan{ 851308725Sdexuan struct hv_pci_dev *hpdev = arg; 852308725Sdexuan union win_slot_encoding wslot = hpdev->desc.wslot; 853308725Sdexuan struct hv_pcibus *hbus = hpdev->hbus; 854308725Sdexuan struct pci_eject_response *eject_pkt; 855308725Sdexuan struct { 856308725Sdexuan struct pci_packet pkt; 857308725Sdexuan uint8_t buffer[sizeof(struct pci_eject_response)]; 858308725Sdexuan } ctxt; 859308725Sdexuan 860308725Sdexuan hv_pci_delete_device(hpdev); 861308725Sdexuan 862308725Sdexuan memset(&ctxt, 0, sizeof(ctxt)); 863308725Sdexuan eject_pkt = (struct pci_eject_response *)&ctxt.pkt.message; 864308725Sdexuan eject_pkt->message_type.type = PCI_EJECTION_COMPLETE; 865308725Sdexuan eject_pkt->wslot.val = wslot.val; 866308725Sdexuan vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 867308725Sdexuan eject_pkt, sizeof(*eject_pkt), 0); 868308725Sdexuan} 869308725Sdexuan 870308725Sdexuanstatic void 871308725Sdexuanhv_pci_eject_device(struct hv_pci_dev *hpdev) 872308725Sdexuan{ 873308725Sdexuan struct hv_pcibus *hbus = hpdev->hbus; 874308725Sdexuan struct taskqueue *taskq; 875308725Sdexuan 876308725Sdexuan if (hbus->detaching) 877308725Sdexuan return; 878308725Sdexuan 879308725Sdexuan /* 880308725Sdexuan * Push this task into the same taskqueue on which 881308725Sdexuan * vmbus_pcib_attach() runs, so we're sure this task can't run 882308725Sdexuan * concurrently with vmbus_pcib_attach(). 883308725Sdexuan */ 884308725Sdexuan TASK_INIT(&hpdev->eject_task, 0, hv_eject_device_work, hpdev); 885308725Sdexuan taskq = vmbus_chan_mgmt_tq(hbus->sc->chan); 886308725Sdexuan taskqueue_enqueue(taskq, &hpdev->eject_task); 887308725Sdexuan} 888308725Sdexuan 889308725Sdexuan#define PCIB_PACKET_SIZE 0x100 890308725Sdexuan 891308725Sdexuanstatic void 892308725Sdexuanvmbus_pcib_on_channel_callback(struct vmbus_channel *chan, void *arg) 893308725Sdexuan{ 894308725Sdexuan struct vmbus_pcib_softc *sc = arg; 895308725Sdexuan struct hv_pcibus *hbus = sc->hbus; 896308725Sdexuan 897308725Sdexuan void *buffer; 898308725Sdexuan int bufferlen = PCIB_PACKET_SIZE; 899308725Sdexuan 900308725Sdexuan struct pci_packet *comp_packet; 901308725Sdexuan struct pci_response *response; 902308725Sdexuan struct pci_incoming_message *new_msg; 903308725Sdexuan struct pci_bus_relations *bus_rel; 904308725Sdexuan struct pci_dev_incoming *dev_msg; 905308725Sdexuan struct hv_pci_dev *hpdev; 906308725Sdexuan 907308725Sdexuan buffer = sc->rx_buf; 908308725Sdexuan do { 909308725Sdexuan struct vmbus_chanpkt_hdr *pkt = buffer; 910308725Sdexuan uint32_t bytes_rxed; 911308725Sdexuan int ret; 912308725Sdexuan 913308725Sdexuan bytes_rxed = bufferlen; 914308725Sdexuan ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); 915308725Sdexuan 916308725Sdexuan if (ret == ENOBUFS) { 917308725Sdexuan /* Handle large packet */ 918308725Sdexuan if (bufferlen > PCIB_PACKET_SIZE) { 919308725Sdexuan free(buffer, M_DEVBUF); 920308725Sdexuan buffer = NULL; 921308725Sdexuan } 922308725Sdexuan 923308725Sdexuan /* alloc new buffer */ 924308725Sdexuan buffer = malloc(bytes_rxed, M_DEVBUF, M_WAITOK | M_ZERO); 925308725Sdexuan bufferlen = bytes_rxed; 926308725Sdexuan 927308725Sdexuan continue; 928308725Sdexuan } 929308725Sdexuan 930308725Sdexuan if (ret != 0) { 931308725Sdexuan /* ignore EIO or EAGAIN */ 932308725Sdexuan break; 933308725Sdexuan } 934308725Sdexuan 935308725Sdexuan if (bytes_rxed <= sizeof(struct pci_response)) 936308725Sdexuan continue; 937308725Sdexuan 938308725Sdexuan switch (pkt->cph_type) { 939308725Sdexuan case VMBUS_CHANPKT_TYPE_COMP: 940337959Sdim comp_packet = 941337959Sdim (struct pci_packet *)(uintptr_t)pkt->cph_xactid; 942308725Sdexuan response = (struct pci_response *)pkt; 943308725Sdexuan comp_packet->completion_func(comp_packet->compl_ctxt, 944308725Sdexuan response, bytes_rxed); 945308725Sdexuan break; 946308725Sdexuan case VMBUS_CHANPKT_TYPE_INBAND: 947308725Sdexuan new_msg = (struct pci_incoming_message *)buffer; 948308725Sdexuan 949308725Sdexuan switch (new_msg->message_type.type) { 950308725Sdexuan case PCI_BUS_RELATIONS: 951308725Sdexuan bus_rel = (struct pci_bus_relations *)buffer; 952308725Sdexuan 953308725Sdexuan if (bus_rel->device_count == 0) 954308725Sdexuan break; 955308725Sdexuan 956308725Sdexuan if (bytes_rxed < 957308725Sdexuan offsetof(struct pci_bus_relations, func) + 958308725Sdexuan (sizeof(struct pci_func_desc) * 959308725Sdexuan (bus_rel->device_count))) 960308725Sdexuan break; 961308725Sdexuan 962308725Sdexuan hv_pci_devices_present(hbus, bus_rel); 963308725Sdexuan break; 964308725Sdexuan 965308725Sdexuan case PCI_EJECT: 966308725Sdexuan dev_msg = (struct pci_dev_incoming *)buffer; 967308725Sdexuan hpdev = get_pcichild_wslot(hbus, 968308725Sdexuan dev_msg->wslot.val); 969308725Sdexuan 970308725Sdexuan if (hpdev) 971308725Sdexuan hv_pci_eject_device(hpdev); 972308725Sdexuan 973308725Sdexuan break; 974308725Sdexuan default: 975308725Sdexuan printf("vmbus_pcib: Unknown msg type 0x%x\n", 976308725Sdexuan new_msg->message_type.type); 977308725Sdexuan break; 978308725Sdexuan } 979308725Sdexuan break; 980308725Sdexuan default: 981308725Sdexuan printf("vmbus_pcib: Unknown VMBus msg type %hd\n", 982308725Sdexuan pkt->cph_type); 983308725Sdexuan break; 984308725Sdexuan } 985308725Sdexuan } while (1); 986308725Sdexuan 987308725Sdexuan if (bufferlen > PCIB_PACKET_SIZE) 988308725Sdexuan free(buffer, M_DEVBUF); 989308725Sdexuan} 990308725Sdexuan 991308725Sdexuanstatic int 992308725Sdexuanhv_pci_protocol_negotiation(struct hv_pcibus *hbus) 993308725Sdexuan{ 994308725Sdexuan struct pci_version_request *version_req; 995308725Sdexuan struct hv_pci_compl comp_pkt; 996308725Sdexuan struct { 997308725Sdexuan struct pci_packet pkt; 998308725Sdexuan uint8_t buffer[sizeof(struct pci_version_request)]; 999308725Sdexuan } ctxt; 1000308725Sdexuan int ret; 1001308725Sdexuan 1002308725Sdexuan init_completion(&comp_pkt.host_event); 1003308725Sdexuan 1004308725Sdexuan ctxt.pkt.completion_func = hv_pci_generic_compl; 1005308725Sdexuan ctxt.pkt.compl_ctxt = &comp_pkt; 1006308725Sdexuan version_req = (struct pci_version_request *)&ctxt.pkt.message; 1007308725Sdexuan version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION; 1008308725Sdexuan version_req->protocol_version = PCI_PROTOCOL_VERSION_CURRENT; 1009308725Sdexuan version_req->is_last_attempt = 1; 1010308725Sdexuan 1011308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 1012308725Sdexuan VMBUS_CHANPKT_FLAG_RC, version_req, sizeof(*version_req), 1013337959Sdim (uint64_t)(uintptr_t)&ctxt.pkt); 1014308725Sdexuan if (ret) 1015308725Sdexuan goto out; 1016308725Sdexuan 1017308725Sdexuan wait_for_completion(&comp_pkt.host_event); 1018308725Sdexuan 1019308725Sdexuan if (comp_pkt.completion_status < 0) { 1020308725Sdexuan device_printf(hbus->pcib, 1021308725Sdexuan "vmbus_pcib version negotiation failed: %x\n", 1022308725Sdexuan comp_pkt.completion_status); 1023308725Sdexuan ret = EPROTO; 1024308725Sdexuan } else { 1025308725Sdexuan ret = 0; 1026308725Sdexuan } 1027308725Sdexuanout: 1028308725Sdexuan free_completion(&comp_pkt.host_event); 1029308725Sdexuan return (ret); 1030308725Sdexuan} 1031308725Sdexuan 1032308725Sdexuan/* Ask the host to send along the list of child devices */ 1033308725Sdexuanstatic int 1034308725Sdexuanhv_pci_query_relations(struct hv_pcibus *hbus) 1035308725Sdexuan{ 1036308725Sdexuan struct pci_message message; 1037308725Sdexuan int ret; 1038308725Sdexuan 1039308725Sdexuan message.type = PCI_QUERY_BUS_RELATIONS; 1040308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 1041308725Sdexuan &message, sizeof(message), 0); 1042308725Sdexuan return (ret); 1043308725Sdexuan} 1044308725Sdexuan 1045308725Sdexuanstatic int 1046308725Sdexuanhv_pci_enter_d0(struct hv_pcibus *hbus) 1047308725Sdexuan{ 1048308725Sdexuan struct pci_bus_d0_entry *d0_entry; 1049308725Sdexuan struct hv_pci_compl comp_pkt; 1050308725Sdexuan struct { 1051308725Sdexuan struct pci_packet pkt; 1052308725Sdexuan uint8_t buffer[sizeof(struct pci_bus_d0_entry)]; 1053308725Sdexuan } ctxt; 1054308725Sdexuan int ret; 1055308725Sdexuan 1056308725Sdexuan /* 1057308725Sdexuan * Tell the host that the bus is ready to use, and moved into the 1058308725Sdexuan * powered-on state. This includes telling the host which region 1059308725Sdexuan * of memory-mapped I/O space has been chosen for configuration space 1060308725Sdexuan * access. 1061308725Sdexuan */ 1062308725Sdexuan init_completion(&comp_pkt.host_event); 1063308725Sdexuan 1064308725Sdexuan ctxt.pkt.completion_func = hv_pci_generic_compl; 1065308725Sdexuan ctxt.pkt.compl_ctxt = &comp_pkt; 1066308725Sdexuan 1067308725Sdexuan d0_entry = (struct pci_bus_d0_entry *)&ctxt.pkt.message; 1068308725Sdexuan memset(d0_entry, 0, sizeof(*d0_entry)); 1069308725Sdexuan d0_entry->message_type.type = PCI_BUS_D0ENTRY; 1070308725Sdexuan d0_entry->mmio_base = rman_get_start(hbus->cfg_res); 1071308725Sdexuan 1072308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 1073308725Sdexuan VMBUS_CHANPKT_FLAG_RC, d0_entry, sizeof(*d0_entry), 1074337959Sdim (uint64_t)(uintptr_t)&ctxt.pkt); 1075308725Sdexuan if (ret) 1076308725Sdexuan goto out; 1077308725Sdexuan 1078308725Sdexuan wait_for_completion(&comp_pkt.host_event); 1079308725Sdexuan 1080308725Sdexuan if (comp_pkt.completion_status < 0) { 1081308725Sdexuan device_printf(hbus->pcib, "vmbus_pcib failed to enable D0\n"); 1082308725Sdexuan ret = EPROTO; 1083308725Sdexuan } else { 1084308725Sdexuan ret = 0; 1085308725Sdexuan } 1086308725Sdexuan 1087308725Sdexuanout: 1088308725Sdexuan free_completion(&comp_pkt.host_event); 1089308725Sdexuan return (ret); 1090308725Sdexuan} 1091308725Sdexuan 1092308725Sdexuan/* 1093308725Sdexuan * It looks this is only needed by Windows VM, but let's send the message too 1094308725Sdexuan * just to make the host happy. 1095308725Sdexuan */ 1096308725Sdexuanstatic int 1097308725Sdexuanhv_send_resources_allocated(struct hv_pcibus *hbus) 1098308725Sdexuan{ 1099308725Sdexuan struct pci_resources_assigned *res_assigned; 1100308725Sdexuan struct hv_pci_compl comp_pkt; 1101308725Sdexuan struct hv_pci_dev *hpdev; 1102308725Sdexuan struct pci_packet *pkt; 1103308725Sdexuan uint32_t wslot; 1104308725Sdexuan int ret = 0; 1105308725Sdexuan 1106308725Sdexuan pkt = malloc(sizeof(*pkt) + sizeof(*res_assigned), 1107308725Sdexuan M_DEVBUF, M_WAITOK | M_ZERO); 1108308725Sdexuan 1109308725Sdexuan for (wslot = 0; wslot < 256; wslot++) { 1110308725Sdexuan hpdev = get_pcichild_wslot(hbus, wslot); 1111308725Sdexuan if (!hpdev) 1112308725Sdexuan continue; 1113308725Sdexuan 1114308725Sdexuan init_completion(&comp_pkt.host_event); 1115308725Sdexuan 1116308725Sdexuan memset(pkt, 0, sizeof(*pkt) + sizeof(*res_assigned)); 1117308725Sdexuan pkt->completion_func = hv_pci_generic_compl; 1118308725Sdexuan pkt->compl_ctxt = &comp_pkt; 1119308725Sdexuan 1120308725Sdexuan res_assigned = (struct pci_resources_assigned *)&pkt->message; 1121308725Sdexuan res_assigned->message_type.type = PCI_RESOURCES_ASSIGNED; 1122308725Sdexuan res_assigned->wslot.val = hpdev->desc.wslot.val; 1123308725Sdexuan 1124308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, 1125308725Sdexuan VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 1126337959Sdim &pkt->message, sizeof(*res_assigned), 1127337959Sdim (uint64_t)(uintptr_t)pkt); 1128308725Sdexuan if (ret) { 1129308725Sdexuan free_completion(&comp_pkt.host_event); 1130308725Sdexuan break; 1131308725Sdexuan } 1132308725Sdexuan 1133308725Sdexuan wait_for_completion(&comp_pkt.host_event); 1134308725Sdexuan free_completion(&comp_pkt.host_event); 1135308725Sdexuan 1136308725Sdexuan if (comp_pkt.completion_status < 0) { 1137308725Sdexuan ret = EPROTO; 1138308725Sdexuan device_printf(hbus->pcib, 1139308725Sdexuan "failed to send PCI_RESOURCES_ASSIGNED\n"); 1140308725Sdexuan break; 1141308725Sdexuan } 1142308725Sdexuan } 1143308725Sdexuan 1144308725Sdexuan free(pkt, M_DEVBUF); 1145308725Sdexuan return (ret); 1146308725Sdexuan} 1147308725Sdexuan 1148308725Sdexuanstatic int 1149308725Sdexuanhv_send_resources_released(struct hv_pcibus *hbus) 1150308725Sdexuan{ 1151308725Sdexuan struct pci_child_message pkt; 1152308725Sdexuan struct hv_pci_dev *hpdev; 1153308725Sdexuan uint32_t wslot; 1154308725Sdexuan int ret; 1155308725Sdexuan 1156308725Sdexuan for (wslot = 0; wslot < 256; wslot++) { 1157308725Sdexuan hpdev = get_pcichild_wslot(hbus, wslot); 1158308725Sdexuan if (!hpdev) 1159308725Sdexuan continue; 1160308725Sdexuan 1161308725Sdexuan pkt.message_type.type = PCI_RESOURCES_RELEASED; 1162308725Sdexuan pkt.wslot.val = hpdev->desc.wslot.val; 1163308725Sdexuan 1164308725Sdexuan ret = vmbus_chan_send(hbus->sc->chan, 1165308725Sdexuan VMBUS_CHANPKT_TYPE_INBAND, 0, &pkt, sizeof(pkt), 0); 1166308725Sdexuan if (ret) 1167308725Sdexuan return (ret); 1168308725Sdexuan } 1169308725Sdexuan 1170308725Sdexuan return (0); 1171308725Sdexuan} 1172308725Sdexuan 1173308725Sdexuan#define hv_cfg_read(x, s) \ 1174308725Sdexuanstatic inline uint##x##_t hv_cfg_read_##s(struct hv_pcibus *bus, \ 1175308725Sdexuan bus_size_t offset) \ 1176308725Sdexuan{ \ 1177308725Sdexuan return (bus_read_##s(bus->cfg_res, offset)); \ 1178308725Sdexuan} 1179308725Sdexuan 1180308725Sdexuan#define hv_cfg_write(x, s) \ 1181308725Sdexuanstatic inline void hv_cfg_write_##s(struct hv_pcibus *bus, \ 1182308725Sdexuan bus_size_t offset, uint##x##_t val) \ 1183308725Sdexuan{ \ 1184308725Sdexuan return (bus_write_##s(bus->cfg_res, offset, val)); \ 1185308725Sdexuan} 1186308725Sdexuan 1187308725Sdexuanhv_cfg_read(8, 1) 1188308725Sdexuanhv_cfg_read(16, 2) 1189308725Sdexuanhv_cfg_read(32, 4) 1190308725Sdexuan 1191308725Sdexuanhv_cfg_write(8, 1) 1192308725Sdexuanhv_cfg_write(16, 2) 1193308725Sdexuanhv_cfg_write(32, 4) 1194308725Sdexuan 1195308725Sdexuanstatic void 1196308725Sdexuan_hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, int size, 1197308725Sdexuan uint32_t *val) 1198308725Sdexuan{ 1199308725Sdexuan struct hv_pcibus *hbus = hpdev->hbus; 1200308725Sdexuan bus_size_t addr = CFG_PAGE_OFFSET + where; 1201308725Sdexuan 1202308725Sdexuan /* 1203308725Sdexuan * If the attempt is to read the IDs or the ROM BAR, simulate that. 1204308725Sdexuan */ 1205308725Sdexuan if (where + size <= PCIR_COMMAND) { 1206308725Sdexuan memcpy(val, ((uint8_t *)&hpdev->desc.v_id) + where, size); 1207308725Sdexuan } else if (where >= PCIR_REVID && where + size <= 1208308725Sdexuan PCIR_CACHELNSZ) { 1209308725Sdexuan memcpy(val, ((uint8_t *)&hpdev->desc.rev) + where - 1210308725Sdexuan PCIR_REVID, size); 1211308725Sdexuan } else if (where >= PCIR_SUBVEND_0 && where + size <= 1212308725Sdexuan PCIR_BIOS) { 1213308725Sdexuan memcpy(val, (uint8_t *)&hpdev->desc.subsystem_id + where - 1214308725Sdexuan PCIR_SUBVEND_0, size); 1215308725Sdexuan } else if (where >= PCIR_BIOS && where + size <= 1216308725Sdexuan PCIR_CAP_PTR) { 1217308725Sdexuan /* ROM BARs are unimplemented */ 1218308725Sdexuan *val = 0; 1219308725Sdexuan } else if ((where >= PCIR_INTLINE && where + size <= 1220308725Sdexuan PCIR_INTPIN) ||(where == PCIR_INTPIN && size == 1)) { 1221308725Sdexuan /* 1222308725Sdexuan * Interrupt Line and Interrupt PIN are hard-wired to zero 1223308725Sdexuan * because this front-end only supports message-signaled 1224308725Sdexuan * interrupts. 1225308725Sdexuan */ 1226308725Sdexuan *val = 0; 1227308725Sdexuan } else if (where + size <= CFG_PAGE_SIZE) { 1228308725Sdexuan mtx_lock(&hbus->config_lock); 1229308725Sdexuan 1230308725Sdexuan /* Choose the function to be read. */ 1231308725Sdexuan hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val); 1232308725Sdexuan 1233308725Sdexuan /* Make sure the function was chosen before we start reading.*/ 1234308725Sdexuan mb(); 1235308725Sdexuan 1236308725Sdexuan /* Read from that function's config space. */ 1237308725Sdexuan switch (size) { 1238308725Sdexuan case 1: 1239308725Sdexuan *((uint8_t *)val) = hv_cfg_read_1(hbus, addr); 1240308725Sdexuan break; 1241308725Sdexuan case 2: 1242308725Sdexuan *((uint16_t *)val) = hv_cfg_read_2(hbus, addr); 1243308725Sdexuan break; 1244308725Sdexuan default: 1245308725Sdexuan *((uint32_t *)val) = hv_cfg_read_4(hbus, addr); 1246308725Sdexuan break; 1247308725Sdexuan } 1248308725Sdexuan /* 1249308725Sdexuan * Make sure the write was done before we release the lock, 1250308725Sdexuan * allowing consecutive reads/writes. 1251308725Sdexuan */ 1252308725Sdexuan mb(); 1253308725Sdexuan 1254308725Sdexuan mtx_unlock(&hbus->config_lock); 1255308725Sdexuan } else { 1256308725Sdexuan /* Invalid config read: it's unlikely to reach here. */ 1257308725Sdexuan memset(val, 0, size); 1258308725Sdexuan } 1259308725Sdexuan} 1260308725Sdexuan 1261308725Sdexuanstatic void 1262308725Sdexuan_hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size, 1263308725Sdexuan uint32_t val) 1264308725Sdexuan{ 1265308725Sdexuan struct hv_pcibus *hbus = hpdev->hbus; 1266308725Sdexuan bus_size_t addr = CFG_PAGE_OFFSET + where; 1267308725Sdexuan 1268308725Sdexuan /* SSIDs and ROM BARs are read-only */ 1269308725Sdexuan if (where >= PCIR_SUBVEND_0 && where + size <= PCIR_CAP_PTR) 1270308725Sdexuan return; 1271308725Sdexuan 1272308725Sdexuan if (where >= PCIR_COMMAND && where + size <= CFG_PAGE_SIZE) { 1273308725Sdexuan mtx_lock(&hbus->config_lock); 1274308725Sdexuan 1275308725Sdexuan /* Choose the function to be written. */ 1276308725Sdexuan hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val); 1277308725Sdexuan 1278308725Sdexuan /* Make sure the function was chosen before we start writing.*/ 1279308725Sdexuan wmb(); 1280308725Sdexuan 1281308725Sdexuan /* Write to that function's config space. */ 1282308725Sdexuan switch (size) { 1283308725Sdexuan case 1: 1284308725Sdexuan hv_cfg_write_1(hbus, addr, (uint8_t)val); 1285308725Sdexuan break; 1286308725Sdexuan case 2: 1287308725Sdexuan hv_cfg_write_2(hbus, addr, (uint16_t)val); 1288308725Sdexuan break; 1289308725Sdexuan default: 1290308725Sdexuan hv_cfg_write_4(hbus, addr, (uint32_t)val); 1291308725Sdexuan break; 1292308725Sdexuan } 1293308725Sdexuan 1294308725Sdexuan /* 1295308725Sdexuan * Make sure the write was done before we release the lock, 1296308725Sdexuan * allowing consecutive reads/writes. 1297308725Sdexuan */ 1298308725Sdexuan mb(); 1299308725Sdexuan 1300308725Sdexuan mtx_unlock(&hbus->config_lock); 1301308725Sdexuan } else { 1302308725Sdexuan /* Invalid config write: it's unlikely to reach here. */ 1303308725Sdexuan return; 1304308725Sdexuan } 1305308725Sdexuan} 1306308725Sdexuan 1307308725Sdexuanstatic void 1308308725Sdexuanvmbus_pcib_set_detaching(void *arg, int pending __unused) 1309308725Sdexuan{ 1310308725Sdexuan struct hv_pcibus *hbus = arg; 1311308725Sdexuan 1312308725Sdexuan atomic_set_int(&hbus->detaching, 1); 1313308725Sdexuan} 1314308725Sdexuan 1315308725Sdexuanstatic void 1316308725Sdexuanvmbus_pcib_pre_detach(struct hv_pcibus *hbus) 1317308725Sdexuan{ 1318308725Sdexuan struct task task; 1319308725Sdexuan 1320308725Sdexuan TASK_INIT(&task, 0, vmbus_pcib_set_detaching, hbus); 1321308725Sdexuan 1322308725Sdexuan /* 1323308725Sdexuan * Make sure the channel callback won't push any possible new 1324308725Sdexuan * PCI_BUS_RELATIONS and PCI_EJECT tasks to sc->taskq. 1325308725Sdexuan */ 1326308725Sdexuan vmbus_chan_run_task(hbus->sc->chan, &task); 1327308725Sdexuan 1328308725Sdexuan taskqueue_drain_all(hbus->sc->taskq); 1329308725Sdexuan} 1330308725Sdexuan 1331308725Sdexuan 1332308725Sdexuan/* 1333308725Sdexuan * Standard probe entry point. 1334308725Sdexuan * 1335308725Sdexuan */ 1336308725Sdexuanstatic int 1337308725Sdexuanvmbus_pcib_probe(device_t dev) 1338308725Sdexuan{ 1339308725Sdexuan if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, 1340308725Sdexuan &g_pass_through_dev_type) == 0) { 1341308725Sdexuan device_set_desc(dev, "Hyper-V PCI Express Pass Through"); 1342308725Sdexuan return (BUS_PROBE_DEFAULT); 1343308725Sdexuan } 1344308725Sdexuan return (ENXIO); 1345308725Sdexuan} 1346308725Sdexuan 1347308725Sdexuan/* 1348308725Sdexuan * Standard attach entry point. 1349308725Sdexuan * 1350308725Sdexuan */ 1351308725Sdexuanstatic int 1352308725Sdexuanvmbus_pcib_attach(device_t dev) 1353308725Sdexuan{ 1354308725Sdexuan const int pci_ring_size = (4 * PAGE_SIZE); 1355308725Sdexuan const struct hyperv_guid *inst_guid; 1356308725Sdexuan struct vmbus_channel *channel; 1357308725Sdexuan struct vmbus_pcib_softc *sc; 1358308725Sdexuan struct hv_pcibus *hbus; 1359308725Sdexuan int rid = 0; 1360308725Sdexuan int ret; 1361308725Sdexuan 1362308725Sdexuan hbus = malloc(sizeof(*hbus), M_DEVBUF, M_WAITOK | M_ZERO); 1363308725Sdexuan hbus->pcib = dev; 1364308725Sdexuan 1365308725Sdexuan channel = vmbus_get_channel(dev); 1366308725Sdexuan inst_guid = vmbus_chan_guid_inst(channel); 1367308725Sdexuan hbus->pci_domain = inst_guid->hv_guid[9] | 1368308725Sdexuan (inst_guid->hv_guid[8] << 8); 1369308725Sdexuan 1370308725Sdexuan mtx_init(&hbus->config_lock, "hbcfg", NULL, MTX_DEF); 1371308725Sdexuan mtx_init(&hbus->device_list_lock, "hbdl", NULL, MTX_DEF); 1372308725Sdexuan TAILQ_INIT(&hbus->children); 1373308725Sdexuan TAILQ_INIT(&hbus->dr_list); 1374308725Sdexuan 1375308725Sdexuan hbus->cfg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 1376308725Sdexuan 0, RM_MAX_END, PCI_CONFIG_MMIO_LENGTH, 1377308725Sdexuan RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE)); 1378308725Sdexuan 1379308725Sdexuan if (!hbus->cfg_res) { 1380308725Sdexuan device_printf(dev, "failed to get resource for cfg window\n"); 1381308725Sdexuan ret = ENXIO; 1382308725Sdexuan goto free_bus; 1383308725Sdexuan } 1384308725Sdexuan 1385308725Sdexuan sc = device_get_softc(dev); 1386308725Sdexuan sc->chan = channel; 1387308725Sdexuan sc->rx_buf = malloc(PCIB_PACKET_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); 1388308725Sdexuan sc->hbus = hbus; 1389308725Sdexuan 1390308725Sdexuan /* 1391308725Sdexuan * The taskq is used to handle PCI_BUS_RELATIONS and PCI_EJECT 1392308725Sdexuan * messages. NB: we can't handle the messages in the channel callback 1393308725Sdexuan * directly, because the message handlers need to send new messages 1394308725Sdexuan * to the host and waits for the host's completion messages, which 1395308725Sdexuan * must also be handled by the channel callback. 1396308725Sdexuan */ 1397308725Sdexuan sc->taskq = taskqueue_create("vmbus_pcib_tq", M_WAITOK, 1398308725Sdexuan taskqueue_thread_enqueue, &sc->taskq); 1399308725Sdexuan taskqueue_start_threads(&sc->taskq, 1, PI_NET, "vmbus_pcib_tq"); 1400308725Sdexuan 1401308725Sdexuan hbus->sc = sc; 1402308725Sdexuan 1403308725Sdexuan init_completion(&hbus->query_completion); 1404308725Sdexuan hbus->query_comp = &hbus->query_completion; 1405308725Sdexuan 1406308725Sdexuan ret = vmbus_chan_open(sc->chan, pci_ring_size, pci_ring_size, 1407308725Sdexuan NULL, 0, vmbus_pcib_on_channel_callback, sc); 1408308725Sdexuan if (ret) 1409308725Sdexuan goto free_res; 1410308725Sdexuan 1411308725Sdexuan ret = hv_pci_protocol_negotiation(hbus); 1412308725Sdexuan if (ret) 1413308725Sdexuan goto vmbus_close; 1414308725Sdexuan 1415308725Sdexuan ret = hv_pci_query_relations(hbus); 1416308725Sdexuan if (ret) 1417308725Sdexuan goto vmbus_close; 1418308725Sdexuan wait_for_completion(hbus->query_comp); 1419308725Sdexuan 1420308725Sdexuan ret = hv_pci_enter_d0(hbus); 1421308725Sdexuan if (ret) 1422308725Sdexuan goto vmbus_close; 1423308725Sdexuan 1424308725Sdexuan ret = hv_send_resources_allocated(hbus); 1425308725Sdexuan if (ret) 1426308725Sdexuan goto vmbus_close; 1427308725Sdexuan 1428308725Sdexuan hbus->pci_bus = device_add_child(dev, "pci", -1); 1429308725Sdexuan if (!hbus->pci_bus) { 1430308725Sdexuan device_printf(dev, "failed to create pci bus\n"); 1431308725Sdexuan ret = ENXIO; 1432308725Sdexuan goto vmbus_close; 1433308725Sdexuan } 1434308725Sdexuan 1435308725Sdexuan bus_generic_attach(dev); 1436308725Sdexuan 1437308725Sdexuan hbus->state = hv_pcibus_installed; 1438308725Sdexuan 1439308725Sdexuan return (0); 1440308725Sdexuan 1441308725Sdexuanvmbus_close: 1442308725Sdexuan vmbus_pcib_pre_detach(hbus); 1443308725Sdexuan vmbus_chan_close(sc->chan); 1444308725Sdexuanfree_res: 1445308725Sdexuan taskqueue_free(sc->taskq); 1446308725Sdexuan free_completion(&hbus->query_completion); 1447308725Sdexuan free(sc->rx_buf, M_DEVBUF); 1448308725Sdexuan bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res); 1449308725Sdexuanfree_bus: 1450308725Sdexuan mtx_destroy(&hbus->device_list_lock); 1451308725Sdexuan mtx_destroy(&hbus->config_lock); 1452308725Sdexuan free(hbus, M_DEVBUF); 1453308725Sdexuan return (ret); 1454308725Sdexuan} 1455308725Sdexuan 1456308725Sdexuan/* 1457308725Sdexuan * Standard detach entry point 1458308725Sdexuan */ 1459308725Sdexuanstatic int 1460308725Sdexuanvmbus_pcib_detach(device_t dev) 1461308725Sdexuan{ 1462308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1463308725Sdexuan struct hv_pcibus *hbus = sc->hbus; 1464308725Sdexuan struct pci_message teardown_packet; 1465308725Sdexuan struct pci_bus_relations relations; 1466308725Sdexuan int ret; 1467308725Sdexuan 1468308725Sdexuan vmbus_pcib_pre_detach(hbus); 1469308725Sdexuan 1470308725Sdexuan if (hbus->state == hv_pcibus_installed) 1471308725Sdexuan bus_generic_detach(dev); 1472308725Sdexuan 1473308725Sdexuan /* Delete any children which might still exist. */ 1474308725Sdexuan memset(&relations, 0, sizeof(relations)); 1475308725Sdexuan hv_pci_devices_present(hbus, &relations); 1476308725Sdexuan 1477308725Sdexuan ret = hv_send_resources_released(hbus); 1478308725Sdexuan if (ret) 1479308725Sdexuan device_printf(dev, "failed to send PCI_RESOURCES_RELEASED\n"); 1480308725Sdexuan 1481308725Sdexuan teardown_packet.type = PCI_BUS_D0EXIT; 1482308725Sdexuan ret = vmbus_chan_send(sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0, 1483308725Sdexuan &teardown_packet, sizeof(struct pci_message), 0); 1484308725Sdexuan if (ret) 1485308725Sdexuan device_printf(dev, "failed to send PCI_BUS_D0EXIT\n"); 1486308725Sdexuan 1487308725Sdexuan taskqueue_drain_all(hbus->sc->taskq); 1488308725Sdexuan vmbus_chan_close(sc->chan); 1489308725Sdexuan taskqueue_free(sc->taskq); 1490308725Sdexuan 1491308725Sdexuan free_completion(&hbus->query_completion); 1492308725Sdexuan free(sc->rx_buf, M_DEVBUF); 1493308725Sdexuan bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res); 1494308725Sdexuan 1495308725Sdexuan mtx_destroy(&hbus->device_list_lock); 1496308725Sdexuan mtx_destroy(&hbus->config_lock); 1497308725Sdexuan free(hbus, M_DEVBUF); 1498308725Sdexuan 1499308725Sdexuan return (0); 1500308725Sdexuan} 1501308725Sdexuan 1502308725Sdexuanstatic int 1503308725Sdexuanvmbus_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *val) 1504308725Sdexuan{ 1505308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1506308725Sdexuan 1507308725Sdexuan switch (which) { 1508308725Sdexuan case PCIB_IVAR_DOMAIN: 1509308725Sdexuan *val = sc->hbus->pci_domain; 1510308725Sdexuan return (0); 1511308725Sdexuan 1512308725Sdexuan case PCIB_IVAR_BUS: 1513308725Sdexuan /* There is only bus 0. */ 1514308725Sdexuan *val = 0; 1515308725Sdexuan return (0); 1516308725Sdexuan } 1517308725Sdexuan return (ENOENT); 1518308725Sdexuan} 1519308725Sdexuan 1520308725Sdexuanstatic int 1521308725Sdexuanvmbus_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t val) 1522308725Sdexuan{ 1523308725Sdexuan return (ENOENT); 1524308725Sdexuan} 1525308725Sdexuan 1526308725Sdexuanstatic struct resource * 1527308725Sdexuanvmbus_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1528308725Sdexuan rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1529308725Sdexuan{ 1530308725Sdexuan unsigned int bar_no; 1531308725Sdexuan struct hv_pci_dev *hpdev; 1532308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1533308725Sdexuan struct resource *res; 1534308725Sdexuan unsigned int devfn; 1535308725Sdexuan 1536308725Sdexuan if (type == PCI_RES_BUS) 1537308725Sdexuan return (pci_domain_alloc_bus(sc->hbus->pci_domain, child, rid, 1538308725Sdexuan start, end, count, flags)); 1539308725Sdexuan 1540308725Sdexuan /* Devices with port I/O BAR are not supported. */ 1541308725Sdexuan if (type == SYS_RES_IOPORT) 1542308725Sdexuan return (NULL); 1543308725Sdexuan 1544308725Sdexuan if (type == SYS_RES_MEMORY) { 1545308725Sdexuan devfn = PCI_DEVFN(pci_get_slot(child), 1546308725Sdexuan pci_get_function(child)); 1547308725Sdexuan hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 1548308725Sdexuan if (!hpdev) 1549308725Sdexuan return (NULL); 1550308725Sdexuan 1551308725Sdexuan bar_no = PCI_RID2BAR(*rid); 1552308725Sdexuan if (bar_no >= MAX_NUM_BARS) 1553308725Sdexuan return (NULL); 1554308725Sdexuan 1555308725Sdexuan /* Make sure a 32-bit BAR gets a 32-bit address */ 1556308725Sdexuan if (!(hpdev->probed_bar[bar_no] & PCIM_BAR_MEM_64)) 1557308725Sdexuan end = ulmin(end, 0xFFFFFFFF); 1558308725Sdexuan } 1559308725Sdexuan 1560308725Sdexuan res = bus_generic_alloc_resource(dev, child, type, rid, 1561308725Sdexuan start, end, count, flags); 1562308725Sdexuan /* 1563308725Sdexuan * If this is a request for a specific range, assume it is 1564308725Sdexuan * correct and pass it up to the parent. 1565308725Sdexuan */ 1566308725Sdexuan if (res == NULL && start + count - 1 == end) 1567308725Sdexuan res = bus_generic_alloc_resource(dev, child, type, rid, 1568308725Sdexuan start, end, count, flags); 1569308725Sdexuan return (res); 1570308725Sdexuan} 1571308725Sdexuan 1572308725Sdexuanstatic int 1573308725Sdexuanvmbus_pcib_release_resource(device_t dev, device_t child, int type, int rid, 1574308725Sdexuan struct resource *r) 1575308725Sdexuan{ 1576308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1577308725Sdexuan 1578308725Sdexuan if (type == PCI_RES_BUS) 1579308725Sdexuan return (pci_domain_release_bus(sc->hbus->pci_domain, child, 1580308725Sdexuan rid, r)); 1581308725Sdexuan 1582308725Sdexuan if (type == SYS_RES_IOPORT) 1583308725Sdexuan return (EINVAL); 1584308725Sdexuan 1585308725Sdexuan return (bus_generic_release_resource(dev, child, type, rid, r)); 1586308725Sdexuan} 1587308725Sdexuan 1588308725Sdexuan#if __FreeBSD_version >= 1100000 1589308725Sdexuanstatic int 1590308725Sdexuanvmbus_pcib_get_cpus(device_t pcib, device_t dev, enum cpu_sets op, 1591308725Sdexuan size_t setsize, cpuset_t *cpuset) 1592308725Sdexuan{ 1593308725Sdexuan return (bus_get_cpus(pcib, op, setsize, cpuset)); 1594308725Sdexuan} 1595308725Sdexuan#endif 1596308725Sdexuan 1597308725Sdexuanstatic uint32_t 1598308725Sdexuanvmbus_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 1599308725Sdexuan u_int reg, int bytes) 1600308725Sdexuan{ 1601308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1602308725Sdexuan struct hv_pci_dev *hpdev; 1603308725Sdexuan unsigned int devfn = PCI_DEVFN(slot, func); 1604308725Sdexuan uint32_t data = 0; 1605308725Sdexuan 1606308725Sdexuan KASSERT(bus == 0, ("bus should be 0, but is %u", bus)); 1607308725Sdexuan 1608308725Sdexuan hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 1609308725Sdexuan if (!hpdev) 1610308725Sdexuan return (~0); 1611308725Sdexuan 1612308725Sdexuan _hv_pcifront_read_config(hpdev, reg, bytes, &data); 1613308725Sdexuan 1614308725Sdexuan return (data); 1615308725Sdexuan} 1616308725Sdexuan 1617308725Sdexuanstatic void 1618308725Sdexuanvmbus_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 1619308725Sdexuan u_int reg, uint32_t data, int bytes) 1620308725Sdexuan{ 1621308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(dev); 1622308725Sdexuan struct hv_pci_dev *hpdev; 1623308725Sdexuan unsigned int devfn = PCI_DEVFN(slot, func); 1624308725Sdexuan 1625308725Sdexuan KASSERT(bus == 0, ("bus should be 0, but is %u", bus)); 1626308725Sdexuan 1627308725Sdexuan hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 1628308725Sdexuan if (!hpdev) 1629308725Sdexuan return; 1630308725Sdexuan 1631308725Sdexuan _hv_pcifront_write_config(hpdev, reg, bytes, data); 1632308725Sdexuan} 1633308725Sdexuan 1634308725Sdexuanstatic int 1635308725Sdexuanvmbus_pcib_route_intr(device_t pcib, device_t dev, int pin) 1636308725Sdexuan{ 1637308725Sdexuan /* We only support MSI/MSI-X and don't support INTx interrupt. */ 1638308725Sdexuan return (PCI_INVALID_IRQ); 1639308725Sdexuan} 1640308725Sdexuan 1641308725Sdexuanstatic int 1642308725Sdexuanvmbus_pcib_alloc_msi(device_t pcib, device_t dev, int count, 1643308725Sdexuan int maxcount, int *irqs) 1644308725Sdexuan{ 1645308725Sdexuan return (PCIB_ALLOC_MSI(device_get_parent(pcib), dev, count, maxcount, 1646308725Sdexuan irqs)); 1647308725Sdexuan} 1648308725Sdexuan 1649308725Sdexuanstatic int 1650308725Sdexuanvmbus_pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 1651308725Sdexuan{ 1652308725Sdexuan return (PCIB_RELEASE_MSI(device_get_parent(pcib), dev, count, irqs)); 1653308725Sdexuan} 1654308725Sdexuan 1655308725Sdexuanstatic int 1656308725Sdexuanvmbus_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 1657308725Sdexuan{ 1658308725Sdexuan return (PCIB_ALLOC_MSIX(device_get_parent(pcib), dev, irq)); 1659308725Sdexuan} 1660308725Sdexuan 1661308725Sdexuanstatic int 1662308725Sdexuanvmbus_pcib_release_msix(device_t pcib, device_t dev, int irq) 1663308725Sdexuan{ 1664308725Sdexuan return (PCIB_RELEASE_MSIX(device_get_parent(pcib), dev, irq)); 1665308725Sdexuan} 1666308725Sdexuan 1667308725Sdexuan#define MSI_INTEL_ADDR_DEST 0x000ff000 1668308725Sdexuan#define MSI_INTEL_DATA_INTVEC IOART_INTVEC /* Interrupt vector. */ 1669308725Sdexuan#define MSI_INTEL_DATA_DELFIXED IOART_DELFIXED 1670308725Sdexuan 1671308725Sdexuanstatic int 1672308725Sdexuanvmbus_pcib_map_msi(device_t pcib, device_t child, int irq, 1673308725Sdexuan uint64_t *addr, uint32_t *data) 1674308725Sdexuan{ 1675308725Sdexuan unsigned int devfn; 1676308725Sdexuan struct hv_pci_dev *hpdev; 1677308725Sdexuan 1678308725Sdexuan uint64_t v_addr; 1679308725Sdexuan uint32_t v_data; 1680308725Sdexuan struct hv_irq_desc *hid, *tmp_hid; 1681308725Sdexuan unsigned int cpu, vcpu_id; 1682308725Sdexuan unsigned int vector; 1683308725Sdexuan 1684308725Sdexuan struct vmbus_pcib_softc *sc = device_get_softc(pcib); 1685308725Sdexuan struct pci_create_interrupt *int_pkt; 1686308725Sdexuan struct compose_comp_ctxt comp; 1687308725Sdexuan struct { 1688308725Sdexuan struct pci_packet pkt; 1689308725Sdexuan uint8_t buffer[sizeof(struct pci_create_interrupt)]; 1690308725Sdexuan } ctxt; 1691308725Sdexuan 1692308725Sdexuan int ret; 1693308725Sdexuan 1694308725Sdexuan devfn = PCI_DEVFN(pci_get_slot(child), pci_get_function(child)); 1695308725Sdexuan hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn)); 1696308725Sdexuan if (!hpdev) 1697308725Sdexuan return (ENOENT); 1698308725Sdexuan 1699308725Sdexuan ret = PCIB_MAP_MSI(device_get_parent(pcib), child, irq, 1700308725Sdexuan &v_addr, &v_data); 1701308725Sdexuan if (ret) 1702308725Sdexuan return (ret); 1703308725Sdexuan 1704308725Sdexuan TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid) { 1705308725Sdexuan if (hid->irq == irq) { 1706308725Sdexuan TAILQ_REMOVE(&hpdev->irq_desc_list, hid, link); 1707308725Sdexuan hv_int_desc_free(hpdev, hid); 1708308725Sdexuan break; 1709308725Sdexuan } 1710308725Sdexuan } 1711308725Sdexuan 1712308725Sdexuan cpu = (v_addr & MSI_INTEL_ADDR_DEST) >> 12; 1713308725Sdexuan vcpu_id = VMBUS_GET_VCPU_ID(device_get_parent(pcib), pcib, cpu); 1714308725Sdexuan vector = v_data & MSI_INTEL_DATA_INTVEC; 1715308725Sdexuan 1716308725Sdexuan init_completion(&comp.comp_pkt.host_event); 1717308725Sdexuan 1718308725Sdexuan memset(&ctxt, 0, sizeof(ctxt)); 1719308725Sdexuan ctxt.pkt.completion_func = hv_pci_compose_compl; 1720308725Sdexuan ctxt.pkt.compl_ctxt = ∁ 1721308725Sdexuan 1722308725Sdexuan int_pkt = (struct pci_create_interrupt *)&ctxt.pkt.message; 1723308725Sdexuan int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE; 1724308725Sdexuan int_pkt->wslot.val = hpdev->desc.wslot.val; 1725308725Sdexuan int_pkt->int_desc.vector = vector; 1726308725Sdexuan int_pkt->int_desc.vector_count = 1; 1727308725Sdexuan int_pkt->int_desc.delivery_mode = MSI_INTEL_DATA_DELFIXED; 1728308725Sdexuan int_pkt->int_desc.cpu_mask = 1ULL << vcpu_id; 1729308725Sdexuan 1730308725Sdexuan ret = vmbus_chan_send(sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 1731308725Sdexuan VMBUS_CHANPKT_FLAG_RC, int_pkt, sizeof(*int_pkt), 1732337959Sdim (uint64_t)(uintptr_t)&ctxt.pkt); 1733308725Sdexuan if (ret) { 1734308725Sdexuan free_completion(&comp.comp_pkt.host_event); 1735308725Sdexuan return (ret); 1736308725Sdexuan } 1737308725Sdexuan 1738308725Sdexuan wait_for_completion(&comp.comp_pkt.host_event); 1739308725Sdexuan free_completion(&comp.comp_pkt.host_event); 1740308725Sdexuan 1741308725Sdexuan if (comp.comp_pkt.completion_status < 0) 1742308725Sdexuan return (EPROTO); 1743308725Sdexuan 1744308725Sdexuan *addr = comp.int_desc.address; 1745308725Sdexuan *data = comp.int_desc.data; 1746308725Sdexuan 1747308725Sdexuan hid = malloc(sizeof(struct hv_irq_desc), M_DEVBUF, M_WAITOK | M_ZERO); 1748308725Sdexuan hid->irq = irq; 1749308725Sdexuan hid->desc = comp.int_desc; 1750308725Sdexuan TAILQ_INSERT_TAIL(&hpdev->irq_desc_list, hid, link); 1751308725Sdexuan 1752308725Sdexuan return (0); 1753308725Sdexuan} 1754308725Sdexuan 1755308725Sdexuanstatic device_method_t vmbus_pcib_methods[] = { 1756308725Sdexuan /* Device interface */ 1757308725Sdexuan DEVMETHOD(device_probe, vmbus_pcib_probe), 1758308725Sdexuan DEVMETHOD(device_attach, vmbus_pcib_attach), 1759308725Sdexuan DEVMETHOD(device_detach, vmbus_pcib_detach), 1760308725Sdexuan DEVMETHOD(device_shutdown, bus_generic_shutdown), 1761308725Sdexuan DEVMETHOD(device_suspend, bus_generic_suspend), 1762308725Sdexuan DEVMETHOD(device_resume, bus_generic_resume), 1763308725Sdexuan 1764308725Sdexuan /* Bus interface */ 1765308725Sdexuan DEVMETHOD(bus_read_ivar, vmbus_pcib_read_ivar), 1766308725Sdexuan DEVMETHOD(bus_write_ivar, vmbus_pcib_write_ivar), 1767308725Sdexuan DEVMETHOD(bus_alloc_resource, vmbus_pcib_alloc_resource), 1768308725Sdexuan DEVMETHOD(bus_release_resource, vmbus_pcib_release_resource), 1769308725Sdexuan DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1770308725Sdexuan DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1771308725Sdexuan DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1772308725Sdexuan DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 1773308725Sdexuan#if __FreeBSD_version >= 1100000 1774308725Sdexuan DEVMETHOD(bus_get_cpus, vmbus_pcib_get_cpus), 1775308725Sdexuan#endif 1776308725Sdexuan 1777308725Sdexuan /* pcib interface */ 1778308725Sdexuan DEVMETHOD(pcib_maxslots, pcib_maxslots), 1779308725Sdexuan DEVMETHOD(pcib_read_config, vmbus_pcib_read_config), 1780308725Sdexuan DEVMETHOD(pcib_write_config, vmbus_pcib_write_config), 1781308725Sdexuan DEVMETHOD(pcib_route_interrupt, vmbus_pcib_route_intr), 1782308725Sdexuan DEVMETHOD(pcib_alloc_msi, vmbus_pcib_alloc_msi), 1783308725Sdexuan DEVMETHOD(pcib_release_msi, vmbus_pcib_release_msi), 1784308725Sdexuan DEVMETHOD(pcib_alloc_msix, vmbus_pcib_alloc_msix), 1785308725Sdexuan DEVMETHOD(pcib_release_msix, vmbus_pcib_release_msix), 1786308725Sdexuan DEVMETHOD(pcib_map_msi, vmbus_pcib_map_msi), 1787308725Sdexuan 1788308725Sdexuan DEVMETHOD_END 1789308725Sdexuan}; 1790308725Sdexuan 1791308725Sdexuanstatic devclass_t pcib_devclass; 1792308725Sdexuan 1793308725SdexuanDEFINE_CLASS_0(pcib, vmbus_pcib_driver, vmbus_pcib_methods, 1794308725Sdexuan sizeof(struct vmbus_pcib_softc)); 1795308725SdexuanDRIVER_MODULE(vmbus_pcib, vmbus, vmbus_pcib_driver, pcib_devclass, 0, 0); 1796308725SdexuanMODULE_DEPEND(vmbus_pcib, vmbus, 1, 1, 1); 1797308794SdexuanMODULE_DEPEND(vmbus_pcib, pci, 1, 1, 1); 1798309313Sdexuan 1799309313Sdexuan#endif /* NEW_PCIB */ 1800