xref: /freebsd/sys/dev/hyperv/pcib/vmbus_pcib.c (revision 75c2786c25fef9a6f8239c9fc1631cd17756579b)
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>
288c582c7cSDexuan Cui __FBSDID("$FreeBSD$");
298c582c7cSDexuan Cui 
30cdb316eeSDexuan Cui #ifdef NEW_PCIB
31cdb316eeSDexuan Cui 
328c582c7cSDexuan Cui #include <sys/param.h>
338c582c7cSDexuan Cui #include <sys/systm.h>
348c582c7cSDexuan Cui #include <sys/types.h>
358c582c7cSDexuan Cui #include <sys/malloc.h>
368c582c7cSDexuan Cui #include <sys/module.h>
378c582c7cSDexuan Cui #include <sys/kernel.h>
388c582c7cSDexuan Cui #include <sys/queue.h>
398c582c7cSDexuan Cui #include <sys/lock.h>
408c582c7cSDexuan Cui #include <sys/sx.h>
418c582c7cSDexuan Cui #include <sys/smp.h>
428c582c7cSDexuan Cui #include <sys/sysctl.h>
438c582c7cSDexuan Cui #include <sys/bus.h>
448c582c7cSDexuan Cui #include <sys/rman.h>
458c582c7cSDexuan Cui #include <sys/mutex.h>
468c582c7cSDexuan Cui #include <sys/errno.h>
478c582c7cSDexuan Cui 
488c582c7cSDexuan Cui #include <vm/vm.h>
498c582c7cSDexuan Cui #include <vm/vm_param.h>
508c582c7cSDexuan Cui #include <vm/vm_kern.h>
518c582c7cSDexuan Cui #include <vm/pmap.h>
528c582c7cSDexuan Cui 
538c582c7cSDexuan Cui #include <machine/atomic.h>
548c582c7cSDexuan Cui #include <machine/bus.h>
558c582c7cSDexuan Cui #include <machine/frame.h>
568c582c7cSDexuan Cui #include <machine/pci_cfgreg.h>
578c582c7cSDexuan Cui #include <machine/resource.h>
588c582c7cSDexuan Cui 
598c582c7cSDexuan Cui #include <sys/pciio.h>
608c582c7cSDexuan Cui #include <dev/pci/pcireg.h>
618c582c7cSDexuan Cui #include <dev/pci/pcivar.h>
628c582c7cSDexuan Cui #include <dev/pci/pci_private.h>
638c582c7cSDexuan Cui #include <dev/pci/pcib_private.h>
648c582c7cSDexuan Cui #include "pcib_if.h"
658c582c7cSDexuan Cui 
668c582c7cSDexuan Cui #include <machine/intr_machdep.h>
678c582c7cSDexuan Cui #include <x86/apicreg.h>
688c582c7cSDexuan Cui 
698c582c7cSDexuan Cui #include <dev/hyperv/include/hyperv.h>
708c582c7cSDexuan Cui #include <dev/hyperv/include/hyperv_busdma.h>
718c582c7cSDexuan Cui #include <dev/hyperv/include/vmbus_xact.h>
728c582c7cSDexuan Cui #include <dev/hyperv/vmbus/vmbus_reg.h>
738c582c7cSDexuan Cui #include <dev/hyperv/vmbus/vmbus_chanvar.h>
748c582c7cSDexuan Cui 
758c582c7cSDexuan Cui #include "vmbus_if.h"
768c582c7cSDexuan Cui 
778c582c7cSDexuan Cui #if __FreeBSD_version < 1100000
788c582c7cSDexuan Cui typedef u_long rman_res_t;
798c582c7cSDexuan Cui #define RM_MAX_END	(~(rman_res_t)0)
808c582c7cSDexuan Cui #endif
818c582c7cSDexuan Cui 
828c582c7cSDexuan Cui struct completion {
838c582c7cSDexuan Cui 	unsigned int done;
848c582c7cSDexuan Cui 	struct mtx lock;
858c582c7cSDexuan Cui };
868c582c7cSDexuan Cui 
878c582c7cSDexuan Cui static void
888c582c7cSDexuan Cui init_completion(struct completion *c)
898c582c7cSDexuan Cui {
908c582c7cSDexuan Cui 	memset(c, 0, sizeof(*c));
918c582c7cSDexuan Cui 	mtx_init(&c->lock, "hvcmpl", NULL, MTX_DEF);
928c582c7cSDexuan Cui 	c->done = 0;
938c582c7cSDexuan Cui }
948c582c7cSDexuan Cui 
958c582c7cSDexuan Cui static void
968c582c7cSDexuan Cui free_completion(struct completion *c)
978c582c7cSDexuan Cui {
988c582c7cSDexuan Cui 	mtx_destroy(&c->lock);
998c582c7cSDexuan Cui }
1008c582c7cSDexuan Cui 
1018c582c7cSDexuan Cui static void
1028c582c7cSDexuan Cui complete(struct completion *c)
1038c582c7cSDexuan Cui {
1048c582c7cSDexuan Cui 	mtx_lock(&c->lock);
1058c582c7cSDexuan Cui 	c->done++;
1068c582c7cSDexuan Cui 	mtx_unlock(&c->lock);
1078c582c7cSDexuan Cui 	wakeup(c);
1088c582c7cSDexuan Cui }
1098c582c7cSDexuan Cui 
1108c582c7cSDexuan Cui static void
1118c582c7cSDexuan Cui wait_for_completion(struct completion *c)
1128c582c7cSDexuan Cui {
1138c582c7cSDexuan Cui 	mtx_lock(&c->lock);
1148c582c7cSDexuan Cui 	while (c->done == 0)
1158c582c7cSDexuan Cui 		mtx_sleep(c, &c->lock, 0, "hvwfc", 0);
1168c582c7cSDexuan Cui 	c->done--;
1178c582c7cSDexuan Cui 	mtx_unlock(&c->lock);
1188c582c7cSDexuan Cui }
1198c582c7cSDexuan Cui 
120*75c2786cSWei Hu /*
121*75c2786cSWei Hu  * Return: 0 if completed, a non-zero value if timed out.
122*75c2786cSWei Hu  */
123*75c2786cSWei Hu static int
124*75c2786cSWei Hu wait_for_completion_timeout(struct completion *c, int timeout)
125*75c2786cSWei Hu {
126*75c2786cSWei Hu 	int ret;
127*75c2786cSWei Hu 
128*75c2786cSWei Hu 	mtx_lock(&c->lock);
129*75c2786cSWei Hu 
130*75c2786cSWei Hu 	if (c->done == 0)
131*75c2786cSWei Hu 		mtx_sleep(c, &c->lock, 0, "hvwfc", timeout);
132*75c2786cSWei Hu 
133*75c2786cSWei Hu 	if (c->done > 0) {
134*75c2786cSWei Hu 		c->done--;
135*75c2786cSWei Hu 		ret = 0;
136*75c2786cSWei Hu 	} else {
137*75c2786cSWei Hu 		ret = 1;
138*75c2786cSWei Hu 	}
139*75c2786cSWei Hu 
140*75c2786cSWei Hu 	mtx_unlock(&c->lock);
141*75c2786cSWei Hu 
142*75c2786cSWei Hu 	return (ret);
143*75c2786cSWei Hu }
144*75c2786cSWei Hu 
1458c582c7cSDexuan Cui #define PCI_MAKE_VERSION(major, minor) ((uint32_t)(((major) << 16) | (major)))
1468c582c7cSDexuan Cui 
1478c582c7cSDexuan Cui enum {
1488c582c7cSDexuan Cui 	PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1),
1498c582c7cSDexuan Cui 	PCI_PROTOCOL_VERSION_CURRENT = PCI_PROTOCOL_VERSION_1_1
1508c582c7cSDexuan Cui };
1518c582c7cSDexuan Cui 
1528c582c7cSDexuan Cui #define PCI_CONFIG_MMIO_LENGTH	0x2000
1538c582c7cSDexuan Cui #define CFG_PAGE_OFFSET 0x1000
1548c582c7cSDexuan Cui #define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET)
1558c582c7cSDexuan Cui 
1568c582c7cSDexuan Cui /*
1578c582c7cSDexuan Cui  * Message Types
1588c582c7cSDexuan Cui  */
1598c582c7cSDexuan Cui 
1608c582c7cSDexuan Cui enum pci_message_type {
1618c582c7cSDexuan Cui 	/*
1628c582c7cSDexuan Cui 	 * Version 1.1
1638c582c7cSDexuan Cui 	 */
1648c582c7cSDexuan Cui 	PCI_MESSAGE_BASE                = 0x42490000,
1658c582c7cSDexuan Cui 	PCI_BUS_RELATIONS               = PCI_MESSAGE_BASE + 0,
1668c582c7cSDexuan Cui 	PCI_QUERY_BUS_RELATIONS         = PCI_MESSAGE_BASE + 1,
1678c582c7cSDexuan Cui 	PCI_POWER_STATE_CHANGE          = PCI_MESSAGE_BASE + 4,
1688c582c7cSDexuan Cui 	PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5,
1698c582c7cSDexuan Cui 	PCI_QUERY_RESOURCE_RESOURCES    = PCI_MESSAGE_BASE + 6,
1708c582c7cSDexuan Cui 	PCI_BUS_D0ENTRY                 = PCI_MESSAGE_BASE + 7,
1718c582c7cSDexuan Cui 	PCI_BUS_D0EXIT                  = PCI_MESSAGE_BASE + 8,
1728c582c7cSDexuan Cui 	PCI_READ_BLOCK                  = PCI_MESSAGE_BASE + 9,
1738c582c7cSDexuan Cui 	PCI_WRITE_BLOCK                 = PCI_MESSAGE_BASE + 0xA,
1748c582c7cSDexuan Cui 	PCI_EJECT                       = PCI_MESSAGE_BASE + 0xB,
1758c582c7cSDexuan Cui 	PCI_QUERY_STOP                  = PCI_MESSAGE_BASE + 0xC,
1768c582c7cSDexuan Cui 	PCI_REENABLE                    = PCI_MESSAGE_BASE + 0xD,
1778c582c7cSDexuan Cui 	PCI_QUERY_STOP_FAILED           = PCI_MESSAGE_BASE + 0xE,
1788c582c7cSDexuan Cui 	PCI_EJECTION_COMPLETE           = PCI_MESSAGE_BASE + 0xF,
1798c582c7cSDexuan Cui 	PCI_RESOURCES_ASSIGNED          = PCI_MESSAGE_BASE + 0x10,
1808c582c7cSDexuan Cui 	PCI_RESOURCES_RELEASED          = PCI_MESSAGE_BASE + 0x11,
1818c582c7cSDexuan Cui 	PCI_INVALIDATE_BLOCK            = PCI_MESSAGE_BASE + 0x12,
1828c582c7cSDexuan Cui 	PCI_QUERY_PROTOCOL_VERSION      = PCI_MESSAGE_BASE + 0x13,
1838c582c7cSDexuan Cui 	PCI_CREATE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x14,
1848c582c7cSDexuan Cui 	PCI_DELETE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x15,
1858c582c7cSDexuan Cui 	PCI_MESSAGE_MAXIMUM
1868c582c7cSDexuan Cui };
1878c582c7cSDexuan Cui 
1888c582c7cSDexuan Cui /*
1898c582c7cSDexuan Cui  * Structures defining the virtual PCI Express protocol.
1908c582c7cSDexuan Cui  */
1918c582c7cSDexuan Cui 
1928c582c7cSDexuan Cui union pci_version {
1938c582c7cSDexuan Cui 	struct {
1948c582c7cSDexuan Cui 		uint16_t minor_version;
1958c582c7cSDexuan Cui 		uint16_t major_version;
1968c582c7cSDexuan Cui 	} parts;
1978c582c7cSDexuan Cui 	uint32_t version;
1988c582c7cSDexuan Cui } __packed;
1998c582c7cSDexuan Cui 
2008c582c7cSDexuan Cui /*
2018c582c7cSDexuan Cui  * This representation is the one used in Windows, which is
2028c582c7cSDexuan Cui  * what is expected when sending this back and forth with
2038c582c7cSDexuan Cui  * the Hyper-V parent partition.
2048c582c7cSDexuan Cui  */
2058c582c7cSDexuan Cui union win_slot_encoding {
2068c582c7cSDexuan Cui 	struct {
2078c582c7cSDexuan Cui 		uint32_t	slot:5;
2088c582c7cSDexuan Cui 		uint32_t	func:3;
2098c582c7cSDexuan Cui 		uint32_t	reserved:24;
2108c582c7cSDexuan Cui 	} bits;
2118c582c7cSDexuan Cui 	uint32_t val;
2128c582c7cSDexuan Cui } __packed;
2138c582c7cSDexuan Cui 
2148c582c7cSDexuan Cui struct pci_func_desc {
2158c582c7cSDexuan Cui 	uint16_t	v_id;	/* vendor ID */
2168c582c7cSDexuan Cui 	uint16_t	d_id;	/* device ID */
2178c582c7cSDexuan Cui 	uint8_t		rev;
2188c582c7cSDexuan Cui 	uint8_t		prog_intf;
2198c582c7cSDexuan Cui 	uint8_t		subclass;
2208c582c7cSDexuan Cui 	uint8_t		base_class;
2218c582c7cSDexuan Cui 	uint32_t	subsystem_id;
2228c582c7cSDexuan Cui 	union win_slot_encoding wslot;
2238c582c7cSDexuan Cui 	uint32_t	ser;	/* serial number */
2248c582c7cSDexuan Cui } __packed;
2258c582c7cSDexuan Cui 
2268c582c7cSDexuan Cui struct hv_msi_desc {
2278c582c7cSDexuan Cui 	uint8_t		vector;
2288c582c7cSDexuan Cui 	uint8_t		delivery_mode;
2298c582c7cSDexuan Cui 	uint16_t	vector_count;
2308c582c7cSDexuan Cui 	uint32_t	reserved;
2318c582c7cSDexuan Cui 	uint64_t	cpu_mask;
2328c582c7cSDexuan Cui } __packed;
2338c582c7cSDexuan Cui 
2348c582c7cSDexuan Cui struct tran_int_desc {
2358c582c7cSDexuan Cui 	uint16_t	reserved;
2368c582c7cSDexuan Cui 	uint16_t	vector_count;
2378c582c7cSDexuan Cui 	uint32_t	data;
2388c582c7cSDexuan Cui 	uint64_t	address;
2398c582c7cSDexuan Cui } __packed;
2408c582c7cSDexuan Cui 
2418c582c7cSDexuan Cui struct pci_message {
2428c582c7cSDexuan Cui 	uint32_t type;
2438c582c7cSDexuan Cui } __packed;
2448c582c7cSDexuan Cui 
2458c582c7cSDexuan Cui struct pci_child_message {
2468c582c7cSDexuan Cui 	struct pci_message message_type;
2478c582c7cSDexuan Cui 	union win_slot_encoding wslot;
2488c582c7cSDexuan Cui } __packed;
2498c582c7cSDexuan Cui 
2508c582c7cSDexuan Cui struct pci_incoming_message {
2518c582c7cSDexuan Cui 	struct vmbus_chanpkt_hdr hdr;
2528c582c7cSDexuan Cui 	struct pci_message message_type;
2538c582c7cSDexuan Cui } __packed;
2548c582c7cSDexuan Cui 
2558c582c7cSDexuan Cui struct pci_response {
2568c582c7cSDexuan Cui 	struct vmbus_chanpkt_hdr hdr;
2578c582c7cSDexuan Cui 	int32_t status;	/* negative values are failures */
2588c582c7cSDexuan Cui } __packed;
2598c582c7cSDexuan Cui 
2608c582c7cSDexuan Cui struct pci_packet {
2618c582c7cSDexuan Cui 	void (*completion_func)(void *context, struct pci_response *resp,
2628c582c7cSDexuan Cui 	    int resp_packet_size);
2638c582c7cSDexuan Cui 	void *compl_ctxt;
2648c582c7cSDexuan Cui 
2658c582c7cSDexuan Cui 	struct pci_message message[0];
2668c582c7cSDexuan Cui };
2678c582c7cSDexuan Cui 
2688c582c7cSDexuan Cui /*
2698c582c7cSDexuan Cui  * Specific message types supporting the PCI protocol.
2708c582c7cSDexuan Cui  */
2718c582c7cSDexuan Cui 
2728c582c7cSDexuan Cui struct pci_version_request {
2738c582c7cSDexuan Cui 	struct pci_message message_type;
2748c582c7cSDexuan Cui 	uint32_t protocol_version;
2758c582c7cSDexuan Cui 	uint32_t is_last_attempt:1;
2768c582c7cSDexuan Cui 	uint32_t reservedz:31;
2778c582c7cSDexuan Cui } __packed;
2788c582c7cSDexuan Cui 
2798c582c7cSDexuan Cui struct pci_bus_d0_entry {
2808c582c7cSDexuan Cui 	struct pci_message message_type;
2818c582c7cSDexuan Cui 	uint32_t reserved;
2828c582c7cSDexuan Cui 	uint64_t mmio_base;
2838c582c7cSDexuan Cui } __packed;
2848c582c7cSDexuan Cui 
2858c582c7cSDexuan Cui struct pci_bus_relations {
2868c582c7cSDexuan Cui 	struct pci_incoming_message incoming;
2878c582c7cSDexuan Cui 	uint32_t device_count;
2888c582c7cSDexuan Cui 	struct pci_func_desc func[0];
2898c582c7cSDexuan Cui } __packed;
2908c582c7cSDexuan Cui 
2918c582c7cSDexuan Cui #define MAX_NUM_BARS	(PCIR_MAX_BAR_0 + 1)
2928c582c7cSDexuan Cui struct pci_q_res_req_response {
2938c582c7cSDexuan Cui 	struct vmbus_chanpkt_hdr hdr;
2948c582c7cSDexuan Cui 	int32_t status; /* negative values are failures */
2958c582c7cSDexuan Cui 	uint32_t probed_bar[MAX_NUM_BARS];
2968c582c7cSDexuan Cui } __packed;
2978c582c7cSDexuan Cui 
2988c582c7cSDexuan Cui struct pci_resources_assigned {
2998c582c7cSDexuan Cui 	struct pci_message message_type;
3008c582c7cSDexuan Cui 	union win_slot_encoding wslot;
3018c582c7cSDexuan Cui 	uint8_t memory_range[0x14][MAX_NUM_BARS]; /* unused here */
3028c582c7cSDexuan Cui 	uint32_t msi_descriptors;
3038c582c7cSDexuan Cui 	uint32_t reserved[4];
3048c582c7cSDexuan Cui } __packed;
3058c582c7cSDexuan Cui 
3068c582c7cSDexuan Cui struct pci_create_interrupt {
3078c582c7cSDexuan Cui 	struct pci_message message_type;
3088c582c7cSDexuan Cui 	union win_slot_encoding wslot;
3098c582c7cSDexuan Cui 	struct hv_msi_desc int_desc;
3108c582c7cSDexuan Cui } __packed;
3118c582c7cSDexuan Cui 
3128c582c7cSDexuan Cui struct pci_create_int_response {
3138c582c7cSDexuan Cui 	struct pci_response response;
3148c582c7cSDexuan Cui 	uint32_t reserved;
3158c582c7cSDexuan Cui 	struct tran_int_desc int_desc;
3168c582c7cSDexuan Cui } __packed;
3178c582c7cSDexuan Cui 
3188c582c7cSDexuan Cui struct pci_delete_interrupt {
3198c582c7cSDexuan Cui 	struct pci_message message_type;
3208c582c7cSDexuan Cui 	union win_slot_encoding wslot;
3218c582c7cSDexuan Cui 	struct tran_int_desc int_desc;
3228c582c7cSDexuan Cui } __packed;
3238c582c7cSDexuan Cui 
3248c582c7cSDexuan Cui struct pci_dev_incoming {
3258c582c7cSDexuan Cui 	struct pci_incoming_message incoming;
3268c582c7cSDexuan Cui 	union win_slot_encoding wslot;
3278c582c7cSDexuan Cui } __packed;
3288c582c7cSDexuan Cui 
3298c582c7cSDexuan Cui struct pci_eject_response {
3308c582c7cSDexuan Cui 	struct pci_message message_type;
3318c582c7cSDexuan Cui 	union win_slot_encoding wslot;
3328c582c7cSDexuan Cui 	uint32_t status;
3338c582c7cSDexuan Cui } __packed;
3348c582c7cSDexuan Cui 
3358c582c7cSDexuan Cui /*
3368c582c7cSDexuan Cui  * Driver specific state.
3378c582c7cSDexuan Cui  */
3388c582c7cSDexuan Cui 
3398c582c7cSDexuan Cui enum hv_pcibus_state {
3408c582c7cSDexuan Cui 	hv_pcibus_init = 0,
3418c582c7cSDexuan Cui 	hv_pcibus_installed,
3428c582c7cSDexuan Cui };
3438c582c7cSDexuan Cui 
3448c582c7cSDexuan Cui struct hv_pcibus {
3458c582c7cSDexuan Cui 	device_t pcib;
3468c582c7cSDexuan Cui 	device_t pci_bus;
3478c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc;
3488c582c7cSDexuan Cui 
3498c582c7cSDexuan Cui 	uint16_t pci_domain;
3508c582c7cSDexuan Cui 
3518c582c7cSDexuan Cui 	enum hv_pcibus_state state;
3528c582c7cSDexuan Cui 
3538c582c7cSDexuan Cui 	struct resource *cfg_res;
3548c582c7cSDexuan Cui 
3558c582c7cSDexuan Cui 	struct completion query_completion, *query_comp;
3568c582c7cSDexuan Cui 
3578c582c7cSDexuan Cui 	struct mtx config_lock; /* Avoid two threads writing index page */
3588c582c7cSDexuan Cui 	struct mtx device_list_lock;    /* Protect lists below */
3598c582c7cSDexuan Cui 	TAILQ_HEAD(, hv_pci_dev) children;
3608c582c7cSDexuan Cui 	TAILQ_HEAD(, hv_dr_state) dr_list;
3618c582c7cSDexuan Cui 
3628c582c7cSDexuan Cui 	volatile int detaching;
3638c582c7cSDexuan Cui };
3648c582c7cSDexuan Cui 
3658c582c7cSDexuan Cui struct hv_pci_dev {
3668c582c7cSDexuan Cui 	TAILQ_ENTRY(hv_pci_dev) link;
3678c582c7cSDexuan Cui 
3688c582c7cSDexuan Cui 	struct pci_func_desc desc;
3698c582c7cSDexuan Cui 
3708c582c7cSDexuan Cui 	bool reported_missing;
3718c582c7cSDexuan Cui 
3728c582c7cSDexuan Cui 	struct hv_pcibus *hbus;
3738c582c7cSDexuan Cui 	struct task eject_task;
3748c582c7cSDexuan Cui 
3758c582c7cSDexuan Cui 	TAILQ_HEAD(, hv_irq_desc) irq_desc_list;
3768c582c7cSDexuan Cui 
3778c582c7cSDexuan Cui 	/*
3788c582c7cSDexuan Cui 	 * What would be observed if one wrote 0xFFFFFFFF to a BAR and then
3798c582c7cSDexuan Cui 	 * read it back, for each of the BAR offsets within config space.
3808c582c7cSDexuan Cui 	 */
3818c582c7cSDexuan Cui 	uint32_t probed_bar[MAX_NUM_BARS];
3828c582c7cSDexuan Cui };
3838c582c7cSDexuan Cui 
3848c582c7cSDexuan Cui /*
3858c582c7cSDexuan Cui  * Tracks "Device Relations" messages from the host, which must be both
3868c582c7cSDexuan Cui  * processed in order.
3878c582c7cSDexuan Cui  */
3888c582c7cSDexuan Cui struct hv_dr_work {
3898c582c7cSDexuan Cui 	struct task task;
3908c582c7cSDexuan Cui 	struct hv_pcibus *bus;
3918c582c7cSDexuan Cui };
3928c582c7cSDexuan Cui 
3938c582c7cSDexuan Cui struct hv_dr_state {
3948c582c7cSDexuan Cui 	TAILQ_ENTRY(hv_dr_state) link;
3958c582c7cSDexuan Cui 	uint32_t device_count;
3968c582c7cSDexuan Cui 	struct pci_func_desc func[0];
3978c582c7cSDexuan Cui };
3988c582c7cSDexuan Cui 
3998c582c7cSDexuan Cui struct hv_irq_desc {
4008c582c7cSDexuan Cui 	TAILQ_ENTRY(hv_irq_desc) link;
4018c582c7cSDexuan Cui 	struct tran_int_desc desc;
4028c582c7cSDexuan Cui 	int irq;
4038c582c7cSDexuan Cui };
4048c582c7cSDexuan Cui 
4058c582c7cSDexuan Cui #define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
4068c582c7cSDexuan Cui #define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
4078c582c7cSDexuan Cui #define PCI_FUNC(devfn)         ((devfn) & 0x07)
4088c582c7cSDexuan Cui 
4098c582c7cSDexuan Cui static uint32_t
4108c582c7cSDexuan Cui devfn_to_wslot(unsigned int devfn)
4118c582c7cSDexuan Cui {
4128c582c7cSDexuan Cui 	union win_slot_encoding wslot;
4138c582c7cSDexuan Cui 
4148c582c7cSDexuan Cui 	wslot.val = 0;
4158c582c7cSDexuan Cui 	wslot.bits.slot = PCI_SLOT(devfn);
4168c582c7cSDexuan Cui 	wslot.bits.func = PCI_FUNC(devfn);
4178c582c7cSDexuan Cui 
4188c582c7cSDexuan Cui 	return (wslot.val);
4198c582c7cSDexuan Cui }
4208c582c7cSDexuan Cui 
4218c582c7cSDexuan Cui static unsigned int
4228c582c7cSDexuan Cui wslot_to_devfn(uint32_t wslot)
4238c582c7cSDexuan Cui {
4248c582c7cSDexuan Cui 	union win_slot_encoding encoding;
4258c582c7cSDexuan Cui 	unsigned int slot;
4268c582c7cSDexuan Cui 	unsigned int func;
4278c582c7cSDexuan Cui 
4288c582c7cSDexuan Cui 	encoding.val = wslot;
4298c582c7cSDexuan Cui 
4308c582c7cSDexuan Cui 	slot = encoding.bits.slot;
4318c582c7cSDexuan Cui 	func = encoding.bits.func;
4328c582c7cSDexuan Cui 
4338c582c7cSDexuan Cui 	return (PCI_DEVFN(slot, func));
4348c582c7cSDexuan Cui }
4358c582c7cSDexuan Cui 
4368c582c7cSDexuan Cui struct vmbus_pcib_softc {
4378c582c7cSDexuan Cui 	struct vmbus_channel	*chan;
4388c582c7cSDexuan Cui 	void *rx_buf;
4398c582c7cSDexuan Cui 
4408c582c7cSDexuan Cui 	struct taskqueue	*taskq;
4418c582c7cSDexuan Cui 
4428c582c7cSDexuan Cui 	struct hv_pcibus	*hbus;
4438c582c7cSDexuan Cui };
4448c582c7cSDexuan Cui 
4458c582c7cSDexuan Cui /* {44C4F61D-4444-4400-9D52-802E27EDE19F} */
4468c582c7cSDexuan Cui static const struct hyperv_guid g_pass_through_dev_type = {
4478c582c7cSDexuan Cui 	.hv_guid = {0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44,
4488c582c7cSDexuan Cui 	    0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F}
4498c582c7cSDexuan Cui };
4508c582c7cSDexuan Cui 
4518c582c7cSDexuan Cui struct hv_pci_compl {
4528c582c7cSDexuan Cui 	struct completion host_event;
4538c582c7cSDexuan Cui 	int32_t completion_status;
4548c582c7cSDexuan Cui };
4558c582c7cSDexuan Cui 
4568c582c7cSDexuan Cui struct q_res_req_compl {
4578c582c7cSDexuan Cui 	struct completion host_event;
4588c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
4598c582c7cSDexuan Cui };
4608c582c7cSDexuan Cui 
4618c582c7cSDexuan Cui struct compose_comp_ctxt {
4628c582c7cSDexuan Cui 	struct hv_pci_compl comp_pkt;
4638c582c7cSDexuan Cui 	struct tran_int_desc int_desc;
4648c582c7cSDexuan Cui };
4658c582c7cSDexuan Cui 
466*75c2786cSWei Hu /*
467*75c2786cSWei Hu  * It is possible the device is revoked during initialization.
468*75c2786cSWei Hu  * Check if this happens during wait.
469*75c2786cSWei Hu  * Return: 0 if response arrived, ENODEV if device revoked.
470*75c2786cSWei Hu  */
471*75c2786cSWei Hu static int
472*75c2786cSWei Hu wait_for_response(struct hv_pcibus *hbus, struct completion *c)
473*75c2786cSWei Hu {
474*75c2786cSWei Hu 	do {
475*75c2786cSWei Hu 		if (vmbus_chan_is_revoked(hbus->sc->chan)) {
476*75c2786cSWei Hu 			device_printf(hbus->pcib,
477*75c2786cSWei Hu 			    "The device is revoked.\n");
478*75c2786cSWei Hu 			return (ENODEV);
479*75c2786cSWei Hu 		}
480*75c2786cSWei Hu 	} while (wait_for_completion_timeout(c, hz /10) != 0);
481*75c2786cSWei Hu 
482*75c2786cSWei Hu 	return 0;
483*75c2786cSWei Hu }
484*75c2786cSWei Hu 
4858c582c7cSDexuan Cui static void
4868c582c7cSDexuan Cui hv_pci_generic_compl(void *context, struct pci_response *resp,
4878c582c7cSDexuan Cui     int resp_packet_size)
4888c582c7cSDexuan Cui {
4898c582c7cSDexuan Cui 	struct hv_pci_compl *comp_pkt = context;
4908c582c7cSDexuan Cui 
4918c582c7cSDexuan Cui 	if (resp_packet_size >= sizeof(struct pci_response))
4928c582c7cSDexuan Cui 		comp_pkt->completion_status = resp->status;
4938c582c7cSDexuan Cui 	else
4948c582c7cSDexuan Cui 		comp_pkt->completion_status = -1;
4958c582c7cSDexuan Cui 
4968c582c7cSDexuan Cui 	complete(&comp_pkt->host_event);
4978c582c7cSDexuan Cui }
4988c582c7cSDexuan Cui 
4998c582c7cSDexuan Cui static void
5008c582c7cSDexuan Cui q_resource_requirements(void *context, struct pci_response *resp,
5018c582c7cSDexuan Cui     int resp_packet_size)
5028c582c7cSDexuan Cui {
5038c582c7cSDexuan Cui 	struct q_res_req_compl *completion = context;
5048c582c7cSDexuan Cui 	struct pci_q_res_req_response *q_res_req =
5058c582c7cSDexuan Cui 	    (struct pci_q_res_req_response *)resp;
5068c582c7cSDexuan Cui 	int i;
5078c582c7cSDexuan Cui 
5088c582c7cSDexuan Cui 	if (resp->status < 0) {
5098c582c7cSDexuan Cui 		printf("vmbus_pcib: failed to query resource requirements\n");
5108c582c7cSDexuan Cui 	} else {
5118c582c7cSDexuan Cui 		for (i = 0; i < MAX_NUM_BARS; i++)
5128c582c7cSDexuan Cui 			completion->hpdev->probed_bar[i] =
5138c582c7cSDexuan Cui 			    q_res_req->probed_bar[i];
5148c582c7cSDexuan Cui 	}
5158c582c7cSDexuan Cui 
5168c582c7cSDexuan Cui 	complete(&completion->host_event);
5178c582c7cSDexuan Cui }
5188c582c7cSDexuan Cui 
5198c582c7cSDexuan Cui static void
5208c582c7cSDexuan Cui hv_pci_compose_compl(void *context, struct pci_response *resp,
5218c582c7cSDexuan Cui     int resp_packet_size)
5228c582c7cSDexuan Cui {
5238c582c7cSDexuan Cui 	struct compose_comp_ctxt *comp_pkt = context;
5248c582c7cSDexuan Cui 	struct pci_create_int_response *int_resp =
5258c582c7cSDexuan Cui 	    (struct pci_create_int_response *)resp;
5268c582c7cSDexuan Cui 
5278c582c7cSDexuan Cui 	comp_pkt->comp_pkt.completion_status = resp->status;
5288c582c7cSDexuan Cui 	comp_pkt->int_desc = int_resp->int_desc;
5298c582c7cSDexuan Cui 	complete(&comp_pkt->comp_pkt.host_event);
5308c582c7cSDexuan Cui }
5318c582c7cSDexuan Cui 
5328c582c7cSDexuan Cui static void
5338c582c7cSDexuan Cui hv_int_desc_free(struct hv_pci_dev *hpdev, struct hv_irq_desc *hid)
5348c582c7cSDexuan Cui {
5358c582c7cSDexuan Cui 	struct pci_delete_interrupt *int_pkt;
5368c582c7cSDexuan Cui 	struct {
5378c582c7cSDexuan Cui 		struct pci_packet pkt;
5388c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_delete_interrupt)];
5398c582c7cSDexuan Cui 	} ctxt;
5408c582c7cSDexuan Cui 
5418c582c7cSDexuan Cui 	memset(&ctxt, 0, sizeof(ctxt));
5428c582c7cSDexuan Cui 	int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
5438c582c7cSDexuan Cui 	int_pkt->message_type.type = PCI_DELETE_INTERRUPT_MESSAGE;
5448c582c7cSDexuan Cui 	int_pkt->wslot.val = hpdev->desc.wslot.val;
5458c582c7cSDexuan Cui 	int_pkt->int_desc = hid->desc;
5468c582c7cSDexuan Cui 
5478c582c7cSDexuan Cui 	vmbus_chan_send(hpdev->hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
5488c582c7cSDexuan Cui 	    int_pkt, sizeof(*int_pkt), 0);
5498c582c7cSDexuan Cui 
5508c582c7cSDexuan Cui 	free(hid, M_DEVBUF);
5518c582c7cSDexuan Cui }
5528c582c7cSDexuan Cui 
5538c582c7cSDexuan Cui static void
5548c582c7cSDexuan Cui hv_pci_delete_device(struct hv_pci_dev *hpdev)
5558c582c7cSDexuan Cui {
5568c582c7cSDexuan Cui 	struct hv_pcibus *hbus = hpdev->hbus;
5578c582c7cSDexuan Cui 	struct hv_irq_desc *hid, *tmp_hid;
5588c582c7cSDexuan Cui 	device_t pci_dev;
5598c582c7cSDexuan Cui 	int devfn;
5608c582c7cSDexuan Cui 
5618c582c7cSDexuan Cui 	devfn = wslot_to_devfn(hpdev->desc.wslot.val);
5628c582c7cSDexuan Cui 
5638c582c7cSDexuan Cui 	mtx_lock(&Giant);
5648c582c7cSDexuan Cui 
5658c582c7cSDexuan Cui 	pci_dev = pci_find_dbsf(hbus->pci_domain,
5668c582c7cSDexuan Cui 	    0, PCI_SLOT(devfn), PCI_FUNC(devfn));
5678c582c7cSDexuan Cui 	if (pci_dev)
5688c582c7cSDexuan Cui 		device_delete_child(hbus->pci_bus, pci_dev);
5698c582c7cSDexuan Cui 
5708c582c7cSDexuan Cui 	mtx_unlock(&Giant);
5718c582c7cSDexuan Cui 
5728c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
5738c582c7cSDexuan Cui 	TAILQ_REMOVE(&hbus->children, hpdev, link);
5748c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
5758c582c7cSDexuan Cui 
5768c582c7cSDexuan Cui 	TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid)
5778c582c7cSDexuan Cui 		hv_int_desc_free(hpdev, hid);
5788c582c7cSDexuan Cui 
5798c582c7cSDexuan Cui 	free(hpdev, M_DEVBUF);
5808c582c7cSDexuan Cui }
5818c582c7cSDexuan Cui 
5828c582c7cSDexuan Cui static struct hv_pci_dev *
5838c582c7cSDexuan Cui new_pcichild_device(struct hv_pcibus *hbus, struct pci_func_desc *desc)
5848c582c7cSDexuan Cui {
5858c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
5868c582c7cSDexuan Cui 	struct pci_child_message *res_req;
5878c582c7cSDexuan Cui 	struct q_res_req_compl comp_pkt;
5888c582c7cSDexuan Cui 	struct {
5898c582c7cSDexuan Cui 		struct pci_packet pkt;
5908c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_child_message)];
5918c582c7cSDexuan Cui 	} ctxt;
5928c582c7cSDexuan Cui 	int ret;
5938c582c7cSDexuan Cui 
5948c582c7cSDexuan Cui 	hpdev = malloc(sizeof(*hpdev), M_DEVBUF, M_WAITOK | M_ZERO);
5958c582c7cSDexuan Cui 	hpdev->hbus = hbus;
5968c582c7cSDexuan Cui 
5978c582c7cSDexuan Cui 	TAILQ_INIT(&hpdev->irq_desc_list);
5988c582c7cSDexuan Cui 
5998c582c7cSDexuan Cui 	init_completion(&comp_pkt.host_event);
6008c582c7cSDexuan Cui 	comp_pkt.hpdev = hpdev;
6018c582c7cSDexuan Cui 
6028c582c7cSDexuan Cui 	ctxt.pkt.compl_ctxt = &comp_pkt;
6038c582c7cSDexuan Cui 	ctxt.pkt.completion_func = q_resource_requirements;
6048c582c7cSDexuan Cui 
6058c582c7cSDexuan Cui 	res_req = (struct pci_child_message *)&ctxt.pkt.message;
6068c582c7cSDexuan Cui 	res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS;
6078c582c7cSDexuan Cui 	res_req->wslot.val = desc->wslot.val;
6088c582c7cSDexuan Cui 
6098c582c7cSDexuan Cui 	ret = vmbus_chan_send(hbus->sc->chan,
6108c582c7cSDexuan Cui 	    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
611aaf13123SDimitry Andric 	    res_req, sizeof(*res_req), (uint64_t)(uintptr_t)&ctxt.pkt);
6128c582c7cSDexuan Cui 	if (ret)
6138c582c7cSDexuan Cui 		goto err;
6148c582c7cSDexuan Cui 
615*75c2786cSWei Hu 	if (wait_for_response(hbus, &comp_pkt.host_event))
616*75c2786cSWei Hu 		goto err;
617*75c2786cSWei Hu 
6188c582c7cSDexuan Cui 	free_completion(&comp_pkt.host_event);
6198c582c7cSDexuan Cui 
6208c582c7cSDexuan Cui 	hpdev->desc = *desc;
6218c582c7cSDexuan Cui 
6228c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
6236944b2e6SDexuan Cui 	if (TAILQ_EMPTY(&hbus->children))
6246944b2e6SDexuan Cui 		hbus->pci_domain = desc->ser & 0xFFFF;
6258c582c7cSDexuan Cui 	TAILQ_INSERT_TAIL(&hbus->children, hpdev, link);
6268c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
6278c582c7cSDexuan Cui 	return (hpdev);
6288c582c7cSDexuan Cui err:
6298c582c7cSDexuan Cui 	free_completion(&comp_pkt.host_event);
6308c582c7cSDexuan Cui 	free(hpdev, M_DEVBUF);
6318c582c7cSDexuan Cui 	return (NULL);
6328c582c7cSDexuan Cui }
6338c582c7cSDexuan Cui 
6348c582c7cSDexuan Cui #if __FreeBSD_version < 1100000
6358c582c7cSDexuan Cui 
6368c582c7cSDexuan Cui /* Old versions don't have BUS_RESCAN(). Let's copy it from FreeBSD 11. */
6378c582c7cSDexuan Cui 
6388c582c7cSDexuan Cui static struct pci_devinfo *
6398c582c7cSDexuan Cui pci_identify_function(device_t pcib, device_t dev, int domain, int busno,
6408c582c7cSDexuan Cui     int slot, int func, size_t dinfo_size)
6418c582c7cSDexuan Cui {
6428c582c7cSDexuan Cui 	struct pci_devinfo *dinfo;
6438c582c7cSDexuan Cui 
6448c582c7cSDexuan Cui 	dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size);
6458c582c7cSDexuan Cui 	if (dinfo != NULL)
6468c582c7cSDexuan Cui 		pci_add_child(dev, dinfo);
6478c582c7cSDexuan Cui 
6488c582c7cSDexuan Cui 	return (dinfo);
6498c582c7cSDexuan Cui }
6508c582c7cSDexuan Cui 
6518c582c7cSDexuan Cui static int
6528c582c7cSDexuan Cui pci_rescan(device_t dev)
6538c582c7cSDexuan Cui {
6548c582c7cSDexuan Cui #define	REG(n, w)	PCIB_READ_CONFIG(pcib, busno, s, f, n, w)
6558c582c7cSDexuan Cui 	device_t pcib = device_get_parent(dev);
6568c582c7cSDexuan Cui 	struct pci_softc *sc;
6578c582c7cSDexuan Cui 	device_t child, *devlist, *unchanged;
6588c582c7cSDexuan Cui 	int devcount, error, i, j, maxslots, oldcount;
6598c582c7cSDexuan Cui 	int busno, domain, s, f, pcifunchigh;
6608c582c7cSDexuan Cui 	uint8_t hdrtype;
6618c582c7cSDexuan Cui 
6628c582c7cSDexuan Cui 	/* No need to check for ARI on a rescan. */
6638c582c7cSDexuan Cui 	error = device_get_children(dev, &devlist, &devcount);
6648c582c7cSDexuan Cui 	if (error)
6658c582c7cSDexuan Cui 		return (error);
6668c582c7cSDexuan Cui 	if (devcount != 0) {
6678c582c7cSDexuan Cui 		unchanged = malloc(devcount * sizeof(device_t), M_TEMP,
6688c582c7cSDexuan Cui 		    M_NOWAIT | M_ZERO);
6698c582c7cSDexuan Cui 		if (unchanged == NULL) {
6708c582c7cSDexuan Cui 			free(devlist, M_TEMP);
6718c582c7cSDexuan Cui 			return (ENOMEM);
6728c582c7cSDexuan Cui 		}
6738c582c7cSDexuan Cui 	} else
6748c582c7cSDexuan Cui 		unchanged = NULL;
6758c582c7cSDexuan Cui 
6768c582c7cSDexuan Cui 	sc = device_get_softc(dev);
6778c582c7cSDexuan Cui 	domain = pcib_get_domain(dev);
6788c582c7cSDexuan Cui 	busno = pcib_get_bus(dev);
6798c582c7cSDexuan Cui 	maxslots = PCIB_MAXSLOTS(pcib);
6808c582c7cSDexuan Cui 	for (s = 0; s <= maxslots; s++) {
6818c582c7cSDexuan Cui 		/* If function 0 is not present, skip to the next slot. */
6828c582c7cSDexuan Cui 		f = 0;
6838c582c7cSDexuan Cui 		if (REG(PCIR_VENDOR, 2) == 0xffff)
6848c582c7cSDexuan Cui 			continue;
6858c582c7cSDexuan Cui 		pcifunchigh = 0;
6868c582c7cSDexuan Cui 		hdrtype = REG(PCIR_HDRTYPE, 1);
6878c582c7cSDexuan Cui 		if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
6888c582c7cSDexuan Cui 			continue;
6898c582c7cSDexuan Cui 		if (hdrtype & PCIM_MFDEV)
6908c582c7cSDexuan Cui 			pcifunchigh = PCIB_MAXFUNCS(pcib);
6918c582c7cSDexuan Cui 		for (f = 0; f <= pcifunchigh; f++) {
6928c582c7cSDexuan Cui 			if (REG(PCIR_VENDOR, 2) == 0xffff)
6938c582c7cSDexuan Cui 				continue;
6948c582c7cSDexuan Cui 
6958c582c7cSDexuan Cui 			/*
6968c582c7cSDexuan Cui 			 * Found a valid function.  Check if a
6978c582c7cSDexuan Cui 			 * device_t for this device already exists.
6988c582c7cSDexuan Cui 			 */
6998c582c7cSDexuan Cui 			for (i = 0; i < devcount; i++) {
7008c582c7cSDexuan Cui 				child = devlist[i];
7018c582c7cSDexuan Cui 				if (child == NULL)
7028c582c7cSDexuan Cui 					continue;
7038c582c7cSDexuan Cui 				if (pci_get_slot(child) == s &&
7048c582c7cSDexuan Cui 				    pci_get_function(child) == f) {
7058c582c7cSDexuan Cui 					unchanged[i] = child;
7068c582c7cSDexuan Cui 					goto next_func;
7078c582c7cSDexuan Cui 				}
7088c582c7cSDexuan Cui 			}
7098c582c7cSDexuan Cui 
7108c582c7cSDexuan Cui 			pci_identify_function(pcib, dev, domain, busno, s, f,
7118c582c7cSDexuan Cui 			    sizeof(struct pci_devinfo));
7128c582c7cSDexuan Cui 		next_func:;
7138c582c7cSDexuan Cui 		}
7148c582c7cSDexuan Cui 	}
7158c582c7cSDexuan Cui 
7168c582c7cSDexuan Cui 	/* Remove devices that are no longer present. */
7178c582c7cSDexuan Cui 	for (i = 0; i < devcount; i++) {
7188c582c7cSDexuan Cui 		if (unchanged[i] != NULL)
7198c582c7cSDexuan Cui 			continue;
7208c582c7cSDexuan Cui 		device_delete_child(dev, devlist[i]);
7218c582c7cSDexuan Cui 	}
7228c582c7cSDexuan Cui 
7238c582c7cSDexuan Cui 	free(devlist, M_TEMP);
7248c582c7cSDexuan Cui 	oldcount = devcount;
7258c582c7cSDexuan Cui 
7268c582c7cSDexuan Cui 	/* Try to attach the devices just added. */
7278c582c7cSDexuan Cui 	error = device_get_children(dev, &devlist, &devcount);
7288c582c7cSDexuan Cui 	if (error) {
7298c582c7cSDexuan Cui 		free(unchanged, M_TEMP);
7308c582c7cSDexuan Cui 		return (error);
7318c582c7cSDexuan Cui 	}
7328c582c7cSDexuan Cui 
7338c582c7cSDexuan Cui 	for (i = 0; i < devcount; i++) {
7348c582c7cSDexuan Cui 		for (j = 0; j < oldcount; j++) {
7358c582c7cSDexuan Cui 			if (devlist[i] == unchanged[j])
7368c582c7cSDexuan Cui 				goto next_device;
7378c582c7cSDexuan Cui 		}
7388c582c7cSDexuan Cui 
7398c582c7cSDexuan Cui 		device_probe_and_attach(devlist[i]);
7408c582c7cSDexuan Cui 	next_device:;
7418c582c7cSDexuan Cui 	}
7428c582c7cSDexuan Cui 
7438c582c7cSDexuan Cui 	free(unchanged, M_TEMP);
7448c582c7cSDexuan Cui 	free(devlist, M_TEMP);
7458c582c7cSDexuan Cui 	return (0);
7468c582c7cSDexuan Cui #undef REG
7478c582c7cSDexuan Cui }
7488c582c7cSDexuan Cui 
7498c582c7cSDexuan Cui #else
7508c582c7cSDexuan Cui 
7518c582c7cSDexuan Cui static int
7528c582c7cSDexuan Cui pci_rescan(device_t dev)
7538c582c7cSDexuan Cui {
7548c582c7cSDexuan Cui 	return (BUS_RESCAN(dev));
7558c582c7cSDexuan Cui }
7568c582c7cSDexuan Cui 
7578c582c7cSDexuan Cui #endif
7588c582c7cSDexuan Cui 
7598c582c7cSDexuan Cui static void
7608c582c7cSDexuan Cui pci_devices_present_work(void *arg, int pending __unused)
7618c582c7cSDexuan Cui {
7628c582c7cSDexuan Cui 	struct hv_dr_work *dr_wrk = arg;
7638c582c7cSDexuan Cui 	struct hv_dr_state *dr = NULL;
7648c582c7cSDexuan Cui 	struct hv_pcibus *hbus;
7658c582c7cSDexuan Cui 	uint32_t child_no;
7668c582c7cSDexuan Cui 	bool found;
7678c582c7cSDexuan Cui 	struct pci_func_desc *new_desc;
7688c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev, *tmp_hpdev;
7698c582c7cSDexuan Cui 	struct completion *query_comp;
7708c582c7cSDexuan Cui 	bool need_rescan = false;
7718c582c7cSDexuan Cui 
7728c582c7cSDexuan Cui 	hbus = dr_wrk->bus;
7738c582c7cSDexuan Cui 	free(dr_wrk, M_DEVBUF);
7748c582c7cSDexuan Cui 
7758c582c7cSDexuan Cui 	/* Pull this off the queue and process it if it was the last one. */
7768c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
7778c582c7cSDexuan Cui 	while (!TAILQ_EMPTY(&hbus->dr_list)) {
7788c582c7cSDexuan Cui 		dr = TAILQ_FIRST(&hbus->dr_list);
7798c582c7cSDexuan Cui 		TAILQ_REMOVE(&hbus->dr_list, dr, link);
7808c582c7cSDexuan Cui 
7818c582c7cSDexuan Cui 		/* Throw this away if the list still has stuff in it. */
7828c582c7cSDexuan Cui 		if (!TAILQ_EMPTY(&hbus->dr_list)) {
7838c582c7cSDexuan Cui 			free(dr, M_DEVBUF);
7848c582c7cSDexuan Cui 			continue;
7858c582c7cSDexuan Cui 		}
7868c582c7cSDexuan Cui 	}
7878c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
7888c582c7cSDexuan Cui 
7898c582c7cSDexuan Cui 	if (!dr)
7908c582c7cSDexuan Cui 		return;
7918c582c7cSDexuan Cui 
7928c582c7cSDexuan Cui 	/* First, mark all existing children as reported missing. */
7938c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
7948c582c7cSDexuan Cui 	TAILQ_FOREACH(hpdev, &hbus->children, link)
7958c582c7cSDexuan Cui 		hpdev->reported_missing = true;
7968c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
7978c582c7cSDexuan Cui 
7988c582c7cSDexuan Cui 	/* Next, add back any reported devices. */
7998c582c7cSDexuan Cui 	for (child_no = 0; child_no < dr->device_count; child_no++) {
8008c582c7cSDexuan Cui 		found = false;
8018c582c7cSDexuan Cui 		new_desc = &dr->func[child_no];
8028c582c7cSDexuan Cui 
8038c582c7cSDexuan Cui 		mtx_lock(&hbus->device_list_lock);
8048c582c7cSDexuan Cui 		TAILQ_FOREACH(hpdev, &hbus->children, link) {
8058c582c7cSDexuan Cui 			if ((hpdev->desc.wslot.val ==
8068c582c7cSDexuan Cui 			    new_desc->wslot.val) &&
8078c582c7cSDexuan Cui 			    (hpdev->desc.v_id == new_desc->v_id) &&
8088c582c7cSDexuan Cui 			    (hpdev->desc.d_id == new_desc->d_id) &&
8098c582c7cSDexuan Cui 			    (hpdev->desc.ser == new_desc->ser)) {
8108c582c7cSDexuan Cui 				hpdev->reported_missing = false;
8118c582c7cSDexuan Cui 				found = true;
8128c582c7cSDexuan Cui 				break;
8138c582c7cSDexuan Cui 			}
8148c582c7cSDexuan Cui 		}
8158c582c7cSDexuan Cui 		mtx_unlock(&hbus->device_list_lock);
8168c582c7cSDexuan Cui 
8178c582c7cSDexuan Cui 		if (!found) {
8188c582c7cSDexuan Cui 			if (!need_rescan)
8198c582c7cSDexuan Cui 				need_rescan = true;
8208c582c7cSDexuan Cui 
8218c582c7cSDexuan Cui 			hpdev = new_pcichild_device(hbus, new_desc);
8228c582c7cSDexuan Cui 			if (!hpdev)
8238c582c7cSDexuan Cui 				printf("vmbus_pcib: failed to add a child\n");
8248c582c7cSDexuan Cui 		}
8258c582c7cSDexuan Cui 	}
8268c582c7cSDexuan Cui 
8278c582c7cSDexuan Cui 	/* Remove missing device(s), if any */
8288c582c7cSDexuan Cui 	TAILQ_FOREACH_SAFE(hpdev, &hbus->children, link, tmp_hpdev) {
8298c582c7cSDexuan Cui 		if (hpdev->reported_missing)
8308c582c7cSDexuan Cui 			hv_pci_delete_device(hpdev);
8318c582c7cSDexuan Cui 	}
8328c582c7cSDexuan Cui 
8338c582c7cSDexuan Cui 	/* Rescan the bus to find any new device, if necessary. */
8348c582c7cSDexuan Cui 	if (hbus->state == hv_pcibus_installed && need_rescan)
8358c582c7cSDexuan Cui 		pci_rescan(hbus->pci_bus);
8368c582c7cSDexuan Cui 
8378c582c7cSDexuan Cui 	/* Wake up hv_pci_query_relations(), if it's waiting. */
8388c582c7cSDexuan Cui 	query_comp = hbus->query_comp;
8398c582c7cSDexuan Cui 	if (query_comp) {
8408c582c7cSDexuan Cui 		hbus->query_comp = NULL;
8418c582c7cSDexuan Cui 		complete(query_comp);
8428c582c7cSDexuan Cui 	}
8438c582c7cSDexuan Cui 
8448c582c7cSDexuan Cui 	free(dr, M_DEVBUF);
8458c582c7cSDexuan Cui }
8468c582c7cSDexuan Cui 
8478c582c7cSDexuan Cui static struct hv_pci_dev *
8488c582c7cSDexuan Cui get_pcichild_wslot(struct hv_pcibus *hbus, uint32_t wslot)
8498c582c7cSDexuan Cui {
8508c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev, *ret = NULL;
8518c582c7cSDexuan Cui 
8528c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
8538c582c7cSDexuan Cui 	TAILQ_FOREACH(hpdev, &hbus->children, link) {
8548c582c7cSDexuan Cui 		if (hpdev->desc.wslot.val == wslot) {
8558c582c7cSDexuan Cui 			ret = hpdev;
8568c582c7cSDexuan Cui 			break;
8578c582c7cSDexuan Cui 		}
8588c582c7cSDexuan Cui 	}
8598c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
8608c582c7cSDexuan Cui 
8618c582c7cSDexuan Cui 	return (ret);
8628c582c7cSDexuan Cui }
8638c582c7cSDexuan Cui 
8648c582c7cSDexuan Cui static void
8658c582c7cSDexuan Cui hv_pci_devices_present(struct hv_pcibus *hbus,
8668c582c7cSDexuan Cui     struct pci_bus_relations *relations)
8678c582c7cSDexuan Cui {
8688c582c7cSDexuan Cui 	struct hv_dr_state *dr;
8698c582c7cSDexuan Cui 	struct hv_dr_work *dr_wrk;
8708c582c7cSDexuan Cui 	unsigned long dr_size;
8718c582c7cSDexuan Cui 
8728c582c7cSDexuan Cui 	if (hbus->detaching && relations->device_count > 0)
8738c582c7cSDexuan Cui 		return;
8748c582c7cSDexuan Cui 
8758c582c7cSDexuan Cui 	dr_size = offsetof(struct hv_dr_state, func) +
8768c582c7cSDexuan Cui 	    (sizeof(struct pci_func_desc) * relations->device_count);
8778c582c7cSDexuan Cui 	dr = malloc(dr_size, M_DEVBUF, M_WAITOK | M_ZERO);
8788c582c7cSDexuan Cui 
8798c582c7cSDexuan Cui 	dr->device_count = relations->device_count;
8808c582c7cSDexuan Cui 	if (dr->device_count != 0)
8818c582c7cSDexuan Cui 		memcpy(dr->func, relations->func,
8828c582c7cSDexuan Cui 		    sizeof(struct pci_func_desc) * dr->device_count);
8838c582c7cSDexuan Cui 
8848c582c7cSDexuan Cui 	mtx_lock(&hbus->device_list_lock);
8858c582c7cSDexuan Cui 	TAILQ_INSERT_TAIL(&hbus->dr_list, dr, link);
8868c582c7cSDexuan Cui 	mtx_unlock(&hbus->device_list_lock);
8878c582c7cSDexuan Cui 
8888c582c7cSDexuan Cui 	dr_wrk = malloc(sizeof(*dr_wrk), M_DEVBUF, M_WAITOK | M_ZERO);
8898c582c7cSDexuan Cui 	dr_wrk->bus = hbus;
8908c582c7cSDexuan Cui 	TASK_INIT(&dr_wrk->task, 0, pci_devices_present_work, dr_wrk);
8918c582c7cSDexuan Cui 	taskqueue_enqueue(hbus->sc->taskq, &dr_wrk->task);
8928c582c7cSDexuan Cui }
8938c582c7cSDexuan Cui 
8948c582c7cSDexuan Cui static void
8958c582c7cSDexuan Cui hv_eject_device_work(void *arg, int pending __unused)
8968c582c7cSDexuan Cui {
8978c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev = arg;
8988c582c7cSDexuan Cui 	union win_slot_encoding wslot = hpdev->desc.wslot;
8998c582c7cSDexuan Cui 	struct hv_pcibus *hbus = hpdev->hbus;
9008c582c7cSDexuan Cui 	struct pci_eject_response *eject_pkt;
9018c582c7cSDexuan Cui 	struct {
9028c582c7cSDexuan Cui 		struct pci_packet pkt;
9038c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_eject_response)];
9048c582c7cSDexuan Cui 	} ctxt;
9058c582c7cSDexuan Cui 
9068c582c7cSDexuan Cui 	hv_pci_delete_device(hpdev);
9078c582c7cSDexuan Cui 
9088c582c7cSDexuan Cui 	memset(&ctxt, 0, sizeof(ctxt));
9098c582c7cSDexuan Cui 	eject_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
9108c582c7cSDexuan Cui 	eject_pkt->message_type.type = PCI_EJECTION_COMPLETE;
9118c582c7cSDexuan Cui 	eject_pkt->wslot.val = wslot.val;
9128c582c7cSDexuan Cui 	vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
9138c582c7cSDexuan Cui 	    eject_pkt, sizeof(*eject_pkt), 0);
9148c582c7cSDexuan Cui }
9158c582c7cSDexuan Cui 
9168c582c7cSDexuan Cui static void
9178c582c7cSDexuan Cui hv_pci_eject_device(struct hv_pci_dev *hpdev)
9188c582c7cSDexuan Cui {
9198c582c7cSDexuan Cui 	struct hv_pcibus *hbus = hpdev->hbus;
9208c582c7cSDexuan Cui 	struct taskqueue *taskq;
9218c582c7cSDexuan Cui 
9228c582c7cSDexuan Cui 	if (hbus->detaching)
9238c582c7cSDexuan Cui 		return;
9248c582c7cSDexuan Cui 
9258c582c7cSDexuan Cui 	/*
9268c582c7cSDexuan Cui 	 * Push this task into the same taskqueue on which
9278c582c7cSDexuan Cui 	 * vmbus_pcib_attach() runs, so we're sure this task can't run
9288c582c7cSDexuan Cui 	 * concurrently with vmbus_pcib_attach().
9298c582c7cSDexuan Cui 	 */
9308c582c7cSDexuan Cui 	TASK_INIT(&hpdev->eject_task, 0, hv_eject_device_work, hpdev);
9318c582c7cSDexuan Cui 	taskq = vmbus_chan_mgmt_tq(hbus->sc->chan);
9328c582c7cSDexuan Cui 	taskqueue_enqueue(taskq, &hpdev->eject_task);
9338c582c7cSDexuan Cui }
9348c582c7cSDexuan Cui 
9358c582c7cSDexuan Cui #define PCIB_PACKET_SIZE	0x100
9368c582c7cSDexuan Cui 
9378c582c7cSDexuan Cui static void
9388c582c7cSDexuan Cui vmbus_pcib_on_channel_callback(struct vmbus_channel *chan, void *arg)
9398c582c7cSDexuan Cui {
9408c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = arg;
9418c582c7cSDexuan Cui 	struct hv_pcibus *hbus = sc->hbus;
9428c582c7cSDexuan Cui 
9438c582c7cSDexuan Cui 	void *buffer;
9448c582c7cSDexuan Cui 	int bufferlen = PCIB_PACKET_SIZE;
9458c582c7cSDexuan Cui 
9468c582c7cSDexuan Cui 	struct pci_packet *comp_packet;
9478c582c7cSDexuan Cui 	struct pci_response *response;
9488c582c7cSDexuan Cui 	struct pci_incoming_message *new_msg;
9498c582c7cSDexuan Cui 	struct pci_bus_relations *bus_rel;
9508c582c7cSDexuan Cui 	struct pci_dev_incoming *dev_msg;
9518c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
9528c582c7cSDexuan Cui 
9538c582c7cSDexuan Cui 	buffer = sc->rx_buf;
9548c582c7cSDexuan Cui 	do {
9558c582c7cSDexuan Cui 		struct vmbus_chanpkt_hdr *pkt = buffer;
9568c582c7cSDexuan Cui 		uint32_t bytes_rxed;
9578c582c7cSDexuan Cui 		int ret;
9588c582c7cSDexuan Cui 
9598c582c7cSDexuan Cui 		bytes_rxed = bufferlen;
9608c582c7cSDexuan Cui 		ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed);
9618c582c7cSDexuan Cui 
9628c582c7cSDexuan Cui 		if (ret == ENOBUFS) {
9638c582c7cSDexuan Cui 			/* Handle large packet */
9648c582c7cSDexuan Cui 			if (bufferlen > PCIB_PACKET_SIZE) {
9658c582c7cSDexuan Cui 				free(buffer, M_DEVBUF);
9668c582c7cSDexuan Cui 				buffer = NULL;
9678c582c7cSDexuan Cui 			}
9688c582c7cSDexuan Cui 
9698c582c7cSDexuan Cui 			/* alloc new buffer */
9708c582c7cSDexuan Cui 			buffer = malloc(bytes_rxed, M_DEVBUF, M_WAITOK | M_ZERO);
9718c582c7cSDexuan Cui 			bufferlen = bytes_rxed;
9728c582c7cSDexuan Cui 
9738c582c7cSDexuan Cui 			continue;
9748c582c7cSDexuan Cui 		}
9758c582c7cSDexuan Cui 
9768c582c7cSDexuan Cui 		if (ret != 0) {
9778c582c7cSDexuan Cui 			/* ignore EIO or EAGAIN */
9788c582c7cSDexuan Cui 			break;
9798c582c7cSDexuan Cui 		}
9808c582c7cSDexuan Cui 
9818c582c7cSDexuan Cui 		if (bytes_rxed <= sizeof(struct pci_response))
9828c582c7cSDexuan Cui 			continue;
9838c582c7cSDexuan Cui 
9848c582c7cSDexuan Cui 		switch (pkt->cph_type) {
9858c582c7cSDexuan Cui 		case VMBUS_CHANPKT_TYPE_COMP:
986aaf13123SDimitry Andric 			comp_packet =
987aaf13123SDimitry Andric 			    (struct pci_packet *)(uintptr_t)pkt->cph_xactid;
9888c582c7cSDexuan Cui 			response = (struct pci_response *)pkt;
9898c582c7cSDexuan Cui 			comp_packet->completion_func(comp_packet->compl_ctxt,
9908c582c7cSDexuan Cui 			    response, bytes_rxed);
9918c582c7cSDexuan Cui 			break;
9928c582c7cSDexuan Cui 		case VMBUS_CHANPKT_TYPE_INBAND:
9938c582c7cSDexuan Cui 			new_msg = (struct pci_incoming_message *)buffer;
9948c582c7cSDexuan Cui 
9958c582c7cSDexuan Cui 			switch (new_msg->message_type.type) {
9968c582c7cSDexuan Cui 			case PCI_BUS_RELATIONS:
9978c582c7cSDexuan Cui 				bus_rel = (struct pci_bus_relations *)buffer;
9988c582c7cSDexuan Cui 
9998c582c7cSDexuan Cui 				if (bus_rel->device_count == 0)
10008c582c7cSDexuan Cui 					break;
10018c582c7cSDexuan Cui 
10028c582c7cSDexuan Cui 				if (bytes_rxed <
10038c582c7cSDexuan Cui 				    offsetof(struct pci_bus_relations, func) +
10048c582c7cSDexuan Cui 				        (sizeof(struct pci_func_desc) *
10058c582c7cSDexuan Cui 				            (bus_rel->device_count)))
10068c582c7cSDexuan Cui 					break;
10078c582c7cSDexuan Cui 
10088c582c7cSDexuan Cui 				hv_pci_devices_present(hbus, bus_rel);
10098c582c7cSDexuan Cui 				break;
10108c582c7cSDexuan Cui 
10118c582c7cSDexuan Cui 			case PCI_EJECT:
10128c582c7cSDexuan Cui 				dev_msg = (struct pci_dev_incoming *)buffer;
10138c582c7cSDexuan Cui 				hpdev = get_pcichild_wslot(hbus,
10148c582c7cSDexuan Cui 				    dev_msg->wslot.val);
10158c582c7cSDexuan Cui 
10168c582c7cSDexuan Cui 				if (hpdev)
10178c582c7cSDexuan Cui 					hv_pci_eject_device(hpdev);
10188c582c7cSDexuan Cui 
10198c582c7cSDexuan Cui 				break;
10208c582c7cSDexuan Cui 			default:
10218c582c7cSDexuan Cui 				printf("vmbus_pcib: Unknown msg type 0x%x\n",
10228c582c7cSDexuan Cui 				    new_msg->message_type.type);
10238c582c7cSDexuan Cui 				break;
10248c582c7cSDexuan Cui 			}
10258c582c7cSDexuan Cui 			break;
10268c582c7cSDexuan Cui 		default:
10278c582c7cSDexuan Cui 			printf("vmbus_pcib: Unknown VMBus msg type %hd\n",
10288c582c7cSDexuan Cui 			    pkt->cph_type);
10298c582c7cSDexuan Cui 			break;
10308c582c7cSDexuan Cui 		}
10318c582c7cSDexuan Cui 	} while (1);
10328c582c7cSDexuan Cui 
10338c582c7cSDexuan Cui 	if (bufferlen > PCIB_PACKET_SIZE)
10348c582c7cSDexuan Cui 		free(buffer, M_DEVBUF);
10358c582c7cSDexuan Cui }
10368c582c7cSDexuan Cui 
10378c582c7cSDexuan Cui static int
10388c582c7cSDexuan Cui hv_pci_protocol_negotiation(struct hv_pcibus *hbus)
10398c582c7cSDexuan Cui {
10408c582c7cSDexuan Cui 	struct pci_version_request *version_req;
10418c582c7cSDexuan Cui 	struct hv_pci_compl comp_pkt;
10428c582c7cSDexuan Cui 	struct {
10438c582c7cSDexuan Cui 		struct pci_packet pkt;
10448c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_version_request)];
10458c582c7cSDexuan Cui 	} ctxt;
10468c582c7cSDexuan Cui 	int ret;
10478c582c7cSDexuan Cui 
10488c582c7cSDexuan Cui 	init_completion(&comp_pkt.host_event);
10498c582c7cSDexuan Cui 
10508c582c7cSDexuan Cui 	ctxt.pkt.completion_func = hv_pci_generic_compl;
10518c582c7cSDexuan Cui 	ctxt.pkt.compl_ctxt = &comp_pkt;
10528c582c7cSDexuan Cui 	version_req = (struct pci_version_request *)&ctxt.pkt.message;
10538c582c7cSDexuan Cui 	version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION;
10548c582c7cSDexuan Cui 	version_req->protocol_version = PCI_PROTOCOL_VERSION_CURRENT;
10558c582c7cSDexuan Cui 	version_req->is_last_attempt = 1;
10568c582c7cSDexuan Cui 
10578c582c7cSDexuan Cui 	ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND,
10588c582c7cSDexuan Cui 	    VMBUS_CHANPKT_FLAG_RC, version_req, sizeof(*version_req),
1059aaf13123SDimitry Andric 	    (uint64_t)(uintptr_t)&ctxt.pkt);
1060*75c2786cSWei Hu 	if (!ret)
1061*75c2786cSWei Hu 		ret = wait_for_response(hbus, &comp_pkt.host_event);
10628c582c7cSDexuan Cui 
1063*75c2786cSWei Hu 	if (ret) {
1064*75c2786cSWei Hu 		device_printf(hbus->pcib,
1065*75c2786cSWei Hu 		    "vmbus_pcib failed to request version: %d\n",
1066*75c2786cSWei Hu 		    ret);
1067*75c2786cSWei Hu 		goto out;
1068*75c2786cSWei Hu 	}
10698c582c7cSDexuan Cui 
10708c582c7cSDexuan Cui 	if (comp_pkt.completion_status < 0) {
10718c582c7cSDexuan Cui 		device_printf(hbus->pcib,
10728c582c7cSDexuan Cui 		    "vmbus_pcib version negotiation failed: %x\n",
10738c582c7cSDexuan Cui 		    comp_pkt.completion_status);
10748c582c7cSDexuan Cui 		ret = EPROTO;
10758c582c7cSDexuan Cui 	} else {
10768c582c7cSDexuan Cui 		ret = 0;
10778c582c7cSDexuan Cui 	}
10788c582c7cSDexuan Cui out:
10798c582c7cSDexuan Cui 	free_completion(&comp_pkt.host_event);
10808c582c7cSDexuan Cui 	return (ret);
10818c582c7cSDexuan Cui }
10828c582c7cSDexuan Cui 
10838c582c7cSDexuan Cui /* Ask the host to send along the list of child devices */
10848c582c7cSDexuan Cui static int
10858c582c7cSDexuan Cui hv_pci_query_relations(struct hv_pcibus *hbus)
10868c582c7cSDexuan Cui {
10878c582c7cSDexuan Cui 	struct pci_message message;
10888c582c7cSDexuan Cui 	int ret;
10898c582c7cSDexuan Cui 
10908c582c7cSDexuan Cui 	message.type = PCI_QUERY_BUS_RELATIONS;
10918c582c7cSDexuan Cui 	ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
10928c582c7cSDexuan Cui 	    &message, sizeof(message), 0);
10938c582c7cSDexuan Cui 	return (ret);
10948c582c7cSDexuan Cui }
10958c582c7cSDexuan Cui 
10968c582c7cSDexuan Cui static int
10978c582c7cSDexuan Cui hv_pci_enter_d0(struct hv_pcibus *hbus)
10988c582c7cSDexuan Cui {
10998c582c7cSDexuan Cui 	struct pci_bus_d0_entry *d0_entry;
11008c582c7cSDexuan Cui 	struct hv_pci_compl comp_pkt;
11018c582c7cSDexuan Cui 	struct {
11028c582c7cSDexuan Cui 		struct pci_packet pkt;
11038c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_bus_d0_entry)];
11048c582c7cSDexuan Cui 	} ctxt;
11058c582c7cSDexuan Cui 	int ret;
11068c582c7cSDexuan Cui 
11078c582c7cSDexuan Cui 	/*
11088c582c7cSDexuan Cui 	 * Tell the host that the bus is ready to use, and moved into the
11098c582c7cSDexuan Cui 	 * powered-on state.  This includes telling the host which region
11108c582c7cSDexuan Cui 	 * of memory-mapped I/O space has been chosen for configuration space
11118c582c7cSDexuan Cui 	 * access.
11128c582c7cSDexuan Cui 	 */
11138c582c7cSDexuan Cui 	init_completion(&comp_pkt.host_event);
11148c582c7cSDexuan Cui 
11158c582c7cSDexuan Cui 	ctxt.pkt.completion_func = hv_pci_generic_compl;
11168c582c7cSDexuan Cui 	ctxt.pkt.compl_ctxt = &comp_pkt;
11178c582c7cSDexuan Cui 
11188c582c7cSDexuan Cui 	d0_entry = (struct pci_bus_d0_entry *)&ctxt.pkt.message;
11198c582c7cSDexuan Cui 	memset(d0_entry, 0, sizeof(*d0_entry));
11208c582c7cSDexuan Cui 	d0_entry->message_type.type = PCI_BUS_D0ENTRY;
11218c582c7cSDexuan Cui 	d0_entry->mmio_base = rman_get_start(hbus->cfg_res);
11228c582c7cSDexuan Cui 
11238c582c7cSDexuan Cui 	ret = vmbus_chan_send(hbus->sc->chan, VMBUS_CHANPKT_TYPE_INBAND,
11248c582c7cSDexuan Cui 	    VMBUS_CHANPKT_FLAG_RC, d0_entry, sizeof(*d0_entry),
1125aaf13123SDimitry Andric 	    (uint64_t)(uintptr_t)&ctxt.pkt);
1126*75c2786cSWei Hu 	if (!ret)
1127*75c2786cSWei Hu 		ret = wait_for_response(hbus, &comp_pkt.host_event);
1128*75c2786cSWei Hu 
11298c582c7cSDexuan Cui 	if (ret)
11308c582c7cSDexuan Cui 		goto out;
11318c582c7cSDexuan Cui 
11328c582c7cSDexuan Cui 	if (comp_pkt.completion_status < 0) {
11338c582c7cSDexuan Cui 		device_printf(hbus->pcib, "vmbus_pcib failed to enable D0\n");
11348c582c7cSDexuan Cui 		ret = EPROTO;
11358c582c7cSDexuan Cui 	} else {
11368c582c7cSDexuan Cui 		ret = 0;
11378c582c7cSDexuan Cui 	}
11388c582c7cSDexuan Cui 
11398c582c7cSDexuan Cui out:
11408c582c7cSDexuan Cui 	free_completion(&comp_pkt.host_event);
11418c582c7cSDexuan Cui 	return (ret);
11428c582c7cSDexuan Cui }
11438c582c7cSDexuan Cui 
11448c582c7cSDexuan Cui /*
11458c582c7cSDexuan Cui  * It looks this is only needed by Windows VM, but let's send the message too
11468c582c7cSDexuan Cui  * just to make the host happy.
11478c582c7cSDexuan Cui  */
11488c582c7cSDexuan Cui static int
11498c582c7cSDexuan Cui hv_send_resources_allocated(struct hv_pcibus *hbus)
11508c582c7cSDexuan Cui {
11518c582c7cSDexuan Cui 	struct pci_resources_assigned *res_assigned;
11528c582c7cSDexuan Cui 	struct hv_pci_compl comp_pkt;
11538c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
11548c582c7cSDexuan Cui 	struct pci_packet *pkt;
11558c582c7cSDexuan Cui 	uint32_t wslot;
11568c582c7cSDexuan Cui 	int ret = 0;
11578c582c7cSDexuan Cui 
11588c582c7cSDexuan Cui 	pkt = malloc(sizeof(*pkt) + sizeof(*res_assigned),
11598c582c7cSDexuan Cui 	    M_DEVBUF, M_WAITOK | M_ZERO);
11608c582c7cSDexuan Cui 
11618c582c7cSDexuan Cui 	for (wslot = 0; wslot < 256; wslot++) {
11628c582c7cSDexuan Cui 		hpdev = get_pcichild_wslot(hbus, wslot);
11638c582c7cSDexuan Cui 		if (!hpdev)
11648c582c7cSDexuan Cui 			continue;
11658c582c7cSDexuan Cui 
11668c582c7cSDexuan Cui 		init_completion(&comp_pkt.host_event);
11678c582c7cSDexuan Cui 
11688c582c7cSDexuan Cui 		memset(pkt, 0, sizeof(*pkt) + sizeof(*res_assigned));
11698c582c7cSDexuan Cui 		pkt->completion_func = hv_pci_generic_compl;
11708c582c7cSDexuan Cui 		pkt->compl_ctxt = &comp_pkt;
11718c582c7cSDexuan Cui 
11728c582c7cSDexuan Cui 		res_assigned = (struct pci_resources_assigned *)&pkt->message;
11738c582c7cSDexuan Cui 		res_assigned->message_type.type = PCI_RESOURCES_ASSIGNED;
11748c582c7cSDexuan Cui 		res_assigned->wslot.val = hpdev->desc.wslot.val;
11758c582c7cSDexuan Cui 
11768c582c7cSDexuan Cui 		ret = vmbus_chan_send(hbus->sc->chan,
11778c582c7cSDexuan Cui 		    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
1178aaf13123SDimitry Andric 		    &pkt->message, sizeof(*res_assigned),
1179aaf13123SDimitry Andric 		    (uint64_t)(uintptr_t)pkt);
1180*75c2786cSWei Hu 		if (!ret)
1181*75c2786cSWei Hu 			ret = wait_for_response(hbus, &comp_pkt.host_event);
11828c582c7cSDexuan Cui 
11838c582c7cSDexuan Cui 		free_completion(&comp_pkt.host_event);
11848c582c7cSDexuan Cui 
1185*75c2786cSWei Hu 		if (ret)
1186*75c2786cSWei Hu 			break;
1187*75c2786cSWei Hu 
11888c582c7cSDexuan Cui 		if (comp_pkt.completion_status < 0) {
11898c582c7cSDexuan Cui 			ret = EPROTO;
11908c582c7cSDexuan Cui 			device_printf(hbus->pcib,
11918c582c7cSDexuan Cui 			    "failed to send PCI_RESOURCES_ASSIGNED\n");
11928c582c7cSDexuan Cui 			break;
11938c582c7cSDexuan Cui 		}
11948c582c7cSDexuan Cui 	}
11958c582c7cSDexuan Cui 
11968c582c7cSDexuan Cui 	free(pkt, M_DEVBUF);
11978c582c7cSDexuan Cui 	return (ret);
11988c582c7cSDexuan Cui }
11998c582c7cSDexuan Cui 
12008c582c7cSDexuan Cui static int
12018c582c7cSDexuan Cui hv_send_resources_released(struct hv_pcibus *hbus)
12028c582c7cSDexuan Cui {
12038c582c7cSDexuan Cui 	struct pci_child_message pkt;
12048c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
12058c582c7cSDexuan Cui 	uint32_t wslot;
12068c582c7cSDexuan Cui 	int ret;
12078c582c7cSDexuan Cui 
12088c582c7cSDexuan Cui 	for (wslot = 0; wslot < 256; wslot++) {
12098c582c7cSDexuan Cui 		hpdev = get_pcichild_wslot(hbus, wslot);
12108c582c7cSDexuan Cui 		if (!hpdev)
12118c582c7cSDexuan Cui 			continue;
12128c582c7cSDexuan Cui 
12138c582c7cSDexuan Cui 		pkt.message_type.type = PCI_RESOURCES_RELEASED;
12148c582c7cSDexuan Cui 		pkt.wslot.val = hpdev->desc.wslot.val;
12158c582c7cSDexuan Cui 
12168c582c7cSDexuan Cui 		ret = vmbus_chan_send(hbus->sc->chan,
12178c582c7cSDexuan Cui 		    VMBUS_CHANPKT_TYPE_INBAND, 0, &pkt, sizeof(pkt), 0);
12188c582c7cSDexuan Cui 		if (ret)
12198c582c7cSDexuan Cui 			return (ret);
12208c582c7cSDexuan Cui 	}
12218c582c7cSDexuan Cui 
12228c582c7cSDexuan Cui 	return (0);
12238c582c7cSDexuan Cui }
12248c582c7cSDexuan Cui 
12258c582c7cSDexuan Cui #define hv_cfg_read(x, s)						\
12268c582c7cSDexuan Cui static inline uint##x##_t hv_cfg_read_##s(struct hv_pcibus *bus,	\
12278c582c7cSDexuan Cui     bus_size_t offset)							\
12288c582c7cSDexuan Cui {									\
12298c582c7cSDexuan Cui 	return (bus_read_##s(bus->cfg_res, offset));			\
12308c582c7cSDexuan Cui }
12318c582c7cSDexuan Cui 
12328c582c7cSDexuan Cui #define hv_cfg_write(x, s)						\
12338c582c7cSDexuan Cui static inline void hv_cfg_write_##s(struct hv_pcibus *bus,		\
12348c582c7cSDexuan Cui     bus_size_t offset, uint##x##_t val)					\
12358c582c7cSDexuan Cui {									\
12368c582c7cSDexuan Cui 	return (bus_write_##s(bus->cfg_res, offset, val));		\
12378c582c7cSDexuan Cui }
12388c582c7cSDexuan Cui 
12398c582c7cSDexuan Cui hv_cfg_read(8, 1)
12408c582c7cSDexuan Cui hv_cfg_read(16, 2)
12418c582c7cSDexuan Cui hv_cfg_read(32, 4)
12428c582c7cSDexuan Cui 
12438c582c7cSDexuan Cui hv_cfg_write(8, 1)
12448c582c7cSDexuan Cui hv_cfg_write(16, 2)
12458c582c7cSDexuan Cui hv_cfg_write(32, 4)
12468c582c7cSDexuan Cui 
12478c582c7cSDexuan Cui static void
12488c582c7cSDexuan Cui _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, int size,
12498c582c7cSDexuan Cui     uint32_t *val)
12508c582c7cSDexuan Cui {
12518c582c7cSDexuan Cui 	struct hv_pcibus *hbus = hpdev->hbus;
12528c582c7cSDexuan Cui 	bus_size_t addr = CFG_PAGE_OFFSET + where;
12538c582c7cSDexuan Cui 
12548c582c7cSDexuan Cui 	/*
12558c582c7cSDexuan Cui 	 * If the attempt is to read the IDs or the ROM BAR, simulate that.
12568c582c7cSDexuan Cui 	 */
12578c582c7cSDexuan Cui 	if (where + size <= PCIR_COMMAND) {
12588c582c7cSDexuan Cui 		memcpy(val, ((uint8_t *)&hpdev->desc.v_id) + where, size);
12598c582c7cSDexuan Cui 	} else if (where >= PCIR_REVID && where + size <=
12608c582c7cSDexuan Cui 		   PCIR_CACHELNSZ) {
12618c582c7cSDexuan Cui 		memcpy(val, ((uint8_t *)&hpdev->desc.rev) + where -
12628c582c7cSDexuan Cui 		       PCIR_REVID, size);
12638c582c7cSDexuan Cui 	} else if (where >= PCIR_SUBVEND_0 && where + size <=
12648c582c7cSDexuan Cui 		   PCIR_BIOS) {
12658c582c7cSDexuan Cui 		memcpy(val, (uint8_t *)&hpdev->desc.subsystem_id + where -
12668c582c7cSDexuan Cui 		       PCIR_SUBVEND_0, size);
12678c582c7cSDexuan Cui 	} else if (where >= PCIR_BIOS && where + size <=
12688c582c7cSDexuan Cui 		   PCIR_CAP_PTR) {
12698c582c7cSDexuan Cui 		/* ROM BARs are unimplemented */
12708c582c7cSDexuan Cui 		*val = 0;
12718c582c7cSDexuan Cui 	} else if ((where >= PCIR_INTLINE && where + size <=
12728c582c7cSDexuan Cui 		   PCIR_INTPIN) ||(where == PCIR_INTPIN && size == 1)) {
12738c582c7cSDexuan Cui 		/*
12748c582c7cSDexuan Cui 		 * Interrupt Line and Interrupt PIN are hard-wired to zero
12758c582c7cSDexuan Cui 		 * because this front-end only supports message-signaled
12768c582c7cSDexuan Cui 		 * interrupts.
12778c582c7cSDexuan Cui 		 */
12788c582c7cSDexuan Cui 		*val = 0;
12798c582c7cSDexuan Cui 	} else if (where + size <= CFG_PAGE_SIZE) {
12808c582c7cSDexuan Cui 		mtx_lock(&hbus->config_lock);
12818c582c7cSDexuan Cui 
12828c582c7cSDexuan Cui 		/* Choose the function to be read. */
12838c582c7cSDexuan Cui 		hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val);
12848c582c7cSDexuan Cui 
12858c582c7cSDexuan Cui 		/* Make sure the function was chosen before we start reading.*/
12868c582c7cSDexuan Cui 		mb();
12878c582c7cSDexuan Cui 
12888c582c7cSDexuan Cui 		/* Read from that function's config space. */
12898c582c7cSDexuan Cui 		switch (size) {
12908c582c7cSDexuan Cui 		case 1:
12918c582c7cSDexuan Cui 			*((uint8_t *)val) = hv_cfg_read_1(hbus, addr);
12928c582c7cSDexuan Cui 			break;
12938c582c7cSDexuan Cui 		case 2:
12948c582c7cSDexuan Cui 			*((uint16_t *)val) = hv_cfg_read_2(hbus, addr);
12958c582c7cSDexuan Cui 			break;
12968c582c7cSDexuan Cui 		default:
12978c582c7cSDexuan Cui 			*((uint32_t *)val) = hv_cfg_read_4(hbus, addr);
12988c582c7cSDexuan Cui 			break;
12998c582c7cSDexuan Cui 		}
13008c582c7cSDexuan Cui 		/*
13018c582c7cSDexuan Cui 		 * Make sure the write was done before we release the lock,
13028c582c7cSDexuan Cui 		 * allowing consecutive reads/writes.
13038c582c7cSDexuan Cui 		 */
13048c582c7cSDexuan Cui 		mb();
13058c582c7cSDexuan Cui 
13068c582c7cSDexuan Cui 		mtx_unlock(&hbus->config_lock);
13078c582c7cSDexuan Cui 	} else {
13088c582c7cSDexuan Cui 		/* Invalid config read: it's unlikely to reach here. */
13098c582c7cSDexuan Cui 		memset(val, 0, size);
13108c582c7cSDexuan Cui 	}
13118c582c7cSDexuan Cui }
13128c582c7cSDexuan Cui 
13138c582c7cSDexuan Cui static void
13148c582c7cSDexuan Cui _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size,
13158c582c7cSDexuan Cui     uint32_t val)
13168c582c7cSDexuan Cui {
13178c582c7cSDexuan Cui 	struct hv_pcibus *hbus = hpdev->hbus;
13188c582c7cSDexuan Cui 	bus_size_t addr = CFG_PAGE_OFFSET + where;
13198c582c7cSDexuan Cui 
13208c582c7cSDexuan Cui 	/* SSIDs and ROM BARs are read-only */
13218c582c7cSDexuan Cui 	if (where >= PCIR_SUBVEND_0 && where + size <= PCIR_CAP_PTR)
13228c582c7cSDexuan Cui 		return;
13238c582c7cSDexuan Cui 
13248c582c7cSDexuan Cui 	if (where >= PCIR_COMMAND && where + size <= CFG_PAGE_SIZE) {
13258c582c7cSDexuan Cui 		mtx_lock(&hbus->config_lock);
13268c582c7cSDexuan Cui 
13278c582c7cSDexuan Cui 		/* Choose the function to be written. */
13288c582c7cSDexuan Cui 		hv_cfg_write_4(hbus, 0, hpdev->desc.wslot.val);
13298c582c7cSDexuan Cui 
13308c582c7cSDexuan Cui 		/* Make sure the function was chosen before we start writing.*/
13318c582c7cSDexuan Cui 		wmb();
13328c582c7cSDexuan Cui 
13338c582c7cSDexuan Cui 		/* Write to that function's config space. */
13348c582c7cSDexuan Cui 		switch (size) {
13358c582c7cSDexuan Cui 		case 1:
13368c582c7cSDexuan Cui 			hv_cfg_write_1(hbus, addr, (uint8_t)val);
13378c582c7cSDexuan Cui 			break;
13388c582c7cSDexuan Cui 		case 2:
13398c582c7cSDexuan Cui 			hv_cfg_write_2(hbus, addr, (uint16_t)val);
13408c582c7cSDexuan Cui 			break;
13418c582c7cSDexuan Cui 		default:
13428c582c7cSDexuan Cui 			hv_cfg_write_4(hbus, addr, (uint32_t)val);
13438c582c7cSDexuan Cui 			break;
13448c582c7cSDexuan Cui 		}
13458c582c7cSDexuan Cui 
13468c582c7cSDexuan Cui 		/*
13478c582c7cSDexuan Cui 		 * Make sure the write was done before we release the lock,
13488c582c7cSDexuan Cui 		 * allowing consecutive reads/writes.
13498c582c7cSDexuan Cui 		 */
13508c582c7cSDexuan Cui 		mb();
13518c582c7cSDexuan Cui 
13528c582c7cSDexuan Cui 		mtx_unlock(&hbus->config_lock);
13538c582c7cSDexuan Cui 	} else {
13548c582c7cSDexuan Cui 		/* Invalid config write: it's unlikely to reach here. */
13558c582c7cSDexuan Cui 		return;
13568c582c7cSDexuan Cui 	}
13578c582c7cSDexuan Cui }
13588c582c7cSDexuan Cui 
13598c582c7cSDexuan Cui static void
13608c582c7cSDexuan Cui vmbus_pcib_set_detaching(void *arg, int pending __unused)
13618c582c7cSDexuan Cui {
13628c582c7cSDexuan Cui 	struct hv_pcibus *hbus = arg;
13638c582c7cSDexuan Cui 
13648c582c7cSDexuan Cui 	atomic_set_int(&hbus->detaching, 1);
13658c582c7cSDexuan Cui }
13668c582c7cSDexuan Cui 
13678c582c7cSDexuan Cui static void
13688c582c7cSDexuan Cui vmbus_pcib_pre_detach(struct hv_pcibus *hbus)
13698c582c7cSDexuan Cui {
13708c582c7cSDexuan Cui 	struct task task;
13718c582c7cSDexuan Cui 
13728c582c7cSDexuan Cui 	TASK_INIT(&task, 0, vmbus_pcib_set_detaching, hbus);
13738c582c7cSDexuan Cui 
13748c582c7cSDexuan Cui 	/*
13758c582c7cSDexuan Cui 	 * Make sure the channel callback won't push any possible new
13768c582c7cSDexuan Cui 	 * PCI_BUS_RELATIONS and PCI_EJECT tasks to sc->taskq.
13778c582c7cSDexuan Cui 	 */
13788c582c7cSDexuan Cui 	vmbus_chan_run_task(hbus->sc->chan, &task);
13798c582c7cSDexuan Cui 
13808c582c7cSDexuan Cui 	taskqueue_drain_all(hbus->sc->taskq);
13818c582c7cSDexuan Cui }
13828c582c7cSDexuan Cui 
13838c582c7cSDexuan Cui 
13848c582c7cSDexuan Cui /*
13858c582c7cSDexuan Cui  * Standard probe entry point.
13868c582c7cSDexuan Cui  *
13878c582c7cSDexuan Cui  */
13888c582c7cSDexuan Cui static int
13898c582c7cSDexuan Cui vmbus_pcib_probe(device_t dev)
13908c582c7cSDexuan Cui {
13918c582c7cSDexuan Cui 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
13928c582c7cSDexuan Cui 	    &g_pass_through_dev_type) == 0) {
13938c582c7cSDexuan Cui 		device_set_desc(dev, "Hyper-V PCI Express Pass Through");
13948c582c7cSDexuan Cui 		return (BUS_PROBE_DEFAULT);
13958c582c7cSDexuan Cui 	}
13968c582c7cSDexuan Cui 	return (ENXIO);
13978c582c7cSDexuan Cui }
13988c582c7cSDexuan Cui 
13998c582c7cSDexuan Cui /*
14008c582c7cSDexuan Cui  * Standard attach entry point.
14018c582c7cSDexuan Cui  *
14028c582c7cSDexuan Cui  */
14038c582c7cSDexuan Cui static int
14048c582c7cSDexuan Cui vmbus_pcib_attach(device_t dev)
14058c582c7cSDexuan Cui {
14068c582c7cSDexuan Cui 	const int pci_ring_size = (4 * PAGE_SIZE);
14078c582c7cSDexuan Cui 	const struct hyperv_guid *inst_guid;
14088c582c7cSDexuan Cui 	struct vmbus_channel *channel;
14098c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc;
14108c582c7cSDexuan Cui 	struct hv_pcibus *hbus;
14118c582c7cSDexuan Cui 	int rid = 0;
14128c582c7cSDexuan Cui 	int ret;
14138c582c7cSDexuan Cui 
14148c582c7cSDexuan Cui 	hbus = malloc(sizeof(*hbus), M_DEVBUF, M_WAITOK | M_ZERO);
14158c582c7cSDexuan Cui 	hbus->pcib = dev;
14168c582c7cSDexuan Cui 
14178c582c7cSDexuan Cui 	channel = vmbus_get_channel(dev);
14188c582c7cSDexuan Cui 	inst_guid = vmbus_chan_guid_inst(channel);
14198c582c7cSDexuan Cui 	hbus->pci_domain = inst_guid->hv_guid[9] |
14208c582c7cSDexuan Cui 			  (inst_guid->hv_guid[8] << 8);
14218c582c7cSDexuan Cui 
14228c582c7cSDexuan Cui 	mtx_init(&hbus->config_lock, "hbcfg", NULL, MTX_DEF);
14238c582c7cSDexuan Cui 	mtx_init(&hbus->device_list_lock, "hbdl", NULL, MTX_DEF);
14248c582c7cSDexuan Cui 	TAILQ_INIT(&hbus->children);
14258c582c7cSDexuan Cui 	TAILQ_INIT(&hbus->dr_list);
14268c582c7cSDexuan Cui 
14278c582c7cSDexuan Cui 	hbus->cfg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
14288c582c7cSDexuan Cui 	    0, RM_MAX_END, PCI_CONFIG_MMIO_LENGTH,
14298c582c7cSDexuan Cui 	    RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE));
14308c582c7cSDexuan Cui 
14318c582c7cSDexuan Cui 	if (!hbus->cfg_res) {
14328c582c7cSDexuan Cui 		device_printf(dev, "failed to get resource for cfg window\n");
14338c582c7cSDexuan Cui 		ret = ENXIO;
14348c582c7cSDexuan Cui 		goto free_bus;
14358c582c7cSDexuan Cui 	}
14368c582c7cSDexuan Cui 
14378c582c7cSDexuan Cui 	sc = device_get_softc(dev);
14388c582c7cSDexuan Cui 	sc->chan = channel;
14398c582c7cSDexuan Cui 	sc->rx_buf = malloc(PCIB_PACKET_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
14408c582c7cSDexuan Cui 	sc->hbus = hbus;
14418c582c7cSDexuan Cui 
14428c582c7cSDexuan Cui 	/*
14438c582c7cSDexuan Cui 	 * The taskq is used to handle PCI_BUS_RELATIONS and PCI_EJECT
14448c582c7cSDexuan Cui 	 * messages. NB: we can't handle the messages in the channel callback
14458c582c7cSDexuan Cui 	 * directly, because the message handlers need to send new messages
14468c582c7cSDexuan Cui 	 * to the host and waits for the host's completion messages, which
14478c582c7cSDexuan Cui 	 * must also be handled by the channel callback.
14488c582c7cSDexuan Cui 	 */
14498c582c7cSDexuan Cui 	sc->taskq = taskqueue_create("vmbus_pcib_tq", M_WAITOK,
14508c582c7cSDexuan Cui 	    taskqueue_thread_enqueue, &sc->taskq);
14518c582c7cSDexuan Cui 	taskqueue_start_threads(&sc->taskq, 1, PI_NET, "vmbus_pcib_tq");
14528c582c7cSDexuan Cui 
14538c582c7cSDexuan Cui 	hbus->sc = sc;
14548c582c7cSDexuan Cui 
14558c582c7cSDexuan Cui 	init_completion(&hbus->query_completion);
14568c582c7cSDexuan Cui 	hbus->query_comp = &hbus->query_completion;
14578c582c7cSDexuan Cui 
14588c582c7cSDexuan Cui 	ret = vmbus_chan_open(sc->chan, pci_ring_size, pci_ring_size,
14598c582c7cSDexuan Cui 		NULL, 0, vmbus_pcib_on_channel_callback, sc);
14608c582c7cSDexuan Cui 	if (ret)
14618c582c7cSDexuan Cui 		goto free_res;
14628c582c7cSDexuan Cui 
14638c582c7cSDexuan Cui 	ret = hv_pci_protocol_negotiation(hbus);
14648c582c7cSDexuan Cui 	if (ret)
14658c582c7cSDexuan Cui 		goto vmbus_close;
14668c582c7cSDexuan Cui 
14678c582c7cSDexuan Cui 	ret = hv_pci_query_relations(hbus);
1468*75c2786cSWei Hu 	if (!ret)
1469*75c2786cSWei Hu 		ret = wait_for_response(hbus, hbus->query_comp);
1470*75c2786cSWei Hu 
14718c582c7cSDexuan Cui 	if (ret)
14728c582c7cSDexuan Cui 		goto vmbus_close;
14738c582c7cSDexuan Cui 
14748c582c7cSDexuan Cui 	ret = hv_pci_enter_d0(hbus);
14758c582c7cSDexuan Cui 	if (ret)
14768c582c7cSDexuan Cui 		goto vmbus_close;
14778c582c7cSDexuan Cui 
14788c582c7cSDexuan Cui 	ret = hv_send_resources_allocated(hbus);
14798c582c7cSDexuan Cui 	if (ret)
14808c582c7cSDexuan Cui 		goto vmbus_close;
14818c582c7cSDexuan Cui 
14828c582c7cSDexuan Cui 	hbus->pci_bus = device_add_child(dev, "pci", -1);
14838c582c7cSDexuan Cui 	if (!hbus->pci_bus) {
14848c582c7cSDexuan Cui 		device_printf(dev, "failed to create pci bus\n");
14858c582c7cSDexuan Cui 		ret = ENXIO;
14868c582c7cSDexuan Cui 		goto vmbus_close;
14878c582c7cSDexuan Cui 	}
14888c582c7cSDexuan Cui 
14898c582c7cSDexuan Cui 	bus_generic_attach(dev);
14908c582c7cSDexuan Cui 
14918c582c7cSDexuan Cui 	hbus->state = hv_pcibus_installed;
14928c582c7cSDexuan Cui 
14938c582c7cSDexuan Cui 	return (0);
14948c582c7cSDexuan Cui 
14958c582c7cSDexuan Cui vmbus_close:
14968c582c7cSDexuan Cui 	vmbus_pcib_pre_detach(hbus);
14978c582c7cSDexuan Cui 	vmbus_chan_close(sc->chan);
14988c582c7cSDexuan Cui free_res:
14998c582c7cSDexuan Cui 	taskqueue_free(sc->taskq);
15008c582c7cSDexuan Cui 	free_completion(&hbus->query_completion);
15018c582c7cSDexuan Cui 	free(sc->rx_buf, M_DEVBUF);
15028c582c7cSDexuan Cui 	bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res);
15038c582c7cSDexuan Cui free_bus:
15048c582c7cSDexuan Cui 	mtx_destroy(&hbus->device_list_lock);
15058c582c7cSDexuan Cui 	mtx_destroy(&hbus->config_lock);
15068c582c7cSDexuan Cui 	free(hbus, M_DEVBUF);
15078c582c7cSDexuan Cui 	return (ret);
15088c582c7cSDexuan Cui }
15098c582c7cSDexuan Cui 
15108c582c7cSDexuan Cui /*
15118c582c7cSDexuan Cui  * Standard detach entry point
15128c582c7cSDexuan Cui  */
15138c582c7cSDexuan Cui static int
15148c582c7cSDexuan Cui vmbus_pcib_detach(device_t dev)
15158c582c7cSDexuan Cui {
15168c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
15178c582c7cSDexuan Cui 	struct hv_pcibus *hbus = sc->hbus;
15188c582c7cSDexuan Cui 	struct pci_message teardown_packet;
15198c582c7cSDexuan Cui 	struct pci_bus_relations relations;
15208c582c7cSDexuan Cui 	int ret;
15218c582c7cSDexuan Cui 
15228c582c7cSDexuan Cui 	vmbus_pcib_pre_detach(hbus);
15238c582c7cSDexuan Cui 
15248c582c7cSDexuan Cui 	if (hbus->state == hv_pcibus_installed)
15258c582c7cSDexuan Cui 		bus_generic_detach(dev);
15268c582c7cSDexuan Cui 
15278c582c7cSDexuan Cui 	/* Delete any children which might still exist. */
15288c582c7cSDexuan Cui 	memset(&relations, 0, sizeof(relations));
15298c582c7cSDexuan Cui 	hv_pci_devices_present(hbus, &relations);
15308c582c7cSDexuan Cui 
15318c582c7cSDexuan Cui 	ret = hv_send_resources_released(hbus);
15328c582c7cSDexuan Cui 	if (ret)
15338c582c7cSDexuan Cui 		device_printf(dev, "failed to send PCI_RESOURCES_RELEASED\n");
15348c582c7cSDexuan Cui 
15358c582c7cSDexuan Cui 	teardown_packet.type = PCI_BUS_D0EXIT;
15368c582c7cSDexuan Cui 	ret = vmbus_chan_send(sc->chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
15378c582c7cSDexuan Cui 	    &teardown_packet, sizeof(struct pci_message), 0);
15388c582c7cSDexuan Cui 	if (ret)
15398c582c7cSDexuan Cui 		device_printf(dev, "failed to send PCI_BUS_D0EXIT\n");
15408c582c7cSDexuan Cui 
15418c582c7cSDexuan Cui 	taskqueue_drain_all(hbus->sc->taskq);
15428c582c7cSDexuan Cui 	vmbus_chan_close(sc->chan);
15438c582c7cSDexuan Cui 	taskqueue_free(sc->taskq);
15448c582c7cSDexuan Cui 
15458c582c7cSDexuan Cui 	free_completion(&hbus->query_completion);
15468c582c7cSDexuan Cui 	free(sc->rx_buf, M_DEVBUF);
15478c582c7cSDexuan Cui 	bus_release_resource(dev, SYS_RES_MEMORY, 0, hbus->cfg_res);
15488c582c7cSDexuan Cui 
15498c582c7cSDexuan Cui 	mtx_destroy(&hbus->device_list_lock);
15508c582c7cSDexuan Cui 	mtx_destroy(&hbus->config_lock);
15518c582c7cSDexuan Cui 	free(hbus, M_DEVBUF);
15528c582c7cSDexuan Cui 
15538c582c7cSDexuan Cui 	return (0);
15548c582c7cSDexuan Cui }
15558c582c7cSDexuan Cui 
15568c582c7cSDexuan Cui static int
15578c582c7cSDexuan Cui vmbus_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *val)
15588c582c7cSDexuan Cui {
15598c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
15608c582c7cSDexuan Cui 
15618c582c7cSDexuan Cui 	switch (which) {
15628c582c7cSDexuan Cui 	case PCIB_IVAR_DOMAIN:
15638c582c7cSDexuan Cui 		*val = sc->hbus->pci_domain;
15648c582c7cSDexuan Cui 		return (0);
15658c582c7cSDexuan Cui 
15668c582c7cSDexuan Cui 	case PCIB_IVAR_BUS:
15678c582c7cSDexuan Cui 		/* There is only bus 0. */
15688c582c7cSDexuan Cui 		*val = 0;
15698c582c7cSDexuan Cui 		return (0);
15708c582c7cSDexuan Cui 	}
15718c582c7cSDexuan Cui 	return (ENOENT);
15728c582c7cSDexuan Cui }
15738c582c7cSDexuan Cui 
15748c582c7cSDexuan Cui static int
15758c582c7cSDexuan Cui vmbus_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t val)
15768c582c7cSDexuan Cui {
15778c582c7cSDexuan Cui 	return (ENOENT);
15788c582c7cSDexuan Cui }
15798c582c7cSDexuan Cui 
15808c582c7cSDexuan Cui static struct resource *
15818c582c7cSDexuan Cui vmbus_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
15828c582c7cSDexuan Cui 	rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
15838c582c7cSDexuan Cui {
15848c582c7cSDexuan Cui 	unsigned int bar_no;
15858c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
15868c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
15878c582c7cSDexuan Cui 	struct resource *res;
15888c582c7cSDexuan Cui 	unsigned int devfn;
15898c582c7cSDexuan Cui 
15908c582c7cSDexuan Cui 	if (type == PCI_RES_BUS)
15918c582c7cSDexuan Cui 		return (pci_domain_alloc_bus(sc->hbus->pci_domain, child, rid,
15928c582c7cSDexuan Cui 		    start, end, count, flags));
15938c582c7cSDexuan Cui 
15948c582c7cSDexuan Cui 	/* Devices with port I/O BAR are not supported. */
15958c582c7cSDexuan Cui 	if (type == SYS_RES_IOPORT)
15968c582c7cSDexuan Cui 		return (NULL);
15978c582c7cSDexuan Cui 
15988c582c7cSDexuan Cui 	if (type == SYS_RES_MEMORY) {
15998c582c7cSDexuan Cui 		devfn = PCI_DEVFN(pci_get_slot(child),
16008c582c7cSDexuan Cui 		    pci_get_function(child));
16018c582c7cSDexuan Cui 		hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn));
16028c582c7cSDexuan Cui 		if (!hpdev)
16038c582c7cSDexuan Cui 			return (NULL);
16048c582c7cSDexuan Cui 
16058c582c7cSDexuan Cui 		bar_no = PCI_RID2BAR(*rid);
16068c582c7cSDexuan Cui 		if (bar_no >= MAX_NUM_BARS)
16078c582c7cSDexuan Cui 			return (NULL);
16088c582c7cSDexuan Cui 
16098c582c7cSDexuan Cui 		/* Make sure a 32-bit BAR gets a 32-bit address */
16108c582c7cSDexuan Cui 		if (!(hpdev->probed_bar[bar_no] & PCIM_BAR_MEM_64))
16118c582c7cSDexuan Cui 			end = ulmin(end, 0xFFFFFFFF);
16128c582c7cSDexuan Cui 	}
16138c582c7cSDexuan Cui 
16148c582c7cSDexuan Cui 	res = bus_generic_alloc_resource(dev, child, type, rid,
16158c582c7cSDexuan Cui 		start, end, count, flags);
16168c582c7cSDexuan Cui 	/*
16178c582c7cSDexuan Cui 	 * If this is a request for a specific range, assume it is
16188c582c7cSDexuan Cui 	 * correct and pass it up to the parent.
16198c582c7cSDexuan Cui 	 */
16208c582c7cSDexuan Cui 	if (res == NULL && start + count - 1 == end)
16218c582c7cSDexuan Cui 		res = bus_generic_alloc_resource(dev, child, type, rid,
16228c582c7cSDexuan Cui 		    start, end, count, flags);
16238c582c7cSDexuan Cui 	return (res);
16248c582c7cSDexuan Cui }
16258c582c7cSDexuan Cui 
16268c582c7cSDexuan Cui static int
16278c582c7cSDexuan Cui vmbus_pcib_release_resource(device_t dev, device_t child, int type, int rid,
16288c582c7cSDexuan Cui     struct resource *r)
16298c582c7cSDexuan Cui {
16308c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
16318c582c7cSDexuan Cui 
16328c582c7cSDexuan Cui 	if (type == PCI_RES_BUS)
16338c582c7cSDexuan Cui 		return (pci_domain_release_bus(sc->hbus->pci_domain, child,
16348c582c7cSDexuan Cui 		    rid, r));
16358c582c7cSDexuan Cui 
16368c582c7cSDexuan Cui 	if (type == SYS_RES_IOPORT)
16378c582c7cSDexuan Cui 		return (EINVAL);
16388c582c7cSDexuan Cui 
16398c582c7cSDexuan Cui 	return (bus_generic_release_resource(dev, child, type, rid, r));
16408c582c7cSDexuan Cui }
16418c582c7cSDexuan Cui 
16428c582c7cSDexuan Cui #if __FreeBSD_version >= 1100000
16438c582c7cSDexuan Cui static int
16448c582c7cSDexuan Cui vmbus_pcib_get_cpus(device_t pcib, device_t dev, enum cpu_sets op,
16458c582c7cSDexuan Cui     size_t setsize, cpuset_t *cpuset)
16468c582c7cSDexuan Cui {
16478c582c7cSDexuan Cui 	return (bus_get_cpus(pcib, op, setsize, cpuset));
16488c582c7cSDexuan Cui }
16498c582c7cSDexuan Cui #endif
16508c582c7cSDexuan Cui 
16518c582c7cSDexuan Cui static uint32_t
16528c582c7cSDexuan Cui vmbus_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
16538c582c7cSDexuan Cui     u_int reg, int bytes)
16548c582c7cSDexuan Cui {
16558c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
16568c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
16578c582c7cSDexuan Cui 	unsigned int devfn = PCI_DEVFN(slot, func);
16588c582c7cSDexuan Cui 	uint32_t data = 0;
16598c582c7cSDexuan Cui 
16608c582c7cSDexuan Cui 	KASSERT(bus == 0, ("bus should be 0, but is %u", bus));
16618c582c7cSDexuan Cui 
16628c582c7cSDexuan Cui 	hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn));
16638c582c7cSDexuan Cui 	if (!hpdev)
16648c582c7cSDexuan Cui 		return (~0);
16658c582c7cSDexuan Cui 
16668c582c7cSDexuan Cui 	_hv_pcifront_read_config(hpdev, reg, bytes, &data);
16678c582c7cSDexuan Cui 
16688c582c7cSDexuan Cui 	return (data);
16698c582c7cSDexuan Cui }
16708c582c7cSDexuan Cui 
16718c582c7cSDexuan Cui static void
16728c582c7cSDexuan Cui vmbus_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
16738c582c7cSDexuan Cui     u_int reg, uint32_t data, int bytes)
16748c582c7cSDexuan Cui {
16758c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(dev);
16768c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
16778c582c7cSDexuan Cui 	unsigned int devfn = PCI_DEVFN(slot, func);
16788c582c7cSDexuan Cui 
16798c582c7cSDexuan Cui 	KASSERT(bus == 0, ("bus should be 0, but is %u", bus));
16808c582c7cSDexuan Cui 
16818c582c7cSDexuan Cui 	hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn));
16828c582c7cSDexuan Cui 	if (!hpdev)
16838c582c7cSDexuan Cui 		return;
16848c582c7cSDexuan Cui 
16858c582c7cSDexuan Cui 	_hv_pcifront_write_config(hpdev, reg, bytes, data);
16868c582c7cSDexuan Cui }
16878c582c7cSDexuan Cui 
16888c582c7cSDexuan Cui static int
16898c582c7cSDexuan Cui vmbus_pcib_route_intr(device_t pcib, device_t dev, int pin)
16908c582c7cSDexuan Cui {
16918c582c7cSDexuan Cui 	/* We only support MSI/MSI-X and don't support INTx interrupt. */
16928c582c7cSDexuan Cui 	return (PCI_INVALID_IRQ);
16938c582c7cSDexuan Cui }
16948c582c7cSDexuan Cui 
16958c582c7cSDexuan Cui static int
16968c582c7cSDexuan Cui vmbus_pcib_alloc_msi(device_t pcib, device_t dev, int count,
16978c582c7cSDexuan Cui     int maxcount, int *irqs)
16988c582c7cSDexuan Cui {
16998c582c7cSDexuan Cui 	return (PCIB_ALLOC_MSI(device_get_parent(pcib), dev, count, maxcount,
17008c582c7cSDexuan Cui 	    irqs));
17018c582c7cSDexuan Cui }
17028c582c7cSDexuan Cui 
17038c582c7cSDexuan Cui static int
17048c582c7cSDexuan Cui vmbus_pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
17058c582c7cSDexuan Cui {
17068c582c7cSDexuan Cui 	return (PCIB_RELEASE_MSI(device_get_parent(pcib), dev, count, irqs));
17078c582c7cSDexuan Cui }
17088c582c7cSDexuan Cui 
17098c582c7cSDexuan Cui static int
17108c582c7cSDexuan Cui vmbus_pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
17118c582c7cSDexuan Cui {
17128c582c7cSDexuan Cui 	return (PCIB_ALLOC_MSIX(device_get_parent(pcib), dev, irq));
17138c582c7cSDexuan Cui }
17148c582c7cSDexuan Cui 
17158c582c7cSDexuan Cui static int
17168c582c7cSDexuan Cui vmbus_pcib_release_msix(device_t pcib, device_t dev, int irq)
17178c582c7cSDexuan Cui {
17188c582c7cSDexuan Cui 	return (PCIB_RELEASE_MSIX(device_get_parent(pcib), dev, irq));
17198c582c7cSDexuan Cui }
17208c582c7cSDexuan Cui 
17218c582c7cSDexuan Cui #define	MSI_INTEL_ADDR_DEST	0x000ff000
17228c582c7cSDexuan Cui #define	MSI_INTEL_DATA_INTVEC	IOART_INTVEC	/* Interrupt vector. */
17238c582c7cSDexuan Cui #define	MSI_INTEL_DATA_DELFIXED	IOART_DELFIXED
17248c582c7cSDexuan Cui 
17258c582c7cSDexuan Cui static int
17268c582c7cSDexuan Cui vmbus_pcib_map_msi(device_t pcib, device_t child, int irq,
17278c582c7cSDexuan Cui     uint64_t *addr, uint32_t *data)
17288c582c7cSDexuan Cui {
17298c582c7cSDexuan Cui 	unsigned int devfn;
17308c582c7cSDexuan Cui 	struct hv_pci_dev *hpdev;
17318c582c7cSDexuan Cui 
17328c582c7cSDexuan Cui 	uint64_t v_addr;
17338c582c7cSDexuan Cui 	uint32_t v_data;
17348c582c7cSDexuan Cui 	struct hv_irq_desc *hid, *tmp_hid;
17358c582c7cSDexuan Cui 	unsigned int cpu, vcpu_id;
17368c582c7cSDexuan Cui 	unsigned int vector;
17378c582c7cSDexuan Cui 
17388c582c7cSDexuan Cui 	struct vmbus_pcib_softc *sc = device_get_softc(pcib);
17398c582c7cSDexuan Cui 	struct pci_create_interrupt *int_pkt;
17408c582c7cSDexuan Cui 	struct compose_comp_ctxt comp;
17418c582c7cSDexuan Cui 	struct {
17428c582c7cSDexuan Cui 		struct pci_packet pkt;
17438c582c7cSDexuan Cui 		uint8_t buffer[sizeof(struct pci_create_interrupt)];
17448c582c7cSDexuan Cui 	} ctxt;
17458c582c7cSDexuan Cui 
17468c582c7cSDexuan Cui 	int ret;
17478c582c7cSDexuan Cui 
17488c582c7cSDexuan Cui 	devfn = PCI_DEVFN(pci_get_slot(child), pci_get_function(child));
17498c582c7cSDexuan Cui 	hpdev = get_pcichild_wslot(sc->hbus, devfn_to_wslot(devfn));
17508c582c7cSDexuan Cui 	if (!hpdev)
17518c582c7cSDexuan Cui 		return (ENOENT);
17528c582c7cSDexuan Cui 
17538c582c7cSDexuan Cui 	ret = PCIB_MAP_MSI(device_get_parent(pcib), child, irq,
17548c582c7cSDexuan Cui 	    &v_addr, &v_data);
17558c582c7cSDexuan Cui 	if (ret)
17568c582c7cSDexuan Cui 		return (ret);
17578c582c7cSDexuan Cui 
17588c582c7cSDexuan Cui 	TAILQ_FOREACH_SAFE(hid, &hpdev->irq_desc_list, link, tmp_hid) {
17598c582c7cSDexuan Cui 		if (hid->irq == irq) {
17608c582c7cSDexuan Cui 			TAILQ_REMOVE(&hpdev->irq_desc_list, hid, link);
17618c582c7cSDexuan Cui 			hv_int_desc_free(hpdev, hid);
17628c582c7cSDexuan Cui 			break;
17638c582c7cSDexuan Cui 		}
17648c582c7cSDexuan Cui 	}
17658c582c7cSDexuan Cui 
17668c582c7cSDexuan Cui 	cpu = (v_addr & MSI_INTEL_ADDR_DEST) >> 12;
17678c582c7cSDexuan Cui 	vcpu_id = VMBUS_GET_VCPU_ID(device_get_parent(pcib), pcib, cpu);
17688c582c7cSDexuan Cui 	vector = v_data & MSI_INTEL_DATA_INTVEC;
17698c582c7cSDexuan Cui 
17708c582c7cSDexuan Cui 	init_completion(&comp.comp_pkt.host_event);
17718c582c7cSDexuan Cui 
17728c582c7cSDexuan Cui 	memset(&ctxt, 0, sizeof(ctxt));
17738c582c7cSDexuan Cui 	ctxt.pkt.completion_func = hv_pci_compose_compl;
17748c582c7cSDexuan Cui 	ctxt.pkt.compl_ctxt = &comp;
17758c582c7cSDexuan Cui 
17768c582c7cSDexuan Cui 	int_pkt = (struct pci_create_interrupt *)&ctxt.pkt.message;
17778c582c7cSDexuan Cui 	int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
17788c582c7cSDexuan Cui 	int_pkt->wslot.val = hpdev->desc.wslot.val;
17798c582c7cSDexuan Cui 	int_pkt->int_desc.vector = vector;
17808c582c7cSDexuan Cui 	int_pkt->int_desc.vector_count = 1;
17818c582c7cSDexuan Cui 	int_pkt->int_desc.delivery_mode = MSI_INTEL_DATA_DELFIXED;
17828c582c7cSDexuan Cui 	int_pkt->int_desc.cpu_mask = 1ULL << vcpu_id;
17838c582c7cSDexuan Cui 
17848c582c7cSDexuan Cui 	ret = vmbus_chan_send(sc->chan,	VMBUS_CHANPKT_TYPE_INBAND,
17858c582c7cSDexuan Cui 	    VMBUS_CHANPKT_FLAG_RC, int_pkt, sizeof(*int_pkt),
1786aaf13123SDimitry Andric 	    (uint64_t)(uintptr_t)&ctxt.pkt);
17878c582c7cSDexuan Cui 	if (ret) {
17888c582c7cSDexuan Cui 		free_completion(&comp.comp_pkt.host_event);
17898c582c7cSDexuan Cui 		return (ret);
17908c582c7cSDexuan Cui 	}
17918c582c7cSDexuan Cui 
17928c582c7cSDexuan Cui 	wait_for_completion(&comp.comp_pkt.host_event);
17938c582c7cSDexuan Cui 	free_completion(&comp.comp_pkt.host_event);
17948c582c7cSDexuan Cui 
17958c582c7cSDexuan Cui 	if (comp.comp_pkt.completion_status < 0)
17968c582c7cSDexuan Cui 		return (EPROTO);
17978c582c7cSDexuan Cui 
17988c582c7cSDexuan Cui 	*addr = comp.int_desc.address;
17998c582c7cSDexuan Cui 	*data = comp.int_desc.data;
18008c582c7cSDexuan Cui 
18018c582c7cSDexuan Cui 	hid = malloc(sizeof(struct hv_irq_desc), M_DEVBUF, M_WAITOK | M_ZERO);
18028c582c7cSDexuan Cui 	hid->irq = irq;
18038c582c7cSDexuan Cui 	hid->desc = comp.int_desc;
18048c582c7cSDexuan Cui 	TAILQ_INSERT_TAIL(&hpdev->irq_desc_list, hid, link);
18058c582c7cSDexuan Cui 
18068c582c7cSDexuan Cui 	return (0);
18078c582c7cSDexuan Cui }
18088c582c7cSDexuan Cui 
18098c582c7cSDexuan Cui static device_method_t vmbus_pcib_methods[] = {
18108c582c7cSDexuan Cui 	/* Device interface */
18118c582c7cSDexuan Cui 	DEVMETHOD(device_probe,         vmbus_pcib_probe),
18128c582c7cSDexuan Cui 	DEVMETHOD(device_attach,        vmbus_pcib_attach),
18138c582c7cSDexuan Cui 	DEVMETHOD(device_detach,        vmbus_pcib_detach),
18148c582c7cSDexuan Cui 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
18158c582c7cSDexuan Cui 	DEVMETHOD(device_suspend,	bus_generic_suspend),
18168c582c7cSDexuan Cui 	DEVMETHOD(device_resume,	bus_generic_resume),
18178c582c7cSDexuan Cui 
18188c582c7cSDexuan Cui 	/* Bus interface */
18198c582c7cSDexuan Cui 	DEVMETHOD(bus_read_ivar,		vmbus_pcib_read_ivar),
18208c582c7cSDexuan Cui 	DEVMETHOD(bus_write_ivar,		vmbus_pcib_write_ivar),
18218c582c7cSDexuan Cui 	DEVMETHOD(bus_alloc_resource,		vmbus_pcib_alloc_resource),
18228c582c7cSDexuan Cui 	DEVMETHOD(bus_release_resource,		vmbus_pcib_release_resource),
18238c582c7cSDexuan Cui 	DEVMETHOD(bus_activate_resource,   bus_generic_activate_resource),
18248c582c7cSDexuan Cui 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
18258c582c7cSDexuan Cui 	DEVMETHOD(bus_setup_intr,	   bus_generic_setup_intr),
18268c582c7cSDexuan Cui 	DEVMETHOD(bus_teardown_intr,	   bus_generic_teardown_intr),
18278c582c7cSDexuan Cui #if __FreeBSD_version >= 1100000
18288c582c7cSDexuan Cui 	DEVMETHOD(bus_get_cpus,			vmbus_pcib_get_cpus),
18298c582c7cSDexuan Cui #endif
18308c582c7cSDexuan Cui 
18318c582c7cSDexuan Cui 	/* pcib interface */
18328c582c7cSDexuan Cui 	DEVMETHOD(pcib_maxslots,		pcib_maxslots),
18338c582c7cSDexuan Cui 	DEVMETHOD(pcib_read_config,		vmbus_pcib_read_config),
18348c582c7cSDexuan Cui 	DEVMETHOD(pcib_write_config,		vmbus_pcib_write_config),
18358c582c7cSDexuan Cui 	DEVMETHOD(pcib_route_interrupt,		vmbus_pcib_route_intr),
18368c582c7cSDexuan Cui 	DEVMETHOD(pcib_alloc_msi,		vmbus_pcib_alloc_msi),
18378c582c7cSDexuan Cui 	DEVMETHOD(pcib_release_msi,		vmbus_pcib_release_msi),
18388c582c7cSDexuan Cui 	DEVMETHOD(pcib_alloc_msix,		vmbus_pcib_alloc_msix),
18398c582c7cSDexuan Cui 	DEVMETHOD(pcib_release_msix,		vmbus_pcib_release_msix),
18408c582c7cSDexuan Cui 	DEVMETHOD(pcib_map_msi,			vmbus_pcib_map_msi),
184128586889SWarner Losh 	DEVMETHOD(pcib_request_feature,		pcib_request_feature_allow),
18428c582c7cSDexuan Cui 
18438c582c7cSDexuan Cui 	DEVMETHOD_END
18448c582c7cSDexuan Cui };
18458c582c7cSDexuan Cui 
18468c582c7cSDexuan Cui static devclass_t pcib_devclass;
18478c582c7cSDexuan Cui 
18488c582c7cSDexuan Cui DEFINE_CLASS_0(pcib, vmbus_pcib_driver, vmbus_pcib_methods,
18498c582c7cSDexuan Cui 		sizeof(struct vmbus_pcib_softc));
18508c582c7cSDexuan Cui DRIVER_MODULE(vmbus_pcib, vmbus, vmbus_pcib_driver, pcib_devclass, 0, 0);
18518c582c7cSDexuan Cui MODULE_DEPEND(vmbus_pcib, vmbus, 1, 1, 1);
18528c582c7cSDexuan Cui MODULE_DEPEND(vmbus_pcib, pci, 1, 1, 1);
1853cdb316eeSDexuan Cui 
1854cdb316eeSDexuan Cui #endif /* NEW_PCIB */
1855