diff options
Diffstat (limited to 'drivers/pci/pci-label.c')
| -rw-r--r-- | drivers/pci/pci-label.c | 380 |
1 files changed, 114 insertions, 266 deletions
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index edaed6f4da6c..0c6446519640 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -1,6 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Purpose: Export the firmware instance and label associated with - * a pci device to sysfs + * 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> @@ -16,7 +18,7 @@ * 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 + * Please see https://linux.dell.com/files/biosdevname/ for more * information. */ @@ -29,59 +31,53 @@ #include <linux/nls.h> #include <linux/acpi.h> #include <linux/pci-acpi.h> -#include <acpi/acpi_bus.h> #include "pci.h" -#define DEVICE_LABEL_DSM 0x07 - -#ifndef CONFIG_DMI - -static inline int -pci_create_smbiosname_file(struct pci_dev *pdev) +static bool device_has_acpi_name(struct device *dev) { - return -1; -} +#ifdef CONFIG_ACPI + acpi_handle handle = ACPI_HANDLE(dev); -static inline void -pci_remove_smbiosname_file(struct pci_dev *pdev) -{ -} + if (!handle) + return false; + return acpi_check_dsm(handle, &pci_acpi_dsm_guid, 0x2, + 1 << DSM_PCI_DEVICE_NAME); #else + return false; +#endif +} +#ifdef CONFIG_DMI enum smbios_attr_enum { SMBIOS_ATTR_NONE = 0, SMBIOS_ATTR_LABEL_SHOW, SMBIOS_ATTR_INSTANCE_SHOW, }; -static size_t -find_smbios_instance_string(struct pci_dev *pdev, char *buf, - enum smbios_attr_enum attribute) +static size_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; + int domain_nr = pci_domain_nr(pdev->bus); + int bus = pdev->bus->number; + int 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 (donboard && donboard->segment == domain_nr && + donboard->bus == bus && + donboard->devfn == devfn) { if (buf) { if (attribute == SMBIOS_ATTR_INSTANCE_SHOW) - return scnprintf(buf, PAGE_SIZE, - "%d\n", - donboard->instance); + return sysfs_emit(buf, "%d\n", + donboard->instance); else if (attribute == SMBIOS_ATTR_LABEL_SHOW) - return scnprintf(buf, PAGE_SIZE, - "%s\n", - dmi->name); + return sysfs_emit(buf, "%s\n", + dmi->name); } return strlen(dmi->name); } @@ -89,295 +85,147 @@ find_smbios_instance_string(struct pci_dev *pdev, char *buf, return 0; } -static umode_t -smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, - int n) +static ssize_t smbios_label_show(struct device *dev, + struct device_attribute *attr, char *buf) { - 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); + struct pci_dev *pdev = to_pci_dev(dev); return find_smbios_instance_string(pdev, buf, SMBIOS_ATTR_LABEL_SHOW); } +static struct device_attribute dev_attr_smbios_label = __ATTR(label, 0444, + smbios_label_show, NULL); -static ssize_t -smbiosinstance_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t index_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct pci_dev *pdev; - pdev = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); return find_smbios_instance_string(pdev, buf, SMBIOS_ATTR_INSTANCE_SHOW); } +static DEVICE_ATTR_RO(index); -static struct device_attribute smbios_attr_label = { - .attr = {.name = "label", .mode = 0444}, - .show = smbioslabel_show, -}; - -static struct device_attribute smbios_attr_instance = { - .attr = {.name = "index", .mode = 0444}, - .show = smbiosinstance_show, -}; - -static struct attribute *smbios_attributes[] = { - &smbios_attr_label.attr, - &smbios_attr_instance.attr, +static struct attribute *smbios_attrs[] = { + &dev_attr_smbios_label.attr, + &dev_attr_index.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) +static umode_t smbios_attr_is_visible(struct kobject *kobj, struct attribute *a, + int n) { - return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group); -} + struct device *dev = kobj_to_dev(kobj); + struct pci_dev *pdev = to_pci_dev(dev); -static void -pci_remove_smbiosname_file(struct pci_dev *pdev) -{ - sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); -} - -#endif + if (device_has_acpi_name(dev)) + return 0; -#ifndef CONFIG_ACPI + if (!find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE)) + return 0; -static inline int -pci_create_acpi_index_label_files(struct pci_dev *pdev) -{ - return -1; -} - -static inline int -pci_remove_acpi_index_label_files(struct pci_dev *pdev) -{ - return -1; -} - -static inline bool -device_has_dsm(struct device *dev) -{ - return false; + return a->mode; } -#else - -static const char device_label_dsm_uuid[] = { - 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D, - 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D +const struct attribute_group pci_dev_smbios_attr_group = { + .attrs = smbios_attrs, + .is_visible = smbios_attr_is_visible, }; +#endif +#ifdef CONFIG_ACPI enum acpi_attr_enum { - ACPI_ATTR_NONE = 0, ACPI_ATTR_LABEL_SHOW, ACPI_ATTR_INDEX_SHOW, }; -static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) +static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) { int len; - len = utf16s_to_utf8s((const wchar_t *)obj-> - package.elements[1].string.pointer, - obj->package.elements[1].string.length, + + len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer, + obj->buffer.length, UTF16_LITTLE_ENDIAN, - buf, PAGE_SIZE); - buf[len] = '\n'; + buf, PAGE_SIZE - 1); + buf[len++] = '\n'; + + return len; } -static int -dsm_get_label(acpi_handle handle, int func, - struct acpi_buffer *output, - char *buf, enum acpi_attr_enum attribute) +static int dsm_get_label(struct device *dev, char *buf, + enum acpi_attr_enum attr) { - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *obj; + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object *obj, *tmp; int len = 0; - int err; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(device_label_dsm_uuid); - params[0].buffer.pointer = (char *)device_label_dsm_uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x02; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - err = acpi_evaluate_object(handle, "_DSM", &input, output); - if (err) + if (!handle) + return -1; + + obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 0x2, + DSM_PCI_DEVICE_NAME, NULL); + if (!obj) return -1; - obj = (union acpi_object *)output->pointer; - - switch (obj->type) { - case ACPI_TYPE_PACKAGE: - if (obj->package.count != 2) - break; - len = obj->package.elements[0].integer.value; - if (buf) { - if (attribute == ACPI_ATTR_INDEX_SHOW) - scnprintf(buf, PAGE_SIZE, "%llu\n", - obj->package.elements[0].integer.value); - else if (attribute == ACPI_ATTR_LABEL_SHOW) - dsm_label_utf16s_to_utf8s(obj, buf); - kfree(output->pointer); - return strlen(buf); + tmp = obj->package.elements; + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && + tmp[0].type == ACPI_TYPE_INTEGER && + (tmp[1].type == ACPI_TYPE_STRING || + tmp[1].type == ACPI_TYPE_BUFFER)) { + /* + * The second string element is optional even when + * this _DSM is implemented; when not implemented, + * this entry must return a null string. + */ + if (attr == ACPI_ATTR_INDEX_SHOW) { + len = sysfs_emit(buf, "%llu\n", tmp->integer.value); + } else if (attr == ACPI_ATTR_LABEL_SHOW) { + if (tmp[1].type == ACPI_TYPE_STRING) + len = sysfs_emit(buf, "%s\n", + tmp[1].string.pointer); + else if (tmp[1].type == ACPI_TYPE_BUFFER) + len = dsm_label_utf16s_to_utf8s(tmp + 1, buf); } - kfree(output->pointer); - return len; - break; - default: - kfree(output->pointer); } - return -1; -} -static bool -device_has_dsm(struct device *dev) -{ - acpi_handle handle; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + ACPI_FREE(obj); - handle = DEVICE_ACPI_HANDLE(dev); - - if (!handle) - return FALSE; - - if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, - ACPI_ATTR_NONE) > 0) - return TRUE; - - return FALSE; -} - -static umode_t -acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) -{ - struct device *dev; - - dev = container_of(kobj, struct device, kobj); - - if (device_has_dsm(dev)) - return S_IRUGO; - - return 0; + return len > 0 ? len : -1; } -static ssize_t -acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t label_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = DEVICE_ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_LABEL_SHOW); - - if (length < 1) - return -1; - - return length; + return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW); } +static DEVICE_ATTR_RO(label); -static ssize_t -acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t acpi_index_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = DEVICE_ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_INDEX_SHOW); - - if (length < 0) - return -1; - - return length; - + return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW); } +static DEVICE_ATTR_RO(acpi_index); -static struct device_attribute acpi_attr_label = { - .attr = {.name = "label", .mode = 0444}, - .show = acpilabel_show, -}; - -static struct device_attribute acpi_attr_index = { - .attr = {.name = "acpi_index", .mode = 0444}, - .show = acpiindex_show, -}; - -static struct attribute *acpi_attributes[] = { - &acpi_attr_label.attr, - &acpi_attr_index.attr, +static struct attribute *acpi_attrs[] = { + &dev_attr_label.attr, + &dev_attr_acpi_index.attr, NULL, }; -static struct attribute_group acpi_attr_group = { - .attrs = acpi_attributes, - .is_visible = acpi_index_string_exist, -}; - -static int -pci_create_acpi_index_label_files(struct pci_dev *pdev) +static umode_t acpi_attr_is_visible(struct kobject *kobj, struct attribute *a, + int n) { - return sysfs_create_group(&pdev->dev.kobj, &acpi_attr_group); -} + struct device *dev = kobj_to_dev(kobj); -static int -pci_remove_acpi_index_label_files(struct pci_dev *pdev) -{ - sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group); - return 0; -} -#endif + if (!device_has_acpi_name(dev)) + return 0; -void pci_create_firmware_label_files(struct pci_dev *pdev) -{ - if (device_has_dsm(&pdev->dev)) - pci_create_acpi_index_label_files(pdev); - else - pci_create_smbiosname_file(pdev); + return a->mode; } -void pci_remove_firmware_label_files(struct pci_dev *pdev) -{ - if (device_has_dsm(&pdev->dev)) - pci_remove_acpi_index_label_files(pdev); - else - pci_remove_smbiosname_file(pdev); -} +const struct attribute_group pci_dev_acpi_attr_group = { + .attrs = acpi_attrs, + .is_visible = acpi_attr_is_visible, +}; +#endif |
