Commit f9ad0f36 authored by Long Li's avatar Long Li Committed by Lorenzo Pieralisi
Browse files

PCI: hv: Decouple the func definition in hv_dr_state from VSP message



hv_dr_state is used to find present PCI devices on the bus. The structure
reuses struct pci_function_description from VSP message to describe a
device.

To prepare support for pci_function_description v2, decouple this
dependence in hv_dr_state so it can work with both v1 and v2 VSP messages.

There is no functionality change.

Signed-off-by: default avatarLong Li <longli@microsoft.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
parent 42c3d418
Loading
Loading
Loading
Loading
+70 −30
Original line number Diff line number Diff line
@@ -505,10 +505,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[0];
};

enum hv_pcichild_state {
@@ -525,7 +539,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;
@@ -1877,7 +1891,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 +2002,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;
@@ -2107,17 +2121,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 +2137,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 +2163,47 @@ 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);
}

/**
@@ -3069,7 +3108,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 +3121,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);