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

fan_core.c (11447B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  fan_core.c - ACPI Fan core Driver
      4 *
      5 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
      6 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
      7 *  Copyright (C) 2022 Intel Corporation. All rights reserved.
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/types.h>
     14#include <linux/uaccess.h>
     15#include <linux/thermal.h>
     16#include <linux/acpi.h>
     17#include <linux/platform_device.h>
     18#include <linux/sort.h>
     19
     20#include "fan.h"
     21
     22MODULE_AUTHOR("Paul Diefenbaugh");
     23MODULE_DESCRIPTION("ACPI Fan Driver");
     24MODULE_LICENSE("GPL");
     25
     26static int acpi_fan_probe(struct platform_device *pdev);
     27static int acpi_fan_remove(struct platform_device *pdev);
     28
     29static const struct acpi_device_id fan_device_ids[] = {
     30	ACPI_FAN_DEVICE_IDS,
     31	{"", 0},
     32};
     33MODULE_DEVICE_TABLE(acpi, fan_device_ids);
     34
     35#ifdef CONFIG_PM_SLEEP
     36static int acpi_fan_suspend(struct device *dev);
     37static int acpi_fan_resume(struct device *dev);
     38static const struct dev_pm_ops acpi_fan_pm = {
     39	.resume = acpi_fan_resume,
     40	.freeze = acpi_fan_suspend,
     41	.thaw = acpi_fan_resume,
     42	.restore = acpi_fan_resume,
     43};
     44#define FAN_PM_OPS_PTR (&acpi_fan_pm)
     45#else
     46#define FAN_PM_OPS_PTR NULL
     47#endif
     48
     49static struct platform_driver acpi_fan_driver = {
     50	.probe = acpi_fan_probe,
     51	.remove = acpi_fan_remove,
     52	.driver = {
     53		.name = "acpi-fan",
     54		.acpi_match_table = fan_device_ids,
     55		.pm = FAN_PM_OPS_PTR,
     56	},
     57};
     58
     59/* thermal cooling device callbacks */
     60static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
     61			     *state)
     62{
     63	struct acpi_device *device = cdev->devdata;
     64	struct acpi_fan *fan = acpi_driver_data(device);
     65
     66	if (fan->acpi4) {
     67		if (fan->fif.fine_grain_ctrl)
     68			*state = 100 / fan->fif.step_size;
     69		else
     70			*state = fan->fps_count - 1;
     71	} else {
     72		*state = 1;
     73	}
     74
     75	return 0;
     76}
     77
     78int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst)
     79{
     80	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
     81	union acpi_object *obj;
     82	acpi_status status;
     83	int ret = 0;
     84
     85	status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
     86	if (ACPI_FAILURE(status)) {
     87		dev_err(&device->dev, "Get fan state failed\n");
     88		return -ENODEV;
     89	}
     90
     91	obj = buffer.pointer;
     92	if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
     93	    obj->package.count != 3 ||
     94	    obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
     95		dev_err(&device->dev, "Invalid _FST data\n");
     96		ret = -EINVAL;
     97		goto err;
     98	}
     99
    100	fst->revision = obj->package.elements[0].integer.value;
    101	fst->control = obj->package.elements[1].integer.value;
    102	fst->speed = obj->package.elements[2].integer.value;
    103
    104err:
    105	kfree(obj);
    106	return ret;
    107}
    108
    109static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
    110{
    111	struct acpi_fan *fan = acpi_driver_data(device);
    112	struct acpi_fan_fst fst;
    113	int status, i;
    114
    115	status = acpi_fan_get_fst(device, &fst);
    116	if (status)
    117		return status;
    118
    119	if (fan->fif.fine_grain_ctrl) {
    120		/* This control should be same what we set using _FSL by spec */
    121		if (fst.control > 100) {
    122			dev_dbg(&device->dev, "Invalid control value returned\n");
    123			goto match_fps;
    124		}
    125
    126		*state = (int) fst.control / fan->fif.step_size;
    127		return 0;
    128	}
    129
    130match_fps:
    131	for (i = 0; i < fan->fps_count; i++) {
    132		if (fst.control == fan->fps[i].control)
    133			break;
    134	}
    135	if (i == fan->fps_count) {
    136		dev_dbg(&device->dev, "Invalid control value returned\n");
    137		return -EINVAL;
    138	}
    139
    140	*state = i;
    141
    142	return status;
    143}
    144
    145static int fan_get_state(struct acpi_device *device, unsigned long *state)
    146{
    147	int result;
    148	int acpi_state = ACPI_STATE_D0;
    149
    150	result = acpi_device_update_power(device, &acpi_state);
    151	if (result)
    152		return result;
    153
    154	*state = acpi_state == ACPI_STATE_D3_COLD
    155			|| acpi_state == ACPI_STATE_D3_HOT ?
    156		0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1);
    157	return 0;
    158}
    159
    160static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
    161			     *state)
    162{
    163	struct acpi_device *device = cdev->devdata;
    164	struct acpi_fan *fan = acpi_driver_data(device);
    165
    166	if (fan->acpi4)
    167		return fan_get_state_acpi4(device, state);
    168	else
    169		return fan_get_state(device, state);
    170}
    171
    172static int fan_set_state(struct acpi_device *device, unsigned long state)
    173{
    174	if (state != 0 && state != 1)
    175		return -EINVAL;
    176
    177	return acpi_device_set_power(device,
    178				     state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
    179}
    180
    181static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
    182{
    183	struct acpi_fan *fan = acpi_driver_data(device);
    184	acpi_status status;
    185	u64 value = state;
    186	int max_state;
    187
    188	if (fan->fif.fine_grain_ctrl)
    189		max_state = 100 / fan->fif.step_size;
    190	else
    191		max_state = fan->fps_count - 1;
    192
    193	if (state > max_state)
    194		return -EINVAL;
    195
    196	if (fan->fif.fine_grain_ctrl) {
    197		value *= fan->fif.step_size;
    198		/* Spec allows compensate the last step only */
    199		if (value + fan->fif.step_size > 100)
    200			value = 100;
    201	} else {
    202		value = fan->fps[state].control;
    203	}
    204
    205	status = acpi_execute_simple_method(device->handle, "_FSL", value);
    206	if (ACPI_FAILURE(status)) {
    207		dev_dbg(&device->dev, "Failed to set state by _FSL\n");
    208		return -ENODEV;
    209	}
    210
    211	return 0;
    212}
    213
    214static int
    215fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
    216{
    217	struct acpi_device *device = cdev->devdata;
    218	struct acpi_fan *fan = acpi_driver_data(device);
    219
    220	if (fan->acpi4)
    221		return fan_set_state_acpi4(device, state);
    222	else
    223		return fan_set_state(device, state);
    224}
    225
    226static const struct thermal_cooling_device_ops fan_cooling_ops = {
    227	.get_max_state = fan_get_max_state,
    228	.get_cur_state = fan_get_cur_state,
    229	.set_cur_state = fan_set_cur_state,
    230};
    231
    232/* --------------------------------------------------------------------------
    233 *                               Driver Interface
    234 * --------------------------------------------------------------------------
    235*/
    236
    237static bool acpi_fan_is_acpi4(struct acpi_device *device)
    238{
    239	return acpi_has_method(device->handle, "_FIF") &&
    240	       acpi_has_method(device->handle, "_FPS") &&
    241	       acpi_has_method(device->handle, "_FSL") &&
    242	       acpi_has_method(device->handle, "_FST");
    243}
    244
    245static int acpi_fan_get_fif(struct acpi_device *device)
    246{
    247	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
    248	struct acpi_fan *fan = acpi_driver_data(device);
    249	struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
    250	u64 fields[4];
    251	struct acpi_buffer fif = { sizeof(fields), fields };
    252	union acpi_object *obj;
    253	acpi_status status;
    254
    255	status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
    256	if (ACPI_FAILURE(status))
    257		return status;
    258
    259	obj = buffer.pointer;
    260	if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
    261		dev_err(&device->dev, "Invalid _FIF data\n");
    262		status = -EINVAL;
    263		goto err;
    264	}
    265
    266	status = acpi_extract_package(obj, &format, &fif);
    267	if (ACPI_FAILURE(status)) {
    268		dev_err(&device->dev, "Invalid _FIF element\n");
    269		status = -EINVAL;
    270	}
    271
    272	fan->fif.revision = fields[0];
    273	fan->fif.fine_grain_ctrl = fields[1];
    274	fan->fif.step_size = fields[2];
    275	fan->fif.low_speed_notification = fields[3];
    276
    277	/* If there is a bug in step size and set as 0, change to 1 */
    278	if (!fan->fif.step_size)
    279		fan->fif.step_size = 1;
    280	/* If step size > 9, change to 9 (by spec valid values 1-9) */
    281	else if (fan->fif.step_size > 9)
    282		fan->fif.step_size = 9;
    283err:
    284	kfree(obj);
    285	return status;
    286}
    287
    288static int acpi_fan_speed_cmp(const void *a, const void *b)
    289{
    290	const struct acpi_fan_fps *fps1 = a;
    291	const struct acpi_fan_fps *fps2 = b;
    292	return fps1->speed - fps2->speed;
    293}
    294
    295static int acpi_fan_get_fps(struct acpi_device *device)
    296{
    297	struct acpi_fan *fan = acpi_driver_data(device);
    298	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
    299	union acpi_object *obj;
    300	acpi_status status;
    301	int i;
    302
    303	status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
    304	if (ACPI_FAILURE(status))
    305		return status;
    306
    307	obj = buffer.pointer;
    308	if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
    309		dev_err(&device->dev, "Invalid _FPS data\n");
    310		status = -EINVAL;
    311		goto err;
    312	}
    313
    314	fan->fps_count = obj->package.count - 1; /* minus revision field */
    315	fan->fps = devm_kcalloc(&device->dev,
    316				fan->fps_count, sizeof(struct acpi_fan_fps),
    317				GFP_KERNEL);
    318	if (!fan->fps) {
    319		dev_err(&device->dev, "Not enough memory\n");
    320		status = -ENOMEM;
    321		goto err;
    322	}
    323	for (i = 0; i < fan->fps_count; i++) {
    324		struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
    325		struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name),
    326						&fan->fps[i] };
    327		status = acpi_extract_package(&obj->package.elements[i + 1],
    328					      &format, &fps);
    329		if (ACPI_FAILURE(status)) {
    330			dev_err(&device->dev, "Invalid _FPS element\n");
    331			goto err;
    332		}
    333	}
    334
    335	/* sort the state array according to fan speed in increase order */
    336	sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
    337	     acpi_fan_speed_cmp, NULL);
    338
    339err:
    340	kfree(obj);
    341	return status;
    342}
    343
    344static int acpi_fan_probe(struct platform_device *pdev)
    345{
    346	int result = 0;
    347	struct thermal_cooling_device *cdev;
    348	struct acpi_fan *fan;
    349	struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
    350	char *name;
    351
    352	fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
    353	if (!fan) {
    354		dev_err(&device->dev, "No memory for fan\n");
    355		return -ENOMEM;
    356	}
    357	device->driver_data = fan;
    358	platform_set_drvdata(pdev, fan);
    359
    360	if (acpi_fan_is_acpi4(device)) {
    361		result = acpi_fan_get_fif(device);
    362		if (result)
    363			return result;
    364
    365		result = acpi_fan_get_fps(device);
    366		if (result)
    367			return result;
    368
    369		result = acpi_fan_create_attributes(device);
    370		if (result)
    371			return result;
    372
    373		fan->acpi4 = true;
    374	} else {
    375		result = acpi_device_update_power(device, NULL);
    376		if (result) {
    377			dev_err(&device->dev, "Failed to set initial power state\n");
    378			goto err_end;
    379		}
    380	}
    381
    382	if (!strncmp(pdev->name, "PNP0C0B", strlen("PNP0C0B")))
    383		name = "Fan";
    384	else
    385		name = acpi_device_bid(device);
    386
    387	cdev = thermal_cooling_device_register(name, device,
    388						&fan_cooling_ops);
    389	if (IS_ERR(cdev)) {
    390		result = PTR_ERR(cdev);
    391		goto err_end;
    392	}
    393
    394	dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
    395
    396	fan->cdev = cdev;
    397	result = sysfs_create_link(&pdev->dev.kobj,
    398				   &cdev->device.kobj,
    399				   "thermal_cooling");
    400	if (result)
    401		dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
    402
    403	result = sysfs_create_link(&cdev->device.kobj,
    404				   &pdev->dev.kobj,
    405				   "device");
    406	if (result) {
    407		dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
    408		goto err_end;
    409	}
    410
    411	return 0;
    412
    413err_end:
    414	if (fan->acpi4)
    415		acpi_fan_delete_attributes(device);
    416
    417	return result;
    418}
    419
    420static int acpi_fan_remove(struct platform_device *pdev)
    421{
    422	struct acpi_fan *fan = platform_get_drvdata(pdev);
    423
    424	if (fan->acpi4) {
    425		struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
    426
    427		acpi_fan_delete_attributes(device);
    428	}
    429	sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
    430	sysfs_remove_link(&fan->cdev->device.kobj, "device");
    431	thermal_cooling_device_unregister(fan->cdev);
    432
    433	return 0;
    434}
    435
    436#ifdef CONFIG_PM_SLEEP
    437static int acpi_fan_suspend(struct device *dev)
    438{
    439	struct acpi_fan *fan = dev_get_drvdata(dev);
    440	if (fan->acpi4)
    441		return 0;
    442
    443	acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
    444
    445	return AE_OK;
    446}
    447
    448static int acpi_fan_resume(struct device *dev)
    449{
    450	int result;
    451	struct acpi_fan *fan = dev_get_drvdata(dev);
    452
    453	if (fan->acpi4)
    454		return 0;
    455
    456	result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
    457	if (result)
    458		dev_err(dev, "Error updating fan power state\n");
    459
    460	return result;
    461}
    462#endif
    463
    464module_platform_driver(acpi_fan_driver);