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

intel_sar.c (9124B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2021, Intel Corporation.
      4 */
      5
      6#include <linux/acpi.h>
      7#include <linux/kobject.h>
      8#include <linux/platform_device.h>
      9#include <linux/sysfs.h>
     10#include "intel_sar.h"
     11
     12/**
     13 * get_int_value: Retrieve integer values from ACPI Object
     14 * @obj: acpi_object pointer which has the integer value
     15 * @out: output pointer will get integer value
     16 *
     17 * Function is used to retrieve integer value from acpi object.
     18 *
     19 * Return:
     20 * * 0 on success
     21 * * -EIO if there is an issue in acpi_object passed.
     22 */
     23static int get_int_value(union acpi_object *obj, int *out)
     24{
     25	if (!obj || obj->type != ACPI_TYPE_INTEGER)
     26		return -EIO;
     27	*out = (int)obj->integer.value;
     28	return 0;
     29}
     30
     31/**
     32 * update_sar_data: sar data is updated based on regulatory mode
     33 * @context: pointer to driver context structure
     34 *
     35 * sar_data is updated based on regulatory value
     36 * context->reg_value will never exceed MAX_REGULATORY
     37 */
     38static void update_sar_data(struct wwan_sar_context *context)
     39{
     40	struct wwan_device_mode_configuration *config =
     41		&context->config_data[context->reg_value];
     42
     43	if (config->device_mode_info &&
     44	    context->sar_data.device_mode < config->total_dev_mode) {
     45		int itr = 0;
     46
     47		for (itr = 0; itr < config->total_dev_mode; itr++) {
     48			if (context->sar_data.device_mode ==
     49				config->device_mode_info[itr].device_mode) {
     50				struct wwan_device_mode_info *dev_mode =
     51				&config->device_mode_info[itr];
     52
     53				context->sar_data.antennatable_index = dev_mode->antennatable_index;
     54				context->sar_data.bandtable_index = dev_mode->bandtable_index;
     55				context->sar_data.sartable_index = dev_mode->sartable_index;
     56				break;
     57			}
     58		}
     59	}
     60}
     61
     62/**
     63 * parse_package: parse acpi package for retrieving SAR information
     64 * @context: pointer to driver context structure
     65 * @item : acpi_object pointer
     66 *
     67 * Given acpi_object is iterated to retrieve information for each device mode.
     68 * If a given package corresponding to a specific device mode is faulty, it is
     69 * skipped and the specific entry in context structure will have the default value
     70 * of zero. Decoding of subsequent device modes is realized by having "continue"
     71 * statements in the for loop on encountering error in parsing given device mode.
     72 *
     73 * Return:
     74 * AE_OK if success
     75 * AE_ERROR on error
     76 */
     77static acpi_status parse_package(struct wwan_sar_context *context, union acpi_object *item)
     78{
     79	struct wwan_device_mode_configuration *data;
     80	int value, itr, reg;
     81	union acpi_object *num;
     82
     83	num = &item->package.elements[0];
     84	if (get_int_value(num, &value) || value < 0 || value >= MAX_REGULATORY)
     85		return AE_ERROR;
     86
     87	reg = value;
     88
     89	data = &context->config_data[reg];
     90	if (data->total_dev_mode > MAX_DEV_MODES ||	data->total_dev_mode == 0 ||
     91	    item->package.count <= data->total_dev_mode)
     92		return AE_ERROR;
     93
     94	data->device_mode_info = kmalloc_array(data->total_dev_mode,
     95					       sizeof(struct wwan_device_mode_info), GFP_KERNEL);
     96	if (!data->device_mode_info)
     97		return AE_ERROR;
     98
     99	for (itr = 0; itr < data->total_dev_mode; itr++) {
    100		struct wwan_device_mode_info temp = { 0 };
    101
    102		num = &item->package.elements[itr + 1];
    103		if (num->type != ACPI_TYPE_PACKAGE || num->package.count < TOTAL_DATA)
    104			continue;
    105		if (get_int_value(&num->package.elements[0], &temp.device_mode))
    106			continue;
    107		if (get_int_value(&num->package.elements[1], &temp.bandtable_index))
    108			continue;
    109		if (get_int_value(&num->package.elements[2], &temp.antennatable_index))
    110			continue;
    111		if (get_int_value(&num->package.elements[3], &temp.sartable_index))
    112			continue;
    113		data->device_mode_info[itr] = temp;
    114	}
    115	return AE_OK;
    116}
    117
    118/**
    119 * sar_get_device_mode: Extraction of information from BIOS via DSM calls
    120 * @device: ACPI device for which to retrieve the data
    121 *
    122 * Retrieve the current device mode information from the BIOS.
    123 *
    124 * Return:
    125 * AE_OK on success
    126 * AE_ERROR on error
    127 */
    128static acpi_status sar_get_device_mode(struct platform_device *device)
    129{
    130	struct wwan_sar_context *context = dev_get_drvdata(&device->dev);
    131	acpi_status status = AE_OK;
    132	union acpi_object *out;
    133	u32 rev = 0;
    134	int value;
    135
    136	out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
    137				COMMAND_ID_DEV_MODE, NULL);
    138	if (get_int_value(out, &value)) {
    139		dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE);
    140		status = AE_ERROR;
    141		goto dev_mode_error;
    142	}
    143	context->sar_data.device_mode = value;
    144	update_sar_data(context);
    145	sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME);
    146
    147dev_mode_error:
    148	ACPI_FREE(out);
    149	return status;
    150}
    151
    152static const struct acpi_device_id sar_device_ids[] = {
    153	{ "INTC1092", 0},
    154	{}
    155};
    156MODULE_DEVICE_TABLE(acpi, sar_device_ids);
    157
    158static ssize_t intc_data_show(struct device *dev, struct device_attribute *attr, char *buf)
    159{
    160	struct wwan_sar_context *context = dev_get_drvdata(dev);
    161
    162	return sysfs_emit(buf, "%d %d %d %d\n", context->sar_data.device_mode,
    163		      context->sar_data.bandtable_index,
    164		      context->sar_data.antennatable_index,
    165		      context->sar_data.sartable_index);
    166}
    167static DEVICE_ATTR_RO(intc_data);
    168
    169static ssize_t intc_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
    170{
    171	struct wwan_sar_context *context = dev_get_drvdata(dev);
    172
    173	return sysfs_emit(buf, "%d\n", context->reg_value);
    174}
    175
    176static ssize_t intc_reg_store(struct device *dev, struct device_attribute *attr,
    177			      const char *buf, size_t count)
    178{
    179	struct wwan_sar_context *context = dev_get_drvdata(dev);
    180	unsigned int value;
    181	int read;
    182
    183	if (!count)
    184		return -EINVAL;
    185	read = kstrtouint(buf, 10, &value);
    186	if (read < 0)
    187		return read;
    188	if (value >= MAX_REGULATORY)
    189		return -EOVERFLOW;
    190	context->reg_value = value;
    191	update_sar_data(context);
    192	sysfs_notify(&dev->kobj, NULL, SYSFS_DATANAME);
    193	return count;
    194}
    195static DEVICE_ATTR_RW(intc_reg);
    196
    197static struct attribute *intcsar_attrs[] = {
    198	&dev_attr_intc_data.attr,
    199	&dev_attr_intc_reg.attr,
    200	NULL
    201};
    202
    203static struct attribute_group intcsar_group = {
    204	.attrs = intcsar_attrs,
    205};
    206
    207static void sar_notify(acpi_handle handle, u32 event, void *data)
    208{
    209	struct platform_device *device = data;
    210
    211	if (event == SAR_EVENT) {
    212		if (sar_get_device_mode(device) != AE_OK)
    213			dev_err(&device->dev, "sar_get_device_mode error");
    214	}
    215}
    216
    217static void sar_get_data(int reg, struct wwan_sar_context *context)
    218{
    219	union acpi_object *out, req;
    220	u32 rev = 0;
    221
    222	req.type = ACPI_TYPE_INTEGER;
    223	req.integer.value = reg;
    224	out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
    225				COMMAND_ID_CONFIG_TABLE, &req);
    226	if (!out)
    227		return;
    228	if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 &&
    229	    out->package.elements[0].type == ACPI_TYPE_INTEGER &&
    230	    out->package.elements[1].type == ACPI_TYPE_INTEGER &&
    231	    out->package.elements[2].type == ACPI_TYPE_PACKAGE &&
    232	    out->package.elements[2].package.count > 0) {
    233		context->config_data[reg].version = out->package.elements[0].integer.value;
    234		context->config_data[reg].total_dev_mode =
    235			out->package.elements[1].integer.value;
    236		if (context->config_data[reg].total_dev_mode <= 0 ||
    237		    context->config_data[reg].total_dev_mode > MAX_DEV_MODES) {
    238			ACPI_FREE(out);
    239			return;
    240		}
    241		parse_package(context, &out->package.elements[2]);
    242	}
    243	ACPI_FREE(out);
    244}
    245
    246static int sar_probe(struct platform_device *device)
    247{
    248	struct wwan_sar_context *context;
    249	int reg;
    250	int result;
    251
    252	context = kzalloc(sizeof(*context), GFP_KERNEL);
    253	if (!context)
    254		return -ENOMEM;
    255
    256	context->sar_device = device;
    257	context->handle = ACPI_HANDLE(&device->dev);
    258	dev_set_drvdata(&device->dev, context);
    259
    260	result = guid_parse(SAR_DSM_UUID, &context->guid);
    261	if (result) {
    262		dev_err(&device->dev, "SAR UUID parse error: %d\n", result);
    263		goto r_free;
    264	}
    265
    266	for (reg = 0; reg < MAX_REGULATORY; reg++)
    267		sar_get_data(reg, context);
    268
    269	if (sar_get_device_mode(device) != AE_OK) {
    270		dev_err(&device->dev, "Failed to get device mode\n");
    271		result = -EIO;
    272		goto r_free;
    273	}
    274
    275	result = sysfs_create_group(&device->dev.kobj, &intcsar_group);
    276	if (result) {
    277		dev_err(&device->dev, "sysfs creation failed\n");
    278		goto r_free;
    279	}
    280
    281	if (acpi_install_notify_handler(ACPI_HANDLE(&device->dev), ACPI_DEVICE_NOTIFY,
    282					sar_notify, (void *)device) != AE_OK) {
    283		dev_err(&device->dev, "Failed acpi_install_notify_handler\n");
    284		result = -EIO;
    285		goto r_sys;
    286	}
    287	return 0;
    288
    289r_sys:
    290	sysfs_remove_group(&device->dev.kobj, &intcsar_group);
    291r_free:
    292	kfree(context);
    293	return result;
    294}
    295
    296static int sar_remove(struct platform_device *device)
    297{
    298	struct wwan_sar_context *context = dev_get_drvdata(&device->dev);
    299	int reg;
    300
    301	acpi_remove_notify_handler(ACPI_HANDLE(&device->dev),
    302				   ACPI_DEVICE_NOTIFY, sar_notify);
    303	sysfs_remove_group(&device->dev.kobj, &intcsar_group);
    304	for (reg = 0; reg < MAX_REGULATORY; reg++)
    305		kfree(context->config_data[reg].device_mode_info);
    306
    307	kfree(context);
    308	return 0;
    309}
    310
    311static struct platform_driver sar_driver = {
    312	.probe = sar_probe,
    313	.remove = sar_remove,
    314	.driver = {
    315		.name = DRVNAME,
    316		.acpi_match_table = ACPI_PTR(sar_device_ids)
    317	}
    318};
    319module_platform_driver(sar_driver);
    320
    321MODULE_LICENSE("GPL v2");
    322MODULE_DESCRIPTION("Platform device driver for INTEL MODEM BIOS SAR");
    323MODULE_AUTHOR("Shravan Sudhakar <s.shravan@intel.com>");