glue.c (8321B)
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#define pr_fmt(fmt) "ACPI: " fmt 10 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 1 78#define FIND_CHILD_MAX_SCORE 2 79 80static int find_child_checks(struct acpi_device *adev, bool check_children) 81{ 82 unsigned long long sta; 83 acpi_status status; 84 85 if (check_children && list_empty(&adev->children)) 86 return -ENODEV; 87 88 status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); 89 if (status == AE_NOT_FOUND) 90 return FIND_CHILD_MIN_SCORE; 91 92 if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) 93 return -ENODEV; 94 95 /* 96 * If the device has a _HID returning a valid ACPI/PNP device ID, it is 97 * better to make it look less attractive here, so that the other device 98 * with the same _ADR value (that may not have a valid device ID) can be 99 * matched going forward. [This means a second spec violation in a row, 100 * so whatever we do here is best effort anyway.] 101 */ 102 if (adev->pnp.type.platform_id) 103 return FIND_CHILD_MIN_SCORE; 104 105 return FIND_CHILD_MAX_SCORE; 106} 107 108struct acpi_device *acpi_find_child_device(struct acpi_device *parent, 109 u64 address, bool check_children) 110{ 111 struct acpi_device *adev, *ret = NULL; 112 int ret_score = 0; 113 114 if (!parent) 115 return NULL; 116 117 list_for_each_entry(adev, &parent->children, node) { 118 acpi_bus_address addr = acpi_device_adr(adev); 119 int score; 120 121 if (!adev->pnp.type.bus_address || addr != address) 122 continue; 123 124 if (!ret) { 125 /* This is the first matching object. Save it. */ 126 ret = adev; 127 continue; 128 } 129 /* 130 * There is more than one matching device object with the same 131 * _ADR value. That really is unexpected, so we are kind of 132 * beyond the scope of the spec here. We have to choose which 133 * one to return, though. 134 * 135 * First, check if the previously found object is good enough 136 * and return it if so. Second, do the same for the object that 137 * we've just found. 138 */ 139 if (!ret_score) { 140 ret_score = find_child_checks(ret, check_children); 141 if (ret_score == FIND_CHILD_MAX_SCORE) 142 return ret; 143 } 144 score = find_child_checks(adev, check_children); 145 if (score == FIND_CHILD_MAX_SCORE) { 146 return adev; 147 } else if (score > ret_score) { 148 ret = adev; 149 ret_score = score; 150 } 151 } 152 return ret; 153} 154EXPORT_SYMBOL_GPL(acpi_find_child_device); 155 156static void acpi_physnode_link_name(char *buf, unsigned int node_id) 157{ 158 if (node_id > 0) 159 snprintf(buf, PHYSICAL_NODE_NAME_SIZE, 160 PHYSICAL_NODE_STRING "%u", node_id); 161 else 162 strcpy(buf, PHYSICAL_NODE_STRING); 163} 164 165int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) 166{ 167 struct acpi_device_physical_node *physical_node, *pn; 168 char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; 169 struct list_head *physnode_list; 170 unsigned int node_id; 171 int retval = -EINVAL; 172 173 if (has_acpi_companion(dev)) { 174 if (acpi_dev) { 175 dev_warn(dev, "ACPI companion already set\n"); 176 return -EINVAL; 177 } else { 178 acpi_dev = ACPI_COMPANION(dev); 179 } 180 } 181 if (!acpi_dev) 182 return -EINVAL; 183 184 acpi_dev_get(acpi_dev); 185 get_device(dev); 186 physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); 187 if (!physical_node) { 188 retval = -ENOMEM; 189 goto err; 190 } 191 192 mutex_lock(&acpi_dev->physical_node_lock); 193 194 /* 195 * Keep the list sorted by node_id so that the IDs of removed nodes can 196 * be recycled easily. 197 */ 198 physnode_list = &acpi_dev->physical_node_list; 199 node_id = 0; 200 list_for_each_entry(pn, &acpi_dev->physical_node_list, node) { 201 /* Sanity check. */ 202 if (pn->dev == dev) { 203 mutex_unlock(&acpi_dev->physical_node_lock); 204 205 dev_warn(dev, "Already associated with ACPI node\n"); 206 kfree(physical_node); 207 if (ACPI_COMPANION(dev) != acpi_dev) 208 goto err; 209 210 put_device(dev); 211 acpi_dev_put(acpi_dev); 212 return 0; 213 } 214 if (pn->node_id == node_id) { 215 physnode_list = &pn->node; 216 node_id++; 217 } 218 } 219 220 physical_node->node_id = node_id; 221 physical_node->dev = dev; 222 list_add(&physical_node->node, physnode_list); 223 acpi_dev->physical_node_count++; 224 225 if (!has_acpi_companion(dev)) 226 ACPI_COMPANION_SET(dev, acpi_dev); 227 228 acpi_physnode_link_name(physical_node_name, node_id); 229 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, 230 physical_node_name); 231 if (retval) 232 dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n", 233 physical_node_name, retval); 234 235 retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj, 236 "firmware_node"); 237 if (retval) 238 dev_err(dev, "Failed to create link firmware_node (%d)\n", 239 retval); 240 241 mutex_unlock(&acpi_dev->physical_node_lock); 242 243 if (acpi_dev->wakeup.flags.valid) 244 device_set_wakeup_capable(dev, true); 245 246 return 0; 247 248 err: 249 ACPI_COMPANION_SET(dev, NULL); 250 put_device(dev); 251 acpi_dev_put(acpi_dev); 252 return retval; 253} 254EXPORT_SYMBOL_GPL(acpi_bind_one); 255 256int acpi_unbind_one(struct device *dev) 257{ 258 struct acpi_device *acpi_dev = ACPI_COMPANION(dev); 259 struct acpi_device_physical_node *entry; 260 261 if (!acpi_dev) 262 return 0; 263 264 mutex_lock(&acpi_dev->physical_node_lock); 265 266 list_for_each_entry(entry, &acpi_dev->physical_node_list, node) 267 if (entry->dev == dev) { 268 char physnode_name[PHYSICAL_NODE_NAME_SIZE]; 269 270 list_del(&entry->node); 271 acpi_dev->physical_node_count--; 272 273 acpi_physnode_link_name(physnode_name, entry->node_id); 274 sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name); 275 sysfs_remove_link(&dev->kobj, "firmware_node"); 276 ACPI_COMPANION_SET(dev, NULL); 277 /* Drop references taken by acpi_bind_one(). */ 278 put_device(dev); 279 acpi_dev_put(acpi_dev); 280 kfree(entry); 281 break; 282 } 283 284 mutex_unlock(&acpi_dev->physical_node_lock); 285 return 0; 286} 287EXPORT_SYMBOL_GPL(acpi_unbind_one); 288 289void acpi_device_notify(struct device *dev) 290{ 291 struct acpi_device *adev; 292 int ret; 293 294 ret = acpi_bind_one(dev, NULL); 295 if (ret) { 296 struct acpi_bus_type *type = acpi_get_bus_type(dev); 297 298 if (!type) 299 goto err; 300 301 adev = type->find_companion(dev); 302 if (!adev) { 303 dev_dbg(dev, "ACPI companion not found\n"); 304 goto err; 305 } 306 ret = acpi_bind_one(dev, adev); 307 if (ret) 308 goto err; 309 310 if (type->setup) { 311 type->setup(dev); 312 goto done; 313 } 314 } else { 315 adev = ACPI_COMPANION(dev); 316 317 if (dev_is_pci(dev)) { 318 pci_acpi_setup(dev, adev); 319 goto done; 320 } else if (dev_is_platform(dev)) { 321 acpi_configure_pmsi_domain(dev); 322 } 323 } 324 325 if (adev->handler && adev->handler->bind) 326 adev->handler->bind(dev); 327 328done: 329 acpi_handle_debug(ACPI_HANDLE(dev), "Bound to device %s\n", 330 dev_name(dev)); 331 332 return; 333 334err: 335 dev_dbg(dev, "No ACPI support\n"); 336} 337 338void acpi_device_notify_remove(struct device *dev) 339{ 340 struct acpi_device *adev = ACPI_COMPANION(dev); 341 342 if (!adev) 343 return; 344 345 if (dev_is_pci(dev)) 346 pci_acpi_cleanup(dev, adev); 347 else if (adev->handler && adev->handler->unbind) 348 adev->handler->unbind(dev); 349 350 acpi_unbind_one(dev); 351}