aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2010-03-08 12:24:29 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-05-11 15:01:07 -0400
commit75568f8094eb0333e9c2109b23cbc8b82d318a3c (patch)
treebdbd169b2220e067bc03f7445e2471aa2f8499a7 /drivers/pci
parentfc2a093e7ad23e935aa29e349bc27173c92f1a95 (diff)
PCI: create function symlinks in /sys/bus/pci/slots/N/
Create convenience symlinks in sysfs, linking slots to device functions, and vice versa. These links make it easier for users to figure out which devices actually live in what slots. For example: sapphire:/sys/bus/pci/slots # ls 1 10 2 3 4 5 6 7 8 9 sapphire:/sys/bus/pci/slots # ls -l 3 total 0 -r--r--r-- 1 root root 65536 Aug 18 14:10 address lrwxrwxrwx 1 root root 0 Aug 18 14:10 function0 -> ../../../../devices/pci0000:23/0000:23:01.0 lrwxrwxrwx 1 root root 0 Aug 18 14:10 function1 -> ../../../../devices/pci0000:23/0000:23:01.1 sapphire:/sys/bus/pci/slots # ls -l 3/function0/slot lrwxrwxrwx 1 root root 0 Aug 18 14:13 3/function0/slot -> ../../../bus/pci/slots/3 The original form of this patch was written by Matthew Wilcox, and was enhanced to include links from the sysfs slots/ directory pointing back at the device functions. Cc: willy@linux.intel.com Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-sysfs.c37
-rw-r--r--drivers/pci/slot.c48
2 files changed, 85 insertions, 0 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index fad93983bfed..941e939d1da9 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1011,6 +1011,39 @@ error:
1011 return retval; 1011 return retval;
1012} 1012}
1013 1013
1014static void pci_remove_slot_links(struct pci_dev *dev)
1015{
1016 char func[10];
1017 struct pci_slot *slot;
1018
1019 sysfs_remove_link(&dev->dev.kobj, "slot");
1020 list_for_each_entry(slot, &dev->bus->slots, list) {
1021 if (slot->number != PCI_SLOT(dev->devfn))
1022 continue;
1023 snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
1024 sysfs_remove_link(&slot->kobj, func);
1025 }
1026}
1027
1028static int pci_create_slot_links(struct pci_dev *dev)
1029{
1030 int result = 0;
1031 char func[10];
1032 struct pci_slot *slot;
1033
1034 list_for_each_entry(slot, &dev->bus->slots, list) {
1035 if (slot->number != PCI_SLOT(dev->devfn))
1036 continue;
1037 result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot");
1038 if (result)
1039 goto out;
1040 snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
1041 result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func);
1042 }
1043out:
1044 return result;
1045}
1046
1014int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 1047int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
1015{ 1048{
1016 int retval; 1049 int retval;
@@ -1073,6 +1106,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
1073 if (retval) 1106 if (retval)
1074 goto err_vga_file; 1107 goto err_vga_file;
1075 1108
1109 pci_create_slot_links(pdev);
1110
1076 return 0; 1111 return 0;
1077 1112
1078err_vga_file: 1113err_vga_file:
@@ -1122,6 +1157,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
1122 if (!sysfs_initialized) 1157 if (!sysfs_initialized)
1123 return; 1158 return;
1124 1159
1160 pci_remove_slot_links(pdev);
1161
1125 pci_remove_capabilities_sysfs(pdev); 1162 pci_remove_capabilities_sysfs(pdev);
1126 1163
1127 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) 1164 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 659eaa0fc48f..e0189cf7c558 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -97,6 +97,50 @@ static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
97 return bus_speed_read(slot->bus->cur_bus_speed, buf); 97 return bus_speed_read(slot->bus->cur_bus_speed, buf);
98} 98}
99 99
100static void remove_sysfs_files(struct pci_slot *slot)
101{
102 char func[10];
103 struct list_head *tmp;
104
105 list_for_each(tmp, &slot->bus->devices) {
106 struct pci_dev *dev = pci_dev_b(tmp);
107 if (PCI_SLOT(dev->devfn) != slot->number)
108 continue;
109 sysfs_remove_link(&dev->dev.kobj, "slot");
110
111 snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
112 sysfs_remove_link(&slot->kobj, func);
113 }
114}
115
116static int create_sysfs_files(struct pci_slot *slot)
117{
118 int result;
119 char func[10];
120 struct list_head *tmp;
121
122 list_for_each(tmp, &slot->bus->devices) {
123 struct pci_dev *dev = pci_dev_b(tmp);
124 if (PCI_SLOT(dev->devfn) != slot->number)
125 continue;
126
127 result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot");
128 if (result)
129 goto fail;
130
131 snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn));
132 result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func);
133 if (result)
134 goto fail;
135 }
136
137 return 0;
138
139fail:
140 remove_sysfs_files(slot);
141 return result;
142}
143
100static void pci_slot_release(struct kobject *kobj) 144static void pci_slot_release(struct kobject *kobj)
101{ 145{
102 struct pci_dev *dev; 146 struct pci_dev *dev;
@@ -109,6 +153,8 @@ static void pci_slot_release(struct kobject *kobj)
109 if (PCI_SLOT(dev->devfn) == slot->number) 153 if (PCI_SLOT(dev->devfn) == slot->number)
110 dev->slot = NULL; 154 dev->slot = NULL;
111 155
156 remove_sysfs_files(slot);
157
112 list_del(&slot->list); 158 list_del(&slot->list);
113 159
114 kfree(slot); 160 kfree(slot);
@@ -300,6 +346,8 @@ placeholder:
300 INIT_LIST_HEAD(&slot->list); 346 INIT_LIST_HEAD(&slot->list);
301 list_add(&slot->list, &parent->slots); 347 list_add(&slot->list, &parent->slots);
302 348
349 create_sysfs_files(slot);
350
303 list_for_each_entry(dev, &parent->devices, bus_list) 351 list_for_each_entry(dev, &parent->devices, bus_list)
304 if (PCI_SLOT(dev->devfn) == slot_nr) 352 if (PCI_SLOT(dev->devfn) == slot_nr)
305 dev->slot = slot; 353 dev->slot = slot;