aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarendra_K@Dell.com <Narendra_K@Dell.com>2011-03-02 12:04:17 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-03-04 13:41:56 -0500
commit6058989bad05b82e78baacce69ec14f27a11b5fd (patch)
tree26353578e7e9a95d2ea101cd9a8e656d85ddd829
parentcdb9755849fbaf2bb9c0a009ba5baa817a0f152d (diff)
PCI: Export ACPI _DSM provided firmware instance number and string name to sysfs
This patch exports ACPI _DSM (Device Specific Method) provided firmware instance number and string name of PCI devices as defined by 'PCI Firmware Specification Revision 3.1' section 4.6.7.( DSM for Naming a PCI or PCI Express Device Under Operating Systems) to sysfs. New files created are: /sys/bus/pci/devices/.../label which contains the firmware name for the device in question, and /sys/bus/pci/devices/.../acpi_index which contains the firmware device type instance for the given device. cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/acpi_index 1 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/label Embedded Broadcom 5709C NIC 1 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.1/acpi_index 2 cat /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.1/label Embedded Broadcom 5709C NIC 2 The ACPI _DSM provided firmware 'instance number' and 'string name' will be given priority if the firmware also provides 'SMBIOS type 41 device type instance and string'. Signed-off-by: Matthew Garrett <mjg@redhat.com> 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>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci31
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/pci-label.c247
-rw-r--r--drivers/pci/pci.h2
5 files changed, 270 insertions, 15 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index f979d825d112..36bf454ba855 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -145,9 +145,11 @@ Date: July 2010
145Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com 145Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
146Description: 146Description:
147 Reading this attribute will provide the firmware 147 Reading this attribute will provide the firmware
148 given name(SMBIOS type 41 string) of the PCI device. 148 given name (SMBIOS type 41 string or ACPI _DSM string) of
149 The attribute will be created only if the firmware 149 the PCI device. The attribute will be created only
150 has given a name to the PCI device. 150 if the firmware has given a name to the PCI device.
151 ACPI _DSM string name will be given priority if the
152 system firmware provides SMBIOS type 41 string also.
151Users: 153Users:
152 Userspace applications interested in knowing the 154 Userspace applications interested in knowing the
153 firmware assigned name of the PCI device. 155 firmware assigned name of the PCI device.
@@ -157,12 +159,27 @@ Date: July 2010
157Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com 159Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
158Description: 160Description:
159 Reading this attribute will provide the firmware 161 Reading this attribute will provide the firmware
160 given instance(SMBIOS type 41 device type instance) 162 given instance (SMBIOS type 41 device type instance) of the
161 of the PCI device. The attribute will be created 163 PCI device. The attribute will be created only if the firmware
162 only if the firmware has given a device type instance 164 has given an instance number to the PCI device.
163 to the PCI device.
164Users: 165Users:
165 Userspace applications interested in knowing the 166 Userspace applications interested in knowing the
166 firmware assigned device type instance of the PCI 167 firmware assigned device type instance of the PCI
167 device that can help in understanding the firmware 168 device that can help in understanding the firmware
168 intended order of the PCI device. 169 intended order of the PCI device.
170
171What: /sys/bus/pci/devices/.../acpi_index
172Date: July 2010
173Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
174Description:
175 Reading this attribute will provide the firmware
176 given instance (ACPI _DSM instance number) of the PCI device.
177 The attribute will be created only if the firmware has given
178 an instance number to the PCI device. ACPI _DSM instance number
179 will be given priority if the system firmware provides SMBIOS
180 type 41 device type instance also.
181Users:
182 Userspace applications interested in knowing the
183 firmware assigned instance number of the PCI
184 device that can help in understanding the firmware
185 intended order of the PCI device.
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index a9523fdc6911..c8ff646c0b05 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -87,3 +87,5 @@ config PCI_IOAPIC
87 depends on ACPI 87 depends on ACPI
88 depends on HOTPLUG 88 depends on HOTPLUG
89 default y 89 default y
90
91select NLS if (DMI || ACPI)
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 98e6fdf34d30..bb1d3b2d81ec 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -53,8 +53,9 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
53 53
54# 54#
55# ACPI Related PCI FW Functions 55# ACPI Related PCI FW Functions
56# ACPI _DSM provided firmware instance and string name
56# 57#
57obj-$(CONFIG_ACPI) += pci-acpi.o 58obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o
58 59
59# SMBIOS provided firmware instance and labels 60# SMBIOS provided firmware instance and labels
60obj-$(CONFIG_DMI) += pci-label.o 61obj-$(CONFIG_DMI) += pci-label.o
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 90c0a729cd3a..824e247edc58 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -5,6 +5,13 @@
5 * by Narendra K <Narendra_K@dell.com>, 5 * by Narendra K <Narendra_K@dell.com>,
6 * Jordan Hargrave <Jordan_Hargrave@dell.com> 6 * Jordan Hargrave <Jordan_Hargrave@dell.com>
7 * 7 *
8 * PCI Firmware Specification Revision 3.1 section 4.6.7 (DSM for Naming a
9 * PCI or PCI Express Device Under Operating Systems) defines an instance
10 * number and string name. This code retrieves them and exports them to sysfs.
11 * If the system firmware does not provide the ACPI _DSM (Device Specific
12 * Method), then the SMBIOS type 41 instance number and string is exported to
13 * sysfs.
14 *
8 * SMBIOS defines type 41 for onboard pci devices. This code retrieves 15 * SMBIOS defines type 41 for onboard pci devices. This code retrieves
9 * the instance number and string from the type 41 record and exports 16 * the instance number and string from the type 41 record and exports
10 * it to sysfs. 17 * it to sysfs.
@@ -19,8 +26,30 @@
19#include <linux/pci_ids.h> 26#include <linux/pci_ids.h>
20#include <linux/module.h> 27#include <linux/module.h>
21#include <linux/device.h> 28#include <linux/device.h>
29#include <linux/nls.h>
30#include <linux/acpi.h>
31#include <linux/pci-acpi.h>
32#include <acpi/acpi_drivers.h>
33#include <acpi/acpi_bus.h>
22#include "pci.h" 34#include "pci.h"
23 35
36#define DEVICE_LABEL_DSM 0x07
37
38#ifndef CONFIG_DMI
39
40static inline int
41pci_create_smbiosname_file(struct pci_dev *pdev)
42{
43 return -1;
44}
45
46static inline void
47pci_remove_smbiosname_file(struct pci_dev *pdev)
48{
49}
50
51#else
52
24enum smbios_attr_enum { 53enum smbios_attr_enum {
25 SMBIOS_ATTR_NONE = 0, 54 SMBIOS_ATTR_NONE = 0,
26 SMBIOS_ATTR_LABEL_SHOW, 55 SMBIOS_ATTR_LABEL_SHOW,
@@ -120,9 +149,7 @@ static struct attribute_group smbios_attr_group = {
120static int 149static int
121pci_create_smbiosname_file(struct pci_dev *pdev) 150pci_create_smbiosname_file(struct pci_dev *pdev)
122{ 151{
123 if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group)) 152 return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group);
124 return 0;
125 return -ENODEV;
126} 153}
127 154
128static void 155static void
@@ -131,13 +158,221 @@ pci_remove_smbiosname_file(struct pci_dev *pdev)
131 sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); 158 sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
132} 159}
133 160
161#endif
162
163#ifndef CONFIG_ACPI
164
165static inline int
166pci_create_acpi_index_label_files(struct pci_dev *pdev)
167{
168 return -1;
169}
170
171static inline int
172pci_remove_acpi_index_label_files(struct pci_dev *pdev)
173{
174 return -1;
175}
176
177#else
178
179static const char device_label_dsm_uuid[] = {
180 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
181 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
182};
183
184enum acpi_attr_enum {
185 ACPI_ATTR_NONE = 0,
186 ACPI_ATTR_LABEL_SHOW,
187 ACPI_ATTR_INDEX_SHOW,
188};
189
190static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
191{
192 int len;
193 len = utf16s_to_utf8s((const wchar_t *)obj->
194 package.elements[1].string.pointer,
195 obj->package.elements[1].string.length,
196 UTF16_LITTLE_ENDIAN,
197 buf, PAGE_SIZE);
198 buf[len] = '\n';
199}
200
201static int
202dsm_get_label(acpi_handle handle, int func,
203 struct acpi_buffer *output,
204 char *buf, enum acpi_attr_enum attribute)
205{
206 struct acpi_object_list input;
207 union acpi_object params[4];
208 union acpi_object *obj;
209 int len = 0;
210
211 int err;
212
213 input.count = 4;
214 input.pointer = params;
215 params[0].type = ACPI_TYPE_BUFFER;
216 params[0].buffer.length = sizeof(device_label_dsm_uuid);
217 params[0].buffer.pointer = (char *)device_label_dsm_uuid;
218 params[1].type = ACPI_TYPE_INTEGER;
219 params[1].integer.value = 0x02;
220 params[2].type = ACPI_TYPE_INTEGER;
221 params[2].integer.value = func;
222 params[3].type = ACPI_TYPE_PACKAGE;
223 params[3].package.count = 0;
224 params[3].package.elements = NULL;
225
226 err = acpi_evaluate_object(handle, "_DSM", &input, output);
227 if (err)
228 return -1;
229
230 obj = (union acpi_object *)output->pointer;
231
232 switch (obj->type) {
233 case ACPI_TYPE_PACKAGE:
234 if (obj->package.count != 2)
235 break;
236 len = obj->package.elements[0].integer.value;
237 if (buf) {
238 if (attribute == ACPI_ATTR_INDEX_SHOW)
239 scnprintf(buf, PAGE_SIZE, "%llu\n",
240 obj->package.elements[0].integer.value);
241 else if (attribute == ACPI_ATTR_LABEL_SHOW)
242 dsm_label_utf16s_to_utf8s(obj, buf);
243 kfree(output->pointer);
244 return strlen(buf);
245 }
246 kfree(output->pointer);
247 return len;
248 break;
249 default:
250 kfree(output->pointer);
251 }
252 return -1;
253}
254
255static bool
256device_has_dsm(struct device *dev)
257{
258 acpi_handle handle;
259 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
260
261 handle = DEVICE_ACPI_HANDLE(dev);
262
263 if (!handle)
264 return FALSE;
265
266 if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL,
267 ACPI_ATTR_NONE) > 0)
268 return TRUE;
269
270 return FALSE;
271}
272
273static mode_t
274acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n)
275{
276 struct device *dev;
277
278 dev = container_of(kobj, struct device, kobj);
279
280 if (device_has_dsm(dev))
281 return S_IRUGO;
282
283 return 0;
284}
285
286static ssize_t
287acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf)
288{
289 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
290 acpi_handle handle;
291 int length;
292
293 handle = DEVICE_ACPI_HANDLE(dev);
294
295 if (!handle)
296 return -1;
297
298 length = dsm_get_label(handle, DEVICE_LABEL_DSM,
299 &output, buf, ACPI_ATTR_LABEL_SHOW);
300
301 if (length < 1)
302 return -1;
303
304 return length;
305}
306
307static ssize_t
308acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf)
309{
310 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
311 acpi_handle handle;
312 int length;
313
314 handle = DEVICE_ACPI_HANDLE(dev);
315
316 if (!handle)
317 return -1;
318
319 length = dsm_get_label(handle, DEVICE_LABEL_DSM,
320 &output, buf, ACPI_ATTR_INDEX_SHOW);
321
322 if (length < 0)
323 return -1;
324
325 return length;
326
327}
328
329static struct device_attribute acpi_attr_label = {
330 .attr = {.name = "label", .mode = 0444},
331 .show = acpilabel_show,
332};
333
334static struct device_attribute acpi_attr_index = {
335 .attr = {.name = "acpi_index", .mode = 0444},
336 .show = acpiindex_show,
337};
338
339static struct attribute *acpi_attributes[] = {
340 &acpi_attr_label.attr,
341 &acpi_attr_index.attr,
342 NULL,
343};
344
345static struct attribute_group acpi_attr_group = {
346 .attrs = acpi_attributes,
347 .is_visible = acpi_index_string_exist,
348};
349
350static int
351pci_create_acpi_index_label_files(struct pci_dev *pdev)
352{
353 return sysfs_create_group(&pdev->dev.kobj, &acpi_attr_group);
354}
355
356static int
357pci_remove_acpi_index_label_files(struct pci_dev *pdev)
358{
359 sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group);
360 return 0;
361}
362#endif
363
134void pci_create_firmware_label_files(struct pci_dev *pdev) 364void pci_create_firmware_label_files(struct pci_dev *pdev)
135{ 365{
136 if (!pci_create_smbiosname_file(pdev)) 366 if (device_has_dsm(&pdev->dev))
137 ; 367 pci_create_acpi_index_label_files(pdev);
368 else
369 pci_create_smbiosname_file(pdev);
138} 370}
139 371
140void pci_remove_firmware_label_files(struct pci_dev *pdev) 372void pci_remove_firmware_label_files(struct pci_dev *pdev)
141{ 373{
142 pci_remove_smbiosname_file(pdev); 374 if (device_has_dsm(&pdev->dev))
375 pci_remove_acpi_index_label_files(pdev);
376 else
377 pci_remove_smbiosname_file(pdev);
143} 378}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f69d6e0fda75..a6ec200fe5ee 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -11,7 +11,7 @@
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 14#if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI)
15static inline void pci_create_firmware_label_files(struct pci_dev *pdev) 15static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
16{ return; } 16{ return; }
17static inline void pci_remove_firmware_label_files(struct pci_dev *pdev) 17static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)