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_pcie.c (10965B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * AMD MP2 PCIe communication driver
      4 * Copyright 2020-2021 Advanced Micro Devices, Inc.
      5 *
      6 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
      7 *	    Sandeep Singh <Sandeep.singh@amd.com>
      8 *	    Basavaraj Natikar <Basavaraj.Natikar@amd.com>
      9 */
     10
     11#include <linux/bitops.h>
     12#include <linux/delay.h>
     13#include <linux/dma-mapping.h>
     14#include <linux/dmi.h>
     15#include <linux/interrupt.h>
     16#include <linux/io-64-nonatomic-lo-hi.h>
     17#include <linux/iopoll.h>
     18#include <linux/module.h>
     19#include <linux/slab.h>
     20
     21#include "amd_sfh_pcie.h"
     22
     23#define DRIVER_NAME	"pcie_mp2_amd"
     24#define DRIVER_DESC	"AMD(R) PCIe MP2 Communication Driver"
     25
     26#define ACEL_EN		BIT(0)
     27#define GYRO_EN		BIT(1)
     28#define MAGNO_EN	BIT(2)
     29#define HPD_EN		BIT(16)
     30#define ALS_EN		BIT(19)
     31
     32static int sensor_mask_override = -1;
     33module_param_named(sensor_mask, sensor_mask_override, int, 0444);
     34MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
     35
     36static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
     37{
     38	union cmd_response cmd_resp;
     39
     40	/* Get response with status within a max of 1600 ms timeout */
     41	if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
     42				(cmd_resp.response_v2.response == sensor_sts &&
     43				cmd_resp.response_v2.status == 0 && (sid == 0xff ||
     44				cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
     45		return cmd_resp.response_v2.response;
     46
     47	return SENSOR_DISABLED;
     48}
     49
     50static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
     51{
     52	union sfh_cmd_base cmd_base;
     53
     54	cmd_base.ul = 0;
     55	cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
     56	cmd_base.cmd_v2.intr_disable = 1;
     57	cmd_base.cmd_v2.period = info.period;
     58	cmd_base.cmd_v2.sensor_id = info.sensor_idx;
     59	cmd_base.cmd_v2.length = 16;
     60
     61	if (info.sensor_idx == als_idx)
     62		cmd_base.cmd_v2.mem_type = USE_C2P_REG;
     63
     64	writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
     65	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
     66}
     67
     68static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
     69{
     70	union sfh_cmd_base cmd_base;
     71
     72	cmd_base.ul = 0;
     73	cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
     74	cmd_base.cmd_v2.intr_disable = 1;
     75	cmd_base.cmd_v2.period = 0;
     76	cmd_base.cmd_v2.sensor_id = sensor_idx;
     77	cmd_base.cmd_v2.length  = 16;
     78
     79	writeq(0x0, privdata->mmio + AMD_C2P_MSG1);
     80	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
     81}
     82
     83static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
     84{
     85	union sfh_cmd_base cmd_base;
     86
     87	cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
     88	cmd_base.cmd_v2.intr_disable = 1;
     89	cmd_base.cmd_v2.period = 0;
     90	cmd_base.cmd_v2.sensor_id = 0;
     91
     92	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
     93}
     94
     95static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata)
     96{
     97	if (readl(privdata->mmio + AMD_P2C_MSG(4))) {
     98		writel(0, privdata->mmio + AMD_P2C_MSG(4));
     99		writel(0xf, privdata->mmio + AMD_P2C_MSG(5));
    100	}
    101}
    102
    103static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata)
    104{
    105	if (privdata->mp2_ops->clear_intr)
    106		privdata->mp2_ops->clear_intr(privdata);
    107}
    108
    109static irqreturn_t amd_sfh_irq_handler(int irq, void *data)
    110{
    111	amd_sfh_clear_intr(data);
    112
    113	return IRQ_HANDLED;
    114}
    115
    116static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata)
    117{
    118	int rc;
    119
    120	pci_intx(privdata->pdev, true);
    121
    122	rc = devm_request_irq(&privdata->pdev->dev, privdata->pdev->irq,
    123			      amd_sfh_irq_handler, 0, DRIVER_NAME, privdata);
    124	if (rc) {
    125		dev_err(&privdata->pdev->dev, "failed to request irq %d err=%d\n",
    126			privdata->pdev->irq, rc);
    127		return rc;
    128	}
    129
    130	return 0;
    131}
    132
    133static int amd_sfh_dis_sts_v2(struct amd_mp2_dev *privdata)
    134{
    135	return (readl(privdata->mmio + AMD_P2C_MSG(1)) &
    136		      SENSOR_DISCOVERY_STATUS_MASK) >> SENSOR_DISCOVERY_STATUS_SHIFT;
    137}
    138
    139void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
    140{
    141	union sfh_cmd_param cmd_param;
    142	union sfh_cmd_base cmd_base;
    143
    144	/* fill up command register */
    145	memset(&cmd_base, 0, sizeof(cmd_base));
    146	cmd_base.s.cmd_id = ENABLE_SENSOR;
    147	cmd_base.s.period = info.period;
    148	cmd_base.s.sensor_id = info.sensor_idx;
    149
    150	/* fill up command param register */
    151	memset(&cmd_param, 0, sizeof(cmd_param));
    152	cmd_param.s.buf_layout = 1;
    153	cmd_param.s.buf_length = 16;
    154
    155	writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG2);
    156	writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
    157	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
    158}
    159
    160void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
    161{
    162	union sfh_cmd_base cmd_base;
    163
    164	/* fill up command register */
    165	memset(&cmd_base, 0, sizeof(cmd_base));
    166	cmd_base.s.cmd_id = DISABLE_SENSOR;
    167	cmd_base.s.period = 0;
    168	cmd_base.s.sensor_id = sensor_idx;
    169
    170	writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
    171	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
    172}
    173
    174void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
    175{
    176	union sfh_cmd_base cmd_base;
    177
    178	/* fill up command register */
    179	memset(&cmd_base, 0, sizeof(cmd_base));
    180	cmd_base.s.cmd_id = STOP_ALL_SENSORS;
    181	cmd_base.s.period = 0;
    182	cmd_base.s.sensor_id = 0;
    183
    184	writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
    185}
    186
    187static const struct dmi_system_id dmi_sensor_mask_overrides[] = {
    188	{
    189		.matches = {
    190			DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 13-ag0xxx"),
    191		},
    192		.driver_data = (void *)(ACEL_EN | MAGNO_EN),
    193	},
    194	{
    195		.matches = {
    196			DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 15-cp0xxx"),
    197		},
    198		.driver_data = (void *)(ACEL_EN | MAGNO_EN),
    199	},
    200	{ }
    201};
    202
    203int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
    204{
    205	int activestatus, num_of_sensors = 0;
    206	const struct dmi_system_id *dmi_id;
    207
    208	if (sensor_mask_override == -1) {
    209		dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
    210		if (dmi_id)
    211			sensor_mask_override = (long)dmi_id->driver_data;
    212	}
    213
    214	if (sensor_mask_override >= 0) {
    215		activestatus = sensor_mask_override;
    216	} else {
    217		activestatus = privdata->mp2_acs >> 4;
    218	}
    219
    220	if (ACEL_EN  & activestatus)
    221		sensor_id[num_of_sensors++] = accel_idx;
    222
    223	if (GYRO_EN & activestatus)
    224		sensor_id[num_of_sensors++] = gyro_idx;
    225
    226	if (MAGNO_EN & activestatus)
    227		sensor_id[num_of_sensors++] = mag_idx;
    228
    229	if (ALS_EN & activestatus)
    230		sensor_id[num_of_sensors++] = als_idx;
    231
    232	if (HPD_EN & activestatus)
    233		sensor_id[num_of_sensors++] = HPD_IDX;
    234
    235	return num_of_sensors;
    236}
    237
    238static void amd_mp2_pci_remove(void *privdata)
    239{
    240	struct amd_mp2_dev *mp2 = privdata;
    241	amd_sfh_hid_client_deinit(privdata);
    242	mp2->mp2_ops->stop_all(mp2);
    243	pci_intx(mp2->pdev, false);
    244	amd_sfh_clear_intr(mp2);
    245}
    246
    247static const struct amd_mp2_ops amd_sfh_ops_v2 = {
    248	.start = amd_start_sensor_v2,
    249	.stop = amd_stop_sensor_v2,
    250	.stop_all = amd_stop_all_sensor_v2,
    251	.response = amd_sfh_wait_response_v2,
    252	.clear_intr = amd_sfh_clear_intr_v2,
    253	.init_intr = amd_sfh_irq_init_v2,
    254	.discovery_status = amd_sfh_dis_sts_v2,
    255};
    256
    257static const struct amd_mp2_ops amd_sfh_ops = {
    258	.start = amd_start_sensor,
    259	.stop = amd_stop_sensor,
    260	.stop_all = amd_stop_all_sensors,
    261};
    262
    263static void mp2_select_ops(struct amd_mp2_dev *privdata)
    264{
    265	u8 acs;
    266
    267	privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
    268	acs = privdata->mp2_acs & GENMASK(3, 0);
    269
    270	switch (acs) {
    271	case V2_STATUS:
    272		privdata->mp2_ops = &amd_sfh_ops_v2;
    273		break;
    274	default:
    275		privdata->mp2_ops = &amd_sfh_ops;
    276		break;
    277	}
    278}
    279
    280static int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
    281{
    282	if (privdata->mp2_ops->init_intr)
    283		return privdata->mp2_ops->init_intr(privdata);
    284
    285	return 0;
    286}
    287
    288static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
    289{
    290	struct amd_mp2_dev *privdata;
    291	int rc;
    292
    293	privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
    294	if (!privdata)
    295		return -ENOMEM;
    296
    297	privdata->pdev = pdev;
    298	dev_set_drvdata(&pdev->dev, privdata);
    299	rc = pcim_enable_device(pdev);
    300	if (rc)
    301		return rc;
    302
    303	rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
    304	if (rc)
    305		return rc;
    306
    307	privdata->mmio = pcim_iomap_table(pdev)[2];
    308	pci_set_master(pdev);
    309	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
    310	if (rc) {
    311		dev_err(&pdev->dev, "failed to set DMA mask\n");
    312		return rc;
    313	}
    314
    315	privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
    316	if (!privdata->cl_data)
    317		return -ENOMEM;
    318
    319	mp2_select_ops(privdata);
    320
    321	rc = amd_sfh_irq_init(privdata);
    322	if (rc) {
    323		dev_err(&pdev->dev, "amd_sfh_irq_init failed\n");
    324		return rc;
    325	}
    326
    327	rc = amd_sfh_hid_client_init(privdata);
    328	if (rc) {
    329		amd_sfh_clear_intr(privdata);
    330		dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
    331		return rc;
    332	}
    333
    334	amd_sfh_clear_intr(privdata);
    335
    336	return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
    337}
    338
    339static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
    340{
    341	struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
    342	struct amdtp_cl_data *cl_data = mp2->cl_data;
    343	struct amd_mp2_sensor_info info;
    344	int i, status;
    345
    346	for (i = 0; i < cl_data->num_hid_devices; i++) {
    347		if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
    348			info.period = AMD_SFH_IDLE_LOOP;
    349			info.sensor_idx = cl_data->sensor_idx[i];
    350			info.dma_address = cl_data->sensor_dma_addr[i];
    351			mp2->mp2_ops->start(mp2, info);
    352			status = amd_sfh_wait_for_response
    353					(mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
    354			if (status == SENSOR_ENABLED)
    355				cl_data->sensor_sts[i] = SENSOR_ENABLED;
    356			dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
    357				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    358				cl_data->sensor_sts[i]);
    359		}
    360	}
    361
    362	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
    363	amd_sfh_clear_intr(mp2);
    364
    365	return 0;
    366}
    367
    368static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
    369{
    370	struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
    371	struct amdtp_cl_data *cl_data = mp2->cl_data;
    372	int i, status;
    373
    374	for (i = 0; i < cl_data->num_hid_devices; i++) {
    375		if (cl_data->sensor_idx[i] != HPD_IDX &&
    376		    cl_data->sensor_sts[i] == SENSOR_ENABLED) {
    377			mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
    378			status = amd_sfh_wait_for_response
    379					(mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
    380			if (status != SENSOR_ENABLED)
    381				cl_data->sensor_sts[i] = SENSOR_DISABLED;
    382			dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
    383				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    384				cl_data->sensor_sts[i]);
    385		}
    386	}
    387
    388	cancel_delayed_work_sync(&cl_data->work_buffer);
    389	amd_sfh_clear_intr(mp2);
    390
    391	return 0;
    392}
    393
    394static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
    395		amd_mp2_pci_resume);
    396
    397static const struct pci_device_id amd_mp2_pci_tbl[] = {
    398	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
    399	{ }
    400};
    401MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
    402
    403static struct pci_driver amd_mp2_pci_driver = {
    404	.name		= DRIVER_NAME,
    405	.id_table	= amd_mp2_pci_tbl,
    406	.probe		= amd_mp2_pci_probe,
    407	.driver.pm	= &amd_mp2_pm_ops,
    408};
    409module_pci_driver(amd_mp2_pci_driver);
    410
    411MODULE_DESCRIPTION(DRIVER_DESC);
    412MODULE_LICENSE("Dual BSD/GPL");
    413MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
    414MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
    415MODULE_AUTHOR("Basavaraj Natikar <Basavaraj.Natikar@amd.com>");