brintos

brintos / linux-shallow public Read only

0
0
Text · 9.6 KiB · 51c2892 Raw
378 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for FPGA Management Engine Error Management4 *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		0x825#define FME_ERROR		0x1026#define MBP_ERROR		BIT_ULL(6)27#define PCIE0_ERROR_MASK	0x1828#define PCIE0_ERROR		0x2029#define PCIE1_ERROR_MASK	0x2830#define PCIE1_ERROR		0x3031#define FME_FIRST_ERROR		0x3832#define FME_NEXT_ERROR		0x4033#define RAS_NONFAT_ERROR_MASK	0x4834#define RAS_NONFAT_ERROR	0x5035#define RAS_CATFAT_ERROR_MASK	0x5836#define RAS_CATFAT_ERROR	0x6037#define RAS_ERROR_INJECT	0x6838#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	else79		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	else124		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	else238		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 is301	 * 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	else328		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 long353fme_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};378