18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) Microsoft Corporation.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author:
68c2ecf20Sopenharmony_ci *   Jake Oshins <jakeo@microsoft.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This driver acts as a paravirtual front-end for PCI Express root buses.
98c2ecf20Sopenharmony_ci * When a PCI Express function (either an entire device or an SR-IOV
108c2ecf20Sopenharmony_ci * Virtual Function) is being passed through to the VM, this driver exposes
118c2ecf20Sopenharmony_ci * a new bus to the guest VM.  This is modeled as a root PCI bus because
128c2ecf20Sopenharmony_ci * no bridges are being exposed to the VM.  In fact, with a "Generation 2"
138c2ecf20Sopenharmony_ci * VM within Hyper-V, there may seem to be no PCI bus at all in the VM
148c2ecf20Sopenharmony_ci * until a device as been exposed using this driver.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Each root PCI bus has its own PCI domain, which is called "Segment" in
178c2ecf20Sopenharmony_ci * the PCI Firmware Specifications.  Thus while each device passed through
188c2ecf20Sopenharmony_ci * to the VM using this front-end will appear at "device 0", the domain will
198c2ecf20Sopenharmony_ci * be unique.  Typically, each bus will have one PCI function on it, though
208c2ecf20Sopenharmony_ci * this driver does support more than one.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * In order to map the interrupts from the device through to the guest VM,
238c2ecf20Sopenharmony_ci * this driver also implements an IRQ Domain, which handles interrupts (either
248c2ecf20Sopenharmony_ci * MSI or MSI-X) associated with the functions on the bus.  As interrupts are
258c2ecf20Sopenharmony_ci * set up, torn down, or reaffined, this driver communicates with the
268c2ecf20Sopenharmony_ci * underlying hypervisor to adjust the mappings in the I/O MMU so that each
278c2ecf20Sopenharmony_ci * interrupt will be delivered to the correct virtual processor at the right
288c2ecf20Sopenharmony_ci * vector.  This driver does not support level-triggered (line-based)
298c2ecf20Sopenharmony_ci * interrupts, and will report that the Interrupt Line register in the
308c2ecf20Sopenharmony_ci * function's configuration space is zero.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * The rest of this driver mostly maps PCI concepts onto underlying Hyper-V
338c2ecf20Sopenharmony_ci * facilities.  For instance, the configuration space of a function exposed
348c2ecf20Sopenharmony_ci * by Hyper-V is mapped into a single page of memory space, and the
358c2ecf20Sopenharmony_ci * read and write handlers for config space must be aware of this mechanism.
368c2ecf20Sopenharmony_ci * Similarly, device setup and teardown involves messages sent to and from
378c2ecf20Sopenharmony_ci * the PCI back-end driver in Hyper-V.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <linux/kernel.h>
418c2ecf20Sopenharmony_ci#include <linux/module.h>
428c2ecf20Sopenharmony_ci#include <linux/pci.h>
438c2ecf20Sopenharmony_ci#include <linux/delay.h>
448c2ecf20Sopenharmony_ci#include <linux/semaphore.h>
458c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
468c2ecf20Sopenharmony_ci#include <asm/irqdomain.h>
478c2ecf20Sopenharmony_ci#include <asm/apic.h>
488c2ecf20Sopenharmony_ci#include <linux/irq.h>
498c2ecf20Sopenharmony_ci#include <linux/msi.h>
508c2ecf20Sopenharmony_ci#include <linux/hyperv.h>
518c2ecf20Sopenharmony_ci#include <linux/refcount.h>
528c2ecf20Sopenharmony_ci#include <asm/mshyperv.h>
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * Protocol versions. The low word is the minor version, the high word the
568c2ecf20Sopenharmony_ci * major version.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define PCI_MAKE_VERSION(major, minor) ((u32)(((major) << 16) | (minor)))
608c2ecf20Sopenharmony_ci#define PCI_MAJOR_VERSION(version) ((u32)(version) >> 16)
618c2ecf20Sopenharmony_ci#define PCI_MINOR_VERSION(version) ((u32)(version) & 0xff)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cienum pci_protocol_version_t {
648c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1),	/* Win10 */
658c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_2 = PCI_MAKE_VERSION(1, 2),	/* RS1 */
668c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_3 = PCI_MAKE_VERSION(1, 3),	/* Vibranium */
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define CPU_AFFINITY_ALL	-1ULL
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * Supported protocol versions in the order of probing - highest go
738c2ecf20Sopenharmony_ci * first.
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic enum pci_protocol_version_t pci_protocol_versions[] = {
768c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_3,
778c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_2,
788c2ecf20Sopenharmony_ci	PCI_PROTOCOL_VERSION_1_1,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define PCI_CONFIG_MMIO_LENGTH	0x2000
828c2ecf20Sopenharmony_ci#define CFG_PAGE_OFFSET 0x1000
838c2ecf20Sopenharmony_ci#define CFG_PAGE_SIZE (PCI_CONFIG_MMIO_LENGTH - CFG_PAGE_OFFSET)
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define MAX_SUPPORTED_MSI_MESSAGES 0x400
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define STATUS_REVISION_MISMATCH 0xC0000059
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* space for 32bit serial number as string */
908c2ecf20Sopenharmony_ci#define SLOT_NAME_SIZE 11
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * Message Types
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cienum pci_message_type {
978c2ecf20Sopenharmony_ci	/*
988c2ecf20Sopenharmony_ci	 * Version 1.1
998c2ecf20Sopenharmony_ci	 */
1008c2ecf20Sopenharmony_ci	PCI_MESSAGE_BASE                = 0x42490000,
1018c2ecf20Sopenharmony_ci	PCI_BUS_RELATIONS               = PCI_MESSAGE_BASE + 0,
1028c2ecf20Sopenharmony_ci	PCI_QUERY_BUS_RELATIONS         = PCI_MESSAGE_BASE + 1,
1038c2ecf20Sopenharmony_ci	PCI_POWER_STATE_CHANGE          = PCI_MESSAGE_BASE + 4,
1048c2ecf20Sopenharmony_ci	PCI_QUERY_RESOURCE_REQUIREMENTS = PCI_MESSAGE_BASE + 5,
1058c2ecf20Sopenharmony_ci	PCI_QUERY_RESOURCE_RESOURCES    = PCI_MESSAGE_BASE + 6,
1068c2ecf20Sopenharmony_ci	PCI_BUS_D0ENTRY                 = PCI_MESSAGE_BASE + 7,
1078c2ecf20Sopenharmony_ci	PCI_BUS_D0EXIT                  = PCI_MESSAGE_BASE + 8,
1088c2ecf20Sopenharmony_ci	PCI_READ_BLOCK                  = PCI_MESSAGE_BASE + 9,
1098c2ecf20Sopenharmony_ci	PCI_WRITE_BLOCK                 = PCI_MESSAGE_BASE + 0xA,
1108c2ecf20Sopenharmony_ci	PCI_EJECT                       = PCI_MESSAGE_BASE + 0xB,
1118c2ecf20Sopenharmony_ci	PCI_QUERY_STOP                  = PCI_MESSAGE_BASE + 0xC,
1128c2ecf20Sopenharmony_ci	PCI_REENABLE                    = PCI_MESSAGE_BASE + 0xD,
1138c2ecf20Sopenharmony_ci	PCI_QUERY_STOP_FAILED           = PCI_MESSAGE_BASE + 0xE,
1148c2ecf20Sopenharmony_ci	PCI_EJECTION_COMPLETE           = PCI_MESSAGE_BASE + 0xF,
1158c2ecf20Sopenharmony_ci	PCI_RESOURCES_ASSIGNED          = PCI_MESSAGE_BASE + 0x10,
1168c2ecf20Sopenharmony_ci	PCI_RESOURCES_RELEASED          = PCI_MESSAGE_BASE + 0x11,
1178c2ecf20Sopenharmony_ci	PCI_INVALIDATE_BLOCK            = PCI_MESSAGE_BASE + 0x12,
1188c2ecf20Sopenharmony_ci	PCI_QUERY_PROTOCOL_VERSION      = PCI_MESSAGE_BASE + 0x13,
1198c2ecf20Sopenharmony_ci	PCI_CREATE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x14,
1208c2ecf20Sopenharmony_ci	PCI_DELETE_INTERRUPT_MESSAGE    = PCI_MESSAGE_BASE + 0x15,
1218c2ecf20Sopenharmony_ci	PCI_RESOURCES_ASSIGNED2		= PCI_MESSAGE_BASE + 0x16,
1228c2ecf20Sopenharmony_ci	PCI_CREATE_INTERRUPT_MESSAGE2	= PCI_MESSAGE_BASE + 0x17,
1238c2ecf20Sopenharmony_ci	PCI_DELETE_INTERRUPT_MESSAGE2	= PCI_MESSAGE_BASE + 0x18, /* unused */
1248c2ecf20Sopenharmony_ci	PCI_BUS_RELATIONS2		= PCI_MESSAGE_BASE + 0x19,
1258c2ecf20Sopenharmony_ci	PCI_MESSAGE_MAXIMUM
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*
1298c2ecf20Sopenharmony_ci * Structures defining the virtual PCI Express protocol.
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciunion pci_version {
1338c2ecf20Sopenharmony_ci	struct {
1348c2ecf20Sopenharmony_ci		u16 minor_version;
1358c2ecf20Sopenharmony_ci		u16 major_version;
1368c2ecf20Sopenharmony_ci	} parts;
1378c2ecf20Sopenharmony_ci	u32 version;
1388c2ecf20Sopenharmony_ci} __packed;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/*
1418c2ecf20Sopenharmony_ci * Function numbers are 8-bits wide on Express, as interpreted through ARI,
1428c2ecf20Sopenharmony_ci * which is all this driver does.  This representation is the one used in
1438c2ecf20Sopenharmony_ci * Windows, which is what is expected when sending this back and forth with
1448c2ecf20Sopenharmony_ci * the Hyper-V parent partition.
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_ciunion win_slot_encoding {
1478c2ecf20Sopenharmony_ci	struct {
1488c2ecf20Sopenharmony_ci		u32	dev:5;
1498c2ecf20Sopenharmony_ci		u32	func:3;
1508c2ecf20Sopenharmony_ci		u32	reserved:24;
1518c2ecf20Sopenharmony_ci	} bits;
1528c2ecf20Sopenharmony_ci	u32 slot;
1538c2ecf20Sopenharmony_ci} __packed;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*
1568c2ecf20Sopenharmony_ci * Pretty much as defined in the PCI Specifications.
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cistruct pci_function_description {
1598c2ecf20Sopenharmony_ci	u16	v_id;	/* vendor ID */
1608c2ecf20Sopenharmony_ci	u16	d_id;	/* device ID */
1618c2ecf20Sopenharmony_ci	u8	rev;
1628c2ecf20Sopenharmony_ci	u8	prog_intf;
1638c2ecf20Sopenharmony_ci	u8	subclass;
1648c2ecf20Sopenharmony_ci	u8	base_class;
1658c2ecf20Sopenharmony_ci	u32	subsystem_id;
1668c2ecf20Sopenharmony_ci	union win_slot_encoding win_slot;
1678c2ecf20Sopenharmony_ci	u32	ser;	/* serial number */
1688c2ecf20Sopenharmony_ci} __packed;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cienum pci_device_description_flags {
1718c2ecf20Sopenharmony_ci	HV_PCI_DEVICE_FLAG_NONE			= 0x0,
1728c2ecf20Sopenharmony_ci	HV_PCI_DEVICE_FLAG_NUMA_AFFINITY	= 0x1,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistruct pci_function_description2 {
1768c2ecf20Sopenharmony_ci	u16	v_id;	/* vendor ID */
1778c2ecf20Sopenharmony_ci	u16	d_id;	/* device ID */
1788c2ecf20Sopenharmony_ci	u8	rev;
1798c2ecf20Sopenharmony_ci	u8	prog_intf;
1808c2ecf20Sopenharmony_ci	u8	subclass;
1818c2ecf20Sopenharmony_ci	u8	base_class;
1828c2ecf20Sopenharmony_ci	u32	subsystem_id;
1838c2ecf20Sopenharmony_ci	union	win_slot_encoding win_slot;
1848c2ecf20Sopenharmony_ci	u32	ser;	/* serial number */
1858c2ecf20Sopenharmony_ci	u32	flags;
1868c2ecf20Sopenharmony_ci	u16	virtual_numa_node;
1878c2ecf20Sopenharmony_ci	u16	reserved;
1888c2ecf20Sopenharmony_ci} __packed;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/**
1918c2ecf20Sopenharmony_ci * struct hv_msi_desc
1928c2ecf20Sopenharmony_ci * @vector:		IDT entry
1938c2ecf20Sopenharmony_ci * @delivery_mode:	As defined in Intel's Programmer's
1948c2ecf20Sopenharmony_ci *			Reference Manual, Volume 3, Chapter 8.
1958c2ecf20Sopenharmony_ci * @vector_count:	Number of contiguous entries in the
1968c2ecf20Sopenharmony_ci *			Interrupt Descriptor Table that are
1978c2ecf20Sopenharmony_ci *			occupied by this Message-Signaled
1988c2ecf20Sopenharmony_ci *			Interrupt. For "MSI", as first defined
1998c2ecf20Sopenharmony_ci *			in PCI 2.2, this can be between 1 and
2008c2ecf20Sopenharmony_ci *			32. For "MSI-X," as first defined in PCI
2018c2ecf20Sopenharmony_ci *			3.0, this must be 1, as each MSI-X table
2028c2ecf20Sopenharmony_ci *			entry would have its own descriptor.
2038c2ecf20Sopenharmony_ci * @reserved:		Empty space
2048c2ecf20Sopenharmony_ci * @cpu_mask:		All the target virtual processors.
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_cistruct hv_msi_desc {
2078c2ecf20Sopenharmony_ci	u8	vector;
2088c2ecf20Sopenharmony_ci	u8	delivery_mode;
2098c2ecf20Sopenharmony_ci	u16	vector_count;
2108c2ecf20Sopenharmony_ci	u32	reserved;
2118c2ecf20Sopenharmony_ci	u64	cpu_mask;
2128c2ecf20Sopenharmony_ci} __packed;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * struct hv_msi_desc2 - 1.2 version of hv_msi_desc
2168c2ecf20Sopenharmony_ci * @vector:		IDT entry
2178c2ecf20Sopenharmony_ci * @delivery_mode:	As defined in Intel's Programmer's
2188c2ecf20Sopenharmony_ci *			Reference Manual, Volume 3, Chapter 8.
2198c2ecf20Sopenharmony_ci * @vector_count:	Number of contiguous entries in the
2208c2ecf20Sopenharmony_ci *			Interrupt Descriptor Table that are
2218c2ecf20Sopenharmony_ci *			occupied by this Message-Signaled
2228c2ecf20Sopenharmony_ci *			Interrupt. For "MSI", as first defined
2238c2ecf20Sopenharmony_ci *			in PCI 2.2, this can be between 1 and
2248c2ecf20Sopenharmony_ci *			32. For "MSI-X," as first defined in PCI
2258c2ecf20Sopenharmony_ci *			3.0, this must be 1, as each MSI-X table
2268c2ecf20Sopenharmony_ci *			entry would have its own descriptor.
2278c2ecf20Sopenharmony_ci * @processor_count:	number of bits enabled in array.
2288c2ecf20Sopenharmony_ci * @processor_array:	All the target virtual processors.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_cistruct hv_msi_desc2 {
2318c2ecf20Sopenharmony_ci	u8	vector;
2328c2ecf20Sopenharmony_ci	u8	delivery_mode;
2338c2ecf20Sopenharmony_ci	u16	vector_count;
2348c2ecf20Sopenharmony_ci	u16	processor_count;
2358c2ecf20Sopenharmony_ci	u16	processor_array[32];
2368c2ecf20Sopenharmony_ci} __packed;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/**
2398c2ecf20Sopenharmony_ci * struct tran_int_desc
2408c2ecf20Sopenharmony_ci * @reserved:		unused, padding
2418c2ecf20Sopenharmony_ci * @vector_count:	same as in hv_msi_desc
2428c2ecf20Sopenharmony_ci * @data:		This is the "data payload" value that is
2438c2ecf20Sopenharmony_ci *			written by the device when it generates
2448c2ecf20Sopenharmony_ci *			a message-signaled interrupt, either MSI
2458c2ecf20Sopenharmony_ci *			or MSI-X.
2468c2ecf20Sopenharmony_ci * @address:		This is the address to which the data
2478c2ecf20Sopenharmony_ci *			payload is written on interrupt
2488c2ecf20Sopenharmony_ci *			generation.
2498c2ecf20Sopenharmony_ci */
2508c2ecf20Sopenharmony_cistruct tran_int_desc {
2518c2ecf20Sopenharmony_ci	u16	reserved;
2528c2ecf20Sopenharmony_ci	u16	vector_count;
2538c2ecf20Sopenharmony_ci	u32	data;
2548c2ecf20Sopenharmony_ci	u64	address;
2558c2ecf20Sopenharmony_ci} __packed;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/*
2588c2ecf20Sopenharmony_ci * A generic message format for virtual PCI.
2598c2ecf20Sopenharmony_ci * Specific message formats are defined later in the file.
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistruct pci_message {
2638c2ecf20Sopenharmony_ci	u32 type;
2648c2ecf20Sopenharmony_ci} __packed;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistruct pci_child_message {
2678c2ecf20Sopenharmony_ci	struct pci_message message_type;
2688c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
2698c2ecf20Sopenharmony_ci} __packed;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistruct pci_incoming_message {
2728c2ecf20Sopenharmony_ci	struct vmpacket_descriptor hdr;
2738c2ecf20Sopenharmony_ci	struct pci_message message_type;
2748c2ecf20Sopenharmony_ci} __packed;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistruct pci_response {
2778c2ecf20Sopenharmony_ci	struct vmpacket_descriptor hdr;
2788c2ecf20Sopenharmony_ci	s32 status;			/* negative values are failures */
2798c2ecf20Sopenharmony_ci} __packed;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistruct pci_packet {
2828c2ecf20Sopenharmony_ci	void (*completion_func)(void *context, struct pci_response *resp,
2838c2ecf20Sopenharmony_ci				int resp_packet_size);
2848c2ecf20Sopenharmony_ci	void *compl_ctxt;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	struct pci_message message[];
2878c2ecf20Sopenharmony_ci};
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/*
2908c2ecf20Sopenharmony_ci * Specific message types supporting the PCI protocol.
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/*
2948c2ecf20Sopenharmony_ci * Version negotiation message. Sent from the guest to the host.
2958c2ecf20Sopenharmony_ci * The guest is free to try different versions until the host
2968c2ecf20Sopenharmony_ci * accepts the version.
2978c2ecf20Sopenharmony_ci *
2988c2ecf20Sopenharmony_ci * pci_version: The protocol version requested.
2998c2ecf20Sopenharmony_ci * is_last_attempt: If TRUE, this is the last version guest will request.
3008c2ecf20Sopenharmony_ci * reservedz: Reserved field, set to zero.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistruct pci_version_request {
3048c2ecf20Sopenharmony_ci	struct pci_message message_type;
3058c2ecf20Sopenharmony_ci	u32 protocol_version;
3068c2ecf20Sopenharmony_ci} __packed;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/*
3098c2ecf20Sopenharmony_ci * Bus D0 Entry.  This is sent from the guest to the host when the virtual
3108c2ecf20Sopenharmony_ci * bus (PCI Express port) is ready for action.
3118c2ecf20Sopenharmony_ci */
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistruct pci_bus_d0_entry {
3148c2ecf20Sopenharmony_ci	struct pci_message message_type;
3158c2ecf20Sopenharmony_ci	u32 reserved;
3168c2ecf20Sopenharmony_ci	u64 mmio_base;
3178c2ecf20Sopenharmony_ci} __packed;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistruct pci_bus_relations {
3208c2ecf20Sopenharmony_ci	struct pci_incoming_message incoming;
3218c2ecf20Sopenharmony_ci	u32 device_count;
3228c2ecf20Sopenharmony_ci	struct pci_function_description func[];
3238c2ecf20Sopenharmony_ci} __packed;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistruct pci_bus_relations2 {
3268c2ecf20Sopenharmony_ci	struct pci_incoming_message incoming;
3278c2ecf20Sopenharmony_ci	u32 device_count;
3288c2ecf20Sopenharmony_ci	struct pci_function_description2 func[];
3298c2ecf20Sopenharmony_ci} __packed;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistruct pci_q_res_req_response {
3328c2ecf20Sopenharmony_ci	struct vmpacket_descriptor hdr;
3338c2ecf20Sopenharmony_ci	s32 status;			/* negative values are failures */
3348c2ecf20Sopenharmony_ci	u32 probed_bar[PCI_STD_NUM_BARS];
3358c2ecf20Sopenharmony_ci} __packed;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistruct pci_set_power {
3388c2ecf20Sopenharmony_ci	struct pci_message message_type;
3398c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3408c2ecf20Sopenharmony_ci	u32 power_state;		/* In Windows terms */
3418c2ecf20Sopenharmony_ci	u32 reserved;
3428c2ecf20Sopenharmony_ci} __packed;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistruct pci_set_power_response {
3458c2ecf20Sopenharmony_ci	struct vmpacket_descriptor hdr;
3468c2ecf20Sopenharmony_ci	s32 status;			/* negative values are failures */
3478c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3488c2ecf20Sopenharmony_ci	u32 resultant_state;		/* In Windows terms */
3498c2ecf20Sopenharmony_ci	u32 reserved;
3508c2ecf20Sopenharmony_ci} __packed;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistruct pci_resources_assigned {
3538c2ecf20Sopenharmony_ci	struct pci_message message_type;
3548c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3558c2ecf20Sopenharmony_ci	u8 memory_range[0x14][6];	/* not used here */
3568c2ecf20Sopenharmony_ci	u32 msi_descriptors;
3578c2ecf20Sopenharmony_ci	u32 reserved[4];
3588c2ecf20Sopenharmony_ci} __packed;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistruct pci_resources_assigned2 {
3618c2ecf20Sopenharmony_ci	struct pci_message message_type;
3628c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3638c2ecf20Sopenharmony_ci	u8 memory_range[0x14][6];	/* not used here */
3648c2ecf20Sopenharmony_ci	u32 msi_descriptor_count;
3658c2ecf20Sopenharmony_ci	u8 reserved[70];
3668c2ecf20Sopenharmony_ci} __packed;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistruct pci_create_interrupt {
3698c2ecf20Sopenharmony_ci	struct pci_message message_type;
3708c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3718c2ecf20Sopenharmony_ci	struct hv_msi_desc int_desc;
3728c2ecf20Sopenharmony_ci} __packed;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistruct pci_create_int_response {
3758c2ecf20Sopenharmony_ci	struct pci_response response;
3768c2ecf20Sopenharmony_ci	u32 reserved;
3778c2ecf20Sopenharmony_ci	struct tran_int_desc int_desc;
3788c2ecf20Sopenharmony_ci} __packed;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistruct pci_create_interrupt2 {
3818c2ecf20Sopenharmony_ci	struct pci_message message_type;
3828c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3838c2ecf20Sopenharmony_ci	struct hv_msi_desc2 int_desc;
3848c2ecf20Sopenharmony_ci} __packed;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistruct pci_delete_interrupt {
3878c2ecf20Sopenharmony_ci	struct pci_message message_type;
3888c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3898c2ecf20Sopenharmony_ci	struct tran_int_desc int_desc;
3908c2ecf20Sopenharmony_ci} __packed;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/*
3938c2ecf20Sopenharmony_ci * Note: the VM must pass a valid block id, wslot and bytes_requested.
3948c2ecf20Sopenharmony_ci */
3958c2ecf20Sopenharmony_cistruct pci_read_block {
3968c2ecf20Sopenharmony_ci	struct pci_message message_type;
3978c2ecf20Sopenharmony_ci	u32 block_id;
3988c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
3998c2ecf20Sopenharmony_ci	u32 bytes_requested;
4008c2ecf20Sopenharmony_ci} __packed;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistruct pci_read_block_response {
4038c2ecf20Sopenharmony_ci	struct vmpacket_descriptor hdr;
4048c2ecf20Sopenharmony_ci	u32 status;
4058c2ecf20Sopenharmony_ci	u8 bytes[HV_CONFIG_BLOCK_SIZE_MAX];
4068c2ecf20Sopenharmony_ci} __packed;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/*
4098c2ecf20Sopenharmony_ci * Note: the VM must pass a valid block id, wslot and byte_count.
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_cistruct pci_write_block {
4128c2ecf20Sopenharmony_ci	struct pci_message message_type;
4138c2ecf20Sopenharmony_ci	u32 block_id;
4148c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
4158c2ecf20Sopenharmony_ci	u32 byte_count;
4168c2ecf20Sopenharmony_ci	u8 bytes[HV_CONFIG_BLOCK_SIZE_MAX];
4178c2ecf20Sopenharmony_ci} __packed;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistruct pci_dev_inval_block {
4208c2ecf20Sopenharmony_ci	struct pci_incoming_message incoming;
4218c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
4228c2ecf20Sopenharmony_ci	u64 block_mask;
4238c2ecf20Sopenharmony_ci} __packed;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistruct pci_dev_incoming {
4268c2ecf20Sopenharmony_ci	struct pci_incoming_message incoming;
4278c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
4288c2ecf20Sopenharmony_ci} __packed;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistruct pci_eject_response {
4318c2ecf20Sopenharmony_ci	struct pci_message message_type;
4328c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
4338c2ecf20Sopenharmony_ci	u32 status;
4348c2ecf20Sopenharmony_ci} __packed;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int pci_ring_size = (4 * PAGE_SIZE);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/*
4398c2ecf20Sopenharmony_ci * Driver specific state.
4408c2ecf20Sopenharmony_ci */
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cienum hv_pcibus_state {
4438c2ecf20Sopenharmony_ci	hv_pcibus_init = 0,
4448c2ecf20Sopenharmony_ci	hv_pcibus_probed,
4458c2ecf20Sopenharmony_ci	hv_pcibus_installed,
4468c2ecf20Sopenharmony_ci	hv_pcibus_removing,
4478c2ecf20Sopenharmony_ci	hv_pcibus_maximum
4488c2ecf20Sopenharmony_ci};
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistruct hv_pcibus_device {
4518c2ecf20Sopenharmony_ci	struct pci_sysdata sysdata;
4528c2ecf20Sopenharmony_ci	/* Protocol version negotiated with the host */
4538c2ecf20Sopenharmony_ci	enum pci_protocol_version_t protocol_version;
4548c2ecf20Sopenharmony_ci	enum hv_pcibus_state state;
4558c2ecf20Sopenharmony_ci	refcount_t remove_lock;
4568c2ecf20Sopenharmony_ci	struct hv_device *hdev;
4578c2ecf20Sopenharmony_ci	resource_size_t low_mmio_space;
4588c2ecf20Sopenharmony_ci	resource_size_t high_mmio_space;
4598c2ecf20Sopenharmony_ci	struct resource *mem_config;
4608c2ecf20Sopenharmony_ci	struct resource *low_mmio_res;
4618c2ecf20Sopenharmony_ci	struct resource *high_mmio_res;
4628c2ecf20Sopenharmony_ci	struct completion *survey_event;
4638c2ecf20Sopenharmony_ci	struct completion remove_event;
4648c2ecf20Sopenharmony_ci	struct pci_bus *pci_bus;
4658c2ecf20Sopenharmony_ci	spinlock_t config_lock;	/* Avoid two threads writing index page */
4668c2ecf20Sopenharmony_ci	spinlock_t device_list_lock;	/* Protect lists below */
4678c2ecf20Sopenharmony_ci	void __iomem *cfg_addr;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	struct list_head resources_for_children;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	struct list_head children;
4728c2ecf20Sopenharmony_ci	struct list_head dr_list;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	struct msi_domain_info msi_info;
4758c2ecf20Sopenharmony_ci	struct msi_controller msi_chip;
4768c2ecf20Sopenharmony_ci	struct irq_domain *irq_domain;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	spinlock_t retarget_msi_interrupt_lock;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	struct workqueue_struct *wq;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/* Highest slot of child device with resources allocated */
4838c2ecf20Sopenharmony_ci	int wslot_res_allocated;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/* hypercall arg, must not cross page boundary */
4868c2ecf20Sopenharmony_ci	struct hv_retarget_device_interrupt retarget_msi_interrupt_params;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/*
4898c2ecf20Sopenharmony_ci	 * Don't put anything here: retarget_msi_interrupt_params must be last
4908c2ecf20Sopenharmony_ci	 */
4918c2ecf20Sopenharmony_ci};
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci/*
4948c2ecf20Sopenharmony_ci * Tracks "Device Relations" messages from the host, which must be both
4958c2ecf20Sopenharmony_ci * processed in order and deferred so that they don't run in the context
4968c2ecf20Sopenharmony_ci * of the incoming packet callback.
4978c2ecf20Sopenharmony_ci */
4988c2ecf20Sopenharmony_cistruct hv_dr_work {
4998c2ecf20Sopenharmony_ci	struct work_struct wrk;
5008c2ecf20Sopenharmony_ci	struct hv_pcibus_device *bus;
5018c2ecf20Sopenharmony_ci};
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistruct hv_pcidev_description {
5048c2ecf20Sopenharmony_ci	u16	v_id;	/* vendor ID */
5058c2ecf20Sopenharmony_ci	u16	d_id;	/* device ID */
5068c2ecf20Sopenharmony_ci	u8	rev;
5078c2ecf20Sopenharmony_ci	u8	prog_intf;
5088c2ecf20Sopenharmony_ci	u8	subclass;
5098c2ecf20Sopenharmony_ci	u8	base_class;
5108c2ecf20Sopenharmony_ci	u32	subsystem_id;
5118c2ecf20Sopenharmony_ci	union	win_slot_encoding win_slot;
5128c2ecf20Sopenharmony_ci	u32	ser;	/* serial number */
5138c2ecf20Sopenharmony_ci	u32	flags;
5148c2ecf20Sopenharmony_ci	u16	virtual_numa_node;
5158c2ecf20Sopenharmony_ci};
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistruct hv_dr_state {
5188c2ecf20Sopenharmony_ci	struct list_head list_entry;
5198c2ecf20Sopenharmony_ci	u32 device_count;
5208c2ecf20Sopenharmony_ci	struct hv_pcidev_description func[];
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistruct hv_pci_dev {
5248c2ecf20Sopenharmony_ci	/* List protected by pci_rescan_remove_lock */
5258c2ecf20Sopenharmony_ci	struct list_head list_entry;
5268c2ecf20Sopenharmony_ci	refcount_t refs;
5278c2ecf20Sopenharmony_ci	struct pci_slot *pci_slot;
5288c2ecf20Sopenharmony_ci	struct hv_pcidev_description desc;
5298c2ecf20Sopenharmony_ci	bool reported_missing;
5308c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
5318c2ecf20Sopenharmony_ci	struct work_struct wrk;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	void (*block_invalidate)(void *context, u64 block_mask);
5348c2ecf20Sopenharmony_ci	void *invalidate_context;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/*
5378c2ecf20Sopenharmony_ci	 * What would be observed if one wrote 0xFFFFFFFF to a BAR and then
5388c2ecf20Sopenharmony_ci	 * read it back, for each of the BAR offsets within config space.
5398c2ecf20Sopenharmony_ci	 */
5408c2ecf20Sopenharmony_ci	u32 probed_bar[PCI_STD_NUM_BARS];
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistruct hv_pci_compl {
5448c2ecf20Sopenharmony_ci	struct completion host_event;
5458c2ecf20Sopenharmony_ci	s32 completion_status;
5468c2ecf20Sopenharmony_ci};
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic void hv_pci_onchannelcallback(void *context);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci/**
5518c2ecf20Sopenharmony_ci * hv_pci_generic_compl() - Invoked for a completion packet
5528c2ecf20Sopenharmony_ci * @context:		Set up by the sender of the packet.
5538c2ecf20Sopenharmony_ci * @resp:		The response packet
5548c2ecf20Sopenharmony_ci * @resp_packet_size:	Size in bytes of the packet
5558c2ecf20Sopenharmony_ci *
5568c2ecf20Sopenharmony_ci * This function is used to trigger an event and report status
5578c2ecf20Sopenharmony_ci * for any message for which the completion packet contains a
5588c2ecf20Sopenharmony_ci * status and nothing else.
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_cistatic void hv_pci_generic_compl(void *context, struct pci_response *resp,
5618c2ecf20Sopenharmony_ci				 int resp_packet_size)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct hv_pci_compl *comp_pkt = context;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (resp_packet_size >= offsetofend(struct pci_response, status))
5668c2ecf20Sopenharmony_ci		comp_pkt->completion_status = resp->status;
5678c2ecf20Sopenharmony_ci	else
5688c2ecf20Sopenharmony_ci		comp_pkt->completion_status = -1;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	complete(&comp_pkt->host_event);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
5748c2ecf20Sopenharmony_ci						u32 wslot);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic void get_pcichild(struct hv_pci_dev *hpdev)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	refcount_inc(&hpdev->refs);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void put_pcichild(struct hv_pci_dev *hpdev)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&hpdev->refs))
5848c2ecf20Sopenharmony_ci		kfree(hpdev);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
5888c2ecf20Sopenharmony_cistatic void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci/*
5918c2ecf20Sopenharmony_ci * There is no good way to get notified from vmbus_onoffer_rescind(),
5928c2ecf20Sopenharmony_ci * so let's use polling here, since this is not a hot path.
5938c2ecf20Sopenharmony_ci */
5948c2ecf20Sopenharmony_cistatic int wait_for_response(struct hv_device *hdev,
5958c2ecf20Sopenharmony_ci			     struct completion *comp)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	while (true) {
5988c2ecf20Sopenharmony_ci		if (hdev->channel->rescind) {
5998c2ecf20Sopenharmony_ci			dev_warn_once(&hdev->device, "The device is gone.\n");
6008c2ecf20Sopenharmony_ci			return -ENODEV;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		if (wait_for_completion_timeout(comp, HZ / 10))
6048c2ecf20Sopenharmony_ci			break;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	return 0;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/**
6118c2ecf20Sopenharmony_ci * devfn_to_wslot() - Convert from Linux PCI slot to Windows
6128c2ecf20Sopenharmony_ci * @devfn:	The Linux representation of PCI slot
6138c2ecf20Sopenharmony_ci *
6148c2ecf20Sopenharmony_ci * Windows uses a slightly different representation of PCI slot.
6158c2ecf20Sopenharmony_ci *
6168c2ecf20Sopenharmony_ci * Return: The Windows representation
6178c2ecf20Sopenharmony_ci */
6188c2ecf20Sopenharmony_cistatic u32 devfn_to_wslot(int devfn)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	union win_slot_encoding wslot;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	wslot.slot = 0;
6238c2ecf20Sopenharmony_ci	wslot.bits.dev = PCI_SLOT(devfn);
6248c2ecf20Sopenharmony_ci	wslot.bits.func = PCI_FUNC(devfn);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return wslot.slot;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci/**
6308c2ecf20Sopenharmony_ci * wslot_to_devfn() - Convert from Windows PCI slot to Linux
6318c2ecf20Sopenharmony_ci * @wslot:	The Windows representation of PCI slot
6328c2ecf20Sopenharmony_ci *
6338c2ecf20Sopenharmony_ci * Windows uses a slightly different representation of PCI slot.
6348c2ecf20Sopenharmony_ci *
6358c2ecf20Sopenharmony_ci * Return: The Linux representation
6368c2ecf20Sopenharmony_ci */
6378c2ecf20Sopenharmony_cistatic int wslot_to_devfn(u32 wslot)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	union win_slot_encoding slot_no;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	slot_no.slot = wslot;
6428c2ecf20Sopenharmony_ci	return PCI_DEVFN(slot_no.bits.dev, slot_no.bits.func);
6438c2ecf20Sopenharmony_ci}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci/*
6468c2ecf20Sopenharmony_ci * PCI Configuration Space for these root PCI buses is implemented as a pair
6478c2ecf20Sopenharmony_ci * of pages in memory-mapped I/O space.  Writing to the first page chooses
6488c2ecf20Sopenharmony_ci * the PCI function being written or read.  Once the first page has been
6498c2ecf20Sopenharmony_ci * written to, the following page maps in the entire configuration space of
6508c2ecf20Sopenharmony_ci * the function.
6518c2ecf20Sopenharmony_ci */
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/**
6548c2ecf20Sopenharmony_ci * _hv_pcifront_read_config() - Internal PCI config read
6558c2ecf20Sopenharmony_ci * @hpdev:	The PCI driver's representation of the device
6568c2ecf20Sopenharmony_ci * @where:	Offset within config space
6578c2ecf20Sopenharmony_ci * @size:	Size of the transfer
6588c2ecf20Sopenharmony_ci * @val:	Pointer to the buffer receiving the data
6598c2ecf20Sopenharmony_ci */
6608c2ecf20Sopenharmony_cistatic void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where,
6618c2ecf20Sopenharmony_ci				     int size, u32 *val)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	unsigned long flags;
6648c2ecf20Sopenharmony_ci	void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/*
6678c2ecf20Sopenharmony_ci	 * If the attempt is to read the IDs or the ROM BAR, simulate that.
6688c2ecf20Sopenharmony_ci	 */
6698c2ecf20Sopenharmony_ci	if (where + size <= PCI_COMMAND) {
6708c2ecf20Sopenharmony_ci		memcpy(val, ((u8 *)&hpdev->desc.v_id) + where, size);
6718c2ecf20Sopenharmony_ci	} else if (where >= PCI_CLASS_REVISION && where + size <=
6728c2ecf20Sopenharmony_ci		   PCI_CACHE_LINE_SIZE) {
6738c2ecf20Sopenharmony_ci		memcpy(val, ((u8 *)&hpdev->desc.rev) + where -
6748c2ecf20Sopenharmony_ci		       PCI_CLASS_REVISION, size);
6758c2ecf20Sopenharmony_ci	} else if (where >= PCI_SUBSYSTEM_VENDOR_ID && where + size <=
6768c2ecf20Sopenharmony_ci		   PCI_ROM_ADDRESS) {
6778c2ecf20Sopenharmony_ci		memcpy(val, (u8 *)&hpdev->desc.subsystem_id + where -
6788c2ecf20Sopenharmony_ci		       PCI_SUBSYSTEM_VENDOR_ID, size);
6798c2ecf20Sopenharmony_ci	} else if (where >= PCI_ROM_ADDRESS && where + size <=
6808c2ecf20Sopenharmony_ci		   PCI_CAPABILITY_LIST) {
6818c2ecf20Sopenharmony_ci		/* ROM BARs are unimplemented */
6828c2ecf20Sopenharmony_ci		*val = 0;
6838c2ecf20Sopenharmony_ci	} else if (where >= PCI_INTERRUPT_LINE && where + size <=
6848c2ecf20Sopenharmony_ci		   PCI_INTERRUPT_PIN) {
6858c2ecf20Sopenharmony_ci		/*
6868c2ecf20Sopenharmony_ci		 * Interrupt Line and Interrupt PIN are hard-wired to zero
6878c2ecf20Sopenharmony_ci		 * because this front-end only supports message-signaled
6888c2ecf20Sopenharmony_ci		 * interrupts.
6898c2ecf20Sopenharmony_ci		 */
6908c2ecf20Sopenharmony_ci		*val = 0;
6918c2ecf20Sopenharmony_ci	} else if (where + size <= CFG_PAGE_SIZE) {
6928c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
6938c2ecf20Sopenharmony_ci		/* Choose the function to be read. (See comment above) */
6948c2ecf20Sopenharmony_ci		writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
6958c2ecf20Sopenharmony_ci		/* Make sure the function was chosen before we start reading. */
6968c2ecf20Sopenharmony_ci		mb();
6978c2ecf20Sopenharmony_ci		/* Read from that function's config space. */
6988c2ecf20Sopenharmony_ci		switch (size) {
6998c2ecf20Sopenharmony_ci		case 1:
7008c2ecf20Sopenharmony_ci			*val = readb(addr);
7018c2ecf20Sopenharmony_ci			break;
7028c2ecf20Sopenharmony_ci		case 2:
7038c2ecf20Sopenharmony_ci			*val = readw(addr);
7048c2ecf20Sopenharmony_ci			break;
7058c2ecf20Sopenharmony_ci		default:
7068c2ecf20Sopenharmony_ci			*val = readl(addr);
7078c2ecf20Sopenharmony_ci			break;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci		/*
7108c2ecf20Sopenharmony_ci		 * Make sure the read was done before we release the spinlock
7118c2ecf20Sopenharmony_ci		 * allowing consecutive reads/writes.
7128c2ecf20Sopenharmony_ci		 */
7138c2ecf20Sopenharmony_ci		mb();
7148c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
7158c2ecf20Sopenharmony_ci	} else {
7168c2ecf20Sopenharmony_ci		dev_err(&hpdev->hbus->hdev->device,
7178c2ecf20Sopenharmony_ci			"Attempt to read beyond a function's config space.\n");
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	u16 ret;
7248c2ecf20Sopenharmony_ci	unsigned long flags;
7258c2ecf20Sopenharmony_ci	void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET +
7268c2ecf20Sopenharmony_ci			     PCI_VENDOR_ID;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	/* Choose the function to be read. (See comment above) */
7318c2ecf20Sopenharmony_ci	writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
7328c2ecf20Sopenharmony_ci	/* Make sure the function was chosen before we start reading. */
7338c2ecf20Sopenharmony_ci	mb();
7348c2ecf20Sopenharmony_ci	/* Read from that function's config space. */
7358c2ecf20Sopenharmony_ci	ret = readw(addr);
7368c2ecf20Sopenharmony_ci	/*
7378c2ecf20Sopenharmony_ci	 * mb() is not required here, because the spin_unlock_irqrestore()
7388c2ecf20Sopenharmony_ci	 * is a barrier.
7398c2ecf20Sopenharmony_ci	 */
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	return ret;
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci/**
7478c2ecf20Sopenharmony_ci * _hv_pcifront_write_config() - Internal PCI config write
7488c2ecf20Sopenharmony_ci * @hpdev:	The PCI driver's representation of the device
7498c2ecf20Sopenharmony_ci * @where:	Offset within config space
7508c2ecf20Sopenharmony_ci * @size:	Size of the transfer
7518c2ecf20Sopenharmony_ci * @val:	The data being transferred
7528c2ecf20Sopenharmony_ci */
7538c2ecf20Sopenharmony_cistatic void _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where,
7548c2ecf20Sopenharmony_ci				      int size, u32 val)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	unsigned long flags;
7578c2ecf20Sopenharmony_ci	void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (where >= PCI_SUBSYSTEM_VENDOR_ID &&
7608c2ecf20Sopenharmony_ci	    where + size <= PCI_CAPABILITY_LIST) {
7618c2ecf20Sopenharmony_ci		/* SSIDs and ROM BARs are read-only */
7628c2ecf20Sopenharmony_ci	} else if (where >= PCI_COMMAND && where + size <= CFG_PAGE_SIZE) {
7638c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hpdev->hbus->config_lock, flags);
7648c2ecf20Sopenharmony_ci		/* Choose the function to be written. (See comment above) */
7658c2ecf20Sopenharmony_ci		writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr);
7668c2ecf20Sopenharmony_ci		/* Make sure the function was chosen before we start writing. */
7678c2ecf20Sopenharmony_ci		wmb();
7688c2ecf20Sopenharmony_ci		/* Write to that function's config space. */
7698c2ecf20Sopenharmony_ci		switch (size) {
7708c2ecf20Sopenharmony_ci		case 1:
7718c2ecf20Sopenharmony_ci			writeb(val, addr);
7728c2ecf20Sopenharmony_ci			break;
7738c2ecf20Sopenharmony_ci		case 2:
7748c2ecf20Sopenharmony_ci			writew(val, addr);
7758c2ecf20Sopenharmony_ci			break;
7768c2ecf20Sopenharmony_ci		default:
7778c2ecf20Sopenharmony_ci			writel(val, addr);
7788c2ecf20Sopenharmony_ci			break;
7798c2ecf20Sopenharmony_ci		}
7808c2ecf20Sopenharmony_ci		/*
7818c2ecf20Sopenharmony_ci		 * Make sure the write was done before we release the spinlock
7828c2ecf20Sopenharmony_ci		 * allowing consecutive reads/writes.
7838c2ecf20Sopenharmony_ci		 */
7848c2ecf20Sopenharmony_ci		mb();
7858c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags);
7868c2ecf20Sopenharmony_ci	} else {
7878c2ecf20Sopenharmony_ci		dev_err(&hpdev->hbus->hdev->device,
7888c2ecf20Sopenharmony_ci			"Attempt to write beyond a function's config space.\n");
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/**
7938c2ecf20Sopenharmony_ci * hv_pcifront_read_config() - Read configuration space
7948c2ecf20Sopenharmony_ci * @bus: PCI Bus structure
7958c2ecf20Sopenharmony_ci * @devfn: Device/function
7968c2ecf20Sopenharmony_ci * @where: Offset from base
7978c2ecf20Sopenharmony_ci * @size: Byte/word/dword
7988c2ecf20Sopenharmony_ci * @val: Value to be read
7998c2ecf20Sopenharmony_ci *
8008c2ecf20Sopenharmony_ci * Return: PCIBIOS_SUCCESSFUL on success
8018c2ecf20Sopenharmony_ci *	   PCIBIOS_DEVICE_NOT_FOUND on failure
8028c2ecf20Sopenharmony_ci */
8038c2ecf20Sopenharmony_cistatic int hv_pcifront_read_config(struct pci_bus *bus, unsigned int devfn,
8048c2ecf20Sopenharmony_ci				   int where, int size, u32 *val)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus =
8078c2ecf20Sopenharmony_ci		container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
8088c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
8118c2ecf20Sopenharmony_ci	if (!hpdev)
8128c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	_hv_pcifront_read_config(hpdev, where, size, val);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
8178c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci/**
8218c2ecf20Sopenharmony_ci * hv_pcifront_write_config() - Write configuration space
8228c2ecf20Sopenharmony_ci * @bus: PCI Bus structure
8238c2ecf20Sopenharmony_ci * @devfn: Device/function
8248c2ecf20Sopenharmony_ci * @where: Offset from base
8258c2ecf20Sopenharmony_ci * @size: Byte/word/dword
8268c2ecf20Sopenharmony_ci * @val: Value to be written to device
8278c2ecf20Sopenharmony_ci *
8288c2ecf20Sopenharmony_ci * Return: PCIBIOS_SUCCESSFUL on success
8298c2ecf20Sopenharmony_ci *	   PCIBIOS_DEVICE_NOT_FOUND on failure
8308c2ecf20Sopenharmony_ci */
8318c2ecf20Sopenharmony_cistatic int hv_pcifront_write_config(struct pci_bus *bus, unsigned int devfn,
8328c2ecf20Sopenharmony_ci				    int where, int size, u32 val)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus =
8358c2ecf20Sopenharmony_ci	    container_of(bus->sysdata, struct hv_pcibus_device, sysdata);
8368c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(devfn));
8398c2ecf20Sopenharmony_ci	if (!hpdev)
8408c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	_hv_pcifront_write_config(hpdev, where, size, val);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
8458c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci/* PCIe operations */
8498c2ecf20Sopenharmony_cistatic struct pci_ops hv_pcifront_ops = {
8508c2ecf20Sopenharmony_ci	.read  = hv_pcifront_read_config,
8518c2ecf20Sopenharmony_ci	.write = hv_pcifront_write_config,
8528c2ecf20Sopenharmony_ci};
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci/*
8558c2ecf20Sopenharmony_ci * Paravirtual backchannel
8568c2ecf20Sopenharmony_ci *
8578c2ecf20Sopenharmony_ci * Hyper-V SR-IOV provides a backchannel mechanism in software for
8588c2ecf20Sopenharmony_ci * communication between a VF driver and a PF driver.  These
8598c2ecf20Sopenharmony_ci * "configuration blocks" are similar in concept to PCI configuration space,
8608c2ecf20Sopenharmony_ci * but instead of doing reads and writes in 32-bit chunks through a very slow
8618c2ecf20Sopenharmony_ci * path, packets of up to 128 bytes can be sent or received asynchronously.
8628c2ecf20Sopenharmony_ci *
8638c2ecf20Sopenharmony_ci * Nearly every SR-IOV device contains just such a communications channel in
8648c2ecf20Sopenharmony_ci * hardware, so using this one in software is usually optional.  Using the
8658c2ecf20Sopenharmony_ci * software channel, however, allows driver implementers to leverage software
8668c2ecf20Sopenharmony_ci * tools that fuzz the communications channel looking for vulnerabilities.
8678c2ecf20Sopenharmony_ci *
8688c2ecf20Sopenharmony_ci * The usage model for these packets puts the responsibility for reading or
8698c2ecf20Sopenharmony_ci * writing on the VF driver.  The VF driver sends a read or a write packet,
8708c2ecf20Sopenharmony_ci * indicating which "block" is being referred to by number.
8718c2ecf20Sopenharmony_ci *
8728c2ecf20Sopenharmony_ci * If the PF driver wishes to initiate communication, it can "invalidate" one or
8738c2ecf20Sopenharmony_ci * more of the first 64 blocks.  This invalidation is delivered via a callback
8748c2ecf20Sopenharmony_ci * supplied by the VF driver by this driver.
8758c2ecf20Sopenharmony_ci *
8768c2ecf20Sopenharmony_ci * No protocol is implied, except that supplied by the PF and VF drivers.
8778c2ecf20Sopenharmony_ci */
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistruct hv_read_config_compl {
8808c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
8818c2ecf20Sopenharmony_ci	void *buf;
8828c2ecf20Sopenharmony_ci	unsigned int len;
8838c2ecf20Sopenharmony_ci	unsigned int bytes_returned;
8848c2ecf20Sopenharmony_ci};
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci/**
8878c2ecf20Sopenharmony_ci * hv_pci_read_config_compl() - Invoked when a response packet
8888c2ecf20Sopenharmony_ci * for a read config block operation arrives.
8898c2ecf20Sopenharmony_ci * @context:		Identifies the read config operation
8908c2ecf20Sopenharmony_ci * @resp:		The response packet itself
8918c2ecf20Sopenharmony_ci * @resp_packet_size:	Size in bytes of the response packet
8928c2ecf20Sopenharmony_ci */
8938c2ecf20Sopenharmony_cistatic void hv_pci_read_config_compl(void *context, struct pci_response *resp,
8948c2ecf20Sopenharmony_ci				     int resp_packet_size)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	struct hv_read_config_compl *comp = context;
8978c2ecf20Sopenharmony_ci	struct pci_read_block_response *read_resp =
8988c2ecf20Sopenharmony_ci		(struct pci_read_block_response *)resp;
8998c2ecf20Sopenharmony_ci	unsigned int data_len, hdr_len;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	hdr_len = offsetof(struct pci_read_block_response, bytes);
9028c2ecf20Sopenharmony_ci	if (resp_packet_size < hdr_len) {
9038c2ecf20Sopenharmony_ci		comp->comp_pkt.completion_status = -1;
9048c2ecf20Sopenharmony_ci		goto out;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	data_len = resp_packet_size - hdr_len;
9088c2ecf20Sopenharmony_ci	if (data_len > 0 && read_resp->status == 0) {
9098c2ecf20Sopenharmony_ci		comp->bytes_returned = min(comp->len, data_len);
9108c2ecf20Sopenharmony_ci		memcpy(comp->buf, read_resp->bytes, comp->bytes_returned);
9118c2ecf20Sopenharmony_ci	} else {
9128c2ecf20Sopenharmony_ci		comp->bytes_returned = 0;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	comp->comp_pkt.completion_status = read_resp->status;
9168c2ecf20Sopenharmony_ciout:
9178c2ecf20Sopenharmony_ci	complete(&comp->comp_pkt.host_event);
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci/**
9218c2ecf20Sopenharmony_ci * hv_read_config_block() - Sends a read config block request to
9228c2ecf20Sopenharmony_ci * the back-end driver running in the Hyper-V parent partition.
9238c2ecf20Sopenharmony_ci * @pdev:		The PCI driver's representation for this device.
9248c2ecf20Sopenharmony_ci * @buf:		Buffer into which the config block will be copied.
9258c2ecf20Sopenharmony_ci * @len:		Size in bytes of buf.
9268c2ecf20Sopenharmony_ci * @block_id:		Identifies the config block which has been requested.
9278c2ecf20Sopenharmony_ci * @bytes_returned:	Size which came back from the back-end driver.
9288c2ecf20Sopenharmony_ci *
9298c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
9308c2ecf20Sopenharmony_ci */
9318c2ecf20Sopenharmony_cistatic int hv_read_config_block(struct pci_dev *pdev, void *buf,
9328c2ecf20Sopenharmony_ci				unsigned int len, unsigned int block_id,
9338c2ecf20Sopenharmony_ci				unsigned int *bytes_returned)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus =
9368c2ecf20Sopenharmony_ci		container_of(pdev->bus->sysdata, struct hv_pcibus_device,
9378c2ecf20Sopenharmony_ci			     sysdata);
9388c2ecf20Sopenharmony_ci	struct {
9398c2ecf20Sopenharmony_ci		struct pci_packet pkt;
9408c2ecf20Sopenharmony_ci		char buf[sizeof(struct pci_read_block)];
9418c2ecf20Sopenharmony_ci	} pkt;
9428c2ecf20Sopenharmony_ci	struct hv_read_config_compl comp_pkt;
9438c2ecf20Sopenharmony_ci	struct pci_read_block *read_blk;
9448c2ecf20Sopenharmony_ci	int ret;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (len == 0 || len > HV_CONFIG_BLOCK_SIZE_MAX)
9478c2ecf20Sopenharmony_ci		return -EINVAL;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.comp_pkt.host_event);
9508c2ecf20Sopenharmony_ci	comp_pkt.buf = buf;
9518c2ecf20Sopenharmony_ci	comp_pkt.len = len;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	memset(&pkt, 0, sizeof(pkt));
9548c2ecf20Sopenharmony_ci	pkt.pkt.completion_func = hv_pci_read_config_compl;
9558c2ecf20Sopenharmony_ci	pkt.pkt.compl_ctxt = &comp_pkt;
9568c2ecf20Sopenharmony_ci	read_blk = (struct pci_read_block *)&pkt.pkt.message;
9578c2ecf20Sopenharmony_ci	read_blk->message_type.type = PCI_READ_BLOCK;
9588c2ecf20Sopenharmony_ci	read_blk->wslot.slot = devfn_to_wslot(pdev->devfn);
9598c2ecf20Sopenharmony_ci	read_blk->block_id = block_id;
9608c2ecf20Sopenharmony_ci	read_blk->bytes_requested = len;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hbus->hdev->channel, read_blk,
9638c2ecf20Sopenharmony_ci			       sizeof(*read_blk), (unsigned long)&pkt.pkt,
9648c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
9658c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
9668c2ecf20Sopenharmony_ci	if (ret)
9678c2ecf20Sopenharmony_ci		return ret;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ret = wait_for_response(hbus->hdev, &comp_pkt.comp_pkt.host_event);
9708c2ecf20Sopenharmony_ci	if (ret)
9718c2ecf20Sopenharmony_ci		return ret;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (comp_pkt.comp_pkt.completion_status != 0 ||
9748c2ecf20Sopenharmony_ci	    comp_pkt.bytes_returned == 0) {
9758c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
9768c2ecf20Sopenharmony_ci			"Read Config Block failed: 0x%x, bytes_returned=%d\n",
9778c2ecf20Sopenharmony_ci			comp_pkt.comp_pkt.completion_status,
9788c2ecf20Sopenharmony_ci			comp_pkt.bytes_returned);
9798c2ecf20Sopenharmony_ci		return -EIO;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	*bytes_returned = comp_pkt.bytes_returned;
9838c2ecf20Sopenharmony_ci	return 0;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci/**
9878c2ecf20Sopenharmony_ci * hv_pci_write_config_compl() - Invoked when a response packet for a write
9888c2ecf20Sopenharmony_ci * config block operation arrives.
9898c2ecf20Sopenharmony_ci * @context:		Identifies the write config operation
9908c2ecf20Sopenharmony_ci * @resp:		The response packet itself
9918c2ecf20Sopenharmony_ci * @resp_packet_size:	Size in bytes of the response packet
9928c2ecf20Sopenharmony_ci */
9938c2ecf20Sopenharmony_cistatic void hv_pci_write_config_compl(void *context, struct pci_response *resp,
9948c2ecf20Sopenharmony_ci				      int resp_packet_size)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct hv_pci_compl *comp_pkt = context;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	comp_pkt->completion_status = resp->status;
9998c2ecf20Sopenharmony_ci	complete(&comp_pkt->host_event);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci/**
10038c2ecf20Sopenharmony_ci * hv_write_config_block() - Sends a write config block request to the
10048c2ecf20Sopenharmony_ci * back-end driver running in the Hyper-V parent partition.
10058c2ecf20Sopenharmony_ci * @pdev:		The PCI driver's representation for this device.
10068c2ecf20Sopenharmony_ci * @buf:		Buffer from which the config block will	be copied.
10078c2ecf20Sopenharmony_ci * @len:		Size in bytes of buf.
10088c2ecf20Sopenharmony_ci * @block_id:		Identifies the config block which is being written.
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
10118c2ecf20Sopenharmony_ci */
10128c2ecf20Sopenharmony_cistatic int hv_write_config_block(struct pci_dev *pdev, void *buf,
10138c2ecf20Sopenharmony_ci				unsigned int len, unsigned int block_id)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus =
10168c2ecf20Sopenharmony_ci		container_of(pdev->bus->sysdata, struct hv_pcibus_device,
10178c2ecf20Sopenharmony_ci			     sysdata);
10188c2ecf20Sopenharmony_ci	struct {
10198c2ecf20Sopenharmony_ci		struct pci_packet pkt;
10208c2ecf20Sopenharmony_ci		char buf[sizeof(struct pci_write_block)];
10218c2ecf20Sopenharmony_ci		u32 reserved;
10228c2ecf20Sopenharmony_ci	} pkt;
10238c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
10248c2ecf20Sopenharmony_ci	struct pci_write_block *write_blk;
10258c2ecf20Sopenharmony_ci	u32 pkt_size;
10268c2ecf20Sopenharmony_ci	int ret;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if (len == 0 || len > HV_CONFIG_BLOCK_SIZE_MAX)
10298c2ecf20Sopenharmony_ci		return -EINVAL;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.host_event);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	memset(&pkt, 0, sizeof(pkt));
10348c2ecf20Sopenharmony_ci	pkt.pkt.completion_func = hv_pci_write_config_compl;
10358c2ecf20Sopenharmony_ci	pkt.pkt.compl_ctxt = &comp_pkt;
10368c2ecf20Sopenharmony_ci	write_blk = (struct pci_write_block *)&pkt.pkt.message;
10378c2ecf20Sopenharmony_ci	write_blk->message_type.type = PCI_WRITE_BLOCK;
10388c2ecf20Sopenharmony_ci	write_blk->wslot.slot = devfn_to_wslot(pdev->devfn);
10398c2ecf20Sopenharmony_ci	write_blk->block_id = block_id;
10408c2ecf20Sopenharmony_ci	write_blk->byte_count = len;
10418c2ecf20Sopenharmony_ci	memcpy(write_blk->bytes, buf, len);
10428c2ecf20Sopenharmony_ci	pkt_size = offsetof(struct pci_write_block, bytes) + len;
10438c2ecf20Sopenharmony_ci	/*
10448c2ecf20Sopenharmony_ci	 * This quirk is required on some hosts shipped around 2018, because
10458c2ecf20Sopenharmony_ci	 * these hosts don't check the pkt_size correctly (new hosts have been
10468c2ecf20Sopenharmony_ci	 * fixed since early 2019). The quirk is also safe on very old hosts
10478c2ecf20Sopenharmony_ci	 * and new hosts, because, on them, what really matters is the length
10488c2ecf20Sopenharmony_ci	 * specified in write_blk->byte_count.
10498c2ecf20Sopenharmony_ci	 */
10508c2ecf20Sopenharmony_ci	pkt_size += sizeof(pkt.reserved);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hbus->hdev->channel, write_blk, pkt_size,
10538c2ecf20Sopenharmony_ci			       (unsigned long)&pkt.pkt, VM_PKT_DATA_INBAND,
10548c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
10558c2ecf20Sopenharmony_ci	if (ret)
10568c2ecf20Sopenharmony_ci		return ret;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	ret = wait_for_response(hbus->hdev, &comp_pkt.host_event);
10598c2ecf20Sopenharmony_ci	if (ret)
10608c2ecf20Sopenharmony_ci		return ret;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if (comp_pkt.completion_status != 0) {
10638c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
10648c2ecf20Sopenharmony_ci			"Write Config Block failed: 0x%x\n",
10658c2ecf20Sopenharmony_ci			comp_pkt.completion_status);
10668c2ecf20Sopenharmony_ci		return -EIO;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	return 0;
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci/**
10738c2ecf20Sopenharmony_ci * hv_register_block_invalidate() - Invoked when a config block invalidation
10748c2ecf20Sopenharmony_ci * arrives from the back-end driver.
10758c2ecf20Sopenharmony_ci * @pdev:		The PCI driver's representation for this device.
10768c2ecf20Sopenharmony_ci * @context:		Identifies the device.
10778c2ecf20Sopenharmony_ci * @block_invalidate:	Identifies all of the blocks being invalidated.
10788c2ecf20Sopenharmony_ci *
10798c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
10808c2ecf20Sopenharmony_ci */
10818c2ecf20Sopenharmony_cistatic int hv_register_block_invalidate(struct pci_dev *pdev, void *context,
10828c2ecf20Sopenharmony_ci					void (*block_invalidate)(void *context,
10838c2ecf20Sopenharmony_ci								 u64 block_mask))
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus =
10868c2ecf20Sopenharmony_ci		container_of(pdev->bus->sysdata, struct hv_pcibus_device,
10878c2ecf20Sopenharmony_ci			     sysdata);
10888c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
10918c2ecf20Sopenharmony_ci	if (!hpdev)
10928c2ecf20Sopenharmony_ci		return -ENODEV;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	hpdev->block_invalidate = block_invalidate;
10958c2ecf20Sopenharmony_ci	hpdev->invalidate_context = context;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
10988c2ecf20Sopenharmony_ci	return 0;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci/* Interrupt management hooks */
11038c2ecf20Sopenharmony_cistatic void hv_int_desc_free(struct hv_pci_dev *hpdev,
11048c2ecf20Sopenharmony_ci			     struct tran_int_desc *int_desc)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	struct pci_delete_interrupt *int_pkt;
11078c2ecf20Sopenharmony_ci	struct {
11088c2ecf20Sopenharmony_ci		struct pci_packet pkt;
11098c2ecf20Sopenharmony_ci		u8 buffer[sizeof(struct pci_delete_interrupt)];
11108c2ecf20Sopenharmony_ci	} ctxt;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	if (!int_desc->vector_count) {
11138c2ecf20Sopenharmony_ci		kfree(int_desc);
11148c2ecf20Sopenharmony_ci		return;
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci	memset(&ctxt, 0, sizeof(ctxt));
11178c2ecf20Sopenharmony_ci	int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
11188c2ecf20Sopenharmony_ci	int_pkt->message_type.type =
11198c2ecf20Sopenharmony_ci		PCI_DELETE_INTERRUPT_MESSAGE;
11208c2ecf20Sopenharmony_ci	int_pkt->wslot.slot = hpdev->desc.win_slot.slot;
11218c2ecf20Sopenharmony_ci	int_pkt->int_desc = *int_desc;
11228c2ecf20Sopenharmony_ci	vmbus_sendpacket(hpdev->hbus->hdev->channel, int_pkt, sizeof(*int_pkt),
11238c2ecf20Sopenharmony_ci			 (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0);
11248c2ecf20Sopenharmony_ci	kfree(int_desc);
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci/**
11288c2ecf20Sopenharmony_ci * hv_msi_free() - Free the MSI.
11298c2ecf20Sopenharmony_ci * @domain:	The interrupt domain pointer
11308c2ecf20Sopenharmony_ci * @info:	Extra MSI-related context
11318c2ecf20Sopenharmony_ci * @irq:	Identifies the IRQ.
11328c2ecf20Sopenharmony_ci *
11338c2ecf20Sopenharmony_ci * The Hyper-V parent partition and hypervisor are tracking the
11348c2ecf20Sopenharmony_ci * messages that are in use, keeping the interrupt redirection
11358c2ecf20Sopenharmony_ci * table up to date.  This callback sends a message that frees
11368c2ecf20Sopenharmony_ci * the IRT entry and related tracking nonsense.
11378c2ecf20Sopenharmony_ci */
11388c2ecf20Sopenharmony_cistatic void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
11398c2ecf20Sopenharmony_ci			unsigned int irq)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
11428c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
11438c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
11448c2ecf20Sopenharmony_ci	struct tran_int_desc *int_desc;
11458c2ecf20Sopenharmony_ci	struct irq_data *irq_data = irq_domain_get_irq_data(domain, irq);
11468c2ecf20Sopenharmony_ci	struct msi_desc *msi = irq_data_get_msi_desc(irq_data);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	pdev = msi_desc_to_pci_dev(msi);
11498c2ecf20Sopenharmony_ci	hbus = info->data;
11508c2ecf20Sopenharmony_ci	int_desc = irq_data_get_irq_chip_data(irq_data);
11518c2ecf20Sopenharmony_ci	if (!int_desc)
11528c2ecf20Sopenharmony_ci		return;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	irq_data->chip_data = NULL;
11558c2ecf20Sopenharmony_ci	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
11568c2ecf20Sopenharmony_ci	if (!hpdev) {
11578c2ecf20Sopenharmony_ci		kfree(int_desc);
11588c2ecf20Sopenharmony_ci		return;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	hv_int_desc_free(hpdev, int_desc);
11628c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
11638c2ecf20Sopenharmony_ci}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_cistatic int hv_set_affinity(struct irq_data *data, const struct cpumask *dest,
11668c2ecf20Sopenharmony_ci			   bool force)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	struct irq_data *parent = data->parent_data;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	return parent->chip->irq_set_affinity(parent, dest, force);
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_cistatic void hv_irq_mask(struct irq_data *data)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	pci_msi_mask_irq(data);
11768c2ecf20Sopenharmony_ci}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_cistatic unsigned int hv_msi_get_int_vector(struct irq_data *data)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct irq_cfg *cfg = irqd_cfg(data);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	return cfg->vector;
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic int hv_msi_prepare(struct irq_domain *domain, struct device *dev,
11868c2ecf20Sopenharmony_ci			  int nvec, msi_alloc_info_t *info)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	int ret = pci_msi_prepare(domain, dev, nvec, info);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/*
11918c2ecf20Sopenharmony_ci	 * By using the interrupt remapper in the hypervisor IOMMU, contiguous
11928c2ecf20Sopenharmony_ci	 * CPU vectors is not needed for multi-MSI
11938c2ecf20Sopenharmony_ci	 */
11948c2ecf20Sopenharmony_ci	if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
11958c2ecf20Sopenharmony_ci		info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	return ret;
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci/**
12018c2ecf20Sopenharmony_ci * hv_irq_unmask() - "Unmask" the IRQ by setting its current
12028c2ecf20Sopenharmony_ci * affinity.
12038c2ecf20Sopenharmony_ci * @data:	Describes the IRQ
12048c2ecf20Sopenharmony_ci *
12058c2ecf20Sopenharmony_ci * Build new a destination for the MSI and make a hypercall to
12068c2ecf20Sopenharmony_ci * update the Interrupt Redirection Table. "Device Logical ID"
12078c2ecf20Sopenharmony_ci * is built out of this PCI bus's instance GUID and the function
12088c2ecf20Sopenharmony_ci * number of the device.
12098c2ecf20Sopenharmony_ci */
12108c2ecf20Sopenharmony_cistatic void hv_irq_unmask(struct irq_data *data)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
12138c2ecf20Sopenharmony_ci	struct irq_cfg *cfg = irqd_cfg(data);
12148c2ecf20Sopenharmony_ci	struct hv_retarget_device_interrupt *params;
12158c2ecf20Sopenharmony_ci	struct tran_int_desc *int_desc;
12168c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
12178c2ecf20Sopenharmony_ci	struct cpumask *dest;
12188c2ecf20Sopenharmony_ci	cpumask_var_t tmp;
12198c2ecf20Sopenharmony_ci	struct pci_bus *pbus;
12208c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
12218c2ecf20Sopenharmony_ci	unsigned long flags;
12228c2ecf20Sopenharmony_ci	u32 var_size = 0;
12238c2ecf20Sopenharmony_ci	int cpu, nr_bank;
12248c2ecf20Sopenharmony_ci	u64 res;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	dest = irq_data_get_effective_affinity_mask(data);
12278c2ecf20Sopenharmony_ci	pdev = msi_desc_to_pci_dev(msi_desc);
12288c2ecf20Sopenharmony_ci	pbus = pdev->bus;
12298c2ecf20Sopenharmony_ci	hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
12308c2ecf20Sopenharmony_ci	int_desc = data->chip_data;
12318c2ecf20Sopenharmony_ci	if (!int_desc) {
12328c2ecf20Sopenharmony_ci		dev_warn(&hbus->hdev->device, "%s() can not unmask irq %u\n",
12338c2ecf20Sopenharmony_ci			 __func__, data->irq);
12348c2ecf20Sopenharmony_ci		return;
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	params = &hbus->retarget_msi_interrupt_params;
12408c2ecf20Sopenharmony_ci	memset(params, 0, sizeof(*params));
12418c2ecf20Sopenharmony_ci	params->partition_id = HV_PARTITION_ID_SELF;
12428c2ecf20Sopenharmony_ci	params->int_entry.source = 1; /* MSI(-X) */
12438c2ecf20Sopenharmony_ci	params->int_entry.msi_entry.address = int_desc->address & 0xffffffff;
12448c2ecf20Sopenharmony_ci	params->int_entry.msi_entry.data = int_desc->data;
12458c2ecf20Sopenharmony_ci	params->device_id = (hbus->hdev->dev_instance.b[5] << 24) |
12468c2ecf20Sopenharmony_ci			   (hbus->hdev->dev_instance.b[4] << 16) |
12478c2ecf20Sopenharmony_ci			   (hbus->hdev->dev_instance.b[7] << 8) |
12488c2ecf20Sopenharmony_ci			   (hbus->hdev->dev_instance.b[6] & 0xf8) |
12498c2ecf20Sopenharmony_ci			   PCI_FUNC(pdev->devfn);
12508c2ecf20Sopenharmony_ci	params->int_target.vector = cfg->vector;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	/*
12538c2ecf20Sopenharmony_ci	 * Honoring apic->irq_delivery_mode set to dest_Fixed by
12548c2ecf20Sopenharmony_ci	 * setting the HV_DEVICE_INTERRUPT_TARGET_MULTICAST flag results in a
12558c2ecf20Sopenharmony_ci	 * spurious interrupt storm. Not doing so does not seem to have a
12568c2ecf20Sopenharmony_ci	 * negative effect (yet?).
12578c2ecf20Sopenharmony_ci	 */
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	if (hbus->protocol_version >= PCI_PROTOCOL_VERSION_1_2) {
12608c2ecf20Sopenharmony_ci		/*
12618c2ecf20Sopenharmony_ci		 * PCI_PROTOCOL_VERSION_1_2 supports the VP_SET version of the
12628c2ecf20Sopenharmony_ci		 * HVCALL_RETARGET_INTERRUPT hypercall, which also coincides
12638c2ecf20Sopenharmony_ci		 * with >64 VP support.
12648c2ecf20Sopenharmony_ci		 * ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED
12658c2ecf20Sopenharmony_ci		 * is not sufficient for this hypercall.
12668c2ecf20Sopenharmony_ci		 */
12678c2ecf20Sopenharmony_ci		params->int_target.flags |=
12688c2ecf20Sopenharmony_ci			HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		if (!alloc_cpumask_var(&tmp, GFP_ATOMIC)) {
12718c2ecf20Sopenharmony_ci			res = 1;
12728c2ecf20Sopenharmony_ci			goto exit_unlock;
12738c2ecf20Sopenharmony_ci		}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci		cpumask_and(tmp, dest, cpu_online_mask);
12768c2ecf20Sopenharmony_ci		nr_bank = cpumask_to_vpset(&params->int_target.vp_set, tmp);
12778c2ecf20Sopenharmony_ci		free_cpumask_var(tmp);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		if (nr_bank <= 0) {
12808c2ecf20Sopenharmony_ci			res = 1;
12818c2ecf20Sopenharmony_ci			goto exit_unlock;
12828c2ecf20Sopenharmony_ci		}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci		/*
12858c2ecf20Sopenharmony_ci		 * var-sized hypercall, var-size starts after vp_mask (thus
12868c2ecf20Sopenharmony_ci		 * vp_set.format does not count, but vp_set.valid_bank_mask
12878c2ecf20Sopenharmony_ci		 * does).
12888c2ecf20Sopenharmony_ci		 */
12898c2ecf20Sopenharmony_ci		var_size = 1 + nr_bank;
12908c2ecf20Sopenharmony_ci	} else {
12918c2ecf20Sopenharmony_ci		for_each_cpu_and(cpu, dest, cpu_online_mask) {
12928c2ecf20Sopenharmony_ci			params->int_target.vp_mask |=
12938c2ecf20Sopenharmony_ci				(1ULL << hv_cpu_number_to_vp_number(cpu));
12948c2ecf20Sopenharmony_ci		}
12958c2ecf20Sopenharmony_ci	}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	res = hv_do_hypercall(HVCALL_RETARGET_INTERRUPT | (var_size << 17),
12988c2ecf20Sopenharmony_ci			      params, NULL);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ciexit_unlock:
13018c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	/*
13048c2ecf20Sopenharmony_ci	 * During hibernation, when a CPU is offlined, the kernel tries
13058c2ecf20Sopenharmony_ci	 * to move the interrupt to the remaining CPUs that haven't
13068c2ecf20Sopenharmony_ci	 * been offlined yet. In this case, the below hv_do_hypercall()
13078c2ecf20Sopenharmony_ci	 * always fails since the vmbus channel has been closed:
13088c2ecf20Sopenharmony_ci	 * refer to cpu_disable_common() -> fixup_irqs() ->
13098c2ecf20Sopenharmony_ci	 * irq_migrate_all_off_this_cpu() -> migrate_one_irq().
13108c2ecf20Sopenharmony_ci	 *
13118c2ecf20Sopenharmony_ci	 * Suppress the error message for hibernation because the failure
13128c2ecf20Sopenharmony_ci	 * during hibernation does not matter (at this time all the devices
13138c2ecf20Sopenharmony_ci	 * have been frozen). Note: the correct affinity info is still updated
13148c2ecf20Sopenharmony_ci	 * into the irqdata data structure in migrate_one_irq() ->
13158c2ecf20Sopenharmony_ci	 * irq_do_set_affinity() -> hv_set_affinity(), so later when the VM
13168c2ecf20Sopenharmony_ci	 * resumes, hv_pci_restore_msi_state() is able to correctly restore
13178c2ecf20Sopenharmony_ci	 * the interrupt with the correct affinity.
13188c2ecf20Sopenharmony_ci	 */
13198c2ecf20Sopenharmony_ci	if (res && hbus->state != hv_pcibus_removing)
13208c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
13218c2ecf20Sopenharmony_ci			"%s() failed: %#llx", __func__, res);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	pci_msi_unmask_irq(data);
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistruct compose_comp_ctxt {
13278c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
13288c2ecf20Sopenharmony_ci	struct tran_int_desc int_desc;
13298c2ecf20Sopenharmony_ci};
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic void hv_pci_compose_compl(void *context, struct pci_response *resp,
13328c2ecf20Sopenharmony_ci				 int resp_packet_size)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	struct compose_comp_ctxt *comp_pkt = context;
13358c2ecf20Sopenharmony_ci	struct pci_create_int_response *int_resp =
13368c2ecf20Sopenharmony_ci		(struct pci_create_int_response *)resp;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	comp_pkt->comp_pkt.completion_status = resp->status;
13398c2ecf20Sopenharmony_ci	comp_pkt->int_desc = int_resp->int_desc;
13408c2ecf20Sopenharmony_ci	complete(&comp_pkt->comp_pkt.host_event);
13418c2ecf20Sopenharmony_ci}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_cistatic u32 hv_compose_msi_req_v1(
13448c2ecf20Sopenharmony_ci	struct pci_create_interrupt *int_pkt, struct cpumask *affinity,
13458c2ecf20Sopenharmony_ci	u32 slot, u8 vector, u8 vector_count)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
13488c2ecf20Sopenharmony_ci	int_pkt->wslot.slot = slot;
13498c2ecf20Sopenharmony_ci	int_pkt->int_desc.vector = vector;
13508c2ecf20Sopenharmony_ci	int_pkt->int_desc.vector_count = vector_count;
13518c2ecf20Sopenharmony_ci	int_pkt->int_desc.delivery_mode = dest_Fixed;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	/*
13548c2ecf20Sopenharmony_ci	 * Create MSI w/ dummy vCPU set, overwritten by subsequent retarget in
13558c2ecf20Sopenharmony_ci	 * hv_irq_unmask().
13568c2ecf20Sopenharmony_ci	 */
13578c2ecf20Sopenharmony_ci	int_pkt->int_desc.cpu_mask = CPU_AFFINITY_ALL;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	return sizeof(*int_pkt);
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_cistatic u32 hv_compose_msi_req_v2(
13638c2ecf20Sopenharmony_ci	struct pci_create_interrupt2 *int_pkt, struct cpumask *affinity,
13648c2ecf20Sopenharmony_ci	u32 slot, u8 vector, u8 vector_count)
13658c2ecf20Sopenharmony_ci{
13668c2ecf20Sopenharmony_ci	int cpu;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE2;
13698c2ecf20Sopenharmony_ci	int_pkt->wslot.slot = slot;
13708c2ecf20Sopenharmony_ci	int_pkt->int_desc.vector = vector;
13718c2ecf20Sopenharmony_ci	int_pkt->int_desc.vector_count = vector_count;
13728c2ecf20Sopenharmony_ci	int_pkt->int_desc.delivery_mode = dest_Fixed;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/*
13758c2ecf20Sopenharmony_ci	 * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
13768c2ecf20Sopenharmony_ci	 * by subsequent retarget in hv_irq_unmask().
13778c2ecf20Sopenharmony_ci	 */
13788c2ecf20Sopenharmony_ci	cpu = cpumask_first_and(affinity, cpu_online_mask);
13798c2ecf20Sopenharmony_ci	int_pkt->int_desc.processor_array[0] =
13808c2ecf20Sopenharmony_ci		hv_cpu_number_to_vp_number(cpu);
13818c2ecf20Sopenharmony_ci	int_pkt->int_desc.processor_count = 1;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	return sizeof(*int_pkt);
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci/**
13878c2ecf20Sopenharmony_ci * hv_compose_msi_msg() - Supplies a valid MSI address/data
13888c2ecf20Sopenharmony_ci * @data:	Everything about this MSI
13898c2ecf20Sopenharmony_ci * @msg:	Buffer that is filled in by this function
13908c2ecf20Sopenharmony_ci *
13918c2ecf20Sopenharmony_ci * This function unpacks the IRQ looking for target CPU set, IDT
13928c2ecf20Sopenharmony_ci * vector and mode and sends a message to the parent partition
13938c2ecf20Sopenharmony_ci * asking for a mapping for that tuple in this partition.  The
13948c2ecf20Sopenharmony_ci * response supplies a data value and address to which that data
13958c2ecf20Sopenharmony_ci * should be written to trigger that interrupt.
13968c2ecf20Sopenharmony_ci */
13978c2ecf20Sopenharmony_cistatic void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
14008c2ecf20Sopenharmony_ci	struct vmbus_channel *channel;
14018c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
14028c2ecf20Sopenharmony_ci	struct pci_bus *pbus;
14038c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
14048c2ecf20Sopenharmony_ci	struct cpumask *dest;
14058c2ecf20Sopenharmony_ci	struct compose_comp_ctxt comp;
14068c2ecf20Sopenharmony_ci	struct tran_int_desc *int_desc;
14078c2ecf20Sopenharmony_ci	struct msi_desc *msi_desc;
14088c2ecf20Sopenharmony_ci	u8 vector, vector_count;
14098c2ecf20Sopenharmony_ci	struct {
14108c2ecf20Sopenharmony_ci		struct pci_packet pci_pkt;
14118c2ecf20Sopenharmony_ci		union {
14128c2ecf20Sopenharmony_ci			struct pci_create_interrupt v1;
14138c2ecf20Sopenharmony_ci			struct pci_create_interrupt2 v2;
14148c2ecf20Sopenharmony_ci		} int_pkts;
14158c2ecf20Sopenharmony_ci	} __packed ctxt;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	u32 size;
14188c2ecf20Sopenharmony_ci	int ret;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	/* Reuse the previous allocation */
14218c2ecf20Sopenharmony_ci	if (data->chip_data) {
14228c2ecf20Sopenharmony_ci		int_desc = data->chip_data;
14238c2ecf20Sopenharmony_ci		msg->address_hi = int_desc->address >> 32;
14248c2ecf20Sopenharmony_ci		msg->address_lo = int_desc->address & 0xffffffff;
14258c2ecf20Sopenharmony_ci		msg->data = int_desc->data;
14268c2ecf20Sopenharmony_ci		return;
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	msi_desc  = irq_data_get_msi_desc(data);
14308c2ecf20Sopenharmony_ci	pdev = msi_desc_to_pci_dev(msi_desc);
14318c2ecf20Sopenharmony_ci	dest = irq_data_get_effective_affinity_mask(data);
14328c2ecf20Sopenharmony_ci	pbus = pdev->bus;
14338c2ecf20Sopenharmony_ci	hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
14348c2ecf20Sopenharmony_ci	channel = hbus->hdev->channel;
14358c2ecf20Sopenharmony_ci	hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
14368c2ecf20Sopenharmony_ci	if (!hpdev)
14378c2ecf20Sopenharmony_ci		goto return_null_message;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	int_desc = kzalloc(sizeof(*int_desc), GFP_ATOMIC);
14408c2ecf20Sopenharmony_ci	if (!int_desc)
14418c2ecf20Sopenharmony_ci		goto drop_reference;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if (!msi_desc->msi_attrib.is_msix && msi_desc->nvec_used > 1) {
14448c2ecf20Sopenharmony_ci		/*
14458c2ecf20Sopenharmony_ci		 * If this is not the first MSI of Multi MSI, we already have
14468c2ecf20Sopenharmony_ci		 * a mapping.  Can exit early.
14478c2ecf20Sopenharmony_ci		 */
14488c2ecf20Sopenharmony_ci		if (msi_desc->irq != data->irq) {
14498c2ecf20Sopenharmony_ci			data->chip_data = int_desc;
14508c2ecf20Sopenharmony_ci			int_desc->address = msi_desc->msg.address_lo |
14518c2ecf20Sopenharmony_ci					    (u64)msi_desc->msg.address_hi << 32;
14528c2ecf20Sopenharmony_ci			int_desc->data = msi_desc->msg.data +
14538c2ecf20Sopenharmony_ci					 (data->irq - msi_desc->irq);
14548c2ecf20Sopenharmony_ci			msg->address_hi = msi_desc->msg.address_hi;
14558c2ecf20Sopenharmony_ci			msg->address_lo = msi_desc->msg.address_lo;
14568c2ecf20Sopenharmony_ci			msg->data = int_desc->data;
14578c2ecf20Sopenharmony_ci			put_pcichild(hpdev);
14588c2ecf20Sopenharmony_ci			return;
14598c2ecf20Sopenharmony_ci		}
14608c2ecf20Sopenharmony_ci		/*
14618c2ecf20Sopenharmony_ci		 * The vector we select here is a dummy value.  The correct
14628c2ecf20Sopenharmony_ci		 * value gets sent to the hypervisor in unmask().  This needs
14638c2ecf20Sopenharmony_ci		 * to be aligned with the count, and also not zero.  Multi-msi
14648c2ecf20Sopenharmony_ci		 * is powers of 2 up to 32, so 32 will always work here.
14658c2ecf20Sopenharmony_ci		 */
14668c2ecf20Sopenharmony_ci		vector = 32;
14678c2ecf20Sopenharmony_ci		vector_count = msi_desc->nvec_used;
14688c2ecf20Sopenharmony_ci	} else {
14698c2ecf20Sopenharmony_ci		vector = hv_msi_get_int_vector(data);
14708c2ecf20Sopenharmony_ci		vector_count = 1;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	memset(&ctxt, 0, sizeof(ctxt));
14748c2ecf20Sopenharmony_ci	init_completion(&comp.comp_pkt.host_event);
14758c2ecf20Sopenharmony_ci	ctxt.pci_pkt.completion_func = hv_pci_compose_compl;
14768c2ecf20Sopenharmony_ci	ctxt.pci_pkt.compl_ctxt = &comp;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	switch (hbus->protocol_version) {
14798c2ecf20Sopenharmony_ci	case PCI_PROTOCOL_VERSION_1_1:
14808c2ecf20Sopenharmony_ci		size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
14818c2ecf20Sopenharmony_ci					dest,
14828c2ecf20Sopenharmony_ci					hpdev->desc.win_slot.slot,
14838c2ecf20Sopenharmony_ci					vector,
14848c2ecf20Sopenharmony_ci					vector_count);
14858c2ecf20Sopenharmony_ci		break;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	case PCI_PROTOCOL_VERSION_1_2:
14888c2ecf20Sopenharmony_ci	case PCI_PROTOCOL_VERSION_1_3:
14898c2ecf20Sopenharmony_ci		size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
14908c2ecf20Sopenharmony_ci					dest,
14918c2ecf20Sopenharmony_ci					hpdev->desc.win_slot.slot,
14928c2ecf20Sopenharmony_ci					vector,
14938c2ecf20Sopenharmony_ci					vector_count);
14948c2ecf20Sopenharmony_ci		break;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	default:
14978c2ecf20Sopenharmony_ci		/* As we only negotiate protocol versions known to this driver,
14988c2ecf20Sopenharmony_ci		 * this path should never hit. However, this is it not a hot
14998c2ecf20Sopenharmony_ci		 * path so we print a message to aid future updates.
15008c2ecf20Sopenharmony_ci		 */
15018c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
15028c2ecf20Sopenharmony_ci			"Unexpected vPCI protocol, update driver.");
15038c2ecf20Sopenharmony_ci		goto free_int_desc;
15048c2ecf20Sopenharmony_ci	}
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hpdev->hbus->hdev->channel, &ctxt.int_pkts,
15078c2ecf20Sopenharmony_ci			       size, (unsigned long)&ctxt.pci_pkt,
15088c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
15098c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
15108c2ecf20Sopenharmony_ci	if (ret) {
15118c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
15128c2ecf20Sopenharmony_ci			"Sending request for interrupt failed: 0x%x",
15138c2ecf20Sopenharmony_ci			comp.comp_pkt.completion_status);
15148c2ecf20Sopenharmony_ci		goto free_int_desc;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	/*
15188c2ecf20Sopenharmony_ci	 * Prevents hv_pci_onchannelcallback() from running concurrently
15198c2ecf20Sopenharmony_ci	 * in the tasklet.
15208c2ecf20Sopenharmony_ci	 */
15218c2ecf20Sopenharmony_ci	tasklet_disable(&channel->callback_event);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/*
15248c2ecf20Sopenharmony_ci	 * Since this function is called with IRQ locks held, can't
15258c2ecf20Sopenharmony_ci	 * do normal wait for completion; instead poll.
15268c2ecf20Sopenharmony_ci	 */
15278c2ecf20Sopenharmony_ci	while (!try_wait_for_completion(&comp.comp_pkt.host_event)) {
15288c2ecf20Sopenharmony_ci		unsigned long flags;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci		/* 0xFFFF means an invalid PCI VENDOR ID. */
15318c2ecf20Sopenharmony_ci		if (hv_pcifront_get_vendor_id(hpdev) == 0xFFFF) {
15328c2ecf20Sopenharmony_ci			dev_err_once(&hbus->hdev->device,
15338c2ecf20Sopenharmony_ci				     "the device has gone\n");
15348c2ecf20Sopenharmony_ci			goto enable_tasklet;
15358c2ecf20Sopenharmony_ci		}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci		/*
15388c2ecf20Sopenharmony_ci		 * Make sure that the ring buffer data structure doesn't get
15398c2ecf20Sopenharmony_ci		 * freed while we dereference the ring buffer pointer.  Test
15408c2ecf20Sopenharmony_ci		 * for the channel's onchannel_callback being NULL within a
15418c2ecf20Sopenharmony_ci		 * sched_lock critical section.  See also the inline comments
15428c2ecf20Sopenharmony_ci		 * in vmbus_reset_channel_cb().
15438c2ecf20Sopenharmony_ci		 */
15448c2ecf20Sopenharmony_ci		spin_lock_irqsave(&channel->sched_lock, flags);
15458c2ecf20Sopenharmony_ci		if (unlikely(channel->onchannel_callback == NULL)) {
15468c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&channel->sched_lock, flags);
15478c2ecf20Sopenharmony_ci			goto enable_tasklet;
15488c2ecf20Sopenharmony_ci		}
15498c2ecf20Sopenharmony_ci		hv_pci_onchannelcallback(hbus);
15508c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&channel->sched_lock, flags);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci		udelay(100);
15538c2ecf20Sopenharmony_ci	}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	tasklet_enable(&channel->callback_event);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	if (comp.comp_pkt.completion_status < 0) {
15588c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
15598c2ecf20Sopenharmony_ci			"Request for interrupt failed: 0x%x",
15608c2ecf20Sopenharmony_ci			comp.comp_pkt.completion_status);
15618c2ecf20Sopenharmony_ci		goto free_int_desc;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	/*
15658c2ecf20Sopenharmony_ci	 * Record the assignment so that this can be unwound later. Using
15668c2ecf20Sopenharmony_ci	 * irq_set_chip_data() here would be appropriate, but the lock it takes
15678c2ecf20Sopenharmony_ci	 * is already held.
15688c2ecf20Sopenharmony_ci	 */
15698c2ecf20Sopenharmony_ci	*int_desc = comp.int_desc;
15708c2ecf20Sopenharmony_ci	data->chip_data = int_desc;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	/* Pass up the result. */
15738c2ecf20Sopenharmony_ci	msg->address_hi = comp.int_desc.address >> 32;
15748c2ecf20Sopenharmony_ci	msg->address_lo = comp.int_desc.address & 0xffffffff;
15758c2ecf20Sopenharmony_ci	msg->data = comp.int_desc.data;
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
15788c2ecf20Sopenharmony_ci	return;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_cienable_tasklet:
15818c2ecf20Sopenharmony_ci	tasklet_enable(&channel->callback_event);
15828c2ecf20Sopenharmony_cifree_int_desc:
15838c2ecf20Sopenharmony_ci	kfree(int_desc);
15848c2ecf20Sopenharmony_cidrop_reference:
15858c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
15868c2ecf20Sopenharmony_cireturn_null_message:
15878c2ecf20Sopenharmony_ci	msg->address_hi = 0;
15888c2ecf20Sopenharmony_ci	msg->address_lo = 0;
15898c2ecf20Sopenharmony_ci	msg->data = 0;
15908c2ecf20Sopenharmony_ci}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci/* HW Interrupt Chip Descriptor */
15938c2ecf20Sopenharmony_cistatic struct irq_chip hv_msi_irq_chip = {
15948c2ecf20Sopenharmony_ci	.name			= "Hyper-V PCIe MSI",
15958c2ecf20Sopenharmony_ci	.irq_compose_msi_msg	= hv_compose_msi_msg,
15968c2ecf20Sopenharmony_ci	.irq_set_affinity	= hv_set_affinity,
15978c2ecf20Sopenharmony_ci	.irq_ack		= irq_chip_ack_parent,
15988c2ecf20Sopenharmony_ci	.irq_mask		= hv_irq_mask,
15998c2ecf20Sopenharmony_ci	.irq_unmask		= hv_irq_unmask,
16008c2ecf20Sopenharmony_ci};
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_cistatic struct msi_domain_ops hv_msi_ops = {
16038c2ecf20Sopenharmony_ci	.msi_prepare	= hv_msi_prepare,
16048c2ecf20Sopenharmony_ci	.msi_free	= hv_msi_free,
16058c2ecf20Sopenharmony_ci};
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci/**
16088c2ecf20Sopenharmony_ci * hv_pcie_init_irq_domain() - Initialize IRQ domain
16098c2ecf20Sopenharmony_ci * @hbus:	The root PCI bus
16108c2ecf20Sopenharmony_ci *
16118c2ecf20Sopenharmony_ci * This function creates an IRQ domain which will be used for
16128c2ecf20Sopenharmony_ci * interrupts from devices that have been passed through.  These
16138c2ecf20Sopenharmony_ci * devices only support MSI and MSI-X, not line-based interrupts
16148c2ecf20Sopenharmony_ci * or simulations of line-based interrupts through PCIe's
16158c2ecf20Sopenharmony_ci * fabric-layer messages.  Because interrupts are remapped, we
16168c2ecf20Sopenharmony_ci * can support multi-message MSI here.
16178c2ecf20Sopenharmony_ci *
16188c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure
16198c2ecf20Sopenharmony_ci */
16208c2ecf20Sopenharmony_cistatic int hv_pcie_init_irq_domain(struct hv_pcibus_device *hbus)
16218c2ecf20Sopenharmony_ci{
16228c2ecf20Sopenharmony_ci	hbus->msi_info.chip = &hv_msi_irq_chip;
16238c2ecf20Sopenharmony_ci	hbus->msi_info.ops = &hv_msi_ops;
16248c2ecf20Sopenharmony_ci	hbus->msi_info.flags = (MSI_FLAG_USE_DEF_DOM_OPS |
16258c2ecf20Sopenharmony_ci		MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI |
16268c2ecf20Sopenharmony_ci		MSI_FLAG_PCI_MSIX);
16278c2ecf20Sopenharmony_ci	hbus->msi_info.handler = handle_edge_irq;
16288c2ecf20Sopenharmony_ci	hbus->msi_info.handler_name = "edge";
16298c2ecf20Sopenharmony_ci	hbus->msi_info.data = hbus;
16308c2ecf20Sopenharmony_ci	hbus->irq_domain = pci_msi_create_irq_domain(hbus->sysdata.fwnode,
16318c2ecf20Sopenharmony_ci						     &hbus->msi_info,
16328c2ecf20Sopenharmony_ci						     x86_vector_domain);
16338c2ecf20Sopenharmony_ci	if (!hbus->irq_domain) {
16348c2ecf20Sopenharmony_ci		dev_err(&hbus->hdev->device,
16358c2ecf20Sopenharmony_ci			"Failed to build an MSI IRQ domain\n");
16368c2ecf20Sopenharmony_ci		return -ENODEV;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	return 0;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci/**
16438c2ecf20Sopenharmony_ci * get_bar_size() - Get the address space consumed by a BAR
16448c2ecf20Sopenharmony_ci * @bar_val:	Value that a BAR returned after -1 was written
16458c2ecf20Sopenharmony_ci *              to it.
16468c2ecf20Sopenharmony_ci *
16478c2ecf20Sopenharmony_ci * This function returns the size of the BAR, rounded up to 1
16488c2ecf20Sopenharmony_ci * page.  It has to be rounded up because the hypervisor's page
16498c2ecf20Sopenharmony_ci * table entry that maps the BAR into the VM can't specify an
16508c2ecf20Sopenharmony_ci * offset within a page.  The invariant is that the hypervisor
16518c2ecf20Sopenharmony_ci * must place any BARs of smaller than page length at the
16528c2ecf20Sopenharmony_ci * beginning of a page.
16538c2ecf20Sopenharmony_ci *
16548c2ecf20Sopenharmony_ci * Return:	Size in bytes of the consumed MMIO space.
16558c2ecf20Sopenharmony_ci */
16568c2ecf20Sopenharmony_cistatic u64 get_bar_size(u64 bar_val)
16578c2ecf20Sopenharmony_ci{
16588c2ecf20Sopenharmony_ci	return round_up((1 + ~(bar_val & PCI_BASE_ADDRESS_MEM_MASK)),
16598c2ecf20Sopenharmony_ci			PAGE_SIZE);
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci/**
16638c2ecf20Sopenharmony_ci * survey_child_resources() - Total all MMIO requirements
16648c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
16658c2ecf20Sopenharmony_ci */
16668c2ecf20Sopenharmony_cistatic void survey_child_resources(struct hv_pcibus_device *hbus)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
16698c2ecf20Sopenharmony_ci	resource_size_t bar_size = 0;
16708c2ecf20Sopenharmony_ci	unsigned long flags;
16718c2ecf20Sopenharmony_ci	struct completion *event;
16728c2ecf20Sopenharmony_ci	u64 bar_val;
16738c2ecf20Sopenharmony_ci	int i;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	/* If nobody is waiting on the answer, don't compute it. */
16768c2ecf20Sopenharmony_ci	event = xchg(&hbus->survey_event, NULL);
16778c2ecf20Sopenharmony_ci	if (!event)
16788c2ecf20Sopenharmony_ci		return;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	/* If the answer has already been computed, go with it. */
16818c2ecf20Sopenharmony_ci	if (hbus->low_mmio_space || hbus->high_mmio_space) {
16828c2ecf20Sopenharmony_ci		complete(event);
16838c2ecf20Sopenharmony_ci		return;
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	/*
16898c2ecf20Sopenharmony_ci	 * Due to an interesting quirk of the PCI spec, all memory regions
16908c2ecf20Sopenharmony_ci	 * for a child device are a power of 2 in size and aligned in memory,
16918c2ecf20Sopenharmony_ci	 * so it's sufficient to just add them up without tracking alignment.
16928c2ecf20Sopenharmony_ci	 */
16938c2ecf20Sopenharmony_ci	list_for_each_entry(hpdev, &hbus->children, list_entry) {
16948c2ecf20Sopenharmony_ci		for (i = 0; i < PCI_STD_NUM_BARS; i++) {
16958c2ecf20Sopenharmony_ci			if (hpdev->probed_bar[i] & PCI_BASE_ADDRESS_SPACE_IO)
16968c2ecf20Sopenharmony_ci				dev_err(&hbus->hdev->device,
16978c2ecf20Sopenharmony_ci					"There's an I/O BAR in this list!\n");
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci			if (hpdev->probed_bar[i] != 0) {
17008c2ecf20Sopenharmony_ci				/*
17018c2ecf20Sopenharmony_ci				 * A probed BAR has all the upper bits set that
17028c2ecf20Sopenharmony_ci				 * can be changed.
17038c2ecf20Sopenharmony_ci				 */
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci				bar_val = hpdev->probed_bar[i];
17068c2ecf20Sopenharmony_ci				if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
17078c2ecf20Sopenharmony_ci					bar_val |=
17088c2ecf20Sopenharmony_ci					((u64)hpdev->probed_bar[++i] << 32);
17098c2ecf20Sopenharmony_ci				else
17108c2ecf20Sopenharmony_ci					bar_val |= 0xffffffff00000000ULL;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci				bar_size = get_bar_size(bar_val);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci				if (bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64)
17158c2ecf20Sopenharmony_ci					hbus->high_mmio_space += bar_size;
17168c2ecf20Sopenharmony_ci				else
17178c2ecf20Sopenharmony_ci					hbus->low_mmio_space += bar_size;
17188c2ecf20Sopenharmony_ci			}
17198c2ecf20Sopenharmony_ci		}
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
17238c2ecf20Sopenharmony_ci	complete(event);
17248c2ecf20Sopenharmony_ci}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci/**
17278c2ecf20Sopenharmony_ci * prepopulate_bars() - Fill in BARs with defaults
17288c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
17298c2ecf20Sopenharmony_ci *
17308c2ecf20Sopenharmony_ci * The core PCI driver code seems much, much happier if the BARs
17318c2ecf20Sopenharmony_ci * for a device have values upon first scan. So fill them in.
17328c2ecf20Sopenharmony_ci * The algorithm below works down from large sizes to small,
17338c2ecf20Sopenharmony_ci * attempting to pack the assignments optimally. The assumption,
17348c2ecf20Sopenharmony_ci * enforced in other parts of the code, is that the beginning of
17358c2ecf20Sopenharmony_ci * the memory-mapped I/O space will be aligned on the largest
17368c2ecf20Sopenharmony_ci * BAR size.
17378c2ecf20Sopenharmony_ci */
17388c2ecf20Sopenharmony_cistatic void prepopulate_bars(struct hv_pcibus_device *hbus)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	resource_size_t high_size = 0;
17418c2ecf20Sopenharmony_ci	resource_size_t low_size = 0;
17428c2ecf20Sopenharmony_ci	resource_size_t high_base = 0;
17438c2ecf20Sopenharmony_ci	resource_size_t low_base = 0;
17448c2ecf20Sopenharmony_ci	resource_size_t bar_size;
17458c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
17468c2ecf20Sopenharmony_ci	unsigned long flags;
17478c2ecf20Sopenharmony_ci	u64 bar_val;
17488c2ecf20Sopenharmony_ci	u32 command;
17498c2ecf20Sopenharmony_ci	bool high;
17508c2ecf20Sopenharmony_ci	int i;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (hbus->low_mmio_space) {
17538c2ecf20Sopenharmony_ci		low_size = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
17548c2ecf20Sopenharmony_ci		low_base = hbus->low_mmio_res->start;
17558c2ecf20Sopenharmony_ci	}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if (hbus->high_mmio_space) {
17588c2ecf20Sopenharmony_ci		high_size = 1ULL <<
17598c2ecf20Sopenharmony_ci			(63 - __builtin_clzll(hbus->high_mmio_space));
17608c2ecf20Sopenharmony_ci		high_base = hbus->high_mmio_res->start;
17618c2ecf20Sopenharmony_ci	}
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	/*
17668c2ecf20Sopenharmony_ci	 * Clear the memory enable bit, in case it's already set. This occurs
17678c2ecf20Sopenharmony_ci	 * in the suspend path of hibernation, where the device is suspended,
17688c2ecf20Sopenharmony_ci	 * resumed and suspended again: see hibernation_snapshot() and
17698c2ecf20Sopenharmony_ci	 * hibernation_platform_enter().
17708c2ecf20Sopenharmony_ci	 *
17718c2ecf20Sopenharmony_ci	 * If the memory enable bit is already set, Hyper-V sliently ignores
17728c2ecf20Sopenharmony_ci	 * the below BAR updates, and the related PCI device driver can not
17738c2ecf20Sopenharmony_ci	 * work, because reading from the device register(s) always returns
17748c2ecf20Sopenharmony_ci	 * 0xFFFFFFFF.
17758c2ecf20Sopenharmony_ci	 */
17768c2ecf20Sopenharmony_ci	list_for_each_entry(hpdev, &hbus->children, list_entry) {
17778c2ecf20Sopenharmony_ci		_hv_pcifront_read_config(hpdev, PCI_COMMAND, 2, &command);
17788c2ecf20Sopenharmony_ci		command &= ~PCI_COMMAND_MEMORY;
17798c2ecf20Sopenharmony_ci		_hv_pcifront_write_config(hpdev, PCI_COMMAND, 2, command);
17808c2ecf20Sopenharmony_ci	}
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	/* Pick addresses for the BARs. */
17838c2ecf20Sopenharmony_ci	do {
17848c2ecf20Sopenharmony_ci		list_for_each_entry(hpdev, &hbus->children, list_entry) {
17858c2ecf20Sopenharmony_ci			for (i = 0; i < PCI_STD_NUM_BARS; i++) {
17868c2ecf20Sopenharmony_ci				bar_val = hpdev->probed_bar[i];
17878c2ecf20Sopenharmony_ci				if (bar_val == 0)
17888c2ecf20Sopenharmony_ci					continue;
17898c2ecf20Sopenharmony_ci				high = bar_val & PCI_BASE_ADDRESS_MEM_TYPE_64;
17908c2ecf20Sopenharmony_ci				if (high) {
17918c2ecf20Sopenharmony_ci					bar_val |=
17928c2ecf20Sopenharmony_ci						((u64)hpdev->probed_bar[i + 1]
17938c2ecf20Sopenharmony_ci						 << 32);
17948c2ecf20Sopenharmony_ci				} else {
17958c2ecf20Sopenharmony_ci					bar_val |= 0xffffffffULL << 32;
17968c2ecf20Sopenharmony_ci				}
17978c2ecf20Sopenharmony_ci				bar_size = get_bar_size(bar_val);
17988c2ecf20Sopenharmony_ci				if (high) {
17998c2ecf20Sopenharmony_ci					if (high_size != bar_size) {
18008c2ecf20Sopenharmony_ci						i++;
18018c2ecf20Sopenharmony_ci						continue;
18028c2ecf20Sopenharmony_ci					}
18038c2ecf20Sopenharmony_ci					_hv_pcifront_write_config(hpdev,
18048c2ecf20Sopenharmony_ci						PCI_BASE_ADDRESS_0 + (4 * i),
18058c2ecf20Sopenharmony_ci						4,
18068c2ecf20Sopenharmony_ci						(u32)(high_base & 0xffffff00));
18078c2ecf20Sopenharmony_ci					i++;
18088c2ecf20Sopenharmony_ci					_hv_pcifront_write_config(hpdev,
18098c2ecf20Sopenharmony_ci						PCI_BASE_ADDRESS_0 + (4 * i),
18108c2ecf20Sopenharmony_ci						4, (u32)(high_base >> 32));
18118c2ecf20Sopenharmony_ci					high_base += bar_size;
18128c2ecf20Sopenharmony_ci				} else {
18138c2ecf20Sopenharmony_ci					if (low_size != bar_size)
18148c2ecf20Sopenharmony_ci						continue;
18158c2ecf20Sopenharmony_ci					_hv_pcifront_write_config(hpdev,
18168c2ecf20Sopenharmony_ci						PCI_BASE_ADDRESS_0 + (4 * i),
18178c2ecf20Sopenharmony_ci						4,
18188c2ecf20Sopenharmony_ci						(u32)(low_base & 0xffffff00));
18198c2ecf20Sopenharmony_ci					low_base += bar_size;
18208c2ecf20Sopenharmony_ci				}
18218c2ecf20Sopenharmony_ci			}
18228c2ecf20Sopenharmony_ci			if (high_size <= 1 && low_size <= 1) {
18238c2ecf20Sopenharmony_ci				/* Set the memory enable bit. */
18248c2ecf20Sopenharmony_ci				_hv_pcifront_read_config(hpdev, PCI_COMMAND, 2,
18258c2ecf20Sopenharmony_ci							 &command);
18268c2ecf20Sopenharmony_ci				command |= PCI_COMMAND_MEMORY;
18278c2ecf20Sopenharmony_ci				_hv_pcifront_write_config(hpdev, PCI_COMMAND, 2,
18288c2ecf20Sopenharmony_ci							  command);
18298c2ecf20Sopenharmony_ci				break;
18308c2ecf20Sopenharmony_ci			}
18318c2ecf20Sopenharmony_ci		}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci		high_size >>= 1;
18348c2ecf20Sopenharmony_ci		low_size >>= 1;
18358c2ecf20Sopenharmony_ci	}  while (high_size || low_size);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci/*
18418c2ecf20Sopenharmony_ci * Assign entries in sysfs pci slot directory.
18428c2ecf20Sopenharmony_ci *
18438c2ecf20Sopenharmony_ci * Note that this function does not need to lock the children list
18448c2ecf20Sopenharmony_ci * because it is called from pci_devices_present_work which
18458c2ecf20Sopenharmony_ci * is serialized with hv_eject_device_work because they are on the
18468c2ecf20Sopenharmony_ci * same ordered workqueue. Therefore hbus->children list will not change
18478c2ecf20Sopenharmony_ci * even when pci_create_slot sleeps.
18488c2ecf20Sopenharmony_ci */
18498c2ecf20Sopenharmony_cistatic void hv_pci_assign_slots(struct hv_pcibus_device *hbus)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
18528c2ecf20Sopenharmony_ci	char name[SLOT_NAME_SIZE];
18538c2ecf20Sopenharmony_ci	int slot_nr;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	list_for_each_entry(hpdev, &hbus->children, list_entry) {
18568c2ecf20Sopenharmony_ci		if (hpdev->pci_slot)
18578c2ecf20Sopenharmony_ci			continue;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci		slot_nr = PCI_SLOT(wslot_to_devfn(hpdev->desc.win_slot.slot));
18608c2ecf20Sopenharmony_ci		snprintf(name, SLOT_NAME_SIZE, "%u", hpdev->desc.ser);
18618c2ecf20Sopenharmony_ci		hpdev->pci_slot = pci_create_slot(hbus->pci_bus, slot_nr,
18628c2ecf20Sopenharmony_ci					  name, NULL);
18638c2ecf20Sopenharmony_ci		if (IS_ERR(hpdev->pci_slot)) {
18648c2ecf20Sopenharmony_ci			pr_warn("pci_create slot %s failed\n", name);
18658c2ecf20Sopenharmony_ci			hpdev->pci_slot = NULL;
18668c2ecf20Sopenharmony_ci		}
18678c2ecf20Sopenharmony_ci	}
18688c2ecf20Sopenharmony_ci}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci/*
18718c2ecf20Sopenharmony_ci * Remove entries in sysfs pci slot directory.
18728c2ecf20Sopenharmony_ci */
18738c2ecf20Sopenharmony_cistatic void hv_pci_remove_slots(struct hv_pcibus_device *hbus)
18748c2ecf20Sopenharmony_ci{
18758c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	list_for_each_entry(hpdev, &hbus->children, list_entry) {
18788c2ecf20Sopenharmony_ci		if (!hpdev->pci_slot)
18798c2ecf20Sopenharmony_ci			continue;
18808c2ecf20Sopenharmony_ci		pci_destroy_slot(hpdev->pci_slot);
18818c2ecf20Sopenharmony_ci		hpdev->pci_slot = NULL;
18828c2ecf20Sopenharmony_ci	}
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci/*
18868c2ecf20Sopenharmony_ci * Set NUMA node for the devices on the bus
18878c2ecf20Sopenharmony_ci */
18888c2ecf20Sopenharmony_cistatic void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	struct pci_dev *dev;
18918c2ecf20Sopenharmony_ci	struct pci_bus *bus = hbus->pci_bus;
18928c2ecf20Sopenharmony_ci	struct hv_pci_dev *hv_dev;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
18958c2ecf20Sopenharmony_ci		hv_dev = get_pcichild_wslot(hbus, devfn_to_wslot(dev->devfn));
18968c2ecf20Sopenharmony_ci		if (!hv_dev)
18978c2ecf20Sopenharmony_ci			continue;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci		if (hv_dev->desc.flags & HV_PCI_DEVICE_FLAG_NUMA_AFFINITY &&
19008c2ecf20Sopenharmony_ci		    hv_dev->desc.virtual_numa_node < num_possible_nodes())
19018c2ecf20Sopenharmony_ci			/*
19028c2ecf20Sopenharmony_ci			 * The kernel may boot with some NUMA nodes offline
19038c2ecf20Sopenharmony_ci			 * (e.g. in a KDUMP kernel) or with NUMA disabled via
19048c2ecf20Sopenharmony_ci			 * "numa=off". In those cases, adjust the host provided
19058c2ecf20Sopenharmony_ci			 * NUMA node to a valid NUMA node used by the kernel.
19068c2ecf20Sopenharmony_ci			 */
19078c2ecf20Sopenharmony_ci			set_dev_node(&dev->dev,
19088c2ecf20Sopenharmony_ci				     numa_map_to_online_node(
19098c2ecf20Sopenharmony_ci					     hv_dev->desc.virtual_numa_node));
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci		put_pcichild(hv_dev);
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci/**
19168c2ecf20Sopenharmony_ci * create_root_hv_pci_bus() - Expose a new root PCI bus
19178c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
19188c2ecf20Sopenharmony_ci *
19198c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
19208c2ecf20Sopenharmony_ci */
19218c2ecf20Sopenharmony_cistatic int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
19228c2ecf20Sopenharmony_ci{
19238c2ecf20Sopenharmony_ci	/* Register the device */
19248c2ecf20Sopenharmony_ci	hbus->pci_bus = pci_create_root_bus(&hbus->hdev->device,
19258c2ecf20Sopenharmony_ci					    0, /* bus number is always zero */
19268c2ecf20Sopenharmony_ci					    &hv_pcifront_ops,
19278c2ecf20Sopenharmony_ci					    &hbus->sysdata,
19288c2ecf20Sopenharmony_ci					    &hbus->resources_for_children);
19298c2ecf20Sopenharmony_ci	if (!hbus->pci_bus)
19308c2ecf20Sopenharmony_ci		return -ENODEV;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	hbus->pci_bus->msi = &hbus->msi_chip;
19338c2ecf20Sopenharmony_ci	hbus->pci_bus->msi->dev = &hbus->hdev->device;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	pci_lock_rescan_remove();
19368c2ecf20Sopenharmony_ci	pci_scan_child_bus(hbus->pci_bus);
19378c2ecf20Sopenharmony_ci	hv_pci_assign_numa_node(hbus);
19388c2ecf20Sopenharmony_ci	pci_bus_assign_resources(hbus->pci_bus);
19398c2ecf20Sopenharmony_ci	hv_pci_assign_slots(hbus);
19408c2ecf20Sopenharmony_ci	pci_bus_add_devices(hbus->pci_bus);
19418c2ecf20Sopenharmony_ci	pci_unlock_rescan_remove();
19428c2ecf20Sopenharmony_ci	hbus->state = hv_pcibus_installed;
19438c2ecf20Sopenharmony_ci	return 0;
19448c2ecf20Sopenharmony_ci}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_cistruct q_res_req_compl {
19478c2ecf20Sopenharmony_ci	struct completion host_event;
19488c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
19498c2ecf20Sopenharmony_ci};
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci/**
19528c2ecf20Sopenharmony_ci * q_resource_requirements() - Query Resource Requirements
19538c2ecf20Sopenharmony_ci * @context:		The completion context.
19548c2ecf20Sopenharmony_ci * @resp:		The response that came from the host.
19558c2ecf20Sopenharmony_ci * @resp_packet_size:	The size in bytes of resp.
19568c2ecf20Sopenharmony_ci *
19578c2ecf20Sopenharmony_ci * This function is invoked on completion of a Query Resource
19588c2ecf20Sopenharmony_ci * Requirements packet.
19598c2ecf20Sopenharmony_ci */
19608c2ecf20Sopenharmony_cistatic void q_resource_requirements(void *context, struct pci_response *resp,
19618c2ecf20Sopenharmony_ci				    int resp_packet_size)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	struct q_res_req_compl *completion = context;
19648c2ecf20Sopenharmony_ci	struct pci_q_res_req_response *q_res_req =
19658c2ecf20Sopenharmony_ci		(struct pci_q_res_req_response *)resp;
19668c2ecf20Sopenharmony_ci	int i;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	if (resp->status < 0) {
19698c2ecf20Sopenharmony_ci		dev_err(&completion->hpdev->hbus->hdev->device,
19708c2ecf20Sopenharmony_ci			"query resource requirements failed: %x\n",
19718c2ecf20Sopenharmony_ci			resp->status);
19728c2ecf20Sopenharmony_ci	} else {
19738c2ecf20Sopenharmony_ci		for (i = 0; i < PCI_STD_NUM_BARS; i++) {
19748c2ecf20Sopenharmony_ci			completion->hpdev->probed_bar[i] =
19758c2ecf20Sopenharmony_ci				q_res_req->probed_bar[i];
19768c2ecf20Sopenharmony_ci		}
19778c2ecf20Sopenharmony_ci	}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	complete(&completion->host_event);
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci/**
19838c2ecf20Sopenharmony_ci * new_pcichild_device() - Create a new child device
19848c2ecf20Sopenharmony_ci * @hbus:	The internal struct tracking this root PCI bus.
19858c2ecf20Sopenharmony_ci * @desc:	The information supplied so far from the host
19868c2ecf20Sopenharmony_ci *              about the device.
19878c2ecf20Sopenharmony_ci *
19888c2ecf20Sopenharmony_ci * This function creates the tracking structure for a new child
19898c2ecf20Sopenharmony_ci * device and kicks off the process of figuring out what it is.
19908c2ecf20Sopenharmony_ci *
19918c2ecf20Sopenharmony_ci * Return: Pointer to the new tracking struct
19928c2ecf20Sopenharmony_ci */
19938c2ecf20Sopenharmony_cistatic struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
19948c2ecf20Sopenharmony_ci		struct hv_pcidev_description *desc)
19958c2ecf20Sopenharmony_ci{
19968c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
19978c2ecf20Sopenharmony_ci	struct pci_child_message *res_req;
19988c2ecf20Sopenharmony_ci	struct q_res_req_compl comp_pkt;
19998c2ecf20Sopenharmony_ci	struct {
20008c2ecf20Sopenharmony_ci		struct pci_packet init_packet;
20018c2ecf20Sopenharmony_ci		u8 buffer[sizeof(struct pci_child_message)];
20028c2ecf20Sopenharmony_ci	} pkt;
20038c2ecf20Sopenharmony_ci	unsigned long flags;
20048c2ecf20Sopenharmony_ci	int ret;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	hpdev = kzalloc(sizeof(*hpdev), GFP_KERNEL);
20078c2ecf20Sopenharmony_ci	if (!hpdev)
20088c2ecf20Sopenharmony_ci		return NULL;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	hpdev->hbus = hbus;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	memset(&pkt, 0, sizeof(pkt));
20138c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.host_event);
20148c2ecf20Sopenharmony_ci	comp_pkt.hpdev = hpdev;
20158c2ecf20Sopenharmony_ci	pkt.init_packet.compl_ctxt = &comp_pkt;
20168c2ecf20Sopenharmony_ci	pkt.init_packet.completion_func = q_resource_requirements;
20178c2ecf20Sopenharmony_ci	res_req = (struct pci_child_message *)&pkt.init_packet.message;
20188c2ecf20Sopenharmony_ci	res_req->message_type.type = PCI_QUERY_RESOURCE_REQUIREMENTS;
20198c2ecf20Sopenharmony_ci	res_req->wslot.slot = desc->win_slot.slot;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hbus->hdev->channel, res_req,
20228c2ecf20Sopenharmony_ci			       sizeof(struct pci_child_message),
20238c2ecf20Sopenharmony_ci			       (unsigned long)&pkt.init_packet,
20248c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
20258c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
20268c2ecf20Sopenharmony_ci	if (ret)
20278c2ecf20Sopenharmony_ci		goto error;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	if (wait_for_response(hbus->hdev, &comp_pkt.host_event))
20308c2ecf20Sopenharmony_ci		goto error;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	hpdev->desc = *desc;
20338c2ecf20Sopenharmony_ci	refcount_set(&hpdev->refs, 1);
20348c2ecf20Sopenharmony_ci	get_pcichild(hpdev);
20358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	list_add_tail(&hpdev->list_entry, &hbus->children);
20388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
20398c2ecf20Sopenharmony_ci	return hpdev;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_cierror:
20428c2ecf20Sopenharmony_ci	kfree(hpdev);
20438c2ecf20Sopenharmony_ci	return NULL;
20448c2ecf20Sopenharmony_ci}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci/**
20478c2ecf20Sopenharmony_ci * get_pcichild_wslot() - Find device from slot
20488c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
20498c2ecf20Sopenharmony_ci * @wslot:	Location on the bus
20508c2ecf20Sopenharmony_ci *
20518c2ecf20Sopenharmony_ci * This function looks up a PCI device and returns the internal
20528c2ecf20Sopenharmony_ci * representation of it.  It acquires a reference on it, so that
20538c2ecf20Sopenharmony_ci * the device won't be deleted while somebody is using it.  The
20548c2ecf20Sopenharmony_ci * caller is responsible for calling put_pcichild() to release
20558c2ecf20Sopenharmony_ci * this reference.
20568c2ecf20Sopenharmony_ci *
20578c2ecf20Sopenharmony_ci * Return:	Internal representation of a PCI device
20588c2ecf20Sopenharmony_ci */
20598c2ecf20Sopenharmony_cistatic struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus,
20608c2ecf20Sopenharmony_ci					     u32 wslot)
20618c2ecf20Sopenharmony_ci{
20628c2ecf20Sopenharmony_ci	unsigned long flags;
20638c2ecf20Sopenharmony_ci	struct hv_pci_dev *iter, *hpdev = NULL;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
20668c2ecf20Sopenharmony_ci	list_for_each_entry(iter, &hbus->children, list_entry) {
20678c2ecf20Sopenharmony_ci		if (iter->desc.win_slot.slot == wslot) {
20688c2ecf20Sopenharmony_ci			hpdev = iter;
20698c2ecf20Sopenharmony_ci			get_pcichild(hpdev);
20708c2ecf20Sopenharmony_ci			break;
20718c2ecf20Sopenharmony_ci		}
20728c2ecf20Sopenharmony_ci	}
20738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	return hpdev;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/**
20798c2ecf20Sopenharmony_ci * pci_devices_present_work() - Handle new list of child devices
20808c2ecf20Sopenharmony_ci * @work:	Work struct embedded in struct hv_dr_work
20818c2ecf20Sopenharmony_ci *
20828c2ecf20Sopenharmony_ci * "Bus Relations" is the Windows term for "children of this
20838c2ecf20Sopenharmony_ci * bus."  The terminology is preserved here for people trying to
20848c2ecf20Sopenharmony_ci * debug the interaction between Hyper-V and Linux.  This
20858c2ecf20Sopenharmony_ci * function is called when the parent partition reports a list
20868c2ecf20Sopenharmony_ci * of functions that should be observed under this PCI Express
20878c2ecf20Sopenharmony_ci * port (bus).
20888c2ecf20Sopenharmony_ci *
20898c2ecf20Sopenharmony_ci * This function updates the list, and must tolerate being
20908c2ecf20Sopenharmony_ci * called multiple times with the same information.  The typical
20918c2ecf20Sopenharmony_ci * number of child devices is one, with very atypical cases
20928c2ecf20Sopenharmony_ci * involving three or four, so the algorithms used here can be
20938c2ecf20Sopenharmony_ci * simple and inefficient.
20948c2ecf20Sopenharmony_ci *
20958c2ecf20Sopenharmony_ci * It must also treat the omission of a previously observed device as
20968c2ecf20Sopenharmony_ci * notification that the device no longer exists.
20978c2ecf20Sopenharmony_ci *
20988c2ecf20Sopenharmony_ci * Note that this function is serialized with hv_eject_device_work(),
20998c2ecf20Sopenharmony_ci * because both are pushed to the ordered workqueue hbus->wq.
21008c2ecf20Sopenharmony_ci */
21018c2ecf20Sopenharmony_cistatic void pci_devices_present_work(struct work_struct *work)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	u32 child_no;
21048c2ecf20Sopenharmony_ci	bool found;
21058c2ecf20Sopenharmony_ci	struct hv_pcidev_description *new_desc;
21068c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
21078c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
21088c2ecf20Sopenharmony_ci	struct list_head removed;
21098c2ecf20Sopenharmony_ci	struct hv_dr_work *dr_wrk;
21108c2ecf20Sopenharmony_ci	struct hv_dr_state *dr = NULL;
21118c2ecf20Sopenharmony_ci	unsigned long flags;
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	dr_wrk = container_of(work, struct hv_dr_work, wrk);
21148c2ecf20Sopenharmony_ci	hbus = dr_wrk->bus;
21158c2ecf20Sopenharmony_ci	kfree(dr_wrk);
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&removed);
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	/* Pull this off the queue and process it if it was the last one. */
21208c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
21218c2ecf20Sopenharmony_ci	while (!list_empty(&hbus->dr_list)) {
21228c2ecf20Sopenharmony_ci		dr = list_first_entry(&hbus->dr_list, struct hv_dr_state,
21238c2ecf20Sopenharmony_ci				      list_entry);
21248c2ecf20Sopenharmony_ci		list_del(&dr->list_entry);
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci		/* Throw this away if the list still has stuff in it. */
21278c2ecf20Sopenharmony_ci		if (!list_empty(&hbus->dr_list)) {
21288c2ecf20Sopenharmony_ci			kfree(dr);
21298c2ecf20Sopenharmony_ci			continue;
21308c2ecf20Sopenharmony_ci		}
21318c2ecf20Sopenharmony_ci	}
21328c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	if (!dr) {
21358c2ecf20Sopenharmony_ci		put_hvpcibus(hbus);
21368c2ecf20Sopenharmony_ci		return;
21378c2ecf20Sopenharmony_ci	}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	/* First, mark all existing children as reported missing. */
21408c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
21418c2ecf20Sopenharmony_ci	list_for_each_entry(hpdev, &hbus->children, list_entry) {
21428c2ecf20Sopenharmony_ci		hpdev->reported_missing = true;
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	/* Next, add back any reported devices. */
21478c2ecf20Sopenharmony_ci	for (child_no = 0; child_no < dr->device_count; child_no++) {
21488c2ecf20Sopenharmony_ci		found = false;
21498c2ecf20Sopenharmony_ci		new_desc = &dr->func[child_no];
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hbus->device_list_lock, flags);
21528c2ecf20Sopenharmony_ci		list_for_each_entry(hpdev, &hbus->children, list_entry) {
21538c2ecf20Sopenharmony_ci			if ((hpdev->desc.win_slot.slot == new_desc->win_slot.slot) &&
21548c2ecf20Sopenharmony_ci			    (hpdev->desc.v_id == new_desc->v_id) &&
21558c2ecf20Sopenharmony_ci			    (hpdev->desc.d_id == new_desc->d_id) &&
21568c2ecf20Sopenharmony_ci			    (hpdev->desc.ser == new_desc->ser)) {
21578c2ecf20Sopenharmony_ci				hpdev->reported_missing = false;
21588c2ecf20Sopenharmony_ci				found = true;
21598c2ecf20Sopenharmony_ci			}
21608c2ecf20Sopenharmony_ci		}
21618c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hbus->device_list_lock, flags);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci		if (!found) {
21648c2ecf20Sopenharmony_ci			hpdev = new_pcichild_device(hbus, new_desc);
21658c2ecf20Sopenharmony_ci			if (!hpdev)
21668c2ecf20Sopenharmony_ci				dev_err(&hbus->hdev->device,
21678c2ecf20Sopenharmony_ci					"couldn't record a child device.\n");
21688c2ecf20Sopenharmony_ci		}
21698c2ecf20Sopenharmony_ci	}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	/* Move missing children to a list on the stack. */
21728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
21738c2ecf20Sopenharmony_ci	do {
21748c2ecf20Sopenharmony_ci		found = false;
21758c2ecf20Sopenharmony_ci		list_for_each_entry(hpdev, &hbus->children, list_entry) {
21768c2ecf20Sopenharmony_ci			if (hpdev->reported_missing) {
21778c2ecf20Sopenharmony_ci				found = true;
21788c2ecf20Sopenharmony_ci				put_pcichild(hpdev);
21798c2ecf20Sopenharmony_ci				list_move_tail(&hpdev->list_entry, &removed);
21808c2ecf20Sopenharmony_ci				break;
21818c2ecf20Sopenharmony_ci			}
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci	} while (found);
21848c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	/* Delete everything that should no longer exist. */
21878c2ecf20Sopenharmony_ci	while (!list_empty(&removed)) {
21888c2ecf20Sopenharmony_ci		hpdev = list_first_entry(&removed, struct hv_pci_dev,
21898c2ecf20Sopenharmony_ci					 list_entry);
21908c2ecf20Sopenharmony_ci		list_del(&hpdev->list_entry);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci		if (hpdev->pci_slot)
21938c2ecf20Sopenharmony_ci			pci_destroy_slot(hpdev->pci_slot);
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci		put_pcichild(hpdev);
21968c2ecf20Sopenharmony_ci	}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	switch (hbus->state) {
21998c2ecf20Sopenharmony_ci	case hv_pcibus_installed:
22008c2ecf20Sopenharmony_ci		/*
22018c2ecf20Sopenharmony_ci		 * Tell the core to rescan bus
22028c2ecf20Sopenharmony_ci		 * because there may have been changes.
22038c2ecf20Sopenharmony_ci		 */
22048c2ecf20Sopenharmony_ci		pci_lock_rescan_remove();
22058c2ecf20Sopenharmony_ci		pci_scan_child_bus(hbus->pci_bus);
22068c2ecf20Sopenharmony_ci		hv_pci_assign_numa_node(hbus);
22078c2ecf20Sopenharmony_ci		hv_pci_assign_slots(hbus);
22088c2ecf20Sopenharmony_ci		pci_unlock_rescan_remove();
22098c2ecf20Sopenharmony_ci		break;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	case hv_pcibus_init:
22128c2ecf20Sopenharmony_ci	case hv_pcibus_probed:
22138c2ecf20Sopenharmony_ci		survey_child_resources(hbus);
22148c2ecf20Sopenharmony_ci		break;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	default:
22178c2ecf20Sopenharmony_ci		break;
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	put_hvpcibus(hbus);
22218c2ecf20Sopenharmony_ci	kfree(dr);
22228c2ecf20Sopenharmony_ci}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci/**
22258c2ecf20Sopenharmony_ci * hv_pci_start_relations_work() - Queue work to start device discovery
22268c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
22278c2ecf20Sopenharmony_ci * @dr:		The list of children returned from host
22288c2ecf20Sopenharmony_ci *
22298c2ecf20Sopenharmony_ci * Return:  0 on success, -errno on failure
22308c2ecf20Sopenharmony_ci */
22318c2ecf20Sopenharmony_cistatic int hv_pci_start_relations_work(struct hv_pcibus_device *hbus,
22328c2ecf20Sopenharmony_ci				       struct hv_dr_state *dr)
22338c2ecf20Sopenharmony_ci{
22348c2ecf20Sopenharmony_ci	struct hv_dr_work *dr_wrk;
22358c2ecf20Sopenharmony_ci	unsigned long flags;
22368c2ecf20Sopenharmony_ci	bool pending_dr;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	if (hbus->state == hv_pcibus_removing) {
22398c2ecf20Sopenharmony_ci		dev_info(&hbus->hdev->device,
22408c2ecf20Sopenharmony_ci			 "PCI VMBus BUS_RELATIONS: ignored\n");
22418c2ecf20Sopenharmony_ci		return -ENOENT;
22428c2ecf20Sopenharmony_ci	}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
22458c2ecf20Sopenharmony_ci	if (!dr_wrk)
22468c2ecf20Sopenharmony_ci		return -ENOMEM;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	INIT_WORK(&dr_wrk->wrk, pci_devices_present_work);
22498c2ecf20Sopenharmony_ci	dr_wrk->bus = hbus;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
22528c2ecf20Sopenharmony_ci	/*
22538c2ecf20Sopenharmony_ci	 * If pending_dr is true, we have already queued a work,
22548c2ecf20Sopenharmony_ci	 * which will see the new dr. Otherwise, we need to
22558c2ecf20Sopenharmony_ci	 * queue a new work.
22568c2ecf20Sopenharmony_ci	 */
22578c2ecf20Sopenharmony_ci	pending_dr = !list_empty(&hbus->dr_list);
22588c2ecf20Sopenharmony_ci	list_add_tail(&dr->list_entry, &hbus->dr_list);
22598c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	if (pending_dr) {
22628c2ecf20Sopenharmony_ci		kfree(dr_wrk);
22638c2ecf20Sopenharmony_ci	} else {
22648c2ecf20Sopenharmony_ci		get_hvpcibus(hbus);
22658c2ecf20Sopenharmony_ci		queue_work(hbus->wq, &dr_wrk->wrk);
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	return 0;
22698c2ecf20Sopenharmony_ci}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci/**
22728c2ecf20Sopenharmony_ci * hv_pci_devices_present() - Handle list of new children
22738c2ecf20Sopenharmony_ci * @hbus:      Root PCI bus, as understood by this driver
22748c2ecf20Sopenharmony_ci * @relations: Packet from host listing children
22758c2ecf20Sopenharmony_ci *
22768c2ecf20Sopenharmony_ci * Process a new list of devices on the bus. The list of devices is
22778c2ecf20Sopenharmony_ci * discovered by VSP and sent to us via VSP message PCI_BUS_RELATIONS,
22788c2ecf20Sopenharmony_ci * whenever a new list of devices for this bus appears.
22798c2ecf20Sopenharmony_ci */
22808c2ecf20Sopenharmony_cistatic void hv_pci_devices_present(struct hv_pcibus_device *hbus,
22818c2ecf20Sopenharmony_ci				   struct pci_bus_relations *relations)
22828c2ecf20Sopenharmony_ci{
22838c2ecf20Sopenharmony_ci	struct hv_dr_state *dr;
22848c2ecf20Sopenharmony_ci	int i;
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	dr = kzalloc(struct_size(dr, func, relations->device_count),
22878c2ecf20Sopenharmony_ci		     GFP_NOWAIT);
22888c2ecf20Sopenharmony_ci	if (!dr)
22898c2ecf20Sopenharmony_ci		return;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci	dr->device_count = relations->device_count;
22928c2ecf20Sopenharmony_ci	for (i = 0; i < dr->device_count; i++) {
22938c2ecf20Sopenharmony_ci		dr->func[i].v_id = relations->func[i].v_id;
22948c2ecf20Sopenharmony_ci		dr->func[i].d_id = relations->func[i].d_id;
22958c2ecf20Sopenharmony_ci		dr->func[i].rev = relations->func[i].rev;
22968c2ecf20Sopenharmony_ci		dr->func[i].prog_intf = relations->func[i].prog_intf;
22978c2ecf20Sopenharmony_ci		dr->func[i].subclass = relations->func[i].subclass;
22988c2ecf20Sopenharmony_ci		dr->func[i].base_class = relations->func[i].base_class;
22998c2ecf20Sopenharmony_ci		dr->func[i].subsystem_id = relations->func[i].subsystem_id;
23008c2ecf20Sopenharmony_ci		dr->func[i].win_slot = relations->func[i].win_slot;
23018c2ecf20Sopenharmony_ci		dr->func[i].ser = relations->func[i].ser;
23028c2ecf20Sopenharmony_ci	}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	if (hv_pci_start_relations_work(hbus, dr))
23058c2ecf20Sopenharmony_ci		kfree(dr);
23068c2ecf20Sopenharmony_ci}
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci/**
23098c2ecf20Sopenharmony_ci * hv_pci_devices_present2() - Handle list of new children
23108c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
23118c2ecf20Sopenharmony_ci * @relations:	Packet from host listing children
23128c2ecf20Sopenharmony_ci *
23138c2ecf20Sopenharmony_ci * This function is the v2 version of hv_pci_devices_present()
23148c2ecf20Sopenharmony_ci */
23158c2ecf20Sopenharmony_cistatic void hv_pci_devices_present2(struct hv_pcibus_device *hbus,
23168c2ecf20Sopenharmony_ci				    struct pci_bus_relations2 *relations)
23178c2ecf20Sopenharmony_ci{
23188c2ecf20Sopenharmony_ci	struct hv_dr_state *dr;
23198c2ecf20Sopenharmony_ci	int i;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	dr = kzalloc(struct_size(dr, func, relations->device_count),
23228c2ecf20Sopenharmony_ci		     GFP_NOWAIT);
23238c2ecf20Sopenharmony_ci	if (!dr)
23248c2ecf20Sopenharmony_ci		return;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	dr->device_count = relations->device_count;
23278c2ecf20Sopenharmony_ci	for (i = 0; i < dr->device_count; i++) {
23288c2ecf20Sopenharmony_ci		dr->func[i].v_id = relations->func[i].v_id;
23298c2ecf20Sopenharmony_ci		dr->func[i].d_id = relations->func[i].d_id;
23308c2ecf20Sopenharmony_ci		dr->func[i].rev = relations->func[i].rev;
23318c2ecf20Sopenharmony_ci		dr->func[i].prog_intf = relations->func[i].prog_intf;
23328c2ecf20Sopenharmony_ci		dr->func[i].subclass = relations->func[i].subclass;
23338c2ecf20Sopenharmony_ci		dr->func[i].base_class = relations->func[i].base_class;
23348c2ecf20Sopenharmony_ci		dr->func[i].subsystem_id = relations->func[i].subsystem_id;
23358c2ecf20Sopenharmony_ci		dr->func[i].win_slot = relations->func[i].win_slot;
23368c2ecf20Sopenharmony_ci		dr->func[i].ser = relations->func[i].ser;
23378c2ecf20Sopenharmony_ci		dr->func[i].flags = relations->func[i].flags;
23388c2ecf20Sopenharmony_ci		dr->func[i].virtual_numa_node =
23398c2ecf20Sopenharmony_ci			relations->func[i].virtual_numa_node;
23408c2ecf20Sopenharmony_ci	}
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	if (hv_pci_start_relations_work(hbus, dr))
23438c2ecf20Sopenharmony_ci		kfree(dr);
23448c2ecf20Sopenharmony_ci}
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci/**
23478c2ecf20Sopenharmony_ci * hv_eject_device_work() - Asynchronously handles ejection
23488c2ecf20Sopenharmony_ci * @work:	Work struct embedded in internal device struct
23498c2ecf20Sopenharmony_ci *
23508c2ecf20Sopenharmony_ci * This function handles ejecting a device.  Windows will
23518c2ecf20Sopenharmony_ci * attempt to gracefully eject a device, waiting 60 seconds to
23528c2ecf20Sopenharmony_ci * hear back from the guest OS that this completed successfully.
23538c2ecf20Sopenharmony_ci * If this timer expires, the device will be forcibly removed.
23548c2ecf20Sopenharmony_ci */
23558c2ecf20Sopenharmony_cistatic void hv_eject_device_work(struct work_struct *work)
23568c2ecf20Sopenharmony_ci{
23578c2ecf20Sopenharmony_ci	struct pci_eject_response *ejct_pkt;
23588c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
23598c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
23608c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
23618c2ecf20Sopenharmony_ci	unsigned long flags;
23628c2ecf20Sopenharmony_ci	int wslot;
23638c2ecf20Sopenharmony_ci	struct {
23648c2ecf20Sopenharmony_ci		struct pci_packet pkt;
23658c2ecf20Sopenharmony_ci		u8 buffer[sizeof(struct pci_eject_response)];
23668c2ecf20Sopenharmony_ci	} ctxt;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	hpdev = container_of(work, struct hv_pci_dev, wrk);
23698c2ecf20Sopenharmony_ci	hbus = hpdev->hbus;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	/*
23728c2ecf20Sopenharmony_ci	 * Ejection can come before or after the PCI bus has been set up, so
23738c2ecf20Sopenharmony_ci	 * attempt to find it and tear down the bus state, if it exists.  This
23748c2ecf20Sopenharmony_ci	 * must be done without constructs like pci_domain_nr(hbus->pci_bus)
23758c2ecf20Sopenharmony_ci	 * because hbus->pci_bus may not exist yet.
23768c2ecf20Sopenharmony_ci	 */
23778c2ecf20Sopenharmony_ci	wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
23788c2ecf20Sopenharmony_ci	pdev = pci_get_domain_bus_and_slot(hbus->sysdata.domain, 0, wslot);
23798c2ecf20Sopenharmony_ci	if (pdev) {
23808c2ecf20Sopenharmony_ci		pci_lock_rescan_remove();
23818c2ecf20Sopenharmony_ci		pci_stop_and_remove_bus_device(pdev);
23828c2ecf20Sopenharmony_ci		pci_dev_put(pdev);
23838c2ecf20Sopenharmony_ci		pci_unlock_rescan_remove();
23848c2ecf20Sopenharmony_ci	}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hbus->device_list_lock, flags);
23878c2ecf20Sopenharmony_ci	list_del(&hpdev->list_entry);
23888c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hbus->device_list_lock, flags);
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	if (hpdev->pci_slot)
23918c2ecf20Sopenharmony_ci		pci_destroy_slot(hpdev->pci_slot);
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	memset(&ctxt, 0, sizeof(ctxt));
23948c2ecf20Sopenharmony_ci	ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
23958c2ecf20Sopenharmony_ci	ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
23968c2ecf20Sopenharmony_ci	ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
23978c2ecf20Sopenharmony_ci	vmbus_sendpacket(hbus->hdev->channel, ejct_pkt,
23988c2ecf20Sopenharmony_ci			 sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
23998c2ecf20Sopenharmony_ci			 VM_PKT_DATA_INBAND, 0);
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	/* For the get_pcichild() in hv_pci_eject_device() */
24028c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
24038c2ecf20Sopenharmony_ci	/* For the two refs got in new_pcichild_device() */
24048c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
24058c2ecf20Sopenharmony_ci	put_pcichild(hpdev);
24068c2ecf20Sopenharmony_ci	/* hpdev has been freed. Do not use it any more. */
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	put_hvpcibus(hbus);
24098c2ecf20Sopenharmony_ci}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci/**
24128c2ecf20Sopenharmony_ci * hv_pci_eject_device() - Handles device ejection
24138c2ecf20Sopenharmony_ci * @hpdev:	Internal device tracking struct
24148c2ecf20Sopenharmony_ci *
24158c2ecf20Sopenharmony_ci * This function is invoked when an ejection packet arrives.  It
24168c2ecf20Sopenharmony_ci * just schedules work so that we don't re-enter the packet
24178c2ecf20Sopenharmony_ci * delivery code handling the ejection.
24188c2ecf20Sopenharmony_ci */
24198c2ecf20Sopenharmony_cistatic void hv_pci_eject_device(struct hv_pci_dev *hpdev)
24208c2ecf20Sopenharmony_ci{
24218c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hpdev->hbus;
24228c2ecf20Sopenharmony_ci	struct hv_device *hdev = hbus->hdev;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	if (hbus->state == hv_pcibus_removing) {
24258c2ecf20Sopenharmony_ci		dev_info(&hdev->device, "PCI VMBus EJECT: ignored\n");
24268c2ecf20Sopenharmony_ci		return;
24278c2ecf20Sopenharmony_ci	}
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	get_pcichild(hpdev);
24308c2ecf20Sopenharmony_ci	INIT_WORK(&hpdev->wrk, hv_eject_device_work);
24318c2ecf20Sopenharmony_ci	get_hvpcibus(hbus);
24328c2ecf20Sopenharmony_ci	queue_work(hbus->wq, &hpdev->wrk);
24338c2ecf20Sopenharmony_ci}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci/**
24368c2ecf20Sopenharmony_ci * hv_pci_onchannelcallback() - Handles incoming packets
24378c2ecf20Sopenharmony_ci * @context:	Internal bus tracking struct
24388c2ecf20Sopenharmony_ci *
24398c2ecf20Sopenharmony_ci * This function is invoked whenever the host sends a packet to
24408c2ecf20Sopenharmony_ci * this channel (which is private to this root PCI bus).
24418c2ecf20Sopenharmony_ci */
24428c2ecf20Sopenharmony_cistatic void hv_pci_onchannelcallback(void *context)
24438c2ecf20Sopenharmony_ci{
24448c2ecf20Sopenharmony_ci	const int packet_size = 0x100;
24458c2ecf20Sopenharmony_ci	int ret;
24468c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = context;
24478c2ecf20Sopenharmony_ci	u32 bytes_recvd;
24488c2ecf20Sopenharmony_ci	u64 req_id;
24498c2ecf20Sopenharmony_ci	struct vmpacket_descriptor *desc;
24508c2ecf20Sopenharmony_ci	unsigned char *buffer;
24518c2ecf20Sopenharmony_ci	int bufferlen = packet_size;
24528c2ecf20Sopenharmony_ci	struct pci_packet *comp_packet;
24538c2ecf20Sopenharmony_ci	struct pci_response *response;
24548c2ecf20Sopenharmony_ci	struct pci_incoming_message *new_message;
24558c2ecf20Sopenharmony_ci	struct pci_bus_relations *bus_rel;
24568c2ecf20Sopenharmony_ci	struct pci_bus_relations2 *bus_rel2;
24578c2ecf20Sopenharmony_ci	struct pci_dev_inval_block *inval;
24588c2ecf20Sopenharmony_ci	struct pci_dev_incoming *dev_message;
24598c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	buffer = kmalloc(bufferlen, GFP_ATOMIC);
24628c2ecf20Sopenharmony_ci	if (!buffer)
24638c2ecf20Sopenharmony_ci		return;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	while (1) {
24668c2ecf20Sopenharmony_ci		ret = vmbus_recvpacket_raw(hbus->hdev->channel, buffer,
24678c2ecf20Sopenharmony_ci					   bufferlen, &bytes_recvd, &req_id);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci		if (ret == -ENOBUFS) {
24708c2ecf20Sopenharmony_ci			kfree(buffer);
24718c2ecf20Sopenharmony_ci			/* Handle large packet */
24728c2ecf20Sopenharmony_ci			bufferlen = bytes_recvd;
24738c2ecf20Sopenharmony_ci			buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
24748c2ecf20Sopenharmony_ci			if (!buffer)
24758c2ecf20Sopenharmony_ci				return;
24768c2ecf20Sopenharmony_ci			continue;
24778c2ecf20Sopenharmony_ci		}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci		/* Zero length indicates there are no more packets. */
24808c2ecf20Sopenharmony_ci		if (ret || !bytes_recvd)
24818c2ecf20Sopenharmony_ci			break;
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci		/*
24848c2ecf20Sopenharmony_ci		 * All incoming packets must be at least as large as a
24858c2ecf20Sopenharmony_ci		 * response.
24868c2ecf20Sopenharmony_ci		 */
24878c2ecf20Sopenharmony_ci		if (bytes_recvd <= sizeof(struct pci_response))
24888c2ecf20Sopenharmony_ci			continue;
24898c2ecf20Sopenharmony_ci		desc = (struct vmpacket_descriptor *)buffer;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci		switch (desc->type) {
24928c2ecf20Sopenharmony_ci		case VM_PKT_COMP:
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci			/*
24958c2ecf20Sopenharmony_ci			 * The host is trusted, and thus it's safe to interpret
24968c2ecf20Sopenharmony_ci			 * this transaction ID as a pointer.
24978c2ecf20Sopenharmony_ci			 */
24988c2ecf20Sopenharmony_ci			comp_packet = (struct pci_packet *)req_id;
24998c2ecf20Sopenharmony_ci			response = (struct pci_response *)buffer;
25008c2ecf20Sopenharmony_ci			comp_packet->completion_func(comp_packet->compl_ctxt,
25018c2ecf20Sopenharmony_ci						     response,
25028c2ecf20Sopenharmony_ci						     bytes_recvd);
25038c2ecf20Sopenharmony_ci			break;
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci		case VM_PKT_DATA_INBAND:
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci			new_message = (struct pci_incoming_message *)buffer;
25088c2ecf20Sopenharmony_ci			switch (new_message->message_type.type) {
25098c2ecf20Sopenharmony_ci			case PCI_BUS_RELATIONS:
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci				bus_rel = (struct pci_bus_relations *)buffer;
25128c2ecf20Sopenharmony_ci				if (bytes_recvd <
25138c2ecf20Sopenharmony_ci					struct_size(bus_rel, func,
25148c2ecf20Sopenharmony_ci						    bus_rel->device_count)) {
25158c2ecf20Sopenharmony_ci					dev_err(&hbus->hdev->device,
25168c2ecf20Sopenharmony_ci						"bus relations too small\n");
25178c2ecf20Sopenharmony_ci					break;
25188c2ecf20Sopenharmony_ci				}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci				hv_pci_devices_present(hbus, bus_rel);
25218c2ecf20Sopenharmony_ci				break;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci			case PCI_BUS_RELATIONS2:
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci				bus_rel2 = (struct pci_bus_relations2 *)buffer;
25268c2ecf20Sopenharmony_ci				if (bytes_recvd <
25278c2ecf20Sopenharmony_ci					struct_size(bus_rel2, func,
25288c2ecf20Sopenharmony_ci						    bus_rel2->device_count)) {
25298c2ecf20Sopenharmony_ci					dev_err(&hbus->hdev->device,
25308c2ecf20Sopenharmony_ci						"bus relations v2 too small\n");
25318c2ecf20Sopenharmony_ci					break;
25328c2ecf20Sopenharmony_ci				}
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci				hv_pci_devices_present2(hbus, bus_rel2);
25358c2ecf20Sopenharmony_ci				break;
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci			case PCI_EJECT:
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci				dev_message = (struct pci_dev_incoming *)buffer;
25408c2ecf20Sopenharmony_ci				hpdev = get_pcichild_wslot(hbus,
25418c2ecf20Sopenharmony_ci						      dev_message->wslot.slot);
25428c2ecf20Sopenharmony_ci				if (hpdev) {
25438c2ecf20Sopenharmony_ci					hv_pci_eject_device(hpdev);
25448c2ecf20Sopenharmony_ci					put_pcichild(hpdev);
25458c2ecf20Sopenharmony_ci				}
25468c2ecf20Sopenharmony_ci				break;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci			case PCI_INVALIDATE_BLOCK:
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci				inval = (struct pci_dev_inval_block *)buffer;
25518c2ecf20Sopenharmony_ci				hpdev = get_pcichild_wslot(hbus,
25528c2ecf20Sopenharmony_ci							   inval->wslot.slot);
25538c2ecf20Sopenharmony_ci				if (hpdev) {
25548c2ecf20Sopenharmony_ci					if (hpdev->block_invalidate) {
25558c2ecf20Sopenharmony_ci						hpdev->block_invalidate(
25568c2ecf20Sopenharmony_ci						    hpdev->invalidate_context,
25578c2ecf20Sopenharmony_ci						    inval->block_mask);
25588c2ecf20Sopenharmony_ci					}
25598c2ecf20Sopenharmony_ci					put_pcichild(hpdev);
25608c2ecf20Sopenharmony_ci				}
25618c2ecf20Sopenharmony_ci				break;
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci			default:
25648c2ecf20Sopenharmony_ci				dev_warn(&hbus->hdev->device,
25658c2ecf20Sopenharmony_ci					"Unimplemented protocol message %x\n",
25668c2ecf20Sopenharmony_ci					new_message->message_type.type);
25678c2ecf20Sopenharmony_ci				break;
25688c2ecf20Sopenharmony_ci			}
25698c2ecf20Sopenharmony_ci			break;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci		default:
25728c2ecf20Sopenharmony_ci			dev_err(&hbus->hdev->device,
25738c2ecf20Sopenharmony_ci				"unhandled packet type %d, tid %llx len %d\n",
25748c2ecf20Sopenharmony_ci				desc->type, req_id, bytes_recvd);
25758c2ecf20Sopenharmony_ci			break;
25768c2ecf20Sopenharmony_ci		}
25778c2ecf20Sopenharmony_ci	}
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	kfree(buffer);
25808c2ecf20Sopenharmony_ci}
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci/**
25838c2ecf20Sopenharmony_ci * hv_pci_protocol_negotiation() - Set up protocol
25848c2ecf20Sopenharmony_ci * @hdev:		VMBus's tracking struct for this root PCI bus.
25858c2ecf20Sopenharmony_ci * @version:		Array of supported channel protocol versions in
25868c2ecf20Sopenharmony_ci *			the order of probing - highest go first.
25878c2ecf20Sopenharmony_ci * @num_version:	Number of elements in the version array.
25888c2ecf20Sopenharmony_ci *
25898c2ecf20Sopenharmony_ci * This driver is intended to support running on Windows 10
25908c2ecf20Sopenharmony_ci * (server) and later versions. It will not run on earlier
25918c2ecf20Sopenharmony_ci * versions, as they assume that many of the operations which
25928c2ecf20Sopenharmony_ci * Linux needs accomplished with a spinlock held were done via
25938c2ecf20Sopenharmony_ci * asynchronous messaging via VMBus.  Windows 10 increases the
25948c2ecf20Sopenharmony_ci * surface area of PCI emulation so that these actions can take
25958c2ecf20Sopenharmony_ci * place by suspending a virtual processor for their duration.
25968c2ecf20Sopenharmony_ci *
25978c2ecf20Sopenharmony_ci * This function negotiates the channel protocol version,
25988c2ecf20Sopenharmony_ci * failing if the host doesn't support the necessary protocol
25998c2ecf20Sopenharmony_ci * level.
26008c2ecf20Sopenharmony_ci */
26018c2ecf20Sopenharmony_cistatic int hv_pci_protocol_negotiation(struct hv_device *hdev,
26028c2ecf20Sopenharmony_ci				       enum pci_protocol_version_t version[],
26038c2ecf20Sopenharmony_ci				       int num_version)
26048c2ecf20Sopenharmony_ci{
26058c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
26068c2ecf20Sopenharmony_ci	struct pci_version_request *version_req;
26078c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
26088c2ecf20Sopenharmony_ci	struct pci_packet *pkt;
26098c2ecf20Sopenharmony_ci	int ret;
26108c2ecf20Sopenharmony_ci	int i;
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	/*
26138c2ecf20Sopenharmony_ci	 * Initiate the handshake with the host and negotiate
26148c2ecf20Sopenharmony_ci	 * a version that the host can support. We start with the
26158c2ecf20Sopenharmony_ci	 * highest version number and go down if the host cannot
26168c2ecf20Sopenharmony_ci	 * support it.
26178c2ecf20Sopenharmony_ci	 */
26188c2ecf20Sopenharmony_ci	pkt = kzalloc(sizeof(*pkt) + sizeof(*version_req), GFP_KERNEL);
26198c2ecf20Sopenharmony_ci	if (!pkt)
26208c2ecf20Sopenharmony_ci		return -ENOMEM;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.host_event);
26238c2ecf20Sopenharmony_ci	pkt->completion_func = hv_pci_generic_compl;
26248c2ecf20Sopenharmony_ci	pkt->compl_ctxt = &comp_pkt;
26258c2ecf20Sopenharmony_ci	version_req = (struct pci_version_request *)&pkt->message;
26268c2ecf20Sopenharmony_ci	version_req->message_type.type = PCI_QUERY_PROTOCOL_VERSION;
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	for (i = 0; i < num_version; i++) {
26298c2ecf20Sopenharmony_ci		version_req->protocol_version = version[i];
26308c2ecf20Sopenharmony_ci		ret = vmbus_sendpacket(hdev->channel, version_req,
26318c2ecf20Sopenharmony_ci				sizeof(struct pci_version_request),
26328c2ecf20Sopenharmony_ci				(unsigned long)pkt, VM_PKT_DATA_INBAND,
26338c2ecf20Sopenharmony_ci				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
26348c2ecf20Sopenharmony_ci		if (!ret)
26358c2ecf20Sopenharmony_ci			ret = wait_for_response(hdev, &comp_pkt.host_event);
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci		if (ret) {
26388c2ecf20Sopenharmony_ci			dev_err(&hdev->device,
26398c2ecf20Sopenharmony_ci				"PCI Pass-through VSP failed to request version: %d",
26408c2ecf20Sopenharmony_ci				ret);
26418c2ecf20Sopenharmony_ci			goto exit;
26428c2ecf20Sopenharmony_ci		}
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci		if (comp_pkt.completion_status >= 0) {
26458c2ecf20Sopenharmony_ci			hbus->protocol_version = version[i];
26468c2ecf20Sopenharmony_ci			dev_info(&hdev->device,
26478c2ecf20Sopenharmony_ci				"PCI VMBus probing: Using version %#x\n",
26488c2ecf20Sopenharmony_ci				hbus->protocol_version);
26498c2ecf20Sopenharmony_ci			goto exit;
26508c2ecf20Sopenharmony_ci		}
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci		if (comp_pkt.completion_status != STATUS_REVISION_MISMATCH) {
26538c2ecf20Sopenharmony_ci			dev_err(&hdev->device,
26548c2ecf20Sopenharmony_ci				"PCI Pass-through VSP failed version request: %#x",
26558c2ecf20Sopenharmony_ci				comp_pkt.completion_status);
26568c2ecf20Sopenharmony_ci			ret = -EPROTO;
26578c2ecf20Sopenharmony_ci			goto exit;
26588c2ecf20Sopenharmony_ci		}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci		reinit_completion(&comp_pkt.host_event);
26618c2ecf20Sopenharmony_ci	}
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	dev_err(&hdev->device,
26648c2ecf20Sopenharmony_ci		"PCI pass-through VSP failed to find supported version");
26658c2ecf20Sopenharmony_ci	ret = -EPROTO;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ciexit:
26688c2ecf20Sopenharmony_ci	kfree(pkt);
26698c2ecf20Sopenharmony_ci	return ret;
26708c2ecf20Sopenharmony_ci}
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci/**
26738c2ecf20Sopenharmony_ci * hv_pci_free_bridge_windows() - Release memory regions for the
26748c2ecf20Sopenharmony_ci * bus
26758c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
26768c2ecf20Sopenharmony_ci */
26778c2ecf20Sopenharmony_cistatic void hv_pci_free_bridge_windows(struct hv_pcibus_device *hbus)
26788c2ecf20Sopenharmony_ci{
26798c2ecf20Sopenharmony_ci	/*
26808c2ecf20Sopenharmony_ci	 * Set the resources back to the way they looked when they
26818c2ecf20Sopenharmony_ci	 * were allocated by setting IORESOURCE_BUSY again.
26828c2ecf20Sopenharmony_ci	 */
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	if (hbus->low_mmio_space && hbus->low_mmio_res) {
26858c2ecf20Sopenharmony_ci		hbus->low_mmio_res->flags |= IORESOURCE_BUSY;
26868c2ecf20Sopenharmony_ci		vmbus_free_mmio(hbus->low_mmio_res->start,
26878c2ecf20Sopenharmony_ci				resource_size(hbus->low_mmio_res));
26888c2ecf20Sopenharmony_ci	}
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci	if (hbus->high_mmio_space && hbus->high_mmio_res) {
26918c2ecf20Sopenharmony_ci		hbus->high_mmio_res->flags |= IORESOURCE_BUSY;
26928c2ecf20Sopenharmony_ci		vmbus_free_mmio(hbus->high_mmio_res->start,
26938c2ecf20Sopenharmony_ci				resource_size(hbus->high_mmio_res));
26948c2ecf20Sopenharmony_ci	}
26958c2ecf20Sopenharmony_ci}
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci/**
26988c2ecf20Sopenharmony_ci * hv_pci_allocate_bridge_windows() - Allocate memory regions
26998c2ecf20Sopenharmony_ci * for the bus
27008c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
27018c2ecf20Sopenharmony_ci *
27028c2ecf20Sopenharmony_ci * This function calls vmbus_allocate_mmio(), which is itself a
27038c2ecf20Sopenharmony_ci * bit of a compromise.  Ideally, we might change the pnp layer
27048c2ecf20Sopenharmony_ci * in the kernel such that it comprehends either PCI devices
27058c2ecf20Sopenharmony_ci * which are "grandchildren of ACPI," with some intermediate bus
27068c2ecf20Sopenharmony_ci * node (in this case, VMBus) or change it such that it
27078c2ecf20Sopenharmony_ci * understands VMBus.  The pnp layer, however, has been declared
27088c2ecf20Sopenharmony_ci * deprecated, and not subject to change.
27098c2ecf20Sopenharmony_ci *
27108c2ecf20Sopenharmony_ci * The workaround, implemented here, is to ask VMBus to allocate
27118c2ecf20Sopenharmony_ci * MMIO space for this bus.  VMBus itself knows which ranges are
27128c2ecf20Sopenharmony_ci * appropriate by looking at its own ACPI objects.  Then, after
27138c2ecf20Sopenharmony_ci * these ranges are claimed, they're modified to look like they
27148c2ecf20Sopenharmony_ci * would have looked if the ACPI and pnp code had allocated
27158c2ecf20Sopenharmony_ci * bridge windows.  These descriptors have to exist in this form
27168c2ecf20Sopenharmony_ci * in order to satisfy the code which will get invoked when the
27178c2ecf20Sopenharmony_ci * endpoint PCI function driver calls request_mem_region() or
27188c2ecf20Sopenharmony_ci * request_mem_region_exclusive().
27198c2ecf20Sopenharmony_ci *
27208c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
27218c2ecf20Sopenharmony_ci */
27228c2ecf20Sopenharmony_cistatic int hv_pci_allocate_bridge_windows(struct hv_pcibus_device *hbus)
27238c2ecf20Sopenharmony_ci{
27248c2ecf20Sopenharmony_ci	resource_size_t align;
27258c2ecf20Sopenharmony_ci	int ret;
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci	if (hbus->low_mmio_space) {
27288c2ecf20Sopenharmony_ci		align = 1ULL << (63 - __builtin_clzll(hbus->low_mmio_space));
27298c2ecf20Sopenharmony_ci		ret = vmbus_allocate_mmio(&hbus->low_mmio_res, hbus->hdev, 0,
27308c2ecf20Sopenharmony_ci					  (u64)(u32)0xffffffff,
27318c2ecf20Sopenharmony_ci					  hbus->low_mmio_space,
27328c2ecf20Sopenharmony_ci					  align, false);
27338c2ecf20Sopenharmony_ci		if (ret) {
27348c2ecf20Sopenharmony_ci			dev_err(&hbus->hdev->device,
27358c2ecf20Sopenharmony_ci				"Need %#llx of low MMIO space. Consider reconfiguring the VM.\n",
27368c2ecf20Sopenharmony_ci				hbus->low_mmio_space);
27378c2ecf20Sopenharmony_ci			return ret;
27388c2ecf20Sopenharmony_ci		}
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci		/* Modify this resource to become a bridge window. */
27418c2ecf20Sopenharmony_ci		hbus->low_mmio_res->flags |= IORESOURCE_WINDOW;
27428c2ecf20Sopenharmony_ci		hbus->low_mmio_res->flags &= ~IORESOURCE_BUSY;
27438c2ecf20Sopenharmony_ci		pci_add_resource(&hbus->resources_for_children,
27448c2ecf20Sopenharmony_ci				 hbus->low_mmio_res);
27458c2ecf20Sopenharmony_ci	}
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	if (hbus->high_mmio_space) {
27488c2ecf20Sopenharmony_ci		align = 1ULL << (63 - __builtin_clzll(hbus->high_mmio_space));
27498c2ecf20Sopenharmony_ci		ret = vmbus_allocate_mmio(&hbus->high_mmio_res, hbus->hdev,
27508c2ecf20Sopenharmony_ci					  0x100000000, -1,
27518c2ecf20Sopenharmony_ci					  hbus->high_mmio_space, align,
27528c2ecf20Sopenharmony_ci					  false);
27538c2ecf20Sopenharmony_ci		if (ret) {
27548c2ecf20Sopenharmony_ci			dev_err(&hbus->hdev->device,
27558c2ecf20Sopenharmony_ci				"Need %#llx of high MMIO space. Consider reconfiguring the VM.\n",
27568c2ecf20Sopenharmony_ci				hbus->high_mmio_space);
27578c2ecf20Sopenharmony_ci			goto release_low_mmio;
27588c2ecf20Sopenharmony_ci		}
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci		/* Modify this resource to become a bridge window. */
27618c2ecf20Sopenharmony_ci		hbus->high_mmio_res->flags |= IORESOURCE_WINDOW;
27628c2ecf20Sopenharmony_ci		hbus->high_mmio_res->flags &= ~IORESOURCE_BUSY;
27638c2ecf20Sopenharmony_ci		pci_add_resource(&hbus->resources_for_children,
27648c2ecf20Sopenharmony_ci				 hbus->high_mmio_res);
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	return 0;
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_cirelease_low_mmio:
27708c2ecf20Sopenharmony_ci	if (hbus->low_mmio_res) {
27718c2ecf20Sopenharmony_ci		vmbus_free_mmio(hbus->low_mmio_res->start,
27728c2ecf20Sopenharmony_ci				resource_size(hbus->low_mmio_res));
27738c2ecf20Sopenharmony_ci	}
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	return ret;
27768c2ecf20Sopenharmony_ci}
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci/**
27798c2ecf20Sopenharmony_ci * hv_allocate_config_window() - Find MMIO space for PCI Config
27808c2ecf20Sopenharmony_ci * @hbus:	Root PCI bus, as understood by this driver
27818c2ecf20Sopenharmony_ci *
27828c2ecf20Sopenharmony_ci * This function claims memory-mapped I/O space for accessing
27838c2ecf20Sopenharmony_ci * configuration space for the functions on this bus.
27848c2ecf20Sopenharmony_ci *
27858c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
27868c2ecf20Sopenharmony_ci */
27878c2ecf20Sopenharmony_cistatic int hv_allocate_config_window(struct hv_pcibus_device *hbus)
27888c2ecf20Sopenharmony_ci{
27898c2ecf20Sopenharmony_ci	int ret;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	/*
27928c2ecf20Sopenharmony_ci	 * Set up a region of MMIO space to use for accessing configuration
27938c2ecf20Sopenharmony_ci	 * space.
27948c2ecf20Sopenharmony_ci	 */
27958c2ecf20Sopenharmony_ci	ret = vmbus_allocate_mmio(&hbus->mem_config, hbus->hdev, 0, -1,
27968c2ecf20Sopenharmony_ci				  PCI_CONFIG_MMIO_LENGTH, 0x1000, false);
27978c2ecf20Sopenharmony_ci	if (ret)
27988c2ecf20Sopenharmony_ci		return ret;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	/*
28018c2ecf20Sopenharmony_ci	 * vmbus_allocate_mmio() gets used for allocating both device endpoint
28028c2ecf20Sopenharmony_ci	 * resource claims (those which cannot be overlapped) and the ranges
28038c2ecf20Sopenharmony_ci	 * which are valid for the children of this bus, which are intended
28048c2ecf20Sopenharmony_ci	 * to be overlapped by those children.  Set the flag on this claim
28058c2ecf20Sopenharmony_ci	 * meaning that this region can't be overlapped.
28068c2ecf20Sopenharmony_ci	 */
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	hbus->mem_config->flags |= IORESOURCE_BUSY;
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	return 0;
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_cistatic void hv_free_config_window(struct hv_pcibus_device *hbus)
28148c2ecf20Sopenharmony_ci{
28158c2ecf20Sopenharmony_ci	vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
28168c2ecf20Sopenharmony_ci}
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_cistatic int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs);
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci/**
28218c2ecf20Sopenharmony_ci * hv_pci_enter_d0() - Bring the "bus" into the D0 power state
28228c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
28238c2ecf20Sopenharmony_ci *
28248c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
28258c2ecf20Sopenharmony_ci */
28268c2ecf20Sopenharmony_cistatic int hv_pci_enter_d0(struct hv_device *hdev)
28278c2ecf20Sopenharmony_ci{
28288c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
28298c2ecf20Sopenharmony_ci	struct pci_bus_d0_entry *d0_entry;
28308c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
28318c2ecf20Sopenharmony_ci	struct pci_packet *pkt;
28328c2ecf20Sopenharmony_ci	bool retry = true;
28338c2ecf20Sopenharmony_ci	int ret;
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_cienter_d0_retry:
28368c2ecf20Sopenharmony_ci	/*
28378c2ecf20Sopenharmony_ci	 * Tell the host that the bus is ready to use, and moved into the
28388c2ecf20Sopenharmony_ci	 * powered-on state.  This includes telling the host which region
28398c2ecf20Sopenharmony_ci	 * of memory-mapped I/O space has been chosen for configuration space
28408c2ecf20Sopenharmony_ci	 * access.
28418c2ecf20Sopenharmony_ci	 */
28428c2ecf20Sopenharmony_ci	pkt = kzalloc(sizeof(*pkt) + sizeof(*d0_entry), GFP_KERNEL);
28438c2ecf20Sopenharmony_ci	if (!pkt)
28448c2ecf20Sopenharmony_ci		return -ENOMEM;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.host_event);
28478c2ecf20Sopenharmony_ci	pkt->completion_func = hv_pci_generic_compl;
28488c2ecf20Sopenharmony_ci	pkt->compl_ctxt = &comp_pkt;
28498c2ecf20Sopenharmony_ci	d0_entry = (struct pci_bus_d0_entry *)&pkt->message;
28508c2ecf20Sopenharmony_ci	d0_entry->message_type.type = PCI_BUS_D0ENTRY;
28518c2ecf20Sopenharmony_ci	d0_entry->mmio_base = hbus->mem_config->start;
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hdev->channel, d0_entry, sizeof(*d0_entry),
28548c2ecf20Sopenharmony_ci			       (unsigned long)pkt, VM_PKT_DATA_INBAND,
28558c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
28568c2ecf20Sopenharmony_ci	if (!ret)
28578c2ecf20Sopenharmony_ci		ret = wait_for_response(hdev, &comp_pkt.host_event);
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	if (ret)
28608c2ecf20Sopenharmony_ci		goto exit;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	/*
28638c2ecf20Sopenharmony_ci	 * In certain case (Kdump) the pci device of interest was
28648c2ecf20Sopenharmony_ci	 * not cleanly shut down and resource is still held on host
28658c2ecf20Sopenharmony_ci	 * side, the host could return invalid device status.
28668c2ecf20Sopenharmony_ci	 * We need to explicitly request host to release the resource
28678c2ecf20Sopenharmony_ci	 * and try to enter D0 again.
28688c2ecf20Sopenharmony_ci	 */
28698c2ecf20Sopenharmony_ci	if (comp_pkt.completion_status < 0 && retry) {
28708c2ecf20Sopenharmony_ci		retry = false;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci		dev_err(&hdev->device, "Retrying D0 Entry\n");
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci		/*
28758c2ecf20Sopenharmony_ci		 * Hv_pci_bus_exit() calls hv_send_resource_released()
28768c2ecf20Sopenharmony_ci		 * to free up resources of its child devices.
28778c2ecf20Sopenharmony_ci		 * In the kdump kernel we need to set the
28788c2ecf20Sopenharmony_ci		 * wslot_res_allocated to 255 so it scans all child
28798c2ecf20Sopenharmony_ci		 * devices to release resources allocated in the
28808c2ecf20Sopenharmony_ci		 * normal kernel before panic happened.
28818c2ecf20Sopenharmony_ci		 */
28828c2ecf20Sopenharmony_ci		hbus->wslot_res_allocated = 255;
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci		ret = hv_pci_bus_exit(hdev, true);
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci		if (ret == 0) {
28878c2ecf20Sopenharmony_ci			kfree(pkt);
28888c2ecf20Sopenharmony_ci			goto enter_d0_retry;
28898c2ecf20Sopenharmony_ci		}
28908c2ecf20Sopenharmony_ci		dev_err(&hdev->device,
28918c2ecf20Sopenharmony_ci			"Retrying D0 failed with ret %d\n", ret);
28928c2ecf20Sopenharmony_ci	}
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	if (comp_pkt.completion_status < 0) {
28958c2ecf20Sopenharmony_ci		dev_err(&hdev->device,
28968c2ecf20Sopenharmony_ci			"PCI Pass-through VSP failed D0 Entry with status %x\n",
28978c2ecf20Sopenharmony_ci			comp_pkt.completion_status);
28988c2ecf20Sopenharmony_ci		ret = -EPROTO;
28998c2ecf20Sopenharmony_ci		goto exit;
29008c2ecf20Sopenharmony_ci	}
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_ci	ret = 0;
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ciexit:
29058c2ecf20Sopenharmony_ci	kfree(pkt);
29068c2ecf20Sopenharmony_ci	return ret;
29078c2ecf20Sopenharmony_ci}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci/**
29108c2ecf20Sopenharmony_ci * hv_pci_query_relations() - Ask host to send list of child
29118c2ecf20Sopenharmony_ci * devices
29128c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
29138c2ecf20Sopenharmony_ci *
29148c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
29158c2ecf20Sopenharmony_ci */
29168c2ecf20Sopenharmony_cistatic int hv_pci_query_relations(struct hv_device *hdev)
29178c2ecf20Sopenharmony_ci{
29188c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
29198c2ecf20Sopenharmony_ci	struct pci_message message;
29208c2ecf20Sopenharmony_ci	struct completion comp;
29218c2ecf20Sopenharmony_ci	int ret;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	/* Ask the host to send along the list of child devices */
29248c2ecf20Sopenharmony_ci	init_completion(&comp);
29258c2ecf20Sopenharmony_ci	if (cmpxchg(&hbus->survey_event, NULL, &comp))
29268c2ecf20Sopenharmony_ci		return -ENOTEMPTY;
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	memset(&message, 0, sizeof(message));
29298c2ecf20Sopenharmony_ci	message.type = PCI_QUERY_BUS_RELATIONS;
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message),
29328c2ecf20Sopenharmony_ci			       0, VM_PKT_DATA_INBAND, 0);
29338c2ecf20Sopenharmony_ci	if (!ret)
29348c2ecf20Sopenharmony_ci		ret = wait_for_response(hdev, &comp);
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	/*
29378c2ecf20Sopenharmony_ci	 * In the case of fast device addition/removal, it's possible that
29388c2ecf20Sopenharmony_ci	 * vmbus_sendpacket() or wait_for_response() returns -ENODEV but we
29398c2ecf20Sopenharmony_ci	 * already got a PCI_BUS_RELATIONS* message from the host and the
29408c2ecf20Sopenharmony_ci	 * channel callback already scheduled a work to hbus->wq, which can be
29418c2ecf20Sopenharmony_ci	 * running pci_devices_present_work() -> survey_child_resources() ->
29428c2ecf20Sopenharmony_ci	 * complete(&hbus->survey_event), even after hv_pci_query_relations()
29438c2ecf20Sopenharmony_ci	 * exits and the stack variable 'comp' is no longer valid; as a result,
29448c2ecf20Sopenharmony_ci	 * a hang or a page fault may happen when the complete() calls
29458c2ecf20Sopenharmony_ci	 * raw_spin_lock_irqsave(). Flush hbus->wq before we exit from
29468c2ecf20Sopenharmony_ci	 * hv_pci_query_relations() to avoid the issues. Note: if 'ret' is
29478c2ecf20Sopenharmony_ci	 * -ENODEV, there can't be any more work item scheduled to hbus->wq
29488c2ecf20Sopenharmony_ci	 * after the flush_workqueue(): see vmbus_onoffer_rescind() ->
29498c2ecf20Sopenharmony_ci	 * vmbus_reset_channel_cb(), vmbus_rescind_cleanup() ->
29508c2ecf20Sopenharmony_ci	 * channel->rescind = true.
29518c2ecf20Sopenharmony_ci	 */
29528c2ecf20Sopenharmony_ci	flush_workqueue(hbus->wq);
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	return ret;
29558c2ecf20Sopenharmony_ci}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci/**
29588c2ecf20Sopenharmony_ci * hv_send_resources_allocated() - Report local resource choices
29598c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
29608c2ecf20Sopenharmony_ci *
29618c2ecf20Sopenharmony_ci * The host OS is expecting to be sent a request as a message
29628c2ecf20Sopenharmony_ci * which contains all the resources that the device will use.
29638c2ecf20Sopenharmony_ci * The response contains those same resources, "translated"
29648c2ecf20Sopenharmony_ci * which is to say, the values which should be used by the
29658c2ecf20Sopenharmony_ci * hardware, when it delivers an interrupt.  (MMIO resources are
29668c2ecf20Sopenharmony_ci * used in local terms.)  This is nice for Windows, and lines up
29678c2ecf20Sopenharmony_ci * with the FDO/PDO split, which doesn't exist in Linux.  Linux
29688c2ecf20Sopenharmony_ci * is deeply expecting to scan an emulated PCI configuration
29698c2ecf20Sopenharmony_ci * space.  So this message is sent here only to drive the state
29708c2ecf20Sopenharmony_ci * machine on the host forward.
29718c2ecf20Sopenharmony_ci *
29728c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
29738c2ecf20Sopenharmony_ci */
29748c2ecf20Sopenharmony_cistatic int hv_send_resources_allocated(struct hv_device *hdev)
29758c2ecf20Sopenharmony_ci{
29768c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
29778c2ecf20Sopenharmony_ci	struct pci_resources_assigned *res_assigned;
29788c2ecf20Sopenharmony_ci	struct pci_resources_assigned2 *res_assigned2;
29798c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
29808c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
29818c2ecf20Sopenharmony_ci	struct pci_packet *pkt;
29828c2ecf20Sopenharmony_ci	size_t size_res;
29838c2ecf20Sopenharmony_ci	int wslot;
29848c2ecf20Sopenharmony_ci	int ret;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2)
29878c2ecf20Sopenharmony_ci			? sizeof(*res_assigned) : sizeof(*res_assigned2);
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	pkt = kmalloc(sizeof(*pkt) + size_res, GFP_KERNEL);
29908c2ecf20Sopenharmony_ci	if (!pkt)
29918c2ecf20Sopenharmony_ci		return -ENOMEM;
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	ret = 0;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	for (wslot = 0; wslot < 256; wslot++) {
29968c2ecf20Sopenharmony_ci		hpdev = get_pcichild_wslot(hbus, wslot);
29978c2ecf20Sopenharmony_ci		if (!hpdev)
29988c2ecf20Sopenharmony_ci			continue;
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci		memset(pkt, 0, sizeof(*pkt) + size_res);
30018c2ecf20Sopenharmony_ci		init_completion(&comp_pkt.host_event);
30028c2ecf20Sopenharmony_ci		pkt->completion_func = hv_pci_generic_compl;
30038c2ecf20Sopenharmony_ci		pkt->compl_ctxt = &comp_pkt;
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci		if (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2) {
30068c2ecf20Sopenharmony_ci			res_assigned =
30078c2ecf20Sopenharmony_ci				(struct pci_resources_assigned *)&pkt->message;
30088c2ecf20Sopenharmony_ci			res_assigned->message_type.type =
30098c2ecf20Sopenharmony_ci				PCI_RESOURCES_ASSIGNED;
30108c2ecf20Sopenharmony_ci			res_assigned->wslot.slot = hpdev->desc.win_slot.slot;
30118c2ecf20Sopenharmony_ci		} else {
30128c2ecf20Sopenharmony_ci			res_assigned2 =
30138c2ecf20Sopenharmony_ci				(struct pci_resources_assigned2 *)&pkt->message;
30148c2ecf20Sopenharmony_ci			res_assigned2->message_type.type =
30158c2ecf20Sopenharmony_ci				PCI_RESOURCES_ASSIGNED2;
30168c2ecf20Sopenharmony_ci			res_assigned2->wslot.slot = hpdev->desc.win_slot.slot;
30178c2ecf20Sopenharmony_ci		}
30188c2ecf20Sopenharmony_ci		put_pcichild(hpdev);
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci		ret = vmbus_sendpacket(hdev->channel, &pkt->message,
30218c2ecf20Sopenharmony_ci				size_res, (unsigned long)pkt,
30228c2ecf20Sopenharmony_ci				VM_PKT_DATA_INBAND,
30238c2ecf20Sopenharmony_ci				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
30248c2ecf20Sopenharmony_ci		if (!ret)
30258c2ecf20Sopenharmony_ci			ret = wait_for_response(hdev, &comp_pkt.host_event);
30268c2ecf20Sopenharmony_ci		if (ret)
30278c2ecf20Sopenharmony_ci			break;
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci		if (comp_pkt.completion_status < 0) {
30308c2ecf20Sopenharmony_ci			ret = -EPROTO;
30318c2ecf20Sopenharmony_ci			dev_err(&hdev->device,
30328c2ecf20Sopenharmony_ci				"resource allocated returned 0x%x",
30338c2ecf20Sopenharmony_ci				comp_pkt.completion_status);
30348c2ecf20Sopenharmony_ci			break;
30358c2ecf20Sopenharmony_ci		}
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci		hbus->wslot_res_allocated = wslot;
30388c2ecf20Sopenharmony_ci	}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci	kfree(pkt);
30418c2ecf20Sopenharmony_ci	return ret;
30428c2ecf20Sopenharmony_ci}
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci/**
30458c2ecf20Sopenharmony_ci * hv_send_resources_released() - Report local resources
30468c2ecf20Sopenharmony_ci * released
30478c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
30488c2ecf20Sopenharmony_ci *
30498c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
30508c2ecf20Sopenharmony_ci */
30518c2ecf20Sopenharmony_cistatic int hv_send_resources_released(struct hv_device *hdev)
30528c2ecf20Sopenharmony_ci{
30538c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
30548c2ecf20Sopenharmony_ci	struct pci_child_message pkt;
30558c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev;
30568c2ecf20Sopenharmony_ci	int wslot;
30578c2ecf20Sopenharmony_ci	int ret;
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci	for (wslot = hbus->wslot_res_allocated; wslot >= 0; wslot--) {
30608c2ecf20Sopenharmony_ci		hpdev = get_pcichild_wslot(hbus, wslot);
30618c2ecf20Sopenharmony_ci		if (!hpdev)
30628c2ecf20Sopenharmony_ci			continue;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci		memset(&pkt, 0, sizeof(pkt));
30658c2ecf20Sopenharmony_ci		pkt.message_type.type = PCI_RESOURCES_RELEASED;
30668c2ecf20Sopenharmony_ci		pkt.wslot.slot = hpdev->desc.win_slot.slot;
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci		put_pcichild(hpdev);
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci		ret = vmbus_sendpacket(hdev->channel, &pkt, sizeof(pkt), 0,
30718c2ecf20Sopenharmony_ci				       VM_PKT_DATA_INBAND, 0);
30728c2ecf20Sopenharmony_ci		if (ret)
30738c2ecf20Sopenharmony_ci			return ret;
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci		hbus->wslot_res_allocated = wslot - 1;
30768c2ecf20Sopenharmony_ci	}
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci	hbus->wslot_res_allocated = -1;
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	return 0;
30818c2ecf20Sopenharmony_ci}
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_cistatic void get_hvpcibus(struct hv_pcibus_device *hbus)
30848c2ecf20Sopenharmony_ci{
30858c2ecf20Sopenharmony_ci	refcount_inc(&hbus->remove_lock);
30868c2ecf20Sopenharmony_ci}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_cistatic void put_hvpcibus(struct hv_pcibus_device *hbus)
30898c2ecf20Sopenharmony_ci{
30908c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&hbus->remove_lock))
30918c2ecf20Sopenharmony_ci		complete(&hbus->remove_event);
30928c2ecf20Sopenharmony_ci}
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci#define HVPCI_DOM_MAP_SIZE (64 * 1024)
30958c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(hvpci_dom_map, HVPCI_DOM_MAP_SIZE);
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci/*
30988c2ecf20Sopenharmony_ci * PCI domain number 0 is used by emulated devices on Gen1 VMs, so define 0
30998c2ecf20Sopenharmony_ci * as invalid for passthrough PCI devices of this driver.
31008c2ecf20Sopenharmony_ci */
31018c2ecf20Sopenharmony_ci#define HVPCI_DOM_INVALID 0
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci/**
31048c2ecf20Sopenharmony_ci * hv_get_dom_num() - Get a valid PCI domain number
31058c2ecf20Sopenharmony_ci * Check if the PCI domain number is in use, and return another number if
31068c2ecf20Sopenharmony_ci * it is in use.
31078c2ecf20Sopenharmony_ci *
31088c2ecf20Sopenharmony_ci * @dom: Requested domain number
31098c2ecf20Sopenharmony_ci *
31108c2ecf20Sopenharmony_ci * return: domain number on success, HVPCI_DOM_INVALID on failure
31118c2ecf20Sopenharmony_ci */
31128c2ecf20Sopenharmony_cistatic u16 hv_get_dom_num(u16 dom)
31138c2ecf20Sopenharmony_ci{
31148c2ecf20Sopenharmony_ci	unsigned int i;
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	if (test_and_set_bit(dom, hvpci_dom_map) == 0)
31178c2ecf20Sopenharmony_ci		return dom;
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ci	for_each_clear_bit(i, hvpci_dom_map, HVPCI_DOM_MAP_SIZE) {
31208c2ecf20Sopenharmony_ci		if (test_and_set_bit(i, hvpci_dom_map) == 0)
31218c2ecf20Sopenharmony_ci			return i;
31228c2ecf20Sopenharmony_ci	}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	return HVPCI_DOM_INVALID;
31258c2ecf20Sopenharmony_ci}
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci/**
31288c2ecf20Sopenharmony_ci * hv_put_dom_num() - Mark the PCI domain number as free
31298c2ecf20Sopenharmony_ci * @dom: Domain number to be freed
31308c2ecf20Sopenharmony_ci */
31318c2ecf20Sopenharmony_cistatic void hv_put_dom_num(u16 dom)
31328c2ecf20Sopenharmony_ci{
31338c2ecf20Sopenharmony_ci	clear_bit(dom, hvpci_dom_map);
31348c2ecf20Sopenharmony_ci}
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci/**
31378c2ecf20Sopenharmony_ci * hv_pci_probe() - New VMBus channel probe, for a root PCI bus
31388c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
31398c2ecf20Sopenharmony_ci * @dev_id:	Identifies the device itself
31408c2ecf20Sopenharmony_ci *
31418c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
31428c2ecf20Sopenharmony_ci */
31438c2ecf20Sopenharmony_cistatic int hv_pci_probe(struct hv_device *hdev,
31448c2ecf20Sopenharmony_ci			const struct hv_vmbus_device_id *dev_id)
31458c2ecf20Sopenharmony_ci{
31468c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
31478c2ecf20Sopenharmony_ci	u16 dom_req, dom;
31488c2ecf20Sopenharmony_ci	char *name;
31498c2ecf20Sopenharmony_ci	int ret;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	/*
31528c2ecf20Sopenharmony_ci	 * hv_pcibus_device contains the hypercall arguments for retargeting in
31538c2ecf20Sopenharmony_ci	 * hv_irq_unmask(). Those must not cross a page boundary.
31548c2ecf20Sopenharmony_ci	 */
31558c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(*hbus) > HV_HYP_PAGE_SIZE);
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	/*
31588c2ecf20Sopenharmony_ci	 * With the recent 59bb47985c1d ("mm, sl[aou]b: guarantee natural
31598c2ecf20Sopenharmony_ci	 * alignment for kmalloc(power-of-two)"), kzalloc() is able to allocate
31608c2ecf20Sopenharmony_ci	 * a 4KB buffer that is guaranteed to be 4KB-aligned. Here the size and
31618c2ecf20Sopenharmony_ci	 * alignment of hbus is important because hbus's field
31628c2ecf20Sopenharmony_ci	 * retarget_msi_interrupt_params must not cross a 4KB page boundary.
31638c2ecf20Sopenharmony_ci	 *
31648c2ecf20Sopenharmony_ci	 * Here we prefer kzalloc to get_zeroed_page(), because a buffer
31658c2ecf20Sopenharmony_ci	 * allocated by the latter is not tracked and scanned by kmemleak, and
31668c2ecf20Sopenharmony_ci	 * hence kmemleak reports the pointer contained in the hbus buffer
31678c2ecf20Sopenharmony_ci	 * (i.e. the hpdev struct, which is created in new_pcichild_device() and
31688c2ecf20Sopenharmony_ci	 * is tracked by hbus->children) as memory leak (false positive).
31698c2ecf20Sopenharmony_ci	 *
31708c2ecf20Sopenharmony_ci	 * If the kernel doesn't have 59bb47985c1d, get_zeroed_page() *must* be
31718c2ecf20Sopenharmony_ci	 * used to allocate the hbus buffer and we can avoid the kmemleak false
31728c2ecf20Sopenharmony_ci	 * positive by using kmemleak_alloc() and kmemleak_free() to ask
31738c2ecf20Sopenharmony_ci	 * kmemleak to track and scan the hbus buffer.
31748c2ecf20Sopenharmony_ci	 */
31758c2ecf20Sopenharmony_ci	hbus = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
31768c2ecf20Sopenharmony_ci	if (!hbus)
31778c2ecf20Sopenharmony_ci		return -ENOMEM;
31788c2ecf20Sopenharmony_ci	hbus->state = hv_pcibus_init;
31798c2ecf20Sopenharmony_ci	hbus->wslot_res_allocated = -1;
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci	/*
31828c2ecf20Sopenharmony_ci	 * The PCI bus "domain" is what is called "segment" in ACPI and other
31838c2ecf20Sopenharmony_ci	 * specs. Pull it from the instance ID, to get something usually
31848c2ecf20Sopenharmony_ci	 * unique. In rare cases of collision, we will find out another number
31858c2ecf20Sopenharmony_ci	 * not in use.
31868c2ecf20Sopenharmony_ci	 *
31878c2ecf20Sopenharmony_ci	 * Note that, since this code only runs in a Hyper-V VM, Hyper-V
31888c2ecf20Sopenharmony_ci	 * together with this guest driver can guarantee that (1) The only
31898c2ecf20Sopenharmony_ci	 * domain used by Gen1 VMs for something that looks like a physical
31908c2ecf20Sopenharmony_ci	 * PCI bus (which is actually emulated by the hypervisor) is domain 0.
31918c2ecf20Sopenharmony_ci	 * (2) There will be no overlap between domains (after fixing possible
31928c2ecf20Sopenharmony_ci	 * collisions) in the same VM.
31938c2ecf20Sopenharmony_ci	 */
31948c2ecf20Sopenharmony_ci	dom_req = hdev->dev_instance.b[5] << 8 | hdev->dev_instance.b[4];
31958c2ecf20Sopenharmony_ci	dom = hv_get_dom_num(dom_req);
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_ci	if (dom == HVPCI_DOM_INVALID) {
31988c2ecf20Sopenharmony_ci		dev_err(&hdev->device,
31998c2ecf20Sopenharmony_ci			"Unable to use dom# 0x%hx or other numbers", dom_req);
32008c2ecf20Sopenharmony_ci		ret = -EINVAL;
32018c2ecf20Sopenharmony_ci		goto free_bus;
32028c2ecf20Sopenharmony_ci	}
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	if (dom != dom_req)
32058c2ecf20Sopenharmony_ci		dev_info(&hdev->device,
32068c2ecf20Sopenharmony_ci			 "PCI dom# 0x%hx has collision, using 0x%hx",
32078c2ecf20Sopenharmony_ci			 dom_req, dom);
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	hbus->sysdata.domain = dom;
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	hbus->hdev = hdev;
32128c2ecf20Sopenharmony_ci	refcount_set(&hbus->remove_lock, 1);
32138c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hbus->children);
32148c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hbus->dr_list);
32158c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hbus->resources_for_children);
32168c2ecf20Sopenharmony_ci	spin_lock_init(&hbus->config_lock);
32178c2ecf20Sopenharmony_ci	spin_lock_init(&hbus->device_list_lock);
32188c2ecf20Sopenharmony_ci	spin_lock_init(&hbus->retarget_msi_interrupt_lock);
32198c2ecf20Sopenharmony_ci	init_completion(&hbus->remove_event);
32208c2ecf20Sopenharmony_ci	hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0,
32218c2ecf20Sopenharmony_ci					   hbus->sysdata.domain);
32228c2ecf20Sopenharmony_ci	if (!hbus->wq) {
32238c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32248c2ecf20Sopenharmony_ci		goto free_dom;
32258c2ecf20Sopenharmony_ci	}
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
32288c2ecf20Sopenharmony_ci			 hv_pci_onchannelcallback, hbus);
32298c2ecf20Sopenharmony_ci	if (ret)
32308c2ecf20Sopenharmony_ci		goto destroy_wq;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	hv_set_drvdata(hdev, hbus);
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_ci	ret = hv_pci_protocol_negotiation(hdev, pci_protocol_versions,
32358c2ecf20Sopenharmony_ci					  ARRAY_SIZE(pci_protocol_versions));
32368c2ecf20Sopenharmony_ci	if (ret)
32378c2ecf20Sopenharmony_ci		goto close;
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	ret = hv_allocate_config_window(hbus);
32408c2ecf20Sopenharmony_ci	if (ret)
32418c2ecf20Sopenharmony_ci		goto close;
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci	hbus->cfg_addr = ioremap(hbus->mem_config->start,
32448c2ecf20Sopenharmony_ci				 PCI_CONFIG_MMIO_LENGTH);
32458c2ecf20Sopenharmony_ci	if (!hbus->cfg_addr) {
32468c2ecf20Sopenharmony_ci		dev_err(&hdev->device,
32478c2ecf20Sopenharmony_ci			"Unable to map a virtual address for config space\n");
32488c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32498c2ecf20Sopenharmony_ci		goto free_config;
32508c2ecf20Sopenharmony_ci	}
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%pUL", &hdev->dev_instance);
32538c2ecf20Sopenharmony_ci	if (!name) {
32548c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32558c2ecf20Sopenharmony_ci		goto unmap;
32568c2ecf20Sopenharmony_ci	}
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci	hbus->sysdata.fwnode = irq_domain_alloc_named_fwnode(name);
32598c2ecf20Sopenharmony_ci	kfree(name);
32608c2ecf20Sopenharmony_ci	if (!hbus->sysdata.fwnode) {
32618c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32628c2ecf20Sopenharmony_ci		goto unmap;
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	ret = hv_pcie_init_irq_domain(hbus);
32668c2ecf20Sopenharmony_ci	if (ret)
32678c2ecf20Sopenharmony_ci		goto free_fwnode;
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	ret = hv_pci_query_relations(hdev);
32708c2ecf20Sopenharmony_ci	if (ret)
32718c2ecf20Sopenharmony_ci		goto free_irq_domain;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	ret = hv_pci_enter_d0(hdev);
32748c2ecf20Sopenharmony_ci	if (ret)
32758c2ecf20Sopenharmony_ci		goto free_irq_domain;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	ret = hv_pci_allocate_bridge_windows(hbus);
32788c2ecf20Sopenharmony_ci	if (ret)
32798c2ecf20Sopenharmony_ci		goto exit_d0;
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	ret = hv_send_resources_allocated(hdev);
32828c2ecf20Sopenharmony_ci	if (ret)
32838c2ecf20Sopenharmony_ci		goto free_windows;
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	prepopulate_bars(hbus);
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	hbus->state = hv_pcibus_probed;
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci	ret = create_root_hv_pci_bus(hbus);
32908c2ecf20Sopenharmony_ci	if (ret)
32918c2ecf20Sopenharmony_ci		goto free_windows;
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	return 0;
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_cifree_windows:
32968c2ecf20Sopenharmony_ci	hv_pci_free_bridge_windows(hbus);
32978c2ecf20Sopenharmony_ciexit_d0:
32988c2ecf20Sopenharmony_ci	(void) hv_pci_bus_exit(hdev, true);
32998c2ecf20Sopenharmony_cifree_irq_domain:
33008c2ecf20Sopenharmony_ci	irq_domain_remove(hbus->irq_domain);
33018c2ecf20Sopenharmony_cifree_fwnode:
33028c2ecf20Sopenharmony_ci	irq_domain_free_fwnode(hbus->sysdata.fwnode);
33038c2ecf20Sopenharmony_ciunmap:
33048c2ecf20Sopenharmony_ci	iounmap(hbus->cfg_addr);
33058c2ecf20Sopenharmony_cifree_config:
33068c2ecf20Sopenharmony_ci	hv_free_config_window(hbus);
33078c2ecf20Sopenharmony_ciclose:
33088c2ecf20Sopenharmony_ci	vmbus_close(hdev->channel);
33098c2ecf20Sopenharmony_cidestroy_wq:
33108c2ecf20Sopenharmony_ci	destroy_workqueue(hbus->wq);
33118c2ecf20Sopenharmony_cifree_dom:
33128c2ecf20Sopenharmony_ci	hv_put_dom_num(hbus->sysdata.domain);
33138c2ecf20Sopenharmony_cifree_bus:
33148c2ecf20Sopenharmony_ci	kfree(hbus);
33158c2ecf20Sopenharmony_ci	return ret;
33168c2ecf20Sopenharmony_ci}
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_cistatic int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
33198c2ecf20Sopenharmony_ci{
33208c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
33218c2ecf20Sopenharmony_ci	struct {
33228c2ecf20Sopenharmony_ci		struct pci_packet teardown_packet;
33238c2ecf20Sopenharmony_ci		u8 buffer[sizeof(struct pci_message)];
33248c2ecf20Sopenharmony_ci	} pkt;
33258c2ecf20Sopenharmony_ci	struct hv_pci_compl comp_pkt;
33268c2ecf20Sopenharmony_ci	struct hv_pci_dev *hpdev, *tmp;
33278c2ecf20Sopenharmony_ci	unsigned long flags;
33288c2ecf20Sopenharmony_ci	int ret;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	/*
33318c2ecf20Sopenharmony_ci	 * After the host sends the RESCIND_CHANNEL message, it doesn't
33328c2ecf20Sopenharmony_ci	 * access the per-channel ringbuffer any longer.
33338c2ecf20Sopenharmony_ci	 */
33348c2ecf20Sopenharmony_ci	if (hdev->channel->rescind)
33358c2ecf20Sopenharmony_ci		return 0;
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ci	if (!keep_devs) {
33388c2ecf20Sopenharmony_ci		struct list_head removed;
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci		/* Move all present children to the list on stack */
33418c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&removed);
33428c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hbus->device_list_lock, flags);
33438c2ecf20Sopenharmony_ci		list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry)
33448c2ecf20Sopenharmony_ci			list_move_tail(&hpdev->list_entry, &removed);
33458c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hbus->device_list_lock, flags);
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci		/* Remove all children in the list */
33488c2ecf20Sopenharmony_ci		list_for_each_entry_safe(hpdev, tmp, &removed, list_entry) {
33498c2ecf20Sopenharmony_ci			list_del(&hpdev->list_entry);
33508c2ecf20Sopenharmony_ci			if (hpdev->pci_slot)
33518c2ecf20Sopenharmony_ci				pci_destroy_slot(hpdev->pci_slot);
33528c2ecf20Sopenharmony_ci			/* For the two refs got in new_pcichild_device() */
33538c2ecf20Sopenharmony_ci			put_pcichild(hpdev);
33548c2ecf20Sopenharmony_ci			put_pcichild(hpdev);
33558c2ecf20Sopenharmony_ci		}
33568c2ecf20Sopenharmony_ci	}
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_ci	ret = hv_send_resources_released(hdev);
33598c2ecf20Sopenharmony_ci	if (ret) {
33608c2ecf20Sopenharmony_ci		dev_err(&hdev->device,
33618c2ecf20Sopenharmony_ci			"Couldn't send resources released packet(s)\n");
33628c2ecf20Sopenharmony_ci		return ret;
33638c2ecf20Sopenharmony_ci	}
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
33668c2ecf20Sopenharmony_ci	init_completion(&comp_pkt.host_event);
33678c2ecf20Sopenharmony_ci	pkt.teardown_packet.completion_func = hv_pci_generic_compl;
33688c2ecf20Sopenharmony_ci	pkt.teardown_packet.compl_ctxt = &comp_pkt;
33698c2ecf20Sopenharmony_ci	pkt.teardown_packet.message[0].type = PCI_BUS_D0EXIT;
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(hdev->channel, &pkt.teardown_packet.message,
33728c2ecf20Sopenharmony_ci			       sizeof(struct pci_message),
33738c2ecf20Sopenharmony_ci			       (unsigned long)&pkt.teardown_packet,
33748c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
33758c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
33768c2ecf20Sopenharmony_ci	if (ret)
33778c2ecf20Sopenharmony_ci		return ret;
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	if (wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ) == 0)
33808c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	return 0;
33838c2ecf20Sopenharmony_ci}
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci/**
33868c2ecf20Sopenharmony_ci * hv_pci_remove() - Remove routine for this VMBus channel
33878c2ecf20Sopenharmony_ci * @hdev:	VMBus's tracking struct for this root PCI bus
33888c2ecf20Sopenharmony_ci *
33898c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure
33908c2ecf20Sopenharmony_ci */
33918c2ecf20Sopenharmony_cistatic int hv_pci_remove(struct hv_device *hdev)
33928c2ecf20Sopenharmony_ci{
33938c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus;
33948c2ecf20Sopenharmony_ci	int ret;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci	hbus = hv_get_drvdata(hdev);
33978c2ecf20Sopenharmony_ci	if (hbus->state == hv_pcibus_installed) {
33988c2ecf20Sopenharmony_ci		tasklet_disable(&hdev->channel->callback_event);
33998c2ecf20Sopenharmony_ci		hbus->state = hv_pcibus_removing;
34008c2ecf20Sopenharmony_ci		tasklet_enable(&hdev->channel->callback_event);
34018c2ecf20Sopenharmony_ci		destroy_workqueue(hbus->wq);
34028c2ecf20Sopenharmony_ci		hbus->wq = NULL;
34038c2ecf20Sopenharmony_ci		/*
34048c2ecf20Sopenharmony_ci		 * At this point, no work is running or can be scheduled
34058c2ecf20Sopenharmony_ci		 * on hbus-wq. We can't race with hv_pci_devices_present()
34068c2ecf20Sopenharmony_ci		 * or hv_pci_eject_device(), it's safe to proceed.
34078c2ecf20Sopenharmony_ci		 */
34088c2ecf20Sopenharmony_ci
34098c2ecf20Sopenharmony_ci		/* Remove the bus from PCI's point of view. */
34108c2ecf20Sopenharmony_ci		pci_lock_rescan_remove();
34118c2ecf20Sopenharmony_ci		pci_stop_root_bus(hbus->pci_bus);
34128c2ecf20Sopenharmony_ci		hv_pci_remove_slots(hbus);
34138c2ecf20Sopenharmony_ci		pci_remove_root_bus(hbus->pci_bus);
34148c2ecf20Sopenharmony_ci		pci_unlock_rescan_remove();
34158c2ecf20Sopenharmony_ci	}
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	ret = hv_pci_bus_exit(hdev, false);
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	vmbus_close(hdev->channel);
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci	iounmap(hbus->cfg_addr);
34228c2ecf20Sopenharmony_ci	hv_free_config_window(hbus);
34238c2ecf20Sopenharmony_ci	pci_free_resource_list(&hbus->resources_for_children);
34248c2ecf20Sopenharmony_ci	hv_pci_free_bridge_windows(hbus);
34258c2ecf20Sopenharmony_ci	irq_domain_remove(hbus->irq_domain);
34268c2ecf20Sopenharmony_ci	irq_domain_free_fwnode(hbus->sysdata.fwnode);
34278c2ecf20Sopenharmony_ci	put_hvpcibus(hbus);
34288c2ecf20Sopenharmony_ci	wait_for_completion(&hbus->remove_event);
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	hv_put_dom_num(hbus->sysdata.domain);
34318c2ecf20Sopenharmony_ci
34328c2ecf20Sopenharmony_ci	kfree(hbus);
34338c2ecf20Sopenharmony_ci	return ret;
34348c2ecf20Sopenharmony_ci}
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_cistatic int hv_pci_suspend(struct hv_device *hdev)
34378c2ecf20Sopenharmony_ci{
34388c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
34398c2ecf20Sopenharmony_ci	enum hv_pcibus_state old_state;
34408c2ecf20Sopenharmony_ci	int ret;
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	/*
34438c2ecf20Sopenharmony_ci	 * hv_pci_suspend() must make sure there are no pending work items
34448c2ecf20Sopenharmony_ci	 * before calling vmbus_close(), since it runs in a process context
34458c2ecf20Sopenharmony_ci	 * as a callback in dpm_suspend().  When it starts to run, the channel
34468c2ecf20Sopenharmony_ci	 * callback hv_pci_onchannelcallback(), which runs in a tasklet
34478c2ecf20Sopenharmony_ci	 * context, can be still running concurrently and scheduling new work
34488c2ecf20Sopenharmony_ci	 * items onto hbus->wq in hv_pci_devices_present() and
34498c2ecf20Sopenharmony_ci	 * hv_pci_eject_device(), and the work item handlers can access the
34508c2ecf20Sopenharmony_ci	 * vmbus channel, which can be being closed by hv_pci_suspend(), e.g.
34518c2ecf20Sopenharmony_ci	 * the work item handler pci_devices_present_work() ->
34528c2ecf20Sopenharmony_ci	 * new_pcichild_device() writes to the vmbus channel.
34538c2ecf20Sopenharmony_ci	 *
34548c2ecf20Sopenharmony_ci	 * To eliminate the race, hv_pci_suspend() disables the channel
34558c2ecf20Sopenharmony_ci	 * callback tasklet, sets hbus->state to hv_pcibus_removing, and
34568c2ecf20Sopenharmony_ci	 * re-enables the tasklet. This way, when hv_pci_suspend() proceeds,
34578c2ecf20Sopenharmony_ci	 * it knows that no new work item can be scheduled, and then it flushes
34588c2ecf20Sopenharmony_ci	 * hbus->wq and safely closes the vmbus channel.
34598c2ecf20Sopenharmony_ci	 */
34608c2ecf20Sopenharmony_ci	tasklet_disable(&hdev->channel->callback_event);
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_ci	/* Change the hbus state to prevent new work items. */
34638c2ecf20Sopenharmony_ci	old_state = hbus->state;
34648c2ecf20Sopenharmony_ci	if (hbus->state == hv_pcibus_installed)
34658c2ecf20Sopenharmony_ci		hbus->state = hv_pcibus_removing;
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	tasklet_enable(&hdev->channel->callback_event);
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	if (old_state != hv_pcibus_installed)
34708c2ecf20Sopenharmony_ci		return -EINVAL;
34718c2ecf20Sopenharmony_ci
34728c2ecf20Sopenharmony_ci	flush_workqueue(hbus->wq);
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	ret = hv_pci_bus_exit(hdev, true);
34758c2ecf20Sopenharmony_ci	if (ret)
34768c2ecf20Sopenharmony_ci		return ret;
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci	vmbus_close(hdev->channel);
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci	return 0;
34818c2ecf20Sopenharmony_ci}
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_cistatic int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg)
34848c2ecf20Sopenharmony_ci{
34858c2ecf20Sopenharmony_ci	struct msi_desc *entry;
34868c2ecf20Sopenharmony_ci	struct irq_data *irq_data;
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	for_each_pci_msi_entry(entry, pdev) {
34898c2ecf20Sopenharmony_ci		irq_data = irq_get_irq_data(entry->irq);
34908c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(!irq_data))
34918c2ecf20Sopenharmony_ci			return -EINVAL;
34928c2ecf20Sopenharmony_ci
34938c2ecf20Sopenharmony_ci		hv_compose_msi_msg(irq_data, &entry->msg);
34948c2ecf20Sopenharmony_ci	}
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	return 0;
34978c2ecf20Sopenharmony_ci}
34988c2ecf20Sopenharmony_ci
34998c2ecf20Sopenharmony_ci/*
35008c2ecf20Sopenharmony_ci * Upon resume, pci_restore_msi_state() -> ... ->  __pci_write_msi_msg()
35018c2ecf20Sopenharmony_ci * directly writes the MSI/MSI-X registers via MMIO, but since Hyper-V
35028c2ecf20Sopenharmony_ci * doesn't trap and emulate the MMIO accesses, here hv_compose_msi_msg()
35038c2ecf20Sopenharmony_ci * must be used to ask Hyper-V to re-create the IOMMU Interrupt Remapping
35048c2ecf20Sopenharmony_ci * Table entries.
35058c2ecf20Sopenharmony_ci */
35068c2ecf20Sopenharmony_cistatic void hv_pci_restore_msi_state(struct hv_pcibus_device *hbus)
35078c2ecf20Sopenharmony_ci{
35088c2ecf20Sopenharmony_ci	pci_walk_bus(hbus->pci_bus, hv_pci_restore_msi_msg, NULL);
35098c2ecf20Sopenharmony_ci}
35108c2ecf20Sopenharmony_ci
35118c2ecf20Sopenharmony_cistatic int hv_pci_resume(struct hv_device *hdev)
35128c2ecf20Sopenharmony_ci{
35138c2ecf20Sopenharmony_ci	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
35148c2ecf20Sopenharmony_ci	enum pci_protocol_version_t version[1];
35158c2ecf20Sopenharmony_ci	int ret;
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci	hbus->state = hv_pcibus_init;
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_ci	ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0,
35208c2ecf20Sopenharmony_ci			 hv_pci_onchannelcallback, hbus);
35218c2ecf20Sopenharmony_ci	if (ret)
35228c2ecf20Sopenharmony_ci		return ret;
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	/* Only use the version that was in use before hibernation. */
35258c2ecf20Sopenharmony_ci	version[0] = hbus->protocol_version;
35268c2ecf20Sopenharmony_ci	ret = hv_pci_protocol_negotiation(hdev, version, 1);
35278c2ecf20Sopenharmony_ci	if (ret)
35288c2ecf20Sopenharmony_ci		goto out;
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci	ret = hv_pci_query_relations(hdev);
35318c2ecf20Sopenharmony_ci	if (ret)
35328c2ecf20Sopenharmony_ci		goto out;
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci	ret = hv_pci_enter_d0(hdev);
35358c2ecf20Sopenharmony_ci	if (ret)
35368c2ecf20Sopenharmony_ci		goto out;
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci	ret = hv_send_resources_allocated(hdev);
35398c2ecf20Sopenharmony_ci	if (ret)
35408c2ecf20Sopenharmony_ci		goto out;
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_ci	prepopulate_bars(hbus);
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	hv_pci_restore_msi_state(hbus);
35458c2ecf20Sopenharmony_ci
35468c2ecf20Sopenharmony_ci	hbus->state = hv_pcibus_installed;
35478c2ecf20Sopenharmony_ci	return 0;
35488c2ecf20Sopenharmony_ciout:
35498c2ecf20Sopenharmony_ci	vmbus_close(hdev->channel);
35508c2ecf20Sopenharmony_ci	return ret;
35518c2ecf20Sopenharmony_ci}
35528c2ecf20Sopenharmony_ci
35538c2ecf20Sopenharmony_cistatic const struct hv_vmbus_device_id hv_pci_id_table[] = {
35548c2ecf20Sopenharmony_ci	/* PCI Pass-through Class ID */
35558c2ecf20Sopenharmony_ci	/* 44C4F61D-4444-4400-9D52-802E27EDE19F */
35568c2ecf20Sopenharmony_ci	{ HV_PCIE_GUID, },
35578c2ecf20Sopenharmony_ci	{ },
35588c2ecf20Sopenharmony_ci};
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vmbus, hv_pci_id_table);
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_cistatic struct hv_driver hv_pci_drv = {
35638c2ecf20Sopenharmony_ci	.name		= "hv_pci",
35648c2ecf20Sopenharmony_ci	.id_table	= hv_pci_id_table,
35658c2ecf20Sopenharmony_ci	.probe		= hv_pci_probe,
35668c2ecf20Sopenharmony_ci	.remove		= hv_pci_remove,
35678c2ecf20Sopenharmony_ci	.suspend	= hv_pci_suspend,
35688c2ecf20Sopenharmony_ci	.resume		= hv_pci_resume,
35698c2ecf20Sopenharmony_ci};
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_cistatic void __exit exit_hv_pci_drv(void)
35728c2ecf20Sopenharmony_ci{
35738c2ecf20Sopenharmony_ci	vmbus_driver_unregister(&hv_pci_drv);
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_ci	hvpci_block_ops.read_block = NULL;
35768c2ecf20Sopenharmony_ci	hvpci_block_ops.write_block = NULL;
35778c2ecf20Sopenharmony_ci	hvpci_block_ops.reg_blk_invalidate = NULL;
35788c2ecf20Sopenharmony_ci}
35798c2ecf20Sopenharmony_ci
35808c2ecf20Sopenharmony_cistatic int __init init_hv_pci_drv(void)
35818c2ecf20Sopenharmony_ci{
35828c2ecf20Sopenharmony_ci	if (!hv_is_hyperv_initialized())
35838c2ecf20Sopenharmony_ci		return -ENODEV;
35848c2ecf20Sopenharmony_ci
35858c2ecf20Sopenharmony_ci	/* Set the invalid domain number's bit, so it will not be used */
35868c2ecf20Sopenharmony_ci	set_bit(HVPCI_DOM_INVALID, hvpci_dom_map);
35878c2ecf20Sopenharmony_ci
35888c2ecf20Sopenharmony_ci	/* Initialize PCI block r/w interface */
35898c2ecf20Sopenharmony_ci	hvpci_block_ops.read_block = hv_read_config_block;
35908c2ecf20Sopenharmony_ci	hvpci_block_ops.write_block = hv_write_config_block;
35918c2ecf20Sopenharmony_ci	hvpci_block_ops.reg_blk_invalidate = hv_register_block_invalidate;
35928c2ecf20Sopenharmony_ci
35938c2ecf20Sopenharmony_ci	return vmbus_driver_register(&hv_pci_drv);
35948c2ecf20Sopenharmony_ci}
35958c2ecf20Sopenharmony_ci
35968c2ecf20Sopenharmony_cimodule_init(init_hv_pci_drv);
35978c2ecf20Sopenharmony_cimodule_exit(exit_hv_pci_drv);
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Hyper-V PCI");
36008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3601