Merge branch 'remotes/lorenzo/pci/hv'
- Fix memory leak in hv probe path (Dexuan Cui) - Add support for Hyper-V protocol 1.3 (Long Li) - Replace zero-length array with flexible-array member (Gustavo A. R. Silva) - Move hypercall definitions to <asm/hyperv-tlfs.h> (Boqun Feng) - Move retarget definitions to <asm/hyperv-tlfs.h> and make them packed (Boqun Feng) - Add struct hv_msi_entry and hv_set_msi_entry_from_desc() to prepare for future virtual PCI on non-x86 (Boqun Feng) * remotes/lorenzo/pci/hv: PCI: hv: Introduce hv_msi_entry PCI: hv: Move retarget related structures into tlfs header PCI: hv: Move hypercall related definitions into tlfs header PCI: hv: Replace zero-length array with flexible-array member PCI: hv: Add support for protocol 1.3 and support PCI_BUS_RELATIONS2 PCI: hv: Decouple the func definition in hv_dr_state from VSP message PCI: hv: Add missing kfree(hbus) in hv_pci_probe()'s error handling path PCI: hv: Remove unnecessary type casting from kzalloc
This commit is contained in:
commit
a29a44c197
|
@ -376,6 +376,7 @@ struct hv_tsc_emulation_status {
|
|||
#define HVCALL_SEND_IPI_EX 0x0015
|
||||
#define HVCALL_POST_MESSAGE 0x005c
|
||||
#define HVCALL_SIGNAL_EVENT 0x005d
|
||||
#define HVCALL_RETARGET_INTERRUPT 0x007e
|
||||
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
|
||||
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
|
||||
|
||||
|
@ -405,6 +406,8 @@ enum HV_GENERIC_SET_FORMAT {
|
|||
HV_GENERIC_SET_ALL,
|
||||
};
|
||||
|
||||
#define HV_PARTITION_ID_SELF ((u64)-1)
|
||||
|
||||
#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
|
||||
#define HV_HYPERCALL_FAST_BIT BIT(16)
|
||||
#define HV_HYPERCALL_VARHEAD_OFFSET 17
|
||||
|
@ -909,4 +912,42 @@ struct hv_tlb_flush_ex {
|
|||
struct hv_partition_assist_pg {
|
||||
u32 tlb_lock_count;
|
||||
};
|
||||
|
||||
union hv_msi_entry {
|
||||
u64 as_uint64;
|
||||
struct {
|
||||
u32 address;
|
||||
u32 data;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
struct hv_interrupt_entry {
|
||||
u32 source; /* 1 for MSI(-X) */
|
||||
u32 reserved1;
|
||||
union hv_msi_entry msi_entry;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* flags for hv_device_interrupt_target.flags
|
||||
*/
|
||||
#define HV_DEVICE_INTERRUPT_TARGET_MULTICAST 1
|
||||
#define HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET 2
|
||||
|
||||
struct hv_device_interrupt_target {
|
||||
u32 vector;
|
||||
u32 flags;
|
||||
union {
|
||||
u64 vp_mask;
|
||||
struct hv_vpset vp_set;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* HvRetargetDeviceInterrupt hypercall */
|
||||
struct hv_retarget_device_interrupt {
|
||||
u64 partition_id; /* use "self" */
|
||||
u64 device_id;
|
||||
struct hv_interrupt_entry int_entry;
|
||||
u64 reserved2;
|
||||
struct hv_device_interrupt_target int_target;
|
||||
} __packed __aligned(8);
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/msi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/hyperv-tlfs.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
@ -240,6 +241,13 @@ bool hv_vcpu_is_preempted(int vcpu);
|
|||
static inline void hv_apic_init(void) {}
|
||||
#endif
|
||||
|
||||
static inline void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry,
|
||||
struct msi_desc *msi_desc)
|
||||
{
|
||||
msi_entry->address = msi_desc->msg.address_lo;
|
||||
msi_entry->data = msi_desc->msg.data;
|
||||
}
|
||||
|
||||
#else /* CONFIG_HYPERV */
|
||||
static inline void hyperv_init(void) {}
|
||||
static inline void hyperv_setup_mmu_ops(void) {}
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
enum pci_protocol_version_t {
|
||||
PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1), /* Win10 */
|
||||
PCI_PROTOCOL_VERSION_1_2 = PCI_MAKE_VERSION(1, 2), /* RS1 */
|
||||
PCI_PROTOCOL_VERSION_1_3 = PCI_MAKE_VERSION(1, 3), /* Vibranium */
|
||||
};
|
||||
|
||||
#define CPU_AFFINITY_ALL -1ULL
|
||||
|
@ -72,6 +73,7 @@ enum pci_protocol_version_t {
|
|||
* first.
|
||||
*/
|
||||
static enum pci_protocol_version_t pci_protocol_versions[] = {
|
||||
PCI_PROTOCOL_VERSION_1_3,
|
||||
PCI_PROTOCOL_VERSION_1_2,
|
||||
PCI_PROTOCOL_VERSION_1_1,
|
||||
};
|
||||
|
@ -119,6 +121,7 @@ enum pci_message_type {
|
|||
PCI_RESOURCES_ASSIGNED2 = PCI_MESSAGE_BASE + 0x16,
|
||||
PCI_CREATE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x17,
|
||||
PCI_DELETE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x18, /* unused */
|
||||
PCI_BUS_RELATIONS2 = PCI_MESSAGE_BASE + 0x19,
|
||||
PCI_MESSAGE_MAXIMUM
|
||||
};
|
||||
|
||||
|
@ -164,6 +167,26 @@ struct pci_function_description {
|
|||
u32 ser; /* serial number */
|
||||
} __packed;
|
||||
|
||||
enum pci_device_description_flags {
|
||||
HV_PCI_DEVICE_FLAG_NONE = 0x0,
|
||||
HV_PCI_DEVICE_FLAG_NUMA_AFFINITY = 0x1,
|
||||
};
|
||||
|
||||
struct pci_function_description2 {
|
||||
u16 v_id; /* vendor ID */
|
||||
u16 d_id; /* device ID */
|
||||
u8 rev;
|
||||
u8 prog_intf;
|
||||
u8 subclass;
|
||||
u8 base_class;
|
||||
u32 subsystem_id;
|
||||
union win_slot_encoding win_slot;
|
||||
u32 ser; /* serial number */
|
||||
u32 flags;
|
||||
u16 virtual_numa_node;
|
||||
u16 reserved;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct hv_msi_desc
|
||||
* @vector: IDT entry
|
||||
|
@ -260,7 +283,7 @@ struct pci_packet {
|
|||
int resp_packet_size);
|
||||
void *compl_ctxt;
|
||||
|
||||
struct pci_message message[0];
|
||||
struct pci_message message[];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -296,7 +319,13 @@ struct pci_bus_d0_entry {
|
|||
struct pci_bus_relations {
|
||||
struct pci_incoming_message incoming;
|
||||
u32 device_count;
|
||||
struct pci_function_description func[0];
|
||||
struct pci_function_description func[];
|
||||
} __packed;
|
||||
|
||||
struct pci_bus_relations2 {
|
||||
struct pci_incoming_message incoming;
|
||||
u32 device_count;
|
||||
struct pci_function_description2 func[];
|
||||
} __packed;
|
||||
|
||||
struct pci_q_res_req_response {
|
||||
|
@ -406,42 +435,6 @@ struct pci_eject_response {
|
|||
|
||||
static int pci_ring_size = (4 * PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Definitions or interrupt steering hypercall.
|
||||
*/
|
||||
#define HV_PARTITION_ID_SELF ((u64)-1)
|
||||
#define HVCALL_RETARGET_INTERRUPT 0x7e
|
||||
|
||||
struct hv_interrupt_entry {
|
||||
u32 source; /* 1 for MSI(-X) */
|
||||
u32 reserved1;
|
||||
u32 address;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags for hv_device_interrupt_target.flags
|
||||
*/
|
||||
#define HV_DEVICE_INTERRUPT_TARGET_MULTICAST 1
|
||||
#define HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET 2
|
||||
|
||||
struct hv_device_interrupt_target {
|
||||
u32 vector;
|
||||
u32 flags;
|
||||
union {
|
||||
u64 vp_mask;
|
||||
struct hv_vpset vp_set;
|
||||
};
|
||||
};
|
||||
|
||||
struct retarget_msi_interrupt {
|
||||
u64 partition_id; /* use "self" */
|
||||
u64 device_id;
|
||||
struct hv_interrupt_entry int_entry;
|
||||
u64 reserved2;
|
||||
struct hv_device_interrupt_target int_target;
|
||||
} __packed __aligned(8);
|
||||
|
||||
/*
|
||||
* Driver specific state.
|
||||
*/
|
||||
|
@ -488,7 +481,7 @@ struct hv_pcibus_device {
|
|||
struct workqueue_struct *wq;
|
||||
|
||||
/* hypercall arg, must not cross page boundary */
|
||||
struct retarget_msi_interrupt retarget_msi_interrupt_params;
|
||||
struct hv_retarget_device_interrupt retarget_msi_interrupt_params;
|
||||
|
||||
/*
|
||||
* Don't put anything here: retarget_msi_interrupt_params must be last
|
||||
|
@ -505,10 +498,24 @@ struct hv_dr_work {
|
|||
struct hv_pcibus_device *bus;
|
||||
};
|
||||
|
||||
struct hv_pcidev_description {
|
||||
u16 v_id; /* vendor ID */
|
||||
u16 d_id; /* device ID */
|
||||
u8 rev;
|
||||
u8 prog_intf;
|
||||
u8 subclass;
|
||||
u8 base_class;
|
||||
u32 subsystem_id;
|
||||
union win_slot_encoding win_slot;
|
||||
u32 ser; /* serial number */
|
||||
u32 flags;
|
||||
u16 virtual_numa_node;
|
||||
};
|
||||
|
||||
struct hv_dr_state {
|
||||
struct list_head list_entry;
|
||||
u32 device_count;
|
||||
struct pci_function_description func[0];
|
||||
struct hv_pcidev_description func[];
|
||||
};
|
||||
|
||||
enum hv_pcichild_state {
|
||||
|
@ -525,7 +532,7 @@ struct hv_pci_dev {
|
|||
refcount_t refs;
|
||||
enum hv_pcichild_state state;
|
||||
struct pci_slot *pci_slot;
|
||||
struct pci_function_description desc;
|
||||
struct hv_pcidev_description desc;
|
||||
bool reported_missing;
|
||||
struct hv_pcibus_device *hbus;
|
||||
struct work_struct wrk;
|
||||
|
@ -1184,7 +1191,7 @@ static void hv_irq_unmask(struct irq_data *data)
|
|||
{
|
||||
struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct retarget_msi_interrupt *params;
|
||||
struct hv_retarget_device_interrupt *params;
|
||||
struct hv_pcibus_device *hbus;
|
||||
struct cpumask *dest;
|
||||
cpumask_var_t tmp;
|
||||
|
@ -1206,8 +1213,7 @@ static void hv_irq_unmask(struct irq_data *data)
|
|||
memset(params, 0, sizeof(*params));
|
||||
params->partition_id = HV_PARTITION_ID_SELF;
|
||||
params->int_entry.source = 1; /* MSI(-X) */
|
||||
params->int_entry.address = msi_desc->msg.address_lo;
|
||||
params->int_entry.data = msi_desc->msg.data;
|
||||
hv_set_msi_entry_from_desc(¶ms->int_entry.msi_entry, msi_desc);
|
||||
params->device_id = (hbus->hdev->dev_instance.b[5] << 24) |
|
||||
(hbus->hdev->dev_instance.b[4] << 16) |
|
||||
(hbus->hdev->dev_instance.b[7] << 8) |
|
||||
|
@ -1401,6 +1407,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
|||
break;
|
||||
|
||||
case PCI_PROTOCOL_VERSION_1_2:
|
||||
case PCI_PROTOCOL_VERSION_1_3:
|
||||
size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
|
||||
dest,
|
||||
hpdev->desc.win_slot.slot,
|
||||
|
@ -1799,6 +1806,27 @@ static void hv_pci_remove_slots(struct hv_pcibus_device *hbus)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set NUMA node for the devices on the bus
|
||||
*/
|
||||
static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = hbus->pci_bus;
|
||||
struct hv_pci_dev *hv_dev;
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
hv_dev = get_pcichild_wslot(hbus, devfn_to_wslot(dev->devfn));
|
||||
if (!hv_dev)
|
||||
continue;
|
||||
|
||||
if (hv_dev->desc.flags & HV_PCI_DEVICE_FLAG_NUMA_AFFINITY)
|
||||
set_dev_node(&dev->dev, hv_dev->desc.virtual_numa_node);
|
||||
|
||||
put_pcichild(hv_dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create_root_hv_pci_bus() - Expose a new root PCI bus
|
||||
* @hbus: Root PCI bus, as understood by this driver
|
||||
|
@ -1821,6 +1849,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
|
|||
|
||||
pci_lock_rescan_remove();
|
||||
pci_scan_child_bus(hbus->pci_bus);
|
||||
hv_pci_assign_numa_node(hbus);
|
||||
pci_bus_assign_resources(hbus->pci_bus);
|
||||
hv_pci_assign_slots(hbus);
|
||||
pci_bus_add_devices(hbus->pci_bus);
|
||||
|
@ -1877,7 +1906,7 @@ static void q_resource_requirements(void *context, struct pci_response *resp,
|
|||
* Return: Pointer to the new tracking struct
|
||||
*/
|
||||
static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
|
||||
struct pci_function_description *desc)
|
||||
struct hv_pcidev_description *desc)
|
||||
{
|
||||
struct hv_pci_dev *hpdev;
|
||||
struct pci_child_message *res_req;
|
||||
|
@ -1988,7 +2017,7 @@ static void pci_devices_present_work(struct work_struct *work)
|
|||
{
|
||||
u32 child_no;
|
||||
bool found;
|
||||
struct pci_function_description *new_desc;
|
||||
struct hv_pcidev_description *new_desc;
|
||||
struct hv_pci_dev *hpdev;
|
||||
struct hv_pcibus_device *hbus;
|
||||
struct list_head removed;
|
||||
|
@ -2089,6 +2118,7 @@ static void pci_devices_present_work(struct work_struct *work)
|
|||
*/
|
||||
pci_lock_rescan_remove();
|
||||
pci_scan_child_bus(hbus->pci_bus);
|
||||
hv_pci_assign_numa_node(hbus);
|
||||
hv_pci_assign_slots(hbus);
|
||||
pci_unlock_rescan_remove();
|
||||
break;
|
||||
|
@ -2107,17 +2137,15 @@ static void pci_devices_present_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
/**
|
||||
* hv_pci_devices_present() - Handles list of new children
|
||||
* hv_pci_start_relations_work() - Queue work to start device discovery
|
||||
* @hbus: Root PCI bus, as understood by this driver
|
||||
* @relations: Packet from host listing children
|
||||
* @dr: The list of children returned from host
|
||||
*
|
||||
* This function is invoked whenever a new list of devices for
|
||||
* this bus appears.
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
|
||||
struct pci_bus_relations *relations)
|
||||
static int hv_pci_start_relations_work(struct hv_pcibus_device *hbus,
|
||||
struct hv_dr_state *dr)
|
||||
{
|
||||
struct hv_dr_state *dr;
|
||||
struct hv_dr_work *dr_wrk;
|
||||
unsigned long flags;
|
||||
bool pending_dr;
|
||||
|
@ -2125,29 +2153,15 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
|
|||
if (hbus->state == hv_pcibus_removing) {
|
||||
dev_info(&hbus->hdev->device,
|
||||
"PCI VMBus BUS_RELATIONS: ignored\n");
|
||||
return;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
|
||||
if (!dr_wrk)
|
||||
return;
|
||||
|
||||
dr = kzalloc(offsetof(struct hv_dr_state, func) +
|
||||
(sizeof(struct pci_function_description) *
|
||||
(relations->device_count)), GFP_NOWAIT);
|
||||
if (!dr) {
|
||||
kfree(dr_wrk);
|
||||
return;
|
||||
}
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&dr_wrk->wrk, pci_devices_present_work);
|
||||
dr_wrk->bus = hbus;
|
||||
dr->device_count = relations->device_count;
|
||||
if (dr->device_count != 0) {
|
||||
memcpy(dr->func, relations->func,
|
||||
sizeof(struct pci_function_description) *
|
||||
dr->device_count);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hbus->device_list_lock, flags);
|
||||
/*
|
||||
|
@ -2165,6 +2179,87 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
|
|||
get_hvpcibus(hbus);
|
||||
queue_work(hbus->wq, &dr_wrk->wrk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hv_pci_devices_present() - Handle list of new children
|
||||
* @hbus: Root PCI bus, as understood by this driver
|
||||
* @relations: Packet from host listing children
|
||||
*
|
||||
* Process a new list of devices on the bus. The list of devices is
|
||||
* discovered by VSP and sent to us via VSP message PCI_BUS_RELATIONS,
|
||||
* whenever a new list of devices for this bus appears.
|
||||
*/
|
||||
static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
|
||||
struct pci_bus_relations *relations)
|
||||
{
|
||||
struct hv_dr_state *dr;
|
||||
int i;
|
||||
|
||||
dr = kzalloc(offsetof(struct hv_dr_state, func) +
|
||||
(sizeof(struct hv_pcidev_description) *
|
||||
(relations->device_count)), GFP_NOWAIT);
|
||||
|
||||
if (!dr)
|
||||
return;
|
||||
|
||||
dr->device_count = relations->device_count;
|
||||
for (i = 0; i < dr->device_count; i++) {
|
||||
dr->func[i].v_id = relations->func[i].v_id;
|
||||
dr->func[i].d_id = relations->func[i].d_id;
|
||||
dr->func[i].rev = relations->func[i].rev;
|
||||
dr->func[i].prog_intf = relations->func[i].prog_intf;
|
||||
dr->func[i].subclass = relations->func[i].subclass;
|
||||
dr->func[i].base_class = relations->func[i].base_class;
|
||||
dr->func[i].subsystem_id = relations->func[i].subsystem_id;
|
||||
dr->func[i].win_slot = relations->func[i].win_slot;
|
||||
dr->func[i].ser = relations->func[i].ser;
|
||||
}
|
||||
|
||||
if (hv_pci_start_relations_work(hbus, dr))
|
||||
kfree(dr);
|
||||
}
|
||||
|
||||
/**
|
||||
* hv_pci_devices_present2() - Handle list of new children
|
||||
* @hbus: Root PCI bus, as understood by this driver
|
||||
* @relations: Packet from host listing children
|
||||
*
|
||||
* This function is the v2 version of hv_pci_devices_present()
|
||||
*/
|
||||
static void hv_pci_devices_present2(struct hv_pcibus_device *hbus,
|
||||
struct pci_bus_relations2 *relations)
|
||||
{
|
||||
struct hv_dr_state *dr;
|
||||
int i;
|
||||
|
||||
dr = kzalloc(offsetof(struct hv_dr_state, func) +
|
||||
(sizeof(struct hv_pcidev_description) *
|
||||
(relations->device_count)), GFP_NOWAIT);
|
||||
|
||||
if (!dr)
|
||||
return;
|
||||
|
||||
dr->device_count = relations->device_count;
|
||||
for (i = 0; i < dr->device_count; i++) {
|
||||
dr->func[i].v_id = relations->func[i].v_id;
|
||||
dr->func[i].d_id = relations->func[i].d_id;
|
||||
dr->func[i].rev = relations->func[i].rev;
|
||||
dr->func[i].prog_intf = relations->func[i].prog_intf;
|
||||
dr->func[i].subclass = relations->func[i].subclass;
|
||||
dr->func[i].base_class = relations->func[i].base_class;
|
||||
dr->func[i].subsystem_id = relations->func[i].subsystem_id;
|
||||
dr->func[i].win_slot = relations->func[i].win_slot;
|
||||
dr->func[i].ser = relations->func[i].ser;
|
||||
dr->func[i].flags = relations->func[i].flags;
|
||||
dr->func[i].virtual_numa_node =
|
||||
relations->func[i].virtual_numa_node;
|
||||
}
|
||||
|
||||
if (hv_pci_start_relations_work(hbus, dr))
|
||||
kfree(dr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2280,6 +2375,7 @@ static void hv_pci_onchannelcallback(void *context)
|
|||
struct pci_response *response;
|
||||
struct pci_incoming_message *new_message;
|
||||
struct pci_bus_relations *bus_rel;
|
||||
struct pci_bus_relations2 *bus_rel2;
|
||||
struct pci_dev_inval_block *inval;
|
||||
struct pci_dev_incoming *dev_message;
|
||||
struct hv_pci_dev *hpdev;
|
||||
|
@ -2347,6 +2443,21 @@ static void hv_pci_onchannelcallback(void *context)
|
|||
hv_pci_devices_present(hbus, bus_rel);
|
||||
break;
|
||||
|
||||
case PCI_BUS_RELATIONS2:
|
||||
|
||||
bus_rel2 = (struct pci_bus_relations2 *)buffer;
|
||||
if (bytes_recvd <
|
||||
offsetof(struct pci_bus_relations2, func) +
|
||||
(sizeof(struct pci_function_description2) *
|
||||
(bus_rel2->device_count))) {
|
||||
dev_err(&hbus->hdev->device,
|
||||
"bus relations v2 too small\n");
|
||||
break;
|
||||
}
|
||||
|
||||
hv_pci_devices_present2(hbus, bus_rel2);
|
||||
break;
|
||||
|
||||
case PCI_EJECT:
|
||||
|
||||
dev_message = (struct pci_dev_incoming *)buffer;
|
||||
|
@ -2922,7 +3033,7 @@ static int hv_pci_probe(struct hv_device *hdev,
|
|||
* positive by using kmemleak_alloc() and kmemleak_free() to ask
|
||||
* kmemleak to track and scan the hbus buffer.
|
||||
*/
|
||||
hbus = (struct hv_pcibus_device *)kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
|
||||
hbus = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
|
||||
if (!hbus)
|
||||
return -ENOMEM;
|
||||
hbus->state = hv_pcibus_init;
|
||||
|
@ -3058,7 +3169,7 @@ static int hv_pci_probe(struct hv_device *hdev,
|
|||
free_dom:
|
||||
hv_put_dom_num(hbus->sysdata.domain);
|
||||
free_bus:
|
||||
free_page((unsigned long)hbus);
|
||||
kfree(hbus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3069,7 +3180,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
|
|||
struct pci_packet teardown_packet;
|
||||
u8 buffer[sizeof(struct pci_message)];
|
||||
} pkt;
|
||||
struct pci_bus_relations relations;
|
||||
struct hv_dr_state *dr;
|
||||
struct hv_pci_compl comp_pkt;
|
||||
int ret;
|
||||
|
||||
|
@ -3082,8 +3193,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
|
|||
|
||||
if (!hibernating) {
|
||||
/* Delete any children which might still exist. */
|
||||
memset(&relations, 0, sizeof(relations));
|
||||
hv_pci_devices_present(hbus, &relations);
|
||||
dr = kzalloc(sizeof(*dr), GFP_KERNEL);
|
||||
if (dr && hv_pci_start_relations_work(hbus, dr))
|
||||
kfree(dr);
|
||||
}
|
||||
|
||||
ret = hv_send_resources_released(hdev);
|
||||
|
|
Loading…
Reference in New Issue