diff options
Diffstat (limited to 'drivers/pci/controller/pci-hyperv.c')
| -rw-r--r-- | drivers/pci/controller/pci-hyperv.c | 39 | 
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index c00f82cc54aa..9ba4d12c179c 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -89,6 +89,9 @@ static enum pci_protocol_version_t pci_protocol_version;  #define STATUS_REVISION_MISMATCH 0xC0000059 +/* space for 32bit serial number as string */ +#define SLOT_NAME_SIZE 11 +  /*   * Message Types   */ @@ -494,6 +497,7 @@ struct hv_pci_dev {  	struct list_head list_entry;  	refcount_t refs;  	enum hv_pcichild_state state; +	struct pci_slot *pci_slot;  	struct pci_function_description desc;  	bool reported_missing;  	struct hv_pcibus_device *hbus; @@ -1457,6 +1461,36 @@ static void prepopulate_bars(struct hv_pcibus_device *hbus)  	spin_unlock_irqrestore(&hbus->device_list_lock, flags);  } +/* + * Assign entries in sysfs pci slot directory. + * + * Note that this function does not need to lock the children list + * because it is called from pci_devices_present_work which + * is serialized with hv_eject_device_work because they are on the + * same ordered workqueue. Therefore hbus->children list will not change + * even when pci_create_slot sleeps. + */ +static void hv_pci_assign_slots(struct hv_pcibus_device *hbus) +{ +	struct hv_pci_dev *hpdev; +	char name[SLOT_NAME_SIZE]; +	int slot_nr; + +	list_for_each_entry(hpdev, &hbus->children, list_entry) { +		if (hpdev->pci_slot) +			continue; + +		slot_nr = PCI_SLOT(wslot_to_devfn(hpdev->desc.win_slot.slot)); +		snprintf(name, SLOT_NAME_SIZE, "%u", hpdev->desc.ser); +		hpdev->pci_slot = pci_create_slot(hbus->pci_bus, slot_nr, +					  name, NULL); +		if (IS_ERR(hpdev->pci_slot)) { +			pr_warn("pci_create slot %s failed\n", name); +			hpdev->pci_slot = NULL; +		} +	} +} +  /**   * create_root_hv_pci_bus() - Expose a new root PCI bus   * @hbus:	Root PCI bus, as understood by this driver @@ -1480,6 +1514,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)  	pci_lock_rescan_remove();  	pci_scan_child_bus(hbus->pci_bus);  	pci_bus_assign_resources(hbus->pci_bus); +	hv_pci_assign_slots(hbus);  	pci_bus_add_devices(hbus->pci_bus);  	pci_unlock_rescan_remove();  	hbus->state = hv_pcibus_installed; @@ -1742,6 +1777,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_slots(hbus);  		pci_unlock_rescan_remove();  		break; @@ -1858,6 +1894,9 @@ static void hv_eject_device_work(struct work_struct *work)  	list_del(&hpdev->list_entry);  	spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags); +	if (hpdev->pci_slot) +		pci_destroy_slot(hpdev->pci_slot); +  	memset(&ctxt, 0, sizeof(ctxt));  	ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;  	ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;  |