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(¶ms->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 = ∁ 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