aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/pci-hyperv.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2018-09-14 15:54:56 -0400
committerDavid S. Miller <davem@davemloft.net>2018-09-17 10:59:41 -0400
commita15f2c08c70811f120d99288d81f70d7f3d104f1 (patch)
tree11c90439f7fa23e52d1a4ac07472f361439f344e /drivers/pci/controller/pci-hyperv.c
parent28ea334bd1657f3c43485b4a8592672fc6835fac (diff)
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: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/pci/controller/pci-hyperv.c')
-rw-r--r--drivers/pci/controller/pci-hyperv.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index c00f82cc54aa..ee80e79db21a 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;
89 89
90#define STATUS_REVISION_MISMATCH 0xC0000059 90#define STATUS_REVISION_MISMATCH 0xC0000059
91 91
92/* space for 32bit serial number as string */
93#define SLOT_NAME_SIZE 11
94
92/* 95/*
93 * Message Types 96 * Message Types
94 */ 97 */
@@ -494,6 +497,7 @@ struct hv_pci_dev {
494 struct list_head list_entry; 497 struct list_head list_entry;
495 refcount_t refs; 498 refcount_t refs;
496 enum hv_pcichild_state state; 499 enum hv_pcichild_state state;
500 struct pci_slot *pci_slot;
497 struct pci_function_description desc; 501 struct pci_function_description desc;
498 bool reported_missing; 502 bool reported_missing;
499 struct hv_pcibus_device *hbus; 503 struct hv_pcibus_device *hbus;
@@ -1457,6 +1461,34 @@ static void prepopulate_bars(struct hv_pcibus_device *hbus)
1457 spin_unlock_irqrestore(&hbus->device_list_lock, flags); 1461 spin_unlock_irqrestore(&hbus->device_list_lock, flags);
1458} 1462}
1459 1463
1464/*
1465 * Assign entries in sysfs pci slot directory.
1466 *
1467 * Note that this function does not need to lock the children list
1468 * because it is called from pci_devices_present_work which
1469 * is serialized with hv_eject_device_work because they are on the
1470 * same ordered workqueue. Therefore hbus->children list will not change
1471 * even when pci_create_slot sleeps.
1472 */
1473static void hv_pci_assign_slots(struct hv_pcibus_device *hbus)
1474{
1475 struct hv_pci_dev *hpdev;
1476 char name[SLOT_NAME_SIZE];
1477 int slot_nr;
1478
1479 list_for_each_entry(hpdev, &hbus->children, list_entry) {
1480 if (hpdev->pci_slot)
1481 continue;
1482
1483 slot_nr = PCI_SLOT(wslot_to_devfn(hpdev->desc.win_slot.slot));
1484 snprintf(name, SLOT_NAME_SIZE, "%u", hpdev->desc.ser);
1485 hpdev->pci_slot = pci_create_slot(hbus->pci_bus, slot_nr,
1486 name, NULL);
1487 if (!hpdev->pci_slot)
1488 pr_warn("pci_create slot %s failed\n", name);
1489 }
1490}
1491
1460/** 1492/**
1461 * create_root_hv_pci_bus() - Expose a new root PCI bus 1493 * create_root_hv_pci_bus() - Expose a new root PCI bus
1462 * @hbus: Root PCI bus, as understood by this driver 1494 * @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 pci_lock_rescan_remove(); 1512 pci_lock_rescan_remove();
1481 pci_scan_child_bus(hbus->pci_bus); 1513 pci_scan_child_bus(hbus->pci_bus);
1482 pci_bus_assign_resources(hbus->pci_bus); 1514 pci_bus_assign_resources(hbus->pci_bus);
1515 hv_pci_assign_slots(hbus);
1483 pci_bus_add_devices(hbus->pci_bus); 1516 pci_bus_add_devices(hbus->pci_bus);
1484 pci_unlock_rescan_remove(); 1517 pci_unlock_rescan_remove();
1485 hbus->state = hv_pcibus_installed; 1518 hbus->state = hv_pcibus_installed;
@@ -1742,6 +1775,7 @@ static void pci_devices_present_work(struct work_struct *work)
1742 */ 1775 */
1743 pci_lock_rescan_remove(); 1776 pci_lock_rescan_remove();
1744 pci_scan_child_bus(hbus->pci_bus); 1777 pci_scan_child_bus(hbus->pci_bus);
1778 hv_pci_assign_slots(hbus);
1745 pci_unlock_rescan_remove(); 1779 pci_unlock_rescan_remove();
1746 break; 1780 break;
1747 1781
@@ -1858,6 +1892,9 @@ static void hv_eject_device_work(struct work_struct *work)
1858 list_del(&hpdev->list_entry); 1892 list_del(&hpdev->list_entry);
1859 spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags); 1893 spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
1860 1894
1895 if (hpdev->pci_slot)
1896 pci_destroy_slot(hpdev->pci_slot);
1897
1861 memset(&ctxt, 0, sizeof(ctxt)); 1898 memset(&ctxt, 0, sizeof(ctxt));
1862 ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message; 1899 ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
1863 ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE; 1900 ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;