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

toshiba_haps.c (5874B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Toshiba HDD Active Protection Sensor (HAPS) driver
      4 *
      5 * Copyright (C) 2014 Azael Avalos <coproscefalo@gmail.com>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/types.h>
     14#include <linux/acpi.h>
     15
     16MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>");
     17MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
     18MODULE_LICENSE("GPL");
     19
     20struct toshiba_haps_dev {
     21	struct acpi_device *acpi_dev;
     22
     23	int protection_level;
     24};
     25
     26static struct toshiba_haps_dev *toshiba_haps;
     27
     28/* HAPS functions */
     29static int toshiba_haps_reset_protection(acpi_handle handle)
     30{
     31	acpi_status status;
     32
     33	status = acpi_evaluate_object(handle, "RSSS", NULL, NULL);
     34	if (ACPI_FAILURE(status)) {
     35		pr_err("Unable to reset the HDD protection\n");
     36		return -EIO;
     37	}
     38
     39	return 0;
     40}
     41
     42static int toshiba_haps_protection_level(acpi_handle handle, int level)
     43{
     44	acpi_status status;
     45
     46	status = acpi_execute_simple_method(handle, "PTLV", level);
     47	if (ACPI_FAILURE(status)) {
     48		pr_err("Error while setting the protection level\n");
     49		return -EIO;
     50	}
     51
     52	pr_debug("HDD protection level set to: %d\n", level);
     53
     54	return 0;
     55}
     56
     57/* sysfs files */
     58static ssize_t protection_level_show(struct device *dev,
     59				     struct device_attribute *attr, char *buf)
     60{
     61	struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
     62
     63	return sprintf(buf, "%i\n", haps->protection_level);
     64}
     65
     66static ssize_t protection_level_store(struct device *dev,
     67				      struct device_attribute *attr,
     68				      const char *buf, size_t count)
     69{
     70	struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
     71	int level;
     72	int ret;
     73
     74	ret = kstrtoint(buf, 0, &level);
     75	if (ret)
     76		return ret;
     77	/*
     78	 * Check for supported levels, which can be:
     79	 * 0 - Disabled | 1 - Low | 2 - Medium | 3 - High
     80	 */
     81	if (level < 0 || level > 3)
     82		return -EINVAL;
     83
     84	/* Set the sensor level */
     85	ret = toshiba_haps_protection_level(haps->acpi_dev->handle, level);
     86	if (ret != 0)
     87		return ret;
     88
     89	haps->protection_level = level;
     90
     91	return count;
     92}
     93static DEVICE_ATTR_RW(protection_level);
     94
     95static ssize_t reset_protection_store(struct device *dev,
     96				      struct device_attribute *attr,
     97				      const char *buf, size_t count)
     98{
     99	struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
    100	int reset;
    101	int ret;
    102
    103	ret = kstrtoint(buf, 0, &reset);
    104	if (ret)
    105		return ret;
    106	/* The only accepted value is 1 */
    107	if (reset != 1)
    108		return -EINVAL;
    109
    110	/* Reset the protection interface */
    111	ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
    112	if (ret != 0)
    113		return ret;
    114
    115	return count;
    116}
    117static DEVICE_ATTR_WO(reset_protection);
    118
    119static struct attribute *haps_attributes[] = {
    120	&dev_attr_protection_level.attr,
    121	&dev_attr_reset_protection.attr,
    122	NULL,
    123};
    124
    125static const struct attribute_group haps_attr_group = {
    126	.attrs = haps_attributes,
    127};
    128
    129/*
    130 * ACPI stuff
    131 */
    132static void toshiba_haps_notify(struct acpi_device *device, u32 event)
    133{
    134	pr_debug("Received event: 0x%x\n", event);
    135
    136	acpi_bus_generate_netlink_event(device->pnp.device_class,
    137					dev_name(&device->dev),
    138					event, 0);
    139}
    140
    141static int toshiba_haps_remove(struct acpi_device *device)
    142{
    143	sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
    144
    145	if (toshiba_haps)
    146		toshiba_haps = NULL;
    147
    148	return 0;
    149}
    150
    151/* Helper function */
    152static int toshiba_haps_available(acpi_handle handle)
    153{
    154	acpi_status status;
    155	u64 hdd_present;
    156
    157	/*
    158	 * A non existent device as well as having (only)
    159	 * Solid State Drives can cause the call to fail.
    160	 */
    161	status = acpi_evaluate_integer(handle, "_STA", NULL, &hdd_present);
    162	if (ACPI_FAILURE(status)) {
    163		pr_err("ACPI call to query HDD protection failed\n");
    164		return 0;
    165	}
    166
    167	if (!hdd_present) {
    168		pr_info("HDD protection not available or using SSD\n");
    169		return 0;
    170	}
    171
    172	return 1;
    173}
    174
    175static int toshiba_haps_add(struct acpi_device *acpi_dev)
    176{
    177	struct toshiba_haps_dev *haps;
    178	int ret;
    179
    180	if (toshiba_haps)
    181		return -EBUSY;
    182
    183	if (!toshiba_haps_available(acpi_dev->handle))
    184		return -ENODEV;
    185
    186	pr_info("Toshiba HDD Active Protection Sensor device\n");
    187
    188	haps = kzalloc(sizeof(struct toshiba_haps_dev), GFP_KERNEL);
    189	if (!haps)
    190		return -ENOMEM;
    191
    192	haps->acpi_dev = acpi_dev;
    193	haps->protection_level = 2;
    194	acpi_dev->driver_data = haps;
    195	dev_set_drvdata(&acpi_dev->dev, haps);
    196
    197	/* Set the protection level, currently at level 2 (Medium) */
    198	ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
    199	if (ret != 0)
    200		return ret;
    201
    202	ret = sysfs_create_group(&acpi_dev->dev.kobj, &haps_attr_group);
    203	if (ret)
    204		return ret;
    205
    206	toshiba_haps = haps;
    207
    208	return 0;
    209}
    210
    211#ifdef CONFIG_PM_SLEEP
    212static int toshiba_haps_suspend(struct device *device)
    213{
    214	struct toshiba_haps_dev *haps;
    215	int ret;
    216
    217	haps = acpi_driver_data(to_acpi_device(device));
    218
    219	/* Deactivate the protection on suspend */
    220	ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
    221
    222	return ret;
    223}
    224
    225static int toshiba_haps_resume(struct device *device)
    226{
    227	struct toshiba_haps_dev *haps;
    228	int ret;
    229
    230	haps = acpi_driver_data(to_acpi_device(device));
    231
    232	/* Set the stored protection level */
    233	ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
    234					    haps->protection_level);
    235
    236	/* Reset the protection on resume */
    237	ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
    238	if (ret != 0)
    239		return ret;
    240
    241	return ret;
    242}
    243#endif
    244
    245static SIMPLE_DEV_PM_OPS(toshiba_haps_pm,
    246			 toshiba_haps_suspend, toshiba_haps_resume);
    247
    248static const struct acpi_device_id haps_device_ids[] = {
    249	{"TOS620A", 0},
    250	{"", 0},
    251};
    252MODULE_DEVICE_TABLE(acpi, haps_device_ids);
    253
    254static struct acpi_driver toshiba_haps_driver = {
    255	.name = "Toshiba HAPS",
    256	.owner = THIS_MODULE,
    257	.ids = haps_device_ids,
    258	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
    259	.ops = {
    260		.add =		toshiba_haps_add,
    261		.remove =	toshiba_haps_remove,
    262		.notify =	toshiba_haps_notify,
    263	},
    264	.drv.pm = &toshiba_haps_pm,
    265};
    266
    267module_acpi_driver(toshiba_haps_driver);