xref: /openbmc/linux/drivers/pci/pci-label.c (revision df2634f43f5106947f3735a0b61a6527a4b278cd)
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},
101 	.show = smbioslabel_show,
102 };
103 
104 static struct device_attribute smbios_attr_instance = {
105 	.attr = {.name = "index", .mode = 0444},
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 }
144