|
@@ -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,34 @@ 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 (!hpdev->pci_slot)
|
|
|
+ pr_warn("pci_create slot %s failed\n", name);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* create_root_hv_pci_bus() - Expose a new root PCI bus
|
|
|
* @hbus: Root PCI bus, as understood by this driver
|
|
@@ -1480,6 +1512,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 +1775,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 +1892,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;
|