Skip to content

Commit

Permalink
PCI: export SMBIOS provided firmware instance and label to sysfs
Browse files Browse the repository at this point in the history
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: Jordan Hargrave <jordan_hargrave@dell.com>
Signed-off-by: Narendra K <narendra_k@dell.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Narendra K authored and jbarnes993 committed Jul 30, 2010
1 parent 8633328 commit 911e1c9
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 0 deletions.
27 changes: 27 additions & 0 deletions Documentation/ABI/testing/sysfs-bus-pci
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,30 @@ Contact: linux-pci@vger.kernel.org
Description:
This symbolic link points to the PCI hotplug controller driver
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.
25 changes: 25 additions & 0 deletions drivers/firmware/dmi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,29 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
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)
{
const u8 *d = (u8*) dm + 5;
Expand All @@ -285,6 +308,8 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
if ((*d & 0x80) == 0)
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)));
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ obj-$(CONFIG_MICROBLAZE) += setup-bus.o
#
obj-$(CONFIG_ACPI) += pci-acpi.o

# SMBIOS provided firmware instance and labels
obj-$(CONFIG_DMI) += pci-label.o

# Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o

Expand Down
143 changes: 143 additions & 0 deletions drivers/pci/pci-label.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* 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);
}
5 changes: 5 additions & 0 deletions drivers/pci/pci-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
if (retval)
goto err_vga_file;

pci_create_firmware_label_files(pdev);

return 0;

err_vga_file:
Expand Down Expand Up @@ -1232,6 +1234,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr);
}

pci_remove_firmware_label_files(pdev);

}

static int __init pci_sysfs_init(void)
Expand Down
9 changes: 9 additions & 0 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_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);
#ifdef HAVE_PCI_MMAP
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
Expand Down
9 changes: 9 additions & 0 deletions include/linux/dmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum dmi_device_type {
DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
};

struct dmi_header {
Expand All @@ -37,6 +38,14 @@ struct dmi_device {

#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);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
extern const char * dmi_get_system_info(int field);
Expand Down

0 comments on commit 911e1c9

Please sign in to comment.