Commit a15f2c08 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

PCI: hv: support reporting serial number as slot information

The Hyper-V host API for PCI provides a unique "serial number" which
can be used as basis for sysfs PCI slot table. This can be useful
for cases where userspace wants to find the PCI device based on
serial number.

When an SR-IOV NIC is added, the host sends an attach message
with serial number. The kernel doesn't use the serial number, but
it is useful when doing the same thing in a userspace driver such
as the DPDK. By having /sys/bus/pci/slots/N it provides a direct
way to find the matching PCI device.

There maybe some cases where serial number is not unique such
as when using GPU's. But the PCI slot infrastructure will handle
that.

This has a side effect which may also be useful. The common udev
network device naming policy uses the slot information (rather
than PCI address).
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 28ea334b
...@@ -89,6 +89,9 @@ static enum pci_protocol_version_t pci_protocol_version; ...@@ -89,6 +89,9 @@ static enum pci_protocol_version_t pci_protocol_version;
#define STATUS_REVISION_MISMATCH 0xC0000059 #define STATUS_REVISION_MISMATCH 0xC0000059
/* space for 32bit serial number as string */
#define SLOT_NAME_SIZE 11
/* /*
* Message Types * Message Types
*/ */
...@@ -494,6 +497,7 @@ struct hv_pci_dev { ...@@ -494,6 +497,7 @@ struct hv_pci_dev {
struct list_head list_entry; struct list_head list_entry;
refcount_t refs; refcount_t refs;
enum hv_pcichild_state state; enum hv_pcichild_state state;
struct pci_slot *pci_slot;
struct pci_function_description desc; struct pci_function_description desc;
bool reported_missing; bool reported_missing;
struct hv_pcibus_device *hbus; struct hv_pcibus_device *hbus;
...@@ -1457,6 +1461,34 @@ static void prepopulate_bars(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); 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 * 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
...@@ -1480,6 +1512,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus) ...@@ -1480,6 +1512,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);
pci_bus_assign_resources(hbus->pci_bus); pci_bus_assign_resources(hbus->pci_bus);
hv_pci_assign_slots(hbus);
pci_bus_add_devices(hbus->pci_bus); pci_bus_add_devices(hbus->pci_bus);
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
hbus->state = hv_pcibus_installed; hbus->state = hv_pcibus_installed;
...@@ -1742,6 +1775,7 @@ static void pci_devices_present_work(struct work_struct *work) ...@@ -1742,6 +1775,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_slots(hbus);
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
break; break;
...@@ -1858,6 +1892,9 @@ static void hv_eject_device_work(struct work_struct *work) ...@@ -1858,6 +1892,9 @@ static void hv_eject_device_work(struct work_struct *work)
list_del(&hpdev->list_entry); list_del(&hpdev->list_entry);
spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags); spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
if (hpdev->pci_slot)
pci_destroy_slot(hpdev->pci_slot);
memset(&ctxt, 0, sizeof(ctxt)); memset(&ctxt, 0, sizeof(ctxt));
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message; ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE; ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
......
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