Commit 911e1c9b05a8e3559a7aa89083930700a0b9e7ee
Committed by
Jesse Barnes
1 parent
8633328be2
Exists in
master
and in
7 other branches
PCI: export SMBIOS provided firmware instance and label to sysfs
This patch exports SMBIOS provided firmware instance and label of onboard PCI devices to sysfs. New files are: /sys/bus/pci/devices/.../label which contains the firmware name for the device in question, and /sys/bus/pci/devices/.../index which contains the firmware device type instance for the given device. Signed-off-by: Jordan Hargrave <jordan_hargrave@dell.com> Signed-off-by: Narendra K <narendra_k@dell.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Showing 7 changed files with 221 additions and 0 deletions Side-by-side Diff
Documentation/ABI/testing/sysfs-bus-pci
... | ... | @@ -139,4 +139,31 @@ |
139 | 139 | Description: |
140 | 140 | This symbolic link points to the PCI hotplug controller driver |
141 | 141 | module that manages the hotplug slot. |
142 | + | |
143 | +What: /sys/bus/pci/devices/.../label | |
144 | +Date: July 2010 | |
145 | +Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com | |
146 | +Description: | |
147 | + Reading this attribute will provide the firmware | |
148 | + given name(SMBIOS type 41 string) of the PCI device. | |
149 | + The attribute will be created only if the firmware | |
150 | + has given a name to the PCI device. | |
151 | +Users: | |
152 | + Userspace applications interested in knowing the | |
153 | + firmware assigned name of the PCI device. | |
154 | + | |
155 | +What: /sys/bus/pci/devices/.../index | |
156 | +Date: July 2010 | |
157 | +Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com | |
158 | +Description: | |
159 | + Reading this attribute will provide the firmware | |
160 | + given instance(SMBIOS type 41 device type instance) | |
161 | + of the PCI device. The attribute will be created | |
162 | + only if the firmware has given a device type instance | |
163 | + to the PCI device. | |
164 | +Users: | |
165 | + Userspace applications interested in knowing the | |
166 | + firmware assigned device type instance of the PCI | |
167 | + device that can help in understanding the firmware | |
168 | + intended order of the PCI device. |
drivers/firmware/dmi_scan.c
... | ... | @@ -277,6 +277,29 @@ |
277 | 277 | list_add_tail(&dev->list, &dmi_devices); |
278 | 278 | } |
279 | 279 | |
280 | +static void __init dmi_save_dev_onboard(int instance, int segment, int bus, | |
281 | + int devfn, const char *name) | |
282 | +{ | |
283 | + struct dmi_dev_onboard *onboard_dev; | |
284 | + | |
285 | + onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1); | |
286 | + if (!onboard_dev) { | |
287 | + printk(KERN_ERR "dmi_save_dev_onboard: out of memory.\n"); | |
288 | + return; | |
289 | + } | |
290 | + onboard_dev->instance = instance; | |
291 | + onboard_dev->segment = segment; | |
292 | + onboard_dev->bus = bus; | |
293 | + onboard_dev->devfn = devfn; | |
294 | + | |
295 | + strcpy((char *)&onboard_dev[1], name); | |
296 | + onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD; | |
297 | + onboard_dev->dev.name = (char *)&onboard_dev[1]; | |
298 | + onboard_dev->dev.device_data = onboard_dev; | |
299 | + | |
300 | + list_add(&onboard_dev->dev.list, &dmi_devices); | |
301 | +} | |
302 | + | |
280 | 303 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) |
281 | 304 | { |
282 | 305 | const u8 *d = (u8*) dm + 5; |
... | ... | @@ -285,6 +308,8 @@ |
285 | 308 | if ((*d & 0x80) == 0) |
286 | 309 | return; |
287 | 310 | |
311 | + dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5), | |
312 | + dmi_string_nosave(dm, *(d-1))); | |
288 | 313 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); |
289 | 314 | } |
290 | 315 |
drivers/pci/Makefile
drivers/pci/pci-label.c
1 | +/* | |
2 | + * Purpose: Export the firmware instance and label associated with | |
3 | + * a pci device to sysfs | |
4 | + * Copyright (C) 2010 Dell Inc. | |
5 | + * by Narendra K <Narendra_K@dell.com>, | |
6 | + * Jordan Hargrave <Jordan_Hargrave@dell.com> | |
7 | + * | |
8 | + * SMBIOS defines type 41 for onboard pci devices. This code retrieves | |
9 | + * the instance number and string from the type 41 record and exports | |
10 | + * it to sysfs. | |
11 | + * | |
12 | + * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more | |
13 | + * information. | |
14 | + */ | |
15 | + | |
16 | +#include <linux/dmi.h> | |
17 | +#include <linux/sysfs.h> | |
18 | +#include <linux/pci.h> | |
19 | +#include <linux/pci_ids.h> | |
20 | +#include <linux/module.h> | |
21 | +#include <linux/device.h> | |
22 | +#include "pci.h" | |
23 | + | |
24 | +enum smbios_attr_enum { | |
25 | + SMBIOS_ATTR_NONE = 0, | |
26 | + SMBIOS_ATTR_LABEL_SHOW, | |
27 | + SMBIOS_ATTR_INSTANCE_SHOW, | |
28 | +}; | |
29 | + | |
30 | +static mode_t | |
31 | +find_smbios_instance_string(struct pci_dev *pdev, char *buf, | |
32 | + enum smbios_attr_enum attribute) | |
33 | +{ | |
34 | + const struct dmi_device *dmi; | |
35 | + struct dmi_dev_onboard *donboard; | |
36 | + int bus; | |
37 | + int devfn; | |
38 | + | |
39 | + bus = pdev->bus->number; | |
40 | + devfn = pdev->devfn; | |
41 | + | |
42 | + dmi = NULL; | |
43 | + while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, | |
44 | + NULL, dmi)) != NULL) { | |
45 | + donboard = dmi->device_data; | |
46 | + if (donboard && donboard->bus == bus && | |
47 | + donboard->devfn == devfn) { | |
48 | + if (buf) { | |
49 | + if (attribute == SMBIOS_ATTR_INSTANCE_SHOW) | |
50 | + return scnprintf(buf, PAGE_SIZE, | |
51 | + "%d\n", | |
52 | + donboard->instance); | |
53 | + else if (attribute == SMBIOS_ATTR_LABEL_SHOW) | |
54 | + return scnprintf(buf, PAGE_SIZE, | |
55 | + "%s\n", | |
56 | + dmi->name); | |
57 | + } | |
58 | + return strlen(dmi->name); | |
59 | + } | |
60 | + } | |
61 | + return 0; | |
62 | +} | |
63 | + | |
64 | +static mode_t | |
65 | +smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, | |
66 | + int n) | |
67 | +{ | |
68 | + struct device *dev; | |
69 | + struct pci_dev *pdev; | |
70 | + | |
71 | + dev = container_of(kobj, struct device, kobj); | |
72 | + pdev = to_pci_dev(dev); | |
73 | + | |
74 | + return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ? | |
75 | + S_IRUGO : 0; | |
76 | +} | |
77 | + | |
78 | +static ssize_t | |
79 | +smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf) | |
80 | +{ | |
81 | + struct pci_dev *pdev; | |
82 | + pdev = to_pci_dev(dev); | |
83 | + | |
84 | + return find_smbios_instance_string(pdev, buf, | |
85 | + SMBIOS_ATTR_LABEL_SHOW); | |
86 | +} | |
87 | + | |
88 | +static ssize_t | |
89 | +smbiosinstance_show(struct device *dev, | |
90 | + struct device_attribute *attr, char *buf) | |
91 | +{ | |
92 | + struct pci_dev *pdev; | |
93 | + pdev = to_pci_dev(dev); | |
94 | + | |
95 | + return find_smbios_instance_string(pdev, buf, | |
96 | + SMBIOS_ATTR_INSTANCE_SHOW); | |
97 | +} | |
98 | + | |
99 | +static struct device_attribute smbios_attr_label = { | |
100 | + .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE}, | |
101 | + .show = smbioslabel_show, | |
102 | +}; | |
103 | + | |
104 | +static struct device_attribute smbios_attr_instance = { | |
105 | + .attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE}, | |
106 | + .show = smbiosinstance_show, | |
107 | +}; | |
108 | + | |
109 | +static struct attribute *smbios_attributes[] = { | |
110 | + &smbios_attr_label.attr, | |
111 | + &smbios_attr_instance.attr, | |
112 | + NULL, | |
113 | +}; | |
114 | + | |
115 | +static struct attribute_group smbios_attr_group = { | |
116 | + .attrs = smbios_attributes, | |
117 | + .is_visible = smbios_instance_string_exist, | |
118 | +}; | |
119 | + | |
120 | +static int | |
121 | +pci_create_smbiosname_file(struct pci_dev *pdev) | |
122 | +{ | |
123 | + if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group)) | |
124 | + return 0; | |
125 | + return -ENODEV; | |
126 | +} | |
127 | + | |
128 | +static void | |
129 | +pci_remove_smbiosname_file(struct pci_dev *pdev) | |
130 | +{ | |
131 | + sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); | |
132 | +} | |
133 | + | |
134 | +void pci_create_firmware_label_files(struct pci_dev *pdev) | |
135 | +{ | |
136 | + if (!pci_create_smbiosname_file(pdev)) | |
137 | + ; | |
138 | +} | |
139 | + | |
140 | +void pci_remove_firmware_label_files(struct pci_dev *pdev) | |
141 | +{ | |
142 | + pci_remove_smbiosname_file(pdev); | |
143 | +} |
drivers/pci/pci-sysfs.c
... | ... | @@ -1165,6 +1165,8 @@ |
1165 | 1165 | if (retval) |
1166 | 1166 | goto err_vga_file; |
1167 | 1167 | |
1168 | + pci_create_firmware_label_files(pdev); | |
1169 | + | |
1168 | 1170 | return 0; |
1169 | 1171 | |
1170 | 1172 | err_vga_file: |
... | ... | @@ -1232,6 +1234,9 @@ |
1232 | 1234 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |
1233 | 1235 | kfree(pdev->rom_attr); |
1234 | 1236 | } |
1237 | + | |
1238 | + pci_remove_firmware_label_files(pdev); | |
1239 | + | |
1235 | 1240 | } |
1236 | 1241 | |
1237 | 1242 | static int __init pci_sysfs_init(void) |
drivers/pci/pci.h
... | ... | @@ -11,6 +11,15 @@ |
11 | 11 | extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); |
12 | 12 | extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); |
13 | 13 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); |
14 | +#ifndef CONFIG_DMI | |
15 | +static inline void pci_create_firmware_label_files(struct pci_dev *pdev) | |
16 | +{ return 0; } | |
17 | +static inline void pci_remove_firmware_label_files(struct pci_dev *pdev) | |
18 | +{ return 0; } | |
19 | +#else | |
20 | +extern void pci_create_firmware_label_files(struct pci_dev *pdev); | |
21 | +extern void pci_remove_firmware_label_files(struct pci_dev *pdev); | |
22 | +#endif | |
14 | 23 | extern void pci_cleanup_rom(struct pci_dev *dev); |
15 | 24 | #ifdef HAVE_PCI_MMAP |
16 | 25 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, |
include/linux/dmi.h
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | DMI_DEV_TYPE_SAS, |
21 | 21 | DMI_DEV_TYPE_IPMI = -1, |
22 | 22 | DMI_DEV_TYPE_OEM_STRING = -2, |
23 | + DMI_DEV_TYPE_DEV_ONBOARD = -3, | |
23 | 24 | }; |
24 | 25 | |
25 | 26 | struct dmi_header { |
... | ... | @@ -36,6 +37,14 @@ |
36 | 37 | }; |
37 | 38 | |
38 | 39 | #ifdef CONFIG_DMI |
40 | + | |
41 | +struct dmi_dev_onboard { | |
42 | + struct dmi_device dev; | |
43 | + int instance; | |
44 | + int segment; | |
45 | + int bus; | |
46 | + int devfn; | |
47 | +}; | |
39 | 48 | |
40 | 49 | extern int dmi_check_system(const struct dmi_system_id *list); |
41 | 50 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); |