diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-pci | 27 | ||||
-rw-r--r-- | drivers/firmware/dmi_scan.c | 25 | ||||
-rw-r--r-- | drivers/pci/Makefile | 3 | ||||
-rw-r--r-- | drivers/pci/pci-label.c | 143 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 5 | ||||
-rw-r--r-- | drivers/pci/pci.h | 9 | ||||
-rw-r--r-- | include/linux/dmi.h | 9 |
7 files changed, 221 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 25be3250f7d6..f979d825d112 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci | |||
@@ -139,3 +139,30 @@ Contact: linux-pci@vger.kernel.org | |||
139 | Description: | 139 | Description: |
140 | This symbolic link points to the PCI hotplug controller driver | 140 | This symbolic link points to the PCI hotplug controller driver |
141 | module that manages the hotplug slot. | 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. | ||
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index d46467271349..b3d22d659990 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
@@ -277,6 +277,29 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm) | |||
277 | list_add_tail(&dev->list, &dmi_devices); | 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 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) | 303 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) |
281 | { | 304 | { |
282 | const u8 *d = (u8*) dm + 5; | 305 | const u8 *d = (u8*) dm + 5; |
@@ -285,6 +308,8 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) | |||
285 | if ((*d & 0x80) == 0) | 308 | if ((*d & 0x80) == 0) |
286 | return; | 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 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); | 313 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); |
289 | } | 314 | } |
290 | 315 | ||
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 0b51857fbaf7..dc1aa0922868 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -55,6 +55,9 @@ obj-$(CONFIG_MICROBLAZE) += setup-bus.o | |||
55 | # | 55 | # |
56 | obj-$(CONFIG_ACPI) += pci-acpi.o | 56 | obj-$(CONFIG_ACPI) += pci-acpi.o |
57 | 57 | ||
58 | # SMBIOS provided firmware instance and labels | ||
59 | obj-$(CONFIG_DMI) += pci-label.o | ||
60 | |||
58 | # Cardbus & CompactPCI use setup-bus | 61 | # Cardbus & CompactPCI use setup-bus |
59 | obj-$(CONFIG_HOTPLUG) += setup-bus.o | 62 | obj-$(CONFIG_HOTPLUG) += setup-bus.o |
60 | 63 | ||
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c new file mode 100644 index 000000000000..111500e86f94 --- /dev/null +++ b/drivers/pci/pci-label.c | |||
@@ -0,0 +1,143 @@ | |||
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 | } | ||
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index f7692dc531e4..b5a7d9bfcb24 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -1165,6 +1165,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
1165 | if (retval) | 1165 | if (retval) |
1166 | goto err_vga_file; | 1166 | goto err_vga_file; |
1167 | 1167 | ||
1168 | pci_create_firmware_label_files(pdev); | ||
1169 | |||
1168 | return 0; | 1170 | return 0; |
1169 | 1171 | ||
1170 | err_vga_file: | 1172 | err_vga_file: |
@@ -1232,6 +1234,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) | |||
1232 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); | 1234 | sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); |
1233 | kfree(pdev->rom_attr); | 1235 | kfree(pdev->rom_attr); |
1234 | } | 1236 | } |
1237 | |||
1238 | pci_remove_firmware_label_files(pdev); | ||
1239 | |||
1235 | } | 1240 | } |
1236 | 1241 | ||
1237 | static int __init pci_sysfs_init(void) | 1242 | static int __init pci_sysfs_init(void) |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index f8077b3c8c8c..d930338e0922 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -11,6 +11,15 @@ | |||
11 | extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); | 11 | extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); |
12 | extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); | 12 | extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); |
13 | extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); | 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 | extern void pci_cleanup_rom(struct pci_dev *dev); | 23 | extern void pci_cleanup_rom(struct pci_dev *dev); |
15 | #ifdef HAVE_PCI_MMAP | 24 | #ifdef HAVE_PCI_MMAP |
16 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, | 25 | extern int pci_mmap_fits(struct pci_dev *pdev, int resno, |
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index a8a3e1ac281d..90e087f8d951 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
@@ -20,6 +20,7 @@ enum dmi_device_type { | |||
20 | DMI_DEV_TYPE_SAS, | 20 | DMI_DEV_TYPE_SAS, |
21 | DMI_DEV_TYPE_IPMI = -1, | 21 | DMI_DEV_TYPE_IPMI = -1, |
22 | DMI_DEV_TYPE_OEM_STRING = -2, | 22 | DMI_DEV_TYPE_OEM_STRING = -2, |
23 | DMI_DEV_TYPE_DEV_ONBOARD = -3, | ||
23 | }; | 24 | }; |
24 | 25 | ||
25 | struct dmi_header { | 26 | struct dmi_header { |
@@ -37,6 +38,14 @@ struct dmi_device { | |||
37 | 38 | ||
38 | #ifdef CONFIG_DMI | 39 | #ifdef CONFIG_DMI |
39 | 40 | ||
41 | struct dmi_dev_onboard { | ||
42 | struct dmi_device dev; | ||
43 | int instance; | ||
44 | int segment; | ||
45 | int bus; | ||
46 | int devfn; | ||
47 | }; | ||
48 | |||
40 | extern int dmi_check_system(const struct dmi_system_id *list); | 49 | extern int dmi_check_system(const struct dmi_system_id *list); |
41 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); | 50 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); |
42 | extern const char * dmi_get_system_info(int field); | 51 | extern const char * dmi_get_system_info(int field); |