aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci27
-rw-r--r--drivers/firmware/dmi_scan.c25
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/pci-label.c143
-rw-r--r--drivers/pci/pci-sysfs.c5
-rw-r--r--drivers/pci/pci.h9
-rw-r--r--include/linux/dmi.h9
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
139Description: 139Description:
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
143What: /sys/bus/pci/devices/.../label
144Date: July 2010
145Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
146Description:
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.
151Users:
152 Userspace applications interested in knowing the
153 firmware assigned name of the PCI device.
154
155What: /sys/bus/pci/devices/.../index
156Date: July 2010
157Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
158Description:
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.
164Users:
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
280static 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
280static void __init dmi_save_extended_devices(const struct dmi_header *dm) 303static 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#
56obj-$(CONFIG_ACPI) += pci-acpi.o 56obj-$(CONFIG_ACPI) += pci-acpi.o
57 57
58# SMBIOS provided firmware instance and labels
59obj-$(CONFIG_DMI) += pci-label.o
60
58# Cardbus & CompactPCI use setup-bus 61# Cardbus & CompactPCI use setup-bus
59obj-$(CONFIG_HOTPLUG) += setup-bus.o 62obj-$(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
24enum smbios_attr_enum {
25 SMBIOS_ATTR_NONE = 0,
26 SMBIOS_ATTR_LABEL_SHOW,
27 SMBIOS_ATTR_INSTANCE_SHOW,
28};
29
30static mode_t
31find_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
64static mode_t
65smbios_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
78static ssize_t
79smbioslabel_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
88static ssize_t
89smbiosinstance_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
99static struct device_attribute smbios_attr_label = {
100 .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE},
101 .show = smbioslabel_show,
102};
103
104static struct device_attribute smbios_attr_instance = {
105 .attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE},
106 .show = smbiosinstance_show,
107};
108
109static struct attribute *smbios_attributes[] = {
110 &smbios_attr_label.attr,
111 &smbios_attr_instance.attr,
112 NULL,
113};
114
115static struct attribute_group smbios_attr_group = {
116 .attrs = smbios_attributes,
117 .is_visible = smbios_instance_string_exist,
118};
119
120static int
121pci_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
128static void
129pci_remove_smbiosname_file(struct pci_dev *pdev)
130{
131 sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
132}
133
134void pci_create_firmware_label_files(struct pci_dev *pdev)
135{
136 if (!pci_create_smbiosname_file(pdev))
137 ;
138}
139
140void 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
1170err_vga_file: 1172err_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
1237static int __init pci_sysfs_init(void) 1242static 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 @@
11extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); 11extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
12extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); 12extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
13extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); 13extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
14#ifndef CONFIG_DMI
15static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
16{ return 0; }
17static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)
18{ return 0; }
19#else
20extern void pci_create_firmware_label_files(struct pci_dev *pdev);
21extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
22#endif
14extern void pci_cleanup_rom(struct pci_dev *dev); 23extern void pci_cleanup_rom(struct pci_dev *dev);
15#ifdef HAVE_PCI_MMAP 24#ifdef HAVE_PCI_MMAP
16extern int pci_mmap_fits(struct pci_dev *pdev, int resno, 25extern 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
25struct dmi_header { 26struct dmi_header {
@@ -37,6 +38,14 @@ struct dmi_device {
37 38
38#ifdef CONFIG_DMI 39#ifdef CONFIG_DMI
39 40
41struct dmi_dev_onboard {
42 struct dmi_device dev;
43 int instance;
44 int segment;
45 int bus;
46 int devfn;
47};
48
40extern int dmi_check_system(const struct dmi_system_id *list); 49extern int dmi_check_system(const struct dmi_system_id *list);
41const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); 50const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
42extern const char * dmi_get_system_info(int field); 51extern const char * dmi_get_system_info(int field);