415 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Link physical devices with ACPI devices support4 *5 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>6 * Copyright (c) 2005 Intel Corp.7 */8 9#define pr_fmt(fmt) "ACPI: " fmt10 11#include <linux/acpi_iort.h>12#include <linux/export.h>13#include <linux/init.h>14#include <linux/list.h>15#include <linux/device.h>16#include <linux/slab.h>17#include <linux/rwsem.h>18#include <linux/acpi.h>19#include <linux/dma-mapping.h>20#include <linux/pci.h>21#include <linux/pci-acpi.h>22#include <linux/platform_device.h>23 24#include "internal.h"25 26static LIST_HEAD(bus_type_list);27static DECLARE_RWSEM(bus_type_sem);28 29#define PHYSICAL_NODE_STRING "physical_node"30#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)31 32int register_acpi_bus_type(struct acpi_bus_type *type)33{34 if (acpi_disabled)35 return -ENODEV;36 if (type && type->match && type->find_companion) {37 down_write(&bus_type_sem);38 list_add_tail(&type->list, &bus_type_list);39 up_write(&bus_type_sem);40 pr_info("bus type %s registered\n", type->name);41 return 0;42 }43 return -ENODEV;44}45EXPORT_SYMBOL_GPL(register_acpi_bus_type);46 47int unregister_acpi_bus_type(struct acpi_bus_type *type)48{49 if (acpi_disabled)50 return 0;51 if (type) {52 down_write(&bus_type_sem);53 list_del_init(&type->list);54 up_write(&bus_type_sem);55 pr_info("bus type %s unregistered\n", type->name);56 return 0;57 }58 return -ENODEV;59}60EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);61 62static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)63{64 struct acpi_bus_type *tmp, *ret = NULL;65 66 down_read(&bus_type_sem);67 list_for_each_entry(tmp, &bus_type_list, list) {68 if (tmp->match(dev)) {69 ret = tmp;70 break;71 }72 }73 up_read(&bus_type_sem);74 return ret;75}76 77#define FIND_CHILD_MIN_SCORE 178#define FIND_CHILD_MID_SCORE 279#define FIND_CHILD_MAX_SCORE 380 81static int match_any(struct acpi_device *adev, void *not_used)82{83 return 1;84}85 86static bool acpi_dev_has_children(struct acpi_device *adev)87{88 return acpi_dev_for_each_child(adev, match_any, NULL) > 0;89}90 91static int find_child_checks(struct acpi_device *adev, bool check_children)92{93 unsigned long long sta;94 acpi_status status;95 96 if (check_children && !acpi_dev_has_children(adev))97 return -ENODEV;98 99 status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);100 if (status == AE_NOT_FOUND) {101 /*102 * Special case: backlight device objects without _STA are103 * preferred to other objects with the same _ADR value, because104 * it is more likely that they are actually useful.105 */106 if (adev->pnp.type.backlight)107 return FIND_CHILD_MID_SCORE;108 109 return FIND_CHILD_MIN_SCORE;110 }111 112 if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))113 return -ENODEV;114 115 /*116 * If the device has a _HID returning a valid ACPI/PNP device ID, it is117 * better to make it look less attractive here, so that the other device118 * with the same _ADR value (that may not have a valid device ID) can be119 * matched going forward. [This means a second spec violation in a row,120 * so whatever we do here is best effort anyway.]121 */122 if (adev->pnp.type.platform_id)123 return FIND_CHILD_MIN_SCORE;124 125 return FIND_CHILD_MAX_SCORE;126}127 128struct find_child_walk_data {129 struct acpi_device *adev;130 u64 address;131 int score;132 bool check_sta;133 bool check_children;134};135 136static int check_one_child(struct acpi_device *adev, void *data)137{138 struct find_child_walk_data *wd = data;139 int score;140 141 if (!adev->pnp.type.bus_address || acpi_device_adr(adev) != wd->address)142 return 0;143 144 if (!wd->adev) {145 /*146 * This is the first matching object, so save it. If it is not147 * necessary to look for any other matching objects, stop the148 * search.149 */150 wd->adev = adev;151 return !(wd->check_sta || wd->check_children);152 }153 154 /*155 * There is more than one matching device object with the same _ADR156 * value. That really is unexpected, so we are kind of beyond the scope157 * of the spec here. We have to choose which one to return, though.158 *159 * First, get the score for the previously found object and terminate160 * the walk if it is maximum.161 */162 if (!wd->score) {163 score = find_child_checks(wd->adev, wd->check_children);164 if (score == FIND_CHILD_MAX_SCORE)165 return 1;166 167 wd->score = score;168 }169 /*170 * Second, if the object that has just been found has a better score,171 * replace the previously found one with it and terminate the walk if172 * the new score is maximum.173 */174 score = find_child_checks(adev, wd->check_children);175 if (score > wd->score) {176 wd->adev = adev;177 if (score == FIND_CHILD_MAX_SCORE)178 return 1;179 180 wd->score = score;181 }182 183 /* Continue, because there may be better matches. */184 return 0;185}186 187static struct acpi_device *acpi_find_child(struct acpi_device *parent,188 u64 address, bool check_children,189 bool check_sta)190{191 struct find_child_walk_data wd = {192 .address = address,193 .check_children = check_children,194 .check_sta = check_sta,195 .adev = NULL,196 .score = 0,197 };198 199 if (parent)200 acpi_dev_for_each_child(parent, check_one_child, &wd);201 202 return wd.adev;203}204 205struct acpi_device *acpi_find_child_device(struct acpi_device *parent,206 u64 address, bool check_children)207{208 return acpi_find_child(parent, address, check_children, true);209}210EXPORT_SYMBOL_GPL(acpi_find_child_device);211 212struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev,213 acpi_bus_address adr)214{215 return acpi_find_child(adev, adr, false, false);216}217EXPORT_SYMBOL_GPL(acpi_find_child_by_adr);218 219static void acpi_physnode_link_name(char *buf, unsigned int node_id)220{221 if (node_id > 0)222 snprintf(buf, PHYSICAL_NODE_NAME_SIZE,223 PHYSICAL_NODE_STRING "%u", node_id);224 else225 strcpy(buf, PHYSICAL_NODE_STRING);226}227 228int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)229{230 struct acpi_device_physical_node *physical_node, *pn;231 char physical_node_name[PHYSICAL_NODE_NAME_SIZE];232 struct list_head *physnode_list;233 unsigned int node_id;234 int retval = -EINVAL;235 236 if (has_acpi_companion(dev)) {237 if (acpi_dev) {238 dev_warn(dev, "ACPI companion already set\n");239 return -EINVAL;240 } else {241 acpi_dev = ACPI_COMPANION(dev);242 }243 }244 if (!acpi_dev)245 return -EINVAL;246 247 acpi_dev_get(acpi_dev);248 get_device(dev);249 physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);250 if (!physical_node) {251 retval = -ENOMEM;252 goto err;253 }254 255 mutex_lock(&acpi_dev->physical_node_lock);256 257 /*258 * Keep the list sorted by node_id so that the IDs of removed nodes can259 * be recycled easily.260 */261 physnode_list = &acpi_dev->physical_node_list;262 node_id = 0;263 list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {264 /* Sanity check. */265 if (pn->dev == dev) {266 mutex_unlock(&acpi_dev->physical_node_lock);267 268 dev_warn(dev, "Already associated with ACPI node\n");269 kfree(physical_node);270 if (ACPI_COMPANION(dev) != acpi_dev)271 goto err;272 273 put_device(dev);274 acpi_dev_put(acpi_dev);275 return 0;276 }277 if (pn->node_id == node_id) {278 physnode_list = &pn->node;279 node_id++;280 }281 }282 283 physical_node->node_id = node_id;284 physical_node->dev = dev;285 list_add(&physical_node->node, physnode_list);286 acpi_dev->physical_node_count++;287 288 if (!has_acpi_companion(dev))289 ACPI_COMPANION_SET(dev, acpi_dev);290 291 acpi_physnode_link_name(physical_node_name, node_id);292 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,293 physical_node_name);294 if (retval)295 dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",296 physical_node_name, retval);297 298 retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,299 "firmware_node");300 if (retval)301 dev_err(dev, "Failed to create link firmware_node (%d)\n",302 retval);303 304 mutex_unlock(&acpi_dev->physical_node_lock);305 306 if (acpi_dev->wakeup.flags.valid)307 device_set_wakeup_capable(dev, true);308 309 return 0;310 311 err:312 ACPI_COMPANION_SET(dev, NULL);313 put_device(dev);314 acpi_dev_put(acpi_dev);315 return retval;316}317EXPORT_SYMBOL_GPL(acpi_bind_one);318 319int acpi_unbind_one(struct device *dev)320{321 struct acpi_device *acpi_dev = ACPI_COMPANION(dev);322 struct acpi_device_physical_node *entry;323 324 if (!acpi_dev)325 return 0;326 327 mutex_lock(&acpi_dev->physical_node_lock);328 329 list_for_each_entry(entry, &acpi_dev->physical_node_list, node)330 if (entry->dev == dev) {331 char physnode_name[PHYSICAL_NODE_NAME_SIZE];332 333 list_del(&entry->node);334 acpi_dev->physical_node_count--;335 336 acpi_physnode_link_name(physnode_name, entry->node_id);337 sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);338 sysfs_remove_link(&dev->kobj, "firmware_node");339 ACPI_COMPANION_SET(dev, NULL);340 /* Drop references taken by acpi_bind_one(). */341 put_device(dev);342 acpi_dev_put(acpi_dev);343 kfree(entry);344 break;345 }346 347 mutex_unlock(&acpi_dev->physical_node_lock);348 return 0;349}350EXPORT_SYMBOL_GPL(acpi_unbind_one);351 352void acpi_device_notify(struct device *dev)353{354 struct acpi_device *adev;355 int ret;356 357 ret = acpi_bind_one(dev, NULL);358 if (ret) {359 struct acpi_bus_type *type = acpi_get_bus_type(dev);360 361 if (!type)362 goto err;363 364 adev = type->find_companion(dev);365 if (!adev) {366 dev_dbg(dev, "ACPI companion not found\n");367 goto err;368 }369 ret = acpi_bind_one(dev, adev);370 if (ret)371 goto err;372 373 if (type->setup) {374 type->setup(dev);375 goto done;376 }377 } else {378 adev = ACPI_COMPANION(dev);379 380 if (dev_is_pci(dev)) {381 pci_acpi_setup(dev, adev);382 goto done;383 } else if (dev_is_platform(dev)) {384 acpi_configure_pmsi_domain(dev);385 }386 }387 388 if (adev->handler && adev->handler->bind)389 adev->handler->bind(dev);390 391done:392 acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n",393 dev_name(dev));394 395 return;396 397err:398 dev_dbg(dev, "No ACPI support\n");399}400 401void acpi_device_notify_remove(struct device *dev)402{403 struct acpi_device *adev = ACPI_COMPANION(dev);404 405 if (!adev)406 return;407 408 if (dev_is_pci(dev))409 pci_acpi_cleanup(dev, adev);410 else if (adev->handler && adev->handler->unbind)411 adev->handler->unbind(dev);412 413 acpi_unbind_one(dev);414}415