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

amd_sfh_client.c (9296B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  AMD SFH Client Layer
      4 *  Copyright 2020-2021 Advanced Micro Devices, Inc.
      5 *  Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
      6 *	     Sandeep Singh <Sandeep.singh@amd.com>
      7 *	     Basavaraj Natikar <Basavaraj.Natikar@amd.com>
      8 */
      9
     10#include <linux/dma-mapping.h>
     11#include <linux/hid.h>
     12#include <linux/list.h>
     13#include <linux/slab.h>
     14#include <linux/workqueue.h>
     15#include <linux/errno.h>
     16
     17#include "hid_descriptor/amd_sfh_hid_desc.h"
     18#include "amd_sfh_pcie.h"
     19#include "amd_sfh_hid.h"
     20
     21
     22struct request_list {
     23	struct hid_device *hid;
     24	struct list_head list;
     25	u8 report_id;
     26	u8 sensor_idx;
     27	u8 report_type;
     28	u8 current_index;
     29};
     30
     31static struct request_list req_list;
     32
     33void amd_sfh_set_report(struct hid_device *hid, int report_id,
     34			int report_type)
     35{
     36	struct amdtp_hid_data *hid_data = hid->driver_data;
     37	struct amdtp_cl_data *cli_data = hid_data->cli_data;
     38	int i;
     39
     40	for (i = 0; i < cli_data->num_hid_devices; i++) {
     41		if (cli_data->hid_sensor_hubs[i] == hid) {
     42			cli_data->cur_hid_dev = i;
     43			break;
     44		}
     45	}
     46	amdtp_hid_wakeup(hid);
     47}
     48
     49int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
     50{
     51	struct amdtp_hid_data *hid_data = hid->driver_data;
     52	struct amdtp_cl_data *cli_data = hid_data->cli_data;
     53	int i;
     54
     55	for (i = 0; i < cli_data->num_hid_devices; i++) {
     56		if (cli_data->hid_sensor_hubs[i] == hid) {
     57			struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL);
     58
     59			if (!new)
     60				return -ENOMEM;
     61
     62			new->current_index = i;
     63			new->sensor_idx = cli_data->sensor_idx[i];
     64			new->hid = hid;
     65			new->report_type = report_type;
     66			new->report_id = report_id;
     67			cli_data->report_id[i] = report_id;
     68			cli_data->request_done[i] = false;
     69			list_add(&new->list, &req_list.list);
     70			break;
     71		}
     72	}
     73	schedule_delayed_work(&cli_data->work, 0);
     74	return 0;
     75}
     76
     77static void amd_sfh_work(struct work_struct *work)
     78{
     79	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
     80	struct amd_input_data *in_data = cli_data->in_data;
     81	struct request_list *req_node;
     82	u8 current_index, sensor_index;
     83	u8 report_id, node_type;
     84	u8 report_size = 0;
     85
     86	req_node = list_last_entry(&req_list.list, struct request_list, list);
     87	list_del(&req_node->list);
     88	current_index = req_node->current_index;
     89	sensor_index = req_node->sensor_idx;
     90	report_id = req_node->report_id;
     91	node_type = req_node->report_type;
     92	kfree(req_node);
     93
     94	if (node_type == HID_FEATURE_REPORT) {
     95		report_size = get_feature_report(sensor_index, report_id,
     96						 cli_data->feature_report[current_index]);
     97		if (report_size)
     98			hid_input_report(cli_data->hid_sensor_hubs[current_index],
     99					 cli_data->report_type[current_index],
    100					 cli_data->feature_report[current_index], report_size, 0);
    101		else
    102			pr_err("AMDSFH: Invalid report size\n");
    103
    104	} else if (node_type == HID_INPUT_REPORT) {
    105		report_size = get_input_report(current_index, sensor_index, report_id, in_data);
    106		if (report_size)
    107			hid_input_report(cli_data->hid_sensor_hubs[current_index],
    108					 cli_data->report_type[current_index],
    109					 in_data->input_report[current_index], report_size, 0);
    110		else
    111			pr_err("AMDSFH: Invalid report size\n");
    112	}
    113	cli_data->cur_hid_dev = current_index;
    114	cli_data->sensor_requested_cnt[current_index] = 0;
    115	amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]);
    116}
    117
    118static void amd_sfh_work_buffer(struct work_struct *work)
    119{
    120	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
    121	struct amd_input_data *in_data = cli_data->in_data;
    122	u8 report_size;
    123	int i;
    124
    125	for (i = 0; i < cli_data->num_hid_devices; i++) {
    126		if (cli_data->sensor_sts[i] == SENSOR_ENABLED) {
    127			report_size = get_input_report
    128				(i, cli_data->sensor_idx[i], cli_data->report_id[i], in_data);
    129			hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
    130					 in_data->input_report[i], report_size, 0);
    131		}
    132	}
    133	schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
    134}
    135
    136u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
    137{
    138	if (mp2->mp2_ops->response)
    139		sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts);
    140
    141	return sensor_sts;
    142}
    143
    144const char *get_sensor_name(int idx)
    145{
    146	switch (idx) {
    147	case accel_idx:
    148		return "accelerometer";
    149	case gyro_idx:
    150		return "gyroscope";
    151	case mag_idx:
    152		return "magnetometer";
    153	case als_idx:
    154		return "ALS";
    155	case HPD_IDX:
    156		return "HPD";
    157	default:
    158		return "unknown sensor type";
    159	}
    160}
    161
    162int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
    163{
    164	struct amd_input_data *in_data = &privdata->in_data;
    165	struct amdtp_cl_data *cl_data = privdata->cl_data;
    166	struct amd_mp2_sensor_info info;
    167	struct device *dev;
    168	u32 feature_report_size;
    169	u32 input_report_size;
    170	int rc, i, status;
    171	u8 cl_idx;
    172
    173	dev = &privdata->pdev->dev;
    174
    175	cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
    176
    177	INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
    178	INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
    179	INIT_LIST_HEAD(&req_list.list);
    180	cl_data->in_data = in_data;
    181
    182	for (i = 0; i < cl_data->num_hid_devices; i++) {
    183		in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
    184								  &cl_data->sensor_dma_addr[i],
    185								  GFP_KERNEL);
    186		cl_data->sensor_sts[i] = SENSOR_DISABLED;
    187		cl_data->sensor_requested_cnt[i] = 0;
    188		cl_data->cur_hid_dev = i;
    189		cl_idx = cl_data->sensor_idx[i];
    190		cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size);
    191		if (!cl_data->report_descr_sz[i]) {
    192			rc = -EINVAL;
    193			goto cleanup;
    194		}
    195		feature_report_size = get_descr_sz(cl_idx, feature_size);
    196		if (!feature_report_size) {
    197			rc = -EINVAL;
    198			goto cleanup;
    199		}
    200		input_report_size =  get_descr_sz(cl_idx, input_size);
    201		if (!input_report_size) {
    202			rc = -EINVAL;
    203			goto cleanup;
    204		}
    205		cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);
    206		if (!cl_data->feature_report[i]) {
    207			rc = -ENOMEM;
    208			goto cleanup;
    209		}
    210		in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
    211		if (!in_data->input_report[i]) {
    212			rc = -ENOMEM;
    213			goto cleanup;
    214		}
    215		info.period = AMD_SFH_IDLE_LOOP;
    216		info.sensor_idx = cl_idx;
    217		info.dma_address = cl_data->sensor_dma_addr[i];
    218
    219		cl_data->report_descr[i] =
    220			devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);
    221		if (!cl_data->report_descr[i]) {
    222			rc = -ENOMEM;
    223			goto cleanup;
    224		}
    225		rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]);
    226		if (rc)
    227			return rc;
    228		privdata->mp2_ops->start(privdata, info);
    229		status = amd_sfh_wait_for_response
    230				(privdata, cl_data->sensor_idx[i], SENSOR_ENABLED);
    231		if (status == SENSOR_ENABLED) {
    232			cl_data->sensor_sts[i] = SENSOR_ENABLED;
    233			rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
    234			if (rc) {
    235				privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
    236				status = amd_sfh_wait_for_response
    237					(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
    238				if (status != SENSOR_ENABLED)
    239					cl_data->sensor_sts[i] = SENSOR_DISABLED;
    240				dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
    241					cl_data->sensor_idx[i],
    242					get_sensor_name(cl_data->sensor_idx[i]),
    243					cl_data->sensor_sts[i]);
    244				goto cleanup;
    245			}
    246		}
    247		dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
    248			cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    249			cl_data->sensor_sts[i]);
    250	}
    251	if (privdata->mp2_ops->discovery_status &&
    252	    privdata->mp2_ops->discovery_status(privdata) == 0) {
    253		amd_sfh_hid_client_deinit(privdata);
    254		for (i = 0; i < cl_data->num_hid_devices; i++) {
    255			devm_kfree(dev, cl_data->feature_report[i]);
    256			devm_kfree(dev, in_data->input_report[i]);
    257			devm_kfree(dev, cl_data->report_descr[i]);
    258		}
    259		dev_warn(dev, "Failed to discover, sensors not enabled\n");
    260		return -EOPNOTSUPP;
    261	}
    262	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
    263	return 0;
    264
    265cleanup:
    266	for (i = 0; i < cl_data->num_hid_devices; i++) {
    267		if (in_data->sensor_virt_addr[i]) {
    268			dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
    269					  in_data->sensor_virt_addr[i],
    270					  cl_data->sensor_dma_addr[i]);
    271		}
    272		devm_kfree(dev, cl_data->feature_report[i]);
    273		devm_kfree(dev, in_data->input_report[i]);
    274		devm_kfree(dev, cl_data->report_descr[i]);
    275	}
    276	return rc;
    277}
    278
    279int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
    280{
    281	struct amdtp_cl_data *cl_data = privdata->cl_data;
    282	struct amd_input_data *in_data = cl_data->in_data;
    283	int i, status;
    284
    285	for (i = 0; i < cl_data->num_hid_devices; i++) {
    286		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
    287			privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
    288			status = amd_sfh_wait_for_response
    289					(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
    290			if (status != SENSOR_ENABLED)
    291				cl_data->sensor_sts[i] = SENSOR_DISABLED;
    292			dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",
    293				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    294				cl_data->sensor_sts[i]);
    295		}
    296	}
    297
    298	cancel_delayed_work_sync(&cl_data->work);
    299	cancel_delayed_work_sync(&cl_data->work_buffer);
    300	amdtp_hid_remove(cl_data);
    301
    302	for (i = 0; i < cl_data->num_hid_devices; i++) {
    303		if (in_data->sensor_virt_addr[i]) {
    304			dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
    305					  in_data->sensor_virt_addr[i],
    306					  cl_data->sensor_dma_addr[i]);
    307		}
    308	}
    309	return 0;
    310}