linux/drivers/acpi/glue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Link physical devices with ACPI devices support
   4 *
   5 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
   6 * Copyright (c) 2005 Intel Corp.
   7 */
   8
   9#include <linux/acpi_iort.h>
  10#include <linux/export.h>
  11#include <linux/init.h>
  12#include <linux/list.h>
  13#include <linux/device.h>
  14#include <linux/slab.h>
  15#include <linux/rwsem.h>
  16#include <linux/acpi.h>
  17#include <linux/dma-mapping.h>
  18#include <linux/platform_device.h>
  19
  20#include "internal.h"
  21
  22#define ACPI_GLUE_DEBUG 0
  23#if ACPI_GLUE_DEBUG
  24#define DBG(fmt, ...)                                           \
  25        printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
  26#else
  27#define DBG(fmt, ...)                                           \
  28do {                                                            \
  29        if (0)                                                  \
  30                printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);   \
  31} while (0)
  32#endif
  33static LIST_HEAD(bus_type_list);
  34static DECLARE_RWSEM(bus_type_sem);
  35
  36#define PHYSICAL_NODE_STRING "physical_node"
  37#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
  38
  39int register_acpi_bus_type(struct acpi_bus_type *type)
  40{
  41        if (acpi_disabled)
  42                return -ENODEV;
  43        if (type && type->match && type->find_companion) {
  44                down_write(&bus_type_sem);
  45                list_add_tail(&type->list, &bus_type_list);
  46                up_write(&bus_type_sem);
  47                printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
  48                return 0;
  49        }
  50        return -ENODEV;
  51}
  52EXPORT_SYMBOL_GPL(register_acpi_bus_type);
  53
  54int unregister_acpi_bus_type(struct acpi_bus_type *type)
  55{
  56        if (acpi_disabled)
  57                return 0;
  58        if (type) {
  59                down_write(&bus_type_sem);
  60                list_del_init(&type->list);
  61                up_write(&bus_type_sem);
  62                printk(KERN_INFO PREFIX "bus type %s unregistered\n",
  63                       type->name);
  64                return 0;
  65        }
  66        return -ENODEV;
  67}
  68EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
  69
  70static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
  71{
  72        struct acpi_bus_type *tmp, *ret = NULL;
  73
  74        down_read(&bus_type_sem);
  75        list_for_each_entry(tmp, &bus_type_list, list) {
  76                if (tmp->match(dev)) {
  77                        ret = tmp;
  78                        break;
  79                }
  80        }
  81        up_read(&bus_type_sem);
  82        return ret;
  83}
  84
  85#define FIND_CHILD_MIN_SCORE    1
  86#define FIND_CHILD_MAX_SCORE    2
  87
  88static int find_child_checks(struct acpi_device *adev, bool check_children)
  89{
  90        bool sta_present = true;
  91        unsigned long long sta;
  92        acpi_status status;
  93
  94        status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
  95        if (status == AE_NOT_FOUND)
  96                sta_present = false;
  97        else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
  98                return -ENODEV;
  99
 100        if (check_children && list_empty(&adev->children))
 101                return -ENODEV;
 102
 103        /*
 104         * If the device has a _HID returning a valid ACPI/PNP device ID, it is
 105         * better to make it look less attractive here, so that the other device
 106         * with the same _ADR value (that may not have a valid device ID) can be
 107         * matched going forward.  [This means a second spec violation in a row,
 108         * so whatever we do here is best effort anyway.]
 109         */
 110        return sta_present && !adev->pnp.type.platform_id ?
 111                        FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 112}
 113
 114struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
 115                                           u64 address, bool check_children)
 116{
 117        struct acpi_device *adev, *ret = NULL;
 118        int ret_score = 0;
 119
 120        if (!parent)
 121                return NULL;
 122
 123        list_for_each_entry(adev, &parent->children, node) {
 124                unsigned long long addr;
 125                acpi_status status;
 126                int score;
 127
 128                status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
 129                                               NULL, &addr);
 130                if (ACPI_FAILURE(status) || addr != address)
 131                        continue;
 132
 133                if (!ret) {
 134                        /* This is the first matching object.  Save it. */
 135                        ret = adev;
 136                        continue;
 137                }
 138                /*
 139                 * There is more than one matching device object with the same
 140                 * _ADR value.  That really is unexpected, so we are kind of
 141                 * beyond the scope of the spec here.  We have to choose which
 142                 * one to return, though.
 143                 *
 144                 * First, check if the previously found object is good enough
 145                 * and return it if so.  Second, do the same for the object that
 146                 * we've just found.
 147                 */
 148                if (!ret_score) {
 149                        ret_score = find_child_checks(ret, check_children);
 150                        if (ret_score == FIND_CHILD_MAX_SCORE)
 151                                return ret;
 152                }
 153                score = find_child_checks(adev, check_children);
 154                if (score == FIND_CHILD_MAX_SCORE) {
 155                        return adev;
 156                } else if (score > ret_score) {
 157                        ret = adev;
 158                        ret_score = score;
 159                }
 160        }
 161        return ret;
 162}
 163EXPORT_SYMBOL_GPL(acpi_find_child_device);
 164
 165static void acpi_physnode_link_name(char *buf, unsigned int node_id)
 166{
 167        if (node_id > 0)
 168                snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
 169                         PHYSICAL_NODE_STRING "%u", node_id);
 170        else
 171                strcpy(buf, PHYSICAL_NODE_STRING);
 172}
 173
 174int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 175{
 176        struct acpi_device_physical_node *physical_node, *pn;
 177        char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
 178        struct list_head *physnode_list;
 179        unsigned int node_id;
 180        int retval = -EINVAL;
 181
 182        if (has_acpi_companion(dev)) {
 183                if (acpi_dev) {
 184                        dev_warn(dev, "ACPI companion already set\n");
 185                        return -EINVAL;
 186                } else {
 187                        acpi_dev = ACPI_COMPANION(dev);
 188                }
 189        }
 190        if (!acpi_dev)
 191                return -EINVAL;
 192
 193        get_device(&acpi_dev->dev);
 194        get_device(dev);
 195        physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
 196        if (!physical_node) {
 197                retval = -ENOMEM;
 198                goto err;
 199        }
 200
 201        mutex_lock(&acpi_dev->physical_node_lock);
 202
 203        /*
 204         * Keep the list sorted by node_id so that the IDs of removed nodes can
 205         * be recycled easily.
 206         */
 207        physnode_list = &acpi_dev->physical_node_list;
 208        node_id = 0;
 209        list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
 210                /* Sanity check. */
 211                if (pn->dev == dev) {
 212                        mutex_unlock(&acpi_dev->physical_node_lock);
 213
 214                        dev_warn(dev, "Already associated with ACPI node\n");
 215                        kfree(physical_node);
 216                        if (ACPI_COMPANION(dev) != acpi_dev)
 217                                goto err;
 218
 219                        put_device(dev);
 220                        put_device(&acpi_dev->dev);
 221                        return 0;
 222                }
 223                if (pn->node_id == node_id) {
 224                        physnode_list = &pn->node;
 225                        node_id++;
 226                }
 227        }
 228
 229        physical_node->node_id = node_id;
 230        physical_node->dev = dev;
 231        list_add(&physical_node->node, physnode_list);
 232        acpi_dev->physical_node_count++;
 233
 234        if (!has_acpi_companion(dev))
 235                ACPI_COMPANION_SET(dev, acpi_dev);
 236
 237        acpi_physnode_link_name(physical_node_name, node_id);
 238        retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
 239                                   physical_node_name);
 240        if (retval)
 241                dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
 242                        physical_node_name, retval);
 243
 244        retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
 245                                   "firmware_node");
 246        if (retval)
 247                dev_err(dev, "Failed to create link firmware_node (%d)\n",
 248                        retval);
 249
 250        mutex_unlock(&acpi_dev->physical_node_lock);
 251
 252        if (acpi_dev->wakeup.flags.valid)
 253                device_set_wakeup_capable(dev, true);
 254
 255        return 0;
 256
 257 err:
 258        ACPI_COMPANION_SET(dev, NULL);
 259        put_device(dev);
 260        put_device(&acpi_dev->dev);
 261        return retval;
 262}
 263EXPORT_SYMBOL_GPL(acpi_bind_one);
 264
 265int acpi_unbind_one(struct device *dev)
 266{
 267        struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
 268        struct acpi_device_physical_node *entry;
 269
 270        if (!acpi_dev)
 271                return 0;
 272
 273        mutex_lock(&acpi_dev->physical_node_lock);
 274
 275        list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
 276                if (entry->dev == dev) {
 277                        char physnode_name[PHYSICAL_NODE_NAME_SIZE];
 278
 279                        list_del(&entry->node);
 280                        acpi_dev->physical_node_count--;
 281
 282                        acpi_physnode_link_name(physnode_name, entry->node_id);
 283                        sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
 284                        sysfs_remove_link(&dev->kobj, "firmware_node");
 285                        ACPI_COMPANION_SET(dev, NULL);
 286                        /* Drop references taken by acpi_bind_one(). */
 287                        put_device(dev);
 288                        put_device(&acpi_dev->dev);
 289                        kfree(entry);
 290                        break;
 291                }
 292
 293        mutex_unlock(&acpi_dev->physical_node_lock);
 294        return 0;
 295}
 296EXPORT_SYMBOL_GPL(acpi_unbind_one);
 297
 298static int acpi_device_notify(struct device *dev)
 299{
 300        struct acpi_bus_type *type = acpi_get_bus_type(dev);
 301        struct acpi_device *adev;
 302        int ret;
 303
 304        ret = acpi_bind_one(dev, NULL);
 305        if (ret && type) {
 306                struct acpi_device *adev;
 307
 308                adev = type->find_companion(dev);
 309                if (!adev) {
 310                        DBG("Unable to get handle for %s\n", dev_name(dev));
 311                        ret = -ENODEV;
 312                        goto out;
 313                }
 314                ret = acpi_bind_one(dev, adev);
 315                if (ret)
 316                        goto out;
 317        }
 318        adev = ACPI_COMPANION(dev);
 319        if (!adev)
 320                goto out;
 321
 322        if (dev_is_platform(dev))
 323                acpi_configure_pmsi_domain(dev);
 324
 325        if (type && type->setup)
 326                type->setup(dev);
 327        else if (adev->handler && adev->handler->bind)
 328                adev->handler->bind(dev);
 329
 330 out:
 331#if ACPI_GLUE_DEBUG
 332        if (!ret) {
 333                struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 334
 335                acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
 336                DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
 337                kfree(buffer.pointer);
 338        } else
 339                DBG("Device %s -> No ACPI support\n", dev_name(dev));
 340#endif
 341
 342        return ret;
 343}
 344
 345static int acpi_device_notify_remove(struct device *dev)
 346{
 347        struct acpi_device *adev = ACPI_COMPANION(dev);
 348        struct acpi_bus_type *type;
 349
 350        if (!adev)
 351                return 0;
 352
 353        type = acpi_get_bus_type(dev);
 354        if (type && type->cleanup)
 355                type->cleanup(dev);
 356        else if (adev->handler && adev->handler->unbind)
 357                adev->handler->unbind(dev);
 358
 359        acpi_unbind_one(dev);
 360        return 0;
 361}
 362
 363int acpi_platform_notify(struct device *dev, enum kobject_action action)
 364{
 365        switch (action) {
 366        case KOBJ_ADD:
 367                acpi_device_notify(dev);
 368                break;
 369        case KOBJ_REMOVE:
 370                acpi_device_notify_remove(dev);
 371                break;
 372        default:
 373                break;
 374        }
 375        return 0;
 376}
 377