Commit a29a44c1 authored by Bjorn Helgaas's avatar Bjorn Helgaas

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
parents b16f2ab2 1cf106d9
...@@ -376,6 +376,7 @@ struct hv_tsc_emulation_status { ...@@ -376,6 +376,7 @@ struct hv_tsc_emulation_status {
#define HVCALL_SEND_IPI_EX 0x0015 #define HVCALL_SEND_IPI_EX 0x0015
#define HVCALL_POST_MESSAGE 0x005c #define HVCALL_POST_MESSAGE 0x005c
#define HVCALL_SIGNAL_EVENT 0x005d #define HVCALL_SIGNAL_EVENT 0x005d
#define HVCALL_RETARGET_INTERRUPT 0x007e
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
...@@ -405,6 +406,8 @@ enum HV_GENERIC_SET_FORMAT { ...@@ -405,6 +406,8 @@ enum HV_GENERIC_SET_FORMAT {
HV_GENERIC_SET_ALL, HV_GENERIC_SET_ALL,
}; };
#define HV_PARTITION_ID_SELF ((u64)-1)
#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0) #define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
#define HV_HYPERCALL_FAST_BIT BIT(16) #define HV_HYPERCALL_FAST_BIT BIT(16)
#define HV_HYPERCALL_VARHEAD_OFFSET 17 #define HV_HYPERCALL_VARHEAD_OFFSET 17
...@@ -909,4 +912,42 @@ struct hv_tlb_flush_ex { ...@@ -909,4 +912,42 @@ struct hv_tlb_flush_ex {
struct hv_partition_assist_pg { struct hv_partition_assist_pg {
u32 tlb_lock_count; 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 #endif
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/nmi.h> #include <linux/nmi.h>
#include <linux/msi.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/hyperv-tlfs.h> #include <asm/hyperv-tlfs.h>
#include <asm/nospec-branch.h> #include <asm/nospec-branch.h>
...@@ -240,6 +241,13 @@ bool hv_vcpu_is_preempted(int vcpu); ...@@ -240,6 +241,13 @@ bool hv_vcpu_is_preempted(int vcpu);
static inline void hv_apic_init(void) {} static inline void hv_apic_init(void) {}
#endif #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 */ #else /* CONFIG_HYPERV */
static inline void hyperv_init(void) {} static inline void hyperv_init(void) {}
static inline void hyperv_setup_mmu_ops(void) {} static inline void hyperv_setup_mmu_ops(void) {}
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
enum pci_protocol_version_t { enum pci_protocol_version_t {
PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1), /* Win10 */ 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_2 = PCI_MAKE_VERSION(1, 2), /* RS1 */
PCI_PROTOCOL_VERSION_1_3 = PCI_MAKE_VERSION(1, 3), /* Vibranium */
}; };
#define CPU_AFFINITY_ALL -1ULL #define CPU_AFFINITY_ALL -1ULL
...@@ -72,6 +73,7 @@ enum pci_protocol_version_t { ...@@ -72,6 +73,7 @@ enum pci_protocol_version_t {
* first. * first.
*/ */
static enum pci_protocol_version_t pci_protocol_versions[] = { static enum pci_protocol_version_t pci_protocol_versions[] = {
PCI_PROTOCOL_VERSION_1_3,
PCI_PROTOCOL_VERSION_1_2, PCI_PROTOCOL_VERSION_1_2,
PCI_PROTOCOL_VERSION_1_1, PCI_PROTOCOL_VERSION_1_1,
}; };
...@@ -119,6 +121,7 @@ enum pci_message_type { ...@@ -119,6 +121,7 @@ enum pci_message_type {
PCI_RESOURCES_ASSIGNED2 = PCI_MESSAGE_BASE + 0x16, PCI_RESOURCES_ASSIGNED2 = PCI_MESSAGE_BASE + 0x16,
PCI_CREATE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x17, PCI_CREATE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x17,
PCI_DELETE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x18, /* unused */ PCI_DELETE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x18, /* unused */
PCI_BUS_RELATIONS2 = PCI_MESSAGE_BASE + 0x19,
PCI_MESSAGE_MAXIMUM PCI_MESSAGE_MAXIMUM
}; };
...@@ -164,6 +167,26 @@ struct pci_function_description { ...@@ -164,6 +167,26 @@ struct pci_function_description {
u32 ser; /* serial number */ u32 ser; /* serial number */
} __packed; } __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 * struct hv_msi_desc
* @vector: IDT entry * @vector: IDT entry
...@@ -260,7 +283,7 @@ struct pci_packet { ...@@ -260,7 +283,7 @@ struct pci_packet {
int resp_packet_size); int resp_packet_size);
void *compl_ctxt; void *compl_ctxt;
struct pci_message message[0]; struct pci_message message[];
}; };
/* /*
...@@ -296,7 +319,13 @@ struct pci_bus_d0_entry { ...@@ -296,7 +319,13 @@ struct pci_bus_d0_entry {
struct pci_bus_relations { struct pci_bus_relations {
struct pci_incoming_message incoming; struct pci_incoming_message incoming;
u32 device_count; 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; } __packed;
struct pci_q_res_req_response { struct pci_q_res_req_response {
...@@ -406,42 +435,6 @@ struct pci_eject_response { ...@@ -406,42 +435,6 @@ struct pci_eject_response {
static int pci_ring_size = (4 * PAGE_SIZE); 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. * Driver specific state.
*/ */
...@@ -488,7 +481,7 @@ struct hv_pcibus_device { ...@@ -488,7 +481,7 @@ struct hv_pcibus_device {
struct workqueue_struct *wq; struct workqueue_struct *wq;
/* hypercall arg, must not cross page boundary */ /* 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 * Don't put anything here: retarget_msi_interrupt_params must be last
...@@ -505,10 +498,24 @@ struct hv_dr_work { ...@@ -505,10 +498,24 @@ struct hv_dr_work {
struct hv_pcibus_device *bus; 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 hv_dr_state {
struct list_head list_entry; struct list_head list_entry;
u32 device_count; u32 device_count;
struct pci_function_description func[0]; struct hv_pcidev_description func[];
}; };
enum hv_pcichild_state { enum hv_pcichild_state {
...@@ -525,7 +532,7 @@ struct hv_pci_dev { ...@@ -525,7 +532,7 @@ struct hv_pci_dev {
refcount_t refs; refcount_t refs;
enum hv_pcichild_state state; enum hv_pcichild_state state;
struct pci_slot *pci_slot; struct pci_slot *pci_slot;
struct pci_function_description desc; struct hv_pcidev_description desc;
bool reported_missing; bool reported_missing;
struct hv_pcibus_device *hbus; struct hv_pcibus_device *hbus;
struct work_struct wrk; struct work_struct wrk;
...@@ -1184,7 +1191,7 @@ static void hv_irq_unmask(struct irq_data *data) ...@@ -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 msi_desc *msi_desc = irq_data_get_msi_desc(data);
struct irq_cfg *cfg = irqd_cfg(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 hv_pcibus_device *hbus;
struct cpumask *dest; struct cpumask *dest;
cpumask_var_t tmp; cpumask_var_t tmp;
...@@ -1206,8 +1213,7 @@ static void hv_irq_unmask(struct irq_data *data) ...@@ -1206,8 +1213,7 @@ static void hv_irq_unmask(struct irq_data *data)
memset(params, 0, sizeof(*params)); memset(params, 0, sizeof(*params));
params->partition_id = HV_PARTITION_ID_SELF; params->partition_id = HV_PARTITION_ID_SELF;
params->int_entry.source = 1; /* MSI(-X) */ params->int_entry.source = 1; /* MSI(-X) */
params->int_entry.address = msi_desc->msg.address_lo; hv_set_msi_entry_from_desc(&params->int_entry.msi_entry, msi_desc);
params->int_entry.data = msi_desc->msg.data;
params->device_id = (hbus->hdev->dev_instance.b[5] << 24) | params->device_id = (hbus->hdev->dev_instance.b[5] << 24) |
(hbus->hdev->dev_instance.b[4] << 16) | (hbus->hdev->dev_instance.b[4] << 16) |
(hbus->hdev->dev_instance.b[7] << 8) | (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) ...@@ -1401,6 +1407,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
break; break;
case PCI_PROTOCOL_VERSION_1_2: case PCI_PROTOCOL_VERSION_1_2:
case PCI_PROTOCOL_VERSION_1_3:
size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2, size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
dest, dest,
hpdev->desc.win_slot.slot, hpdev->desc.win_slot.slot,
...@@ -1799,6 +1806,27 @@ static void hv_pci_remove_slots(struct hv_pcibus_device *hbus) ...@@ -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 * create_root_hv_pci_bus() - Expose a new root PCI bus
* @hbus: Root PCI bus, as understood by this driver * @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) ...@@ -1821,6 +1849,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
pci_lock_rescan_remove(); pci_lock_rescan_remove();
pci_scan_child_bus(hbus->pci_bus); pci_scan_child_bus(hbus->pci_bus);
hv_pci_assign_numa_node(hbus);
pci_bus_assign_resources(hbus->pci_bus); pci_bus_assign_resources(hbus->pci_bus);
hv_pci_assign_slots(hbus); hv_pci_assign_slots(hbus);
pci_bus_add_devices(hbus->pci_bus); pci_bus_add_devices(hbus->pci_bus);
...@@ -1877,7 +1906,7 @@ static void q_resource_requirements(void *context, struct pci_response *resp, ...@@ -1877,7 +1906,7 @@ static void q_resource_requirements(void *context, struct pci_response *resp,
* Return: Pointer to the new tracking struct * Return: Pointer to the new tracking struct
*/ */
static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, 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 hv_pci_dev *hpdev;
struct pci_child_message *res_req; struct pci_child_message *res_req;
...@@ -1988,7 +2017,7 @@ static void pci_devices_present_work(struct work_struct *work) ...@@ -1988,7 +2017,7 @@ static void pci_devices_present_work(struct work_struct *work)
{ {
u32 child_no; u32 child_no;
bool found; bool found;
struct pci_function_description *new_desc; struct hv_pcidev_description *new_desc;
struct hv_pci_dev *hpdev; struct hv_pci_dev *hpdev;
struct hv_pcibus_device *hbus; struct hv_pcibus_device *hbus;
struct list_head removed; struct list_head removed;
...@@ -2089,6 +2118,7 @@ static void pci_devices_present_work(struct work_struct *work) ...@@ -2089,6 +2118,7 @@ static void pci_devices_present_work(struct work_struct *work)
*/ */
pci_lock_rescan_remove(); pci_lock_rescan_remove();
pci_scan_child_bus(hbus->pci_bus); pci_scan_child_bus(hbus->pci_bus);
hv_pci_assign_numa_node(hbus);
hv_pci_assign_slots(hbus); hv_pci_assign_slots(hbus);
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
break; break;
...@@ -2107,17 +2137,15 @@ static void pci_devices_present_work(struct work_struct *work) ...@@ -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 * @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 * Return: 0 on success, -errno on failure
* this bus appears.
*/ */
static void hv_pci_devices_present(struct hv_pcibus_device *hbus, static int hv_pci_start_relations_work(struct hv_pcibus_device *hbus,
struct pci_bus_relations *relations) struct hv_dr_state *dr)
{ {
struct hv_dr_state *dr;
struct hv_dr_work *dr_wrk; struct hv_dr_work *dr_wrk;
unsigned long flags; unsigned long flags;
bool pending_dr; bool pending_dr;
...@@ -2125,29 +2153,15 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, ...@@ -2125,29 +2153,15 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
if (hbus->state == hv_pcibus_removing) { if (hbus->state == hv_pcibus_removing) {
dev_info(&hbus->hdev->device, dev_info(&hbus->hdev->device,
"PCI VMBus BUS_RELATIONS: ignored\n"); "PCI VMBus BUS_RELATIONS: ignored\n");
return; return -ENOENT;
} }
dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT); dr_wrk = kzalloc(sizeof(*dr_wrk), GFP_NOWAIT);
if (!dr_wrk) if (!dr_wrk)
return; return -ENOMEM;
dr = kzalloc(offsetof(struct hv_dr_state, func) +
(sizeof(struct pci_function_description) *
(relations->device_count)), GFP_NOWAIT);
if (!dr) {
kfree(dr_wrk);
return;
}
INIT_WORK(&dr_wrk->wrk, pci_devices_present_work); INIT_WORK(&dr_wrk->wrk, pci_devices_present_work);
dr_wrk->bus = hbus; 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); spin_lock_irqsave(&hbus->device_list_lock, flags);
/* /*
...@@ -2165,6 +2179,87 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, ...@@ -2165,6 +2179,87 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
get_hvpcibus(hbus); get_hvpcibus(hbus);
queue_work(hbus->wq, &dr_wrk->wrk); 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) ...@@ -2280,6 +2375,7 @@ static void hv_pci_onchannelcallback(void *context)
struct pci_response *response; struct pci_response *response;
struct pci_incoming_message *new_message; struct pci_incoming_message *new_message;
struct pci_bus_relations *bus_rel; struct pci_bus_relations *bus_rel;
struct pci_bus_relations2 *bus_rel2;
struct pci_dev_inval_block *inval; struct pci_dev_inval_block *inval;
struct pci_dev_incoming *dev_message; struct pci_dev_incoming *dev_message;
struct hv_pci_dev *hpdev; struct hv_pci_dev *hpdev;
...@@ -2347,6 +2443,21 @@ static void hv_pci_onchannelcallback(void *context) ...@@ -2347,6 +2443,21 @@ static void hv_pci_onchannelcallback(void *context)
hv_pci_devices_present(hbus, bus_rel); hv_pci_devices_present(hbus, bus_rel);
break; 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: case PCI_EJECT:
dev_message = (struct pci_dev_incoming *)buffer; dev_message = (struct pci_dev_incoming *)buffer;
...@@ -2922,7 +3033,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -2922,7 +3033,7 @@ static int hv_pci_probe(struct hv_device *hdev,
* positive by using kmemleak_alloc() and kmemleak_free() to ask * positive by using kmemleak_alloc() and kmemleak_free() to ask
* kmemleak to track and scan the hbus buffer. * 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) if (!hbus)
return -ENOMEM; return -ENOMEM;
hbus->state = hv_pcibus_init; hbus->state = hv_pcibus_init;
...@@ -3058,7 +3169,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -3058,7 +3169,7 @@ static int hv_pci_probe(struct hv_device *hdev,
free_dom: free_dom:
hv_put_dom_num(hbus->sysdata.domain); hv_put_dom_num(hbus->sysdata.domain);
free_bus: free_bus:
free_page((unsigned long)hbus); kfree(hbus);
return ret; return ret;
} }
...@@ -3069,7 +3180,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating) ...@@ -3069,7 +3180,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
struct pci_packet teardown_packet; struct pci_packet teardown_packet;
u8 buffer[sizeof(struct pci_message)]; u8 buffer[sizeof(struct pci_message)];
} pkt; } pkt;
struct pci_bus_relations relations; struct hv_dr_state *dr;
struct hv_pci_compl comp_pkt; struct hv_pci_compl comp_pkt;
int ret; int ret;
...@@ -3082,8 +3193,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating) ...@@ -3082,8 +3193,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
if (!hibernating) { if (!hibernating) {
/* Delete any children which might still exist. */ /* Delete any children which might still exist. */
memset(&relations, 0, sizeof(relations)); dr = kzalloc(sizeof(*dr), GFP_KERNEL);
hv_pci_devices_present(hbus, &relations); if (dr && hv_pci_start_relations_work(hbus, dr))
kfree(dr);
} }
ret = hv_send_resources_released(hdev); ret = hv_send_resources_released(hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment