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

core.c (7559B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * pnpacpi -- PnP ACPI driver
      4 *
      5 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
      6 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
      7 */
      8
      9#include <linux/export.h>
     10#include <linux/acpi.h>
     11#include <linux/pnp.h>
     12#include <linux/slab.h>
     13#include <linux/mod_devicetable.h>
     14
     15#include "../base.h"
     16#include "pnpacpi.h"
     17
     18static int num;
     19
     20/*
     21 * Compatible Device IDs
     22 */
     23#define TEST_HEX(c) \
     24	if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
     25		return 0
     26#define TEST_ALPHA(c) \
     27	if (!('A' <= (c) && (c) <= 'Z')) \
     28		return 0
     29static int __init ispnpidacpi(const char *id)
     30{
     31	TEST_ALPHA(id[0]);
     32	TEST_ALPHA(id[1]);
     33	TEST_ALPHA(id[2]);
     34	TEST_HEX(id[3]);
     35	TEST_HEX(id[4]);
     36	TEST_HEX(id[5]);
     37	TEST_HEX(id[6]);
     38	if (id[7] != '\0')
     39		return 0;
     40	return 1;
     41}
     42
     43static int pnpacpi_get_resources(struct pnp_dev *dev)
     44{
     45	pnp_dbg(&dev->dev, "get resources\n");
     46	return pnpacpi_parse_allocated_resource(dev);
     47}
     48
     49static int pnpacpi_set_resources(struct pnp_dev *dev)
     50{
     51	struct acpi_device *acpi_dev;
     52	acpi_handle handle;
     53	int ret = 0;
     54
     55	pnp_dbg(&dev->dev, "set resources\n");
     56
     57	acpi_dev = ACPI_COMPANION(&dev->dev);
     58	if (!acpi_dev) {
     59		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
     60		return -ENODEV;
     61	}
     62
     63	if (WARN_ON_ONCE(acpi_dev != dev->data))
     64		dev->data = acpi_dev;
     65
     66	handle = acpi_dev->handle;
     67	if (acpi_has_method(handle, METHOD_NAME__SRS)) {
     68		struct acpi_buffer buffer;
     69
     70		ret = pnpacpi_build_resource_template(dev, &buffer);
     71		if (ret)
     72			return ret;
     73
     74		ret = pnpacpi_encode_resources(dev, &buffer);
     75		if (!ret) {
     76			acpi_status status;
     77
     78			status = acpi_set_current_resources(handle, &buffer);
     79			if (ACPI_FAILURE(status))
     80				ret = -EIO;
     81		}
     82		kfree(buffer.pointer);
     83	}
     84	if (!ret && acpi_device_power_manageable(acpi_dev))
     85		ret = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
     86
     87	return ret;
     88}
     89
     90static int pnpacpi_disable_resources(struct pnp_dev *dev)
     91{
     92	struct acpi_device *acpi_dev;
     93	acpi_status status;
     94
     95	dev_dbg(&dev->dev, "disable resources\n");
     96
     97	acpi_dev = ACPI_COMPANION(&dev->dev);
     98	if (!acpi_dev) {
     99		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
    100		return 0;
    101	}
    102
    103	/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
    104	if (acpi_device_power_manageable(acpi_dev))
    105		acpi_device_set_power(acpi_dev, ACPI_STATE_D3_COLD);
    106
    107	/* continue even if acpi_device_set_power() fails */
    108	status = acpi_evaluate_object(acpi_dev->handle, "_DIS", NULL, NULL);
    109	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
    110		return -ENODEV;
    111
    112	return 0;
    113}
    114
    115#ifdef CONFIG_ACPI_SLEEP
    116static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
    117{
    118	struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
    119
    120	if (!acpi_dev) {
    121		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
    122		return false;
    123	}
    124
    125	return acpi_bus_can_wakeup(acpi_dev->handle);
    126}
    127
    128static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
    129{
    130	struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
    131	int error = 0;
    132
    133	if (!acpi_dev) {
    134		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
    135		return 0;
    136	}
    137
    138	if (device_can_wakeup(&dev->dev)) {
    139		error = acpi_pm_set_device_wakeup(&dev->dev,
    140					      device_may_wakeup(&dev->dev));
    141		if (error)
    142			return error;
    143	}
    144
    145	if (acpi_device_power_manageable(acpi_dev)) {
    146		int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
    147							ACPI_STATE_D3_COLD);
    148		if (power_state < 0)
    149			power_state = (state.event == PM_EVENT_ON) ?
    150					ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
    151
    152		/*
    153		 * acpi_device_set_power() can fail (keyboard port can't be
    154		 * powered-down?), and in any case, our return value is ignored
    155		 * by pnp_bus_suspend().  Hence we don't revert the wakeup
    156		 * setting if the set_power fails.
    157		 */
    158		error = acpi_device_set_power(acpi_dev, power_state);
    159	}
    160
    161	return error;
    162}
    163
    164static int pnpacpi_resume(struct pnp_dev *dev)
    165{
    166	struct acpi_device *acpi_dev = ACPI_COMPANION(&dev->dev);
    167	int error = 0;
    168
    169	if (!acpi_dev) {
    170		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
    171		return -ENODEV;
    172	}
    173
    174	if (device_may_wakeup(&dev->dev))
    175		acpi_pm_set_device_wakeup(&dev->dev, false);
    176
    177	if (acpi_device_power_manageable(acpi_dev))
    178		error = acpi_device_set_power(acpi_dev, ACPI_STATE_D0);
    179
    180	return error;
    181}
    182#endif
    183
    184struct pnp_protocol pnpacpi_protocol = {
    185	.name	 = "Plug and Play ACPI",
    186	.get	 = pnpacpi_get_resources,
    187	.set	 = pnpacpi_set_resources,
    188	.disable = pnpacpi_disable_resources,
    189#ifdef CONFIG_ACPI_SLEEP
    190	.can_wakeup = pnpacpi_can_wakeup,
    191	.suspend = pnpacpi_suspend,
    192	.resume = pnpacpi_resume,
    193#endif
    194};
    195EXPORT_SYMBOL(pnpacpi_protocol);
    196
    197static const char *__init pnpacpi_get_id(struct acpi_device *device)
    198{
    199	struct acpi_hardware_id *id;
    200
    201	list_for_each_entry(id, &device->pnp.ids, list) {
    202		if (ispnpidacpi(id->id))
    203			return id->id;
    204	}
    205
    206	return NULL;
    207}
    208
    209static int __init pnpacpi_add_device(struct acpi_device *device)
    210{
    211	struct pnp_dev *dev;
    212	const char *pnpid;
    213	struct acpi_hardware_id *id;
    214	int error;
    215
    216	/* Skip devices that are already bound */
    217	if (device->physical_node_count)
    218		return 0;
    219
    220	/*
    221	 * If a PnPacpi device is not present , the device
    222	 * driver should not be loaded.
    223	 */
    224	if (!acpi_has_method(device->handle, "_CRS"))
    225		return 0;
    226
    227	pnpid = pnpacpi_get_id(device);
    228	if (!pnpid)
    229		return 0;
    230
    231	if (!device->status.present)
    232		return 0;
    233
    234	dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
    235	if (!dev)
    236		return -ENOMEM;
    237
    238	ACPI_COMPANION_SET(&dev->dev, device);
    239	dev->data = device;
    240	/* .enabled means the device can decode the resources */
    241	dev->active = device->status.enabled;
    242	if (acpi_has_method(device->handle, "_SRS"))
    243		dev->capabilities |= PNP_CONFIGURABLE;
    244	dev->capabilities |= PNP_READ;
    245	if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
    246		dev->capabilities |= PNP_WRITE;
    247	if (device->flags.removable)
    248		dev->capabilities |= PNP_REMOVABLE;
    249	if (acpi_has_method(device->handle, "_DIS"))
    250		dev->capabilities |= PNP_DISABLE;
    251
    252	if (strlen(acpi_device_name(device)))
    253		strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
    254	else
    255		strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
    256
    257	if (dev->active)
    258		pnpacpi_parse_allocated_resource(dev);
    259
    260	if (dev->capabilities & PNP_CONFIGURABLE)
    261		pnpacpi_parse_resource_option_data(dev);
    262
    263	list_for_each_entry(id, &device->pnp.ids, list) {
    264		if (!strcmp(id->id, pnpid))
    265			continue;
    266		if (!ispnpidacpi(id->id))
    267			continue;
    268		pnp_add_id(dev, id->id);
    269	}
    270
    271	/* clear out the damaged flags */
    272	if (!dev->active)
    273		pnp_init_resources(dev);
    274
    275	error = pnp_add_device(dev);
    276	if (error) {
    277		put_device(&dev->dev);
    278		return error;
    279	}
    280
    281	num++;
    282
    283	return 0;
    284}
    285
    286static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
    287						     u32 lvl, void *context,
    288						     void **rv)
    289{
    290	struct acpi_device *device = acpi_fetch_acpi_dev(handle);
    291
    292	if (!device)
    293		return AE_CTRL_DEPTH;
    294	if (acpi_is_pnp_device(device))
    295		pnpacpi_add_device(device);
    296	return AE_OK;
    297}
    298
    299int pnpacpi_disabled __initdata;
    300static int __init pnpacpi_init(void)
    301{
    302	if (acpi_disabled || pnpacpi_disabled) {
    303		printk(KERN_INFO "pnp: PnP ACPI: disabled\n");
    304		return 0;
    305	}
    306	printk(KERN_INFO "pnp: PnP ACPI init\n");
    307	pnp_register_protocol(&pnpacpi_protocol);
    308	acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
    309	printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num);
    310	pnp_platform_devices = 1;
    311	return 0;
    312}
    313
    314fs_initcall(pnpacpi_init);
    315
    316static int __init pnpacpi_setup(char *str)
    317{
    318	if (str == NULL)
    319		return 1;
    320	if (!strncmp(str, "off", 3))
    321		pnpacpi_disabled = 1;
    322	return 1;
    323}
    324
    325__setup("pnpacpi=", pnpacpi_setup);