Commit 911e1c9b authored by Narendra K's avatar Narendra K Committed by Jesse Barnes

PCI: export SMBIOS provided firmware instance and label to sysfs

This patch exports SMBIOS provided firmware instance and label of
onboard PCI devices to sysfs.  New files are:
  /sys/bus/pci/devices/.../label which contains the firmware name for
the device in question, and
  /sys/bus/pci/devices/.../index which contains the firmware device type
instance for the given device.
Signed-off-by: default avatarJordan Hargrave <jordan_hargrave@dell.com>
Signed-off-by: default avatarNarendra K <narendra_k@dell.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 8633328b
...@@ -139,3 +139,30 @@ Contact: linux-pci@vger.kernel.org ...@@ -139,3 +139,30 @@ Contact: linux-pci@vger.kernel.org
Description: Description:
This symbolic link points to the PCI hotplug controller driver This symbolic link points to the PCI hotplug controller driver
module that manages the hotplug slot. module that manages the hotplug slot.
What: /sys/bus/pci/devices/.../label
Date: July 2010
Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
Description:
Reading this attribute will provide the firmware
given name(SMBIOS type 41 string) of the PCI device.
The attribute will be created only if the firmware
has given a name to the PCI device.
Users:
Userspace applications interested in knowing the
firmware assigned name of the PCI device.
What: /sys/bus/pci/devices/.../index
Date: July 2010
Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
Description:
Reading this attribute will provide the firmware
given instance(SMBIOS type 41 device type instance)
of the PCI device. The attribute will be created
only if the firmware has given a device type instance
to the PCI device.
Users:
Userspace applications interested in knowing the
firmware assigned device type instance of the PCI
device that can help in understanding the firmware
intended order of the PCI device.
...@@ -277,6 +277,29 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm) ...@@ -277,6 +277,29 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
list_add_tail(&dev->list, &dmi_devices); list_add_tail(&dev->list, &dmi_devices);
} }
static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
int devfn, const char *name)
{
struct dmi_dev_onboard *onboard_dev;
onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
if (!onboard_dev) {
printk(KERN_ERR "dmi_save_dev_onboard: out of memory.\n");
return;
}
onboard_dev->instance = instance;
onboard_dev->segment = segment;
onboard_dev->bus = bus;
onboard_dev->devfn = devfn;
strcpy((char *)&onboard_dev[1], name);
onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD;
onboard_dev->dev.name = (char *)&onboard_dev[1];
onboard_dev->dev.device_data = onboard_dev;
list_add(&onboard_dev->dev.list, &dmi_devices);
}
static void __init dmi_save_extended_devices(const struct dmi_header *dm) static void __init dmi_save_extended_devices(const struct dmi_header *dm)
{ {
const u8 *d = (u8*) dm + 5; const u8 *d = (u8*) dm + 5;
...@@ -285,6 +308,8 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) ...@@ -285,6 +308,8 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
if ((*d & 0x80) == 0) if ((*d & 0x80) == 0)
return; return;
dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5),
dmi_string_nosave(dm, *(d-1)));
dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
} }
......
...@@ -55,6 +55,9 @@ obj-$(CONFIG_MICROBLAZE) += setup-bus.o ...@@ -55,6 +55,9 @@ obj-$(CONFIG_MICROBLAZE) += setup-bus.o
# #
obj-$(CONFIG_ACPI) += pci-acpi.o obj-$(CONFIG_ACPI) += pci-acpi.o
# SMBIOS provided firmware instance and labels
obj-$(CONFIG_DMI) += pci-label.o
# Cardbus & CompactPCI use setup-bus # Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o obj-$(CONFIG_HOTPLUG) += setup-bus.o
......
/*
* Purpose: Export the firmware instance and label associated with
* a pci device to sysfs
* Copyright (C) 2010 Dell Inc.
* by Narendra K <Narendra_K@dell.com>,
* Jordan Hargrave <Jordan_Hargrave@dell.com>
*
* SMBIOS defines type 41 for onboard pci devices. This code retrieves
* the instance number and string from the type 41 record and exports
* it to sysfs.
*
* Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more
* information.
*/
#include <linux/dmi.h>
#include <linux/sysfs.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/module.h>
#include <linux/device.h>
#include "pci.h"
enum smbios_attr_enum {
SMBIOS_ATTR_NONE = 0,
SMBIOS_ATTR_LABEL_SHOW,
SMBIOS_ATTR_INSTANCE_SHOW,
};
static mode_t
find_smbios_instance_string(struct pci_dev *pdev, char *buf,
enum smbios_attr_enum attribute)
{
const struct dmi_device *dmi;
struct dmi_dev_onboard *donboard;
int bus;
int devfn;
bus = pdev->bus->number;
devfn = pdev->devfn;
dmi = NULL;
while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD,
NULL, dmi)) != NULL) {
donboard = dmi->device_data;
if (donboard && donboard->bus == bus &&
donboard->devfn == devfn) {
if (buf) {
if (attribute == SMBIOS_ATTR_INSTANCE_SHOW)
return scnprintf(buf, PAGE_SIZE,
"%d\n",
donboard->instance);
else if (attribute == SMBIOS_ATTR_LABEL_SHOW)
return scnprintf(buf, PAGE_SIZE,
"%s\n",
dmi->name);
}
return strlen(dmi->name);
}
}
return 0;
}
static mode_t
smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr,
int n)
{
struct device *dev;
struct pci_dev *pdev;
dev = container_of(kobj, struct device, kobj);
pdev = to_pci_dev(dev);
return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ?
S_IRUGO : 0;
}
static ssize_t
smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev;
pdev = to_pci_dev(dev);
return find_smbios_instance_string(pdev, buf,
SMBIOS_ATTR_LABEL_SHOW);
}
static ssize_t
smbiosinstance_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev;
pdev = to_pci_dev(dev);
return find_smbios_instance_string(pdev, buf,
SMBIOS_ATTR_INSTANCE_SHOW);
}
static struct device_attribute smbios_attr_label = {
.attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE},
.show = smbioslabel_show,
};
static struct device_attribute smbios_attr_instance = {
.attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE},
.show = smbiosinstance_show,
};
static struct attribute *smbios_attributes[] = {
&smbios_attr_label.attr,
&smbios_attr_instance.attr,
NULL,
};
static struct attribute_group smbios_attr_group = {
.attrs = smbios_attributes,
.is_visible = smbios_instance_string_exist,
};
static int
pci_create_smbiosname_file(struct pci_dev *pdev)
{
if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group))
return 0;
return -ENODEV;
}
static void
pci_remove_smbiosname_file(struct pci_dev *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
}
void pci_create_firmware_label_files(struct pci_dev *pdev)
{
if (!pci_create_smbiosname_file(pdev))
;
}
void pci_remove_firmware_label_files(struct pci_dev *pdev)
{
pci_remove_smbiosname_file(pdev);
}
...@@ -1165,6 +1165,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) ...@@ -1165,6 +1165,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
if (retval) if (retval)
goto err_vga_file; goto err_vga_file;
pci_create_firmware_label_files(pdev);
return 0; return 0;
err_vga_file: err_vga_file:
...@@ -1232,6 +1234,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) ...@@ -1232,6 +1234,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr); kfree(pdev->rom_attr);
} }
pci_remove_firmware_label_files(pdev);
} }
static int __init pci_sysfs_init(void) static int __init pci_sysfs_init(void)
......
...@@ -11,6 +11,15 @@ ...@@ -11,6 +11,15 @@
extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
#ifndef CONFIG_DMI
static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
{ return 0; }
static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)
{ return 0; }
#else
extern void pci_create_firmware_label_files(struct pci_dev *pdev);
extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
#endif
extern void pci_cleanup_rom(struct pci_dev *dev); extern void pci_cleanup_rom(struct pci_dev *dev);
#ifdef HAVE_PCI_MMAP #ifdef HAVE_PCI_MMAP
extern int pci_mmap_fits(struct pci_dev *pdev, int resno, extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
......
...@@ -20,6 +20,7 @@ enum dmi_device_type { ...@@ -20,6 +20,7 @@ enum dmi_device_type {
DMI_DEV_TYPE_SAS, DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1, DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2, DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
}; };
struct dmi_header { struct dmi_header {
...@@ -37,6 +38,14 @@ struct dmi_device { ...@@ -37,6 +38,14 @@ struct dmi_device {
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
struct dmi_dev_onboard {
struct dmi_device dev;
int instance;
int segment;
int bus;
int devfn;
};
extern int dmi_check_system(const struct dmi_system_id *list); extern int dmi_check_system(const struct dmi_system_id *list);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
extern const char * dmi_get_system_info(int field); extern const char * dmi_get_system_info(int field);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment