1*911e1c9bSNarendra K /* 2*911e1c9bSNarendra K * Purpose: Export the firmware instance and label associated with 3*911e1c9bSNarendra K * a pci device to sysfs 4*911e1c9bSNarendra K * Copyright (C) 2010 Dell Inc. 5*911e1c9bSNarendra K * by Narendra K <Narendra_K@dell.com>, 6*911e1c9bSNarendra K * Jordan Hargrave <Jordan_Hargrave@dell.com> 7*911e1c9bSNarendra K * 8*911e1c9bSNarendra K * SMBIOS defines type 41 for onboard pci devices. This code retrieves 9*911e1c9bSNarendra K * the instance number and string from the type 41 record and exports 10*911e1c9bSNarendra K * it to sysfs. 11*911e1c9bSNarendra K * 12*911e1c9bSNarendra K * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more 13*911e1c9bSNarendra K * information. 14*911e1c9bSNarendra K */ 15*911e1c9bSNarendra K 16*911e1c9bSNarendra K #include <linux/dmi.h> 17*911e1c9bSNarendra K #include <linux/sysfs.h> 18*911e1c9bSNarendra K #include <linux/pci.h> 19*911e1c9bSNarendra K #include <linux/pci_ids.h> 20*911e1c9bSNarendra K #include <linux/module.h> 21*911e1c9bSNarendra K #include <linux/device.h> 22*911e1c9bSNarendra K #include "pci.h" 23*911e1c9bSNarendra K 24*911e1c9bSNarendra K enum smbios_attr_enum { 25*911e1c9bSNarendra K SMBIOS_ATTR_NONE = 0, 26*911e1c9bSNarendra K SMBIOS_ATTR_LABEL_SHOW, 27*911e1c9bSNarendra K SMBIOS_ATTR_INSTANCE_SHOW, 28*911e1c9bSNarendra K }; 29*911e1c9bSNarendra K 30*911e1c9bSNarendra K static mode_t 31*911e1c9bSNarendra K find_smbios_instance_string(struct pci_dev *pdev, char *buf, 32*911e1c9bSNarendra K enum smbios_attr_enum attribute) 33*911e1c9bSNarendra K { 34*911e1c9bSNarendra K const struct dmi_device *dmi; 35*911e1c9bSNarendra K struct dmi_dev_onboard *donboard; 36*911e1c9bSNarendra K int bus; 37*911e1c9bSNarendra K int devfn; 38*911e1c9bSNarendra K 39*911e1c9bSNarendra K bus = pdev->bus->number; 40*911e1c9bSNarendra K devfn = pdev->devfn; 41*911e1c9bSNarendra K 42*911e1c9bSNarendra K dmi = NULL; 43*911e1c9bSNarendra K while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, 44*911e1c9bSNarendra K NULL, dmi)) != NULL) { 45*911e1c9bSNarendra K donboard = dmi->device_data; 46*911e1c9bSNarendra K if (donboard && donboard->bus == bus && 47*911e1c9bSNarendra K donboard->devfn == devfn) { 48*911e1c9bSNarendra K if (buf) { 49*911e1c9bSNarendra K if (attribute == SMBIOS_ATTR_INSTANCE_SHOW) 50*911e1c9bSNarendra K return scnprintf(buf, PAGE_SIZE, 51*911e1c9bSNarendra K "%d\n", 52*911e1c9bSNarendra K donboard->instance); 53*911e1c9bSNarendra K else if (attribute == SMBIOS_ATTR_LABEL_SHOW) 54*911e1c9bSNarendra K return scnprintf(buf, PAGE_SIZE, 55*911e1c9bSNarendra K "%s\n", 56*911e1c9bSNarendra K dmi->name); 57*911e1c9bSNarendra K } 58*911e1c9bSNarendra K return strlen(dmi->name); 59*911e1c9bSNarendra K } 60*911e1c9bSNarendra K } 61*911e1c9bSNarendra K return 0; 62*911e1c9bSNarendra K } 63*911e1c9bSNarendra K 64*911e1c9bSNarendra K static mode_t 65*911e1c9bSNarendra K smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, 66*911e1c9bSNarendra K int n) 67*911e1c9bSNarendra K { 68*911e1c9bSNarendra K struct device *dev; 69*911e1c9bSNarendra K struct pci_dev *pdev; 70*911e1c9bSNarendra K 71*911e1c9bSNarendra K dev = container_of(kobj, struct device, kobj); 72*911e1c9bSNarendra K pdev = to_pci_dev(dev); 73*911e1c9bSNarendra K 74*911e1c9bSNarendra K return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ? 75*911e1c9bSNarendra K S_IRUGO : 0; 76*911e1c9bSNarendra K } 77*911e1c9bSNarendra K 78*911e1c9bSNarendra K static ssize_t 79*911e1c9bSNarendra K smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf) 80*911e1c9bSNarendra K { 81*911e1c9bSNarendra K struct pci_dev *pdev; 82*911e1c9bSNarendra K pdev = to_pci_dev(dev); 83*911e1c9bSNarendra K 84*911e1c9bSNarendra K return find_smbios_instance_string(pdev, buf, 85*911e1c9bSNarendra K SMBIOS_ATTR_LABEL_SHOW); 86*911e1c9bSNarendra K } 87*911e1c9bSNarendra K 88*911e1c9bSNarendra K static ssize_t 89*911e1c9bSNarendra K smbiosinstance_show(struct device *dev, 90*911e1c9bSNarendra K struct device_attribute *attr, char *buf) 91*911e1c9bSNarendra K { 92*911e1c9bSNarendra K struct pci_dev *pdev; 93*911e1c9bSNarendra K pdev = to_pci_dev(dev); 94*911e1c9bSNarendra K 95*911e1c9bSNarendra K return find_smbios_instance_string(pdev, buf, 96*911e1c9bSNarendra K SMBIOS_ATTR_INSTANCE_SHOW); 97*911e1c9bSNarendra K } 98*911e1c9bSNarendra K 99*911e1c9bSNarendra K static struct device_attribute smbios_attr_label = { 100*911e1c9bSNarendra K .attr = {.name = "label", .mode = 0444, .owner = THIS_MODULE}, 101*911e1c9bSNarendra K .show = smbioslabel_show, 102*911e1c9bSNarendra K }; 103*911e1c9bSNarendra K 104*911e1c9bSNarendra K static struct device_attribute smbios_attr_instance = { 105*911e1c9bSNarendra K .attr = {.name = "index", .mode = 0444, .owner = THIS_MODULE}, 106*911e1c9bSNarendra K .show = smbiosinstance_show, 107*911e1c9bSNarendra K }; 108*911e1c9bSNarendra K 109*911e1c9bSNarendra K static struct attribute *smbios_attributes[] = { 110*911e1c9bSNarendra K &smbios_attr_label.attr, 111*911e1c9bSNarendra K &smbios_attr_instance.attr, 112*911e1c9bSNarendra K NULL, 113*911e1c9bSNarendra K }; 114*911e1c9bSNarendra K 115*911e1c9bSNarendra K static struct attribute_group smbios_attr_group = { 116*911e1c9bSNarendra K .attrs = smbios_attributes, 117*911e1c9bSNarendra K .is_visible = smbios_instance_string_exist, 118*911e1c9bSNarendra K }; 119*911e1c9bSNarendra K 120*911e1c9bSNarendra K static int 121*911e1c9bSNarendra K pci_create_smbiosname_file(struct pci_dev *pdev) 122*911e1c9bSNarendra K { 123*911e1c9bSNarendra K if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group)) 124*911e1c9bSNarendra K return 0; 125*911e1c9bSNarendra K return -ENODEV; 126*911e1c9bSNarendra K } 127*911e1c9bSNarendra K 128*911e1c9bSNarendra K static void 129*911e1c9bSNarendra K pci_remove_smbiosname_file(struct pci_dev *pdev) 130*911e1c9bSNarendra K { 131*911e1c9bSNarendra K sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); 132*911e1c9bSNarendra K } 133*911e1c9bSNarendra K 134*911e1c9bSNarendra K void pci_create_firmware_label_files(struct pci_dev *pdev) 135*911e1c9bSNarendra K { 136*911e1c9bSNarendra K if (!pci_create_smbiosname_file(pdev)) 137*911e1c9bSNarendra K ; 138*911e1c9bSNarendra K } 139*911e1c9bSNarendra K 140*911e1c9bSNarendra K void pci_remove_firmware_label_files(struct pci_dev *pdev) 141*911e1c9bSNarendra K { 142*911e1c9bSNarendra K pci_remove_smbiosname_file(pdev); 143*911e1c9bSNarendra K } 144