root/drivers/acpi/glue.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. register_acpi_bus_type
  2. unregister_acpi_bus_type
  3. acpi_get_bus_type
  4. find_child_checks
  5. acpi_find_child_device
  6. acpi_physnode_link_name
  7. acpi_bind_one
  8. acpi_unbind_one
  9. acpi_device_notify
  10. acpi_device_notify_remove
  11. acpi_platform_notify

   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, ...)                                           \
  28 do {                                                            \
  29         if (0)                                                  \
  30                 printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);   \
  31 } while (0)
  32 #endif
  33 static LIST_HEAD(bus_type_list);
  34 static 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 
  39 int 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 }
  52 EXPORT_SYMBOL_GPL(register_acpi_bus_type);
  53 
  54 int 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 }
  68 EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
  69 
  70 static 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 
  88 static 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 
 114 struct 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 }
 163 EXPORT_SYMBOL_GPL(acpi_find_child_device);
 164 
 165 static 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 
 174 int 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 }
 263 EXPORT_SYMBOL_GPL(acpi_bind_one);
 264 
 265 int 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 }
 296 EXPORT_SYMBOL_GPL(acpi_unbind_one);
 297 
 298 static 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 
 345 static 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 
 363 int 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 }

/* [<][>][^][v][top][bottom][index][help] */