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

dfl-fme-error.c (9849B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for FPGA Management Engine Error Management
      4 *
      5 * Copyright 2019 Intel Corporation, Inc.
      6 *
      7 * Authors:
      8 *   Kang Luwei <luwei.kang@intel.com>
      9 *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
     10 *   Wu Hao <hao.wu@intel.com>
     11 *   Joseph Grecco <joe.grecco@intel.com>
     12 *   Enno Luebbers <enno.luebbers@intel.com>
     13 *   Tim Whisonant <tim.whisonant@intel.com>
     14 *   Ananda Ravuri <ananda.ravuri@intel.com>
     15 *   Mitchel, Henry <henry.mitchel@intel.com>
     16 */
     17
     18#include <linux/fpga-dfl.h>
     19#include <linux/uaccess.h>
     20
     21#include "dfl.h"
     22#include "dfl-fme.h"
     23
     24#define FME_ERROR_MASK		0x8
     25#define FME_ERROR		0x10
     26#define MBP_ERROR		BIT_ULL(6)
     27#define PCIE0_ERROR_MASK	0x18
     28#define PCIE0_ERROR		0x20
     29#define PCIE1_ERROR_MASK	0x28
     30#define PCIE1_ERROR		0x30
     31#define FME_FIRST_ERROR		0x38
     32#define FME_NEXT_ERROR		0x40
     33#define RAS_NONFAT_ERROR_MASK	0x48
     34#define RAS_NONFAT_ERROR	0x50
     35#define RAS_CATFAT_ERROR_MASK	0x58
     36#define RAS_CATFAT_ERROR	0x60
     37#define RAS_ERROR_INJECT	0x68
     38#define INJECT_ERROR_MASK	GENMASK_ULL(2, 0)
     39
     40#define ERROR_MASK		GENMASK_ULL(63, 0)
     41
     42static ssize_t pcie0_errors_show(struct device *dev,
     43				 struct device_attribute *attr, char *buf)
     44{
     45	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
     46	void __iomem *base;
     47	u64 value;
     48
     49	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
     50
     51	mutex_lock(&pdata->lock);
     52	value = readq(base + PCIE0_ERROR);
     53	mutex_unlock(&pdata->lock);
     54
     55	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
     56}
     57
     58static ssize_t pcie0_errors_store(struct device *dev,
     59				  struct device_attribute *attr,
     60				  const char *buf, size_t count)
     61{
     62	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
     63	void __iomem *base;
     64	int ret = 0;
     65	u64 v, val;
     66
     67	if (kstrtou64(buf, 0, &val))
     68		return -EINVAL;
     69
     70	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
     71
     72	mutex_lock(&pdata->lock);
     73	writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK);
     74
     75	v = readq(base + PCIE0_ERROR);
     76	if (val == v)
     77		writeq(v, base + PCIE0_ERROR);
     78	else
     79		ret = -EINVAL;
     80
     81	writeq(0ULL, base + PCIE0_ERROR_MASK);
     82	mutex_unlock(&pdata->lock);
     83	return ret ? ret : count;
     84}
     85static DEVICE_ATTR_RW(pcie0_errors);
     86
     87static ssize_t pcie1_errors_show(struct device *dev,
     88				 struct device_attribute *attr, char *buf)
     89{
     90	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
     91	void __iomem *base;
     92	u64 value;
     93
     94	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
     95
     96	mutex_lock(&pdata->lock);
     97	value = readq(base + PCIE1_ERROR);
     98	mutex_unlock(&pdata->lock);
     99
    100	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
    101}
    102
    103static ssize_t pcie1_errors_store(struct device *dev,
    104				  struct device_attribute *attr,
    105				  const char *buf, size_t count)
    106{
    107	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    108	void __iomem *base;
    109	int ret = 0;
    110	u64 v, val;
    111
    112	if (kstrtou64(buf, 0, &val))
    113		return -EINVAL;
    114
    115	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    116
    117	mutex_lock(&pdata->lock);
    118	writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK);
    119
    120	v = readq(base + PCIE1_ERROR);
    121	if (val == v)
    122		writeq(v, base + PCIE1_ERROR);
    123	else
    124		ret = -EINVAL;
    125
    126	writeq(0ULL, base + PCIE1_ERROR_MASK);
    127	mutex_unlock(&pdata->lock);
    128	return ret ? ret : count;
    129}
    130static DEVICE_ATTR_RW(pcie1_errors);
    131
    132static ssize_t nonfatal_errors_show(struct device *dev,
    133				    struct device_attribute *attr, char *buf)
    134{
    135	void __iomem *base;
    136
    137	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    138
    139	return sprintf(buf, "0x%llx\n",
    140		       (unsigned long long)readq(base + RAS_NONFAT_ERROR));
    141}
    142static DEVICE_ATTR_RO(nonfatal_errors);
    143
    144static ssize_t catfatal_errors_show(struct device *dev,
    145				    struct device_attribute *attr, char *buf)
    146{
    147	void __iomem *base;
    148
    149	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    150
    151	return sprintf(buf, "0x%llx\n",
    152		       (unsigned long long)readq(base + RAS_CATFAT_ERROR));
    153}
    154static DEVICE_ATTR_RO(catfatal_errors);
    155
    156static ssize_t inject_errors_show(struct device *dev,
    157				  struct device_attribute *attr, char *buf)
    158{
    159	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    160	void __iomem *base;
    161	u64 v;
    162
    163	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    164
    165	mutex_lock(&pdata->lock);
    166	v = readq(base + RAS_ERROR_INJECT);
    167	mutex_unlock(&pdata->lock);
    168
    169	return sprintf(buf, "0x%llx\n",
    170		       (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v));
    171}
    172
    173static ssize_t inject_errors_store(struct device *dev,
    174				   struct device_attribute *attr,
    175				   const char *buf, size_t count)
    176{
    177	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    178	void __iomem *base;
    179	u8 inject_error;
    180	u64 v;
    181
    182	if (kstrtou8(buf, 0, &inject_error))
    183		return -EINVAL;
    184
    185	if (inject_error & ~INJECT_ERROR_MASK)
    186		return -EINVAL;
    187
    188	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    189
    190	mutex_lock(&pdata->lock);
    191	v = readq(base + RAS_ERROR_INJECT);
    192	v &= ~INJECT_ERROR_MASK;
    193	v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error);
    194	writeq(v, base + RAS_ERROR_INJECT);
    195	mutex_unlock(&pdata->lock);
    196
    197	return count;
    198}
    199static DEVICE_ATTR_RW(inject_errors);
    200
    201static ssize_t fme_errors_show(struct device *dev,
    202			       struct device_attribute *attr, char *buf)
    203{
    204	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    205	void __iomem *base;
    206	u64 value;
    207
    208	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    209
    210	mutex_lock(&pdata->lock);
    211	value = readq(base + FME_ERROR);
    212	mutex_unlock(&pdata->lock);
    213
    214	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
    215}
    216
    217static ssize_t fme_errors_store(struct device *dev,
    218				struct device_attribute *attr,
    219				const char *buf, size_t count)
    220{
    221	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    222	void __iomem *base;
    223	u64 v, val;
    224	int ret = 0;
    225
    226	if (kstrtou64(buf, 0, &val))
    227		return -EINVAL;
    228
    229	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    230
    231	mutex_lock(&pdata->lock);
    232	writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK);
    233
    234	v = readq(base + FME_ERROR);
    235	if (val == v)
    236		writeq(v, base + FME_ERROR);
    237	else
    238		ret = -EINVAL;
    239
    240	/* Workaround: disable MBP_ERROR if feature revision is 0 */
    241	writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR,
    242	       base + FME_ERROR_MASK);
    243	mutex_unlock(&pdata->lock);
    244	return ret ? ret : count;
    245}
    246static DEVICE_ATTR_RW(fme_errors);
    247
    248static ssize_t first_error_show(struct device *dev,
    249				struct device_attribute *attr, char *buf)
    250{
    251	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    252	void __iomem *base;
    253	u64 value;
    254
    255	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    256
    257	mutex_lock(&pdata->lock);
    258	value = readq(base + FME_FIRST_ERROR);
    259	mutex_unlock(&pdata->lock);
    260
    261	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
    262}
    263static DEVICE_ATTR_RO(first_error);
    264
    265static ssize_t next_error_show(struct device *dev,
    266			       struct device_attribute *attr, char *buf)
    267{
    268	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    269	void __iomem *base;
    270	u64 value;
    271
    272	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    273
    274	mutex_lock(&pdata->lock);
    275	value = readq(base + FME_NEXT_ERROR);
    276	mutex_unlock(&pdata->lock);
    277
    278	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
    279}
    280static DEVICE_ATTR_RO(next_error);
    281
    282static struct attribute *fme_global_err_attrs[] = {
    283	&dev_attr_pcie0_errors.attr,
    284	&dev_attr_pcie1_errors.attr,
    285	&dev_attr_nonfatal_errors.attr,
    286	&dev_attr_catfatal_errors.attr,
    287	&dev_attr_inject_errors.attr,
    288	&dev_attr_fme_errors.attr,
    289	&dev_attr_first_error.attr,
    290	&dev_attr_next_error.attr,
    291	NULL,
    292};
    293
    294static umode_t fme_global_err_attrs_visible(struct kobject *kobj,
    295					    struct attribute *attr, int n)
    296{
    297	struct device *dev = kobj_to_dev(kobj);
    298
    299	/*
    300	 * sysfs entries are visible only if related private feature is
    301	 * enumerated.
    302	 */
    303	if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR))
    304		return 0;
    305
    306	return attr->mode;
    307}
    308
    309const struct attribute_group fme_global_err_group = {
    310	.name       = "errors",
    311	.attrs      = fme_global_err_attrs,
    312	.is_visible = fme_global_err_attrs_visible,
    313};
    314
    315static void fme_err_mask(struct device *dev, bool mask)
    316{
    317	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
    318	void __iomem *base;
    319
    320	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
    321
    322	mutex_lock(&pdata->lock);
    323
    324	/* Workaround: keep MBP_ERROR always masked if revision is 0 */
    325	if (dfl_feature_revision(base))
    326		writeq(mask ? ERROR_MASK : 0, base + FME_ERROR_MASK);
    327	else
    328		writeq(mask ? ERROR_MASK : MBP_ERROR, base + FME_ERROR_MASK);
    329
    330	writeq(mask ? ERROR_MASK : 0, base + PCIE0_ERROR_MASK);
    331	writeq(mask ? ERROR_MASK : 0, base + PCIE1_ERROR_MASK);
    332	writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK);
    333	writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK);
    334
    335	mutex_unlock(&pdata->lock);
    336}
    337
    338static int fme_global_err_init(struct platform_device *pdev,
    339			       struct dfl_feature *feature)
    340{
    341	fme_err_mask(&pdev->dev, false);
    342
    343	return 0;
    344}
    345
    346static void fme_global_err_uinit(struct platform_device *pdev,
    347				 struct dfl_feature *feature)
    348{
    349	fme_err_mask(&pdev->dev, true);
    350}
    351
    352static long
    353fme_global_error_ioctl(struct platform_device *pdev,
    354		       struct dfl_feature *feature,
    355		       unsigned int cmd, unsigned long arg)
    356{
    357	switch (cmd) {
    358	case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
    359		return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
    360	case DFL_FPGA_FME_ERR_SET_IRQ:
    361		return dfl_feature_ioctl_set_irq(pdev, feature, arg);
    362	default:
    363		dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
    364		return -ENODEV;
    365	}
    366}
    367
    368const struct dfl_feature_id fme_global_err_id_table[] = {
    369	{.id = FME_FEATURE_ID_GLOBAL_ERR,},
    370	{0,}
    371};
    372
    373const struct dfl_feature_ops fme_global_err_ops = {
    374	.init = fme_global_err_init,
    375	.uinit = fme_global_err_uinit,
    376	.ioctl = fme_global_error_ioctl,
    377};