cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}