Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * dev-path-parser.c - EFI Device Path parser
0004  * Copyright (C) 2016 Lukas Wunner <lukas@wunner.de>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License (version 2) as
0008  * published by the Free Software Foundation.
0009  */
0010 
0011 #include <linux/acpi.h>
0012 #include <linux/efi.h>
0013 #include <linux/pci.h>
0014 
0015 static long __init parse_acpi_path(const struct efi_dev_path *node,
0016                    struct device *parent, struct device **child)
0017 {
0018     char hid[ACPI_ID_LEN], uid[11]; /* UINT_MAX + null byte */
0019     struct acpi_device *adev;
0020     struct device *phys_dev;
0021 
0022     if (node->header.length != 12)
0023         return -EINVAL;
0024 
0025     sprintf(hid, "%c%c%c%04X",
0026         'A' + ((node->acpi.hid >> 10) & 0x1f) - 1,
0027         'A' + ((node->acpi.hid >>  5) & 0x1f) - 1,
0028         'A' + ((node->acpi.hid >>  0) & 0x1f) - 1,
0029             node->acpi.hid >> 16);
0030     sprintf(uid, "%u", node->acpi.uid);
0031 
0032     for_each_acpi_dev_match(adev, hid, NULL, -1) {
0033         if (adev->pnp.unique_id && !strcmp(adev->pnp.unique_id, uid))
0034             break;
0035         if (!adev->pnp.unique_id && node->acpi.uid == 0)
0036             break;
0037     }
0038     if (!adev)
0039         return -ENODEV;
0040 
0041     phys_dev = acpi_get_first_physical_node(adev);
0042     if (phys_dev) {
0043         *child = get_device(phys_dev);
0044         acpi_dev_put(adev);
0045     } else
0046         *child = &adev->dev;
0047 
0048     return 0;
0049 }
0050 
0051 static int __init match_pci_dev(struct device *dev, void *data)
0052 {
0053     unsigned int devfn = *(unsigned int *)data;
0054 
0055     return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
0056 }
0057 
0058 static long __init parse_pci_path(const struct efi_dev_path *node,
0059                   struct device *parent, struct device **child)
0060 {
0061     unsigned int devfn;
0062 
0063     if (node->header.length != 6)
0064         return -EINVAL;
0065     if (!parent)
0066         return -EINVAL;
0067 
0068     devfn = PCI_DEVFN(node->pci.dev, node->pci.fn);
0069 
0070     *child = device_find_child(parent, &devfn, match_pci_dev);
0071     if (!*child)
0072         return -ENODEV;
0073 
0074     return 0;
0075 }
0076 
0077 /*
0078  * Insert parsers for further node types here.
0079  *
0080  * Each parser takes a pointer to the @node and to the @parent (will be NULL
0081  * for the first device path node). If a device corresponding to @node was
0082  * found below @parent, its reference count should be incremented and the
0083  * device returned in @child.
0084  *
0085  * The return value should be 0 on success or a negative int on failure.
0086  * The special return values 0x01 (EFI_DEV_END_INSTANCE) and 0xFF
0087  * (EFI_DEV_END_ENTIRE) signal the end of the device path, only
0088  * parse_end_path() is supposed to return this.
0089  *
0090  * Be sure to validate the node length and contents before commencing the
0091  * search for a device.
0092  */
0093 
0094 static long __init parse_end_path(const struct efi_dev_path *node,
0095                   struct device *parent, struct device **child)
0096 {
0097     if (node->header.length != 4)
0098         return -EINVAL;
0099     if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
0100         node->header.sub_type != EFI_DEV_END_ENTIRE)
0101         return -EINVAL;
0102     if (!parent)
0103         return -ENODEV;
0104 
0105     *child = get_device(parent);
0106     return node->header.sub_type;
0107 }
0108 
0109 /**
0110  * efi_get_device_by_path - find device by EFI Device Path
0111  * @node: EFI Device Path
0112  * @len: maximum length of EFI Device Path in bytes
0113  *
0114  * Parse a series of EFI Device Path nodes at @node and find the corresponding
0115  * device.  If the device was found, its reference count is incremented and a
0116  * pointer to it is returned.  The caller needs to drop the reference with
0117  * put_device() after use.  The @node pointer is updated to point to the
0118  * location immediately after the "End of Hardware Device Path" node.
0119  *
0120  * If another Device Path instance follows, @len is decremented by the number
0121  * of bytes consumed.  Otherwise @len is set to %0.
0122  *
0123  * If a Device Path node is malformed or its corresponding device is not found,
0124  * @node is updated to point to this offending node and an ERR_PTR is returned.
0125  *
0126  * If @len is initially %0, the function returns %NULL.  Thus, to iterate over
0127  * all instances in a path, the following idiom may be used:
0128  *
0129  *  while (!IS_ERR_OR_NULL(dev = efi_get_device_by_path(&node, &len))) {
0130  *      // do something with dev
0131  *      put_device(dev);
0132  *  }
0133  *  if (IS_ERR(dev))
0134  *      // report error
0135  *
0136  * Devices can only be found if they're already instantiated. Most buses
0137  * instantiate devices in the "subsys" initcall level, hence the earliest
0138  * initcall level in which this function should be called is "fs".
0139  *
0140  * Returns the device on success or
0141  *  %ERR_PTR(-ENODEV) if no device was found,
0142  *  %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
0143  *  %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
0144  */
0145 struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
0146                           size_t *len)
0147 {
0148     struct device *parent = NULL, *child;
0149     long ret = 0;
0150 
0151     if (!*len)
0152         return NULL;
0153 
0154     while (!ret) {
0155         if (*len < 4 || *len < (*node)->header.length)
0156             ret = -EINVAL;
0157         else if ((*node)->header.type       == EFI_DEV_ACPI &&
0158              (*node)->header.sub_type   == EFI_DEV_BASIC_ACPI)
0159             ret = parse_acpi_path(*node, parent, &child);
0160         else if ((*node)->header.type       == EFI_DEV_HW &&
0161              (*node)->header.sub_type   == EFI_DEV_PCI)
0162             ret = parse_pci_path(*node, parent, &child);
0163         else if (((*node)->header.type      == EFI_DEV_END_PATH ||
0164               (*node)->header.type      == EFI_DEV_END_PATH2))
0165             ret = parse_end_path(*node, parent, &child);
0166         else
0167             ret = -ENOTSUPP;
0168 
0169         put_device(parent);
0170         if (ret < 0)
0171             return ERR_PTR(ret);
0172 
0173         parent = child;
0174         *node  = (void *)*node + (*node)->header.length;
0175         *len  -= (*node)->header.length;
0176     }
0177 
0178     if (ret == EFI_DEV_END_ENTIRE)
0179         *len = 0;
0180 
0181     return child;
0182 }