diff options
Diffstat (limited to 'drivers/pci')
-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 |
4 files changed, 160 insertions, 0 deletions
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, |