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 = &comp;
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