18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for FPGA Management Engine Error Management
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2019 Intel Corporation, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Authors:
88c2ecf20Sopenharmony_ci *   Kang Luwei <luwei.kang@intel.com>
98c2ecf20Sopenharmony_ci *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
108c2ecf20Sopenharmony_ci *   Wu Hao <hao.wu@intel.com>
118c2ecf20Sopenharmony_ci *   Joseph Grecco <joe.grecco@intel.com>
128c2ecf20Sopenharmony_ci *   Enno Luebbers <enno.luebbers@intel.com>
138c2ecf20Sopenharmony_ci *   Tim Whisonant <tim.whisonant@intel.com>
148c2ecf20Sopenharmony_ci *   Ananda Ravuri <ananda.ravuri@intel.com>
158c2ecf20Sopenharmony_ci *   Mitchel, Henry <henry.mitchel@intel.com>
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/fpga-dfl.h>
198c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "dfl.h"
228c2ecf20Sopenharmony_ci#include "dfl-fme.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define FME_ERROR_MASK		0x8
258c2ecf20Sopenharmony_ci#define FME_ERROR		0x10
268c2ecf20Sopenharmony_ci#define MBP_ERROR		BIT_ULL(6)
278c2ecf20Sopenharmony_ci#define PCIE0_ERROR_MASK	0x18
288c2ecf20Sopenharmony_ci#define PCIE0_ERROR		0x20
298c2ecf20Sopenharmony_ci#define PCIE1_ERROR_MASK	0x28
308c2ecf20Sopenharmony_ci#define PCIE1_ERROR		0x30
318c2ecf20Sopenharmony_ci#define FME_FIRST_ERROR		0x38
328c2ecf20Sopenharmony_ci#define FME_NEXT_ERROR		0x40
338c2ecf20Sopenharmony_ci#define RAS_NONFAT_ERROR_MASK	0x48
348c2ecf20Sopenharmony_ci#define RAS_NONFAT_ERROR	0x50
358c2ecf20Sopenharmony_ci#define RAS_CATFAT_ERROR_MASK	0x58
368c2ecf20Sopenharmony_ci#define RAS_CATFAT_ERROR	0x60
378c2ecf20Sopenharmony_ci#define RAS_ERROR_INJECT	0x68
388c2ecf20Sopenharmony_ci#define INJECT_ERROR_MASK	GENMASK_ULL(2, 0)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define ERROR_MASK		GENMASK_ULL(63, 0)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic ssize_t pcie0_errors_show(struct device *dev,
438c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
468c2ecf20Sopenharmony_ci	void __iomem *base;
478c2ecf20Sopenharmony_ci	u64 value;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
528c2ecf20Sopenharmony_ci	value = readq(base + PCIE0_ERROR);
538c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic ssize_t pcie0_errors_store(struct device *dev,
598c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
608c2ecf20Sopenharmony_ci				  const char *buf, size_t count)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
638c2ecf20Sopenharmony_ci	void __iomem *base;
648c2ecf20Sopenharmony_ci	int ret = 0;
658c2ecf20Sopenharmony_ci	u64 v, val;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (kstrtou64(buf, 0, &val))
688c2ecf20Sopenharmony_ci		return -EINVAL;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
738c2ecf20Sopenharmony_ci	writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	v = readq(base + PCIE0_ERROR);
768c2ecf20Sopenharmony_ci	if (val == v)
778c2ecf20Sopenharmony_ci		writeq(v, base + PCIE0_ERROR);
788c2ecf20Sopenharmony_ci	else
798c2ecf20Sopenharmony_ci		ret = -EINVAL;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	writeq(0ULL, base + PCIE0_ERROR_MASK);
828c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
838c2ecf20Sopenharmony_ci	return ret ? ret : count;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pcie0_errors);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic ssize_t pcie1_errors_show(struct device *dev,
888c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
918c2ecf20Sopenharmony_ci	void __iomem *base;
928c2ecf20Sopenharmony_ci	u64 value;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
978c2ecf20Sopenharmony_ci	value = readq(base + PCIE1_ERROR);
988c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic ssize_t pcie1_errors_store(struct device *dev,
1048c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
1058c2ecf20Sopenharmony_ci				  const char *buf, size_t count)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
1088c2ecf20Sopenharmony_ci	void __iomem *base;
1098c2ecf20Sopenharmony_ci	int ret = 0;
1108c2ecf20Sopenharmony_ci	u64 v, val;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (kstrtou64(buf, 0, &val))
1138c2ecf20Sopenharmony_ci		return -EINVAL;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
1188c2ecf20Sopenharmony_ci	writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	v = readq(base + PCIE1_ERROR);
1218c2ecf20Sopenharmony_ci	if (val == v)
1228c2ecf20Sopenharmony_ci		writeq(v, base + PCIE1_ERROR);
1238c2ecf20Sopenharmony_ci	else
1248c2ecf20Sopenharmony_ci		ret = -EINVAL;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	writeq(0ULL, base + PCIE1_ERROR_MASK);
1278c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
1288c2ecf20Sopenharmony_ci	return ret ? ret : count;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pcie1_errors);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic ssize_t nonfatal_errors_show(struct device *dev,
1338c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	void __iomem *base;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n",
1408c2ecf20Sopenharmony_ci		       (unsigned long long)readq(base + RAS_NONFAT_ERROR));
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(nonfatal_errors);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic ssize_t catfatal_errors_show(struct device *dev,
1458c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	void __iomem *base;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n",
1528c2ecf20Sopenharmony_ci		       (unsigned long long)readq(base + RAS_CATFAT_ERROR));
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(catfatal_errors);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic ssize_t inject_errors_show(struct device *dev,
1578c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
1608c2ecf20Sopenharmony_ci	void __iomem *base;
1618c2ecf20Sopenharmony_ci	u64 v;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
1668c2ecf20Sopenharmony_ci	v = readq(base + RAS_ERROR_INJECT);
1678c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n",
1708c2ecf20Sopenharmony_ci		       (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v));
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic ssize_t inject_errors_store(struct device *dev,
1748c2ecf20Sopenharmony_ci				   struct device_attribute *attr,
1758c2ecf20Sopenharmony_ci				   const char *buf, size_t count)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
1788c2ecf20Sopenharmony_ci	void __iomem *base;
1798c2ecf20Sopenharmony_ci	u8 inject_error;
1808c2ecf20Sopenharmony_ci	u64 v;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (kstrtou8(buf, 0, &inject_error))
1838c2ecf20Sopenharmony_ci		return -EINVAL;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (inject_error & ~INJECT_ERROR_MASK)
1868c2ecf20Sopenharmony_ci		return -EINVAL;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
1918c2ecf20Sopenharmony_ci	v = readq(base + RAS_ERROR_INJECT);
1928c2ecf20Sopenharmony_ci	v &= ~INJECT_ERROR_MASK;
1938c2ecf20Sopenharmony_ci	v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error);
1948c2ecf20Sopenharmony_ci	writeq(v, base + RAS_ERROR_INJECT);
1958c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return count;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(inject_errors);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic ssize_t fme_errors_show(struct device *dev,
2028c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
2058c2ecf20Sopenharmony_ci	void __iomem *base;
2068c2ecf20Sopenharmony_ci	u64 value;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
2118c2ecf20Sopenharmony_ci	value = readq(base + FME_ERROR);
2128c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic ssize_t fme_errors_store(struct device *dev,
2188c2ecf20Sopenharmony_ci				struct device_attribute *attr,
2198c2ecf20Sopenharmony_ci				const char *buf, size_t count)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
2228c2ecf20Sopenharmony_ci	void __iomem *base;
2238c2ecf20Sopenharmony_ci	u64 v, val;
2248c2ecf20Sopenharmony_ci	int ret = 0;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (kstrtou64(buf, 0, &val))
2278c2ecf20Sopenharmony_ci		return -EINVAL;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
2328c2ecf20Sopenharmony_ci	writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	v = readq(base + FME_ERROR);
2358c2ecf20Sopenharmony_ci	if (val == v)
2368c2ecf20Sopenharmony_ci		writeq(v, base + FME_ERROR);
2378c2ecf20Sopenharmony_ci	else
2388c2ecf20Sopenharmony_ci		ret = -EINVAL;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Workaround: disable MBP_ERROR if feature revision is 0 */
2418c2ecf20Sopenharmony_ci	writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR,
2428c2ecf20Sopenharmony_ci	       base + FME_ERROR_MASK);
2438c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
2448c2ecf20Sopenharmony_ci	return ret ? ret : count;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fme_errors);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic ssize_t first_error_show(struct device *dev,
2498c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
2528c2ecf20Sopenharmony_ci	void __iomem *base;
2538c2ecf20Sopenharmony_ci	u64 value;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
2588c2ecf20Sopenharmony_ci	value = readq(base + FME_FIRST_ERROR);
2598c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(first_error);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic ssize_t next_error_show(struct device *dev,
2668c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
2698c2ecf20Sopenharmony_ci	void __iomem *base;
2708c2ecf20Sopenharmony_ci	u64 value;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
2758c2ecf20Sopenharmony_ci	value = readq(base + FME_NEXT_ERROR);
2768c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(next_error);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic struct attribute *fme_global_err_attrs[] = {
2838c2ecf20Sopenharmony_ci	&dev_attr_pcie0_errors.attr,
2848c2ecf20Sopenharmony_ci	&dev_attr_pcie1_errors.attr,
2858c2ecf20Sopenharmony_ci	&dev_attr_nonfatal_errors.attr,
2868c2ecf20Sopenharmony_ci	&dev_attr_catfatal_errors.attr,
2878c2ecf20Sopenharmony_ci	&dev_attr_inject_errors.attr,
2888c2ecf20Sopenharmony_ci	&dev_attr_fme_errors.attr,
2898c2ecf20Sopenharmony_ci	&dev_attr_first_error.attr,
2908c2ecf20Sopenharmony_ci	&dev_attr_next_error.attr,
2918c2ecf20Sopenharmony_ci	NULL,
2928c2ecf20Sopenharmony_ci};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic umode_t fme_global_err_attrs_visible(struct kobject *kobj,
2958c2ecf20Sopenharmony_ci					    struct attribute *attr, int n)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * sysfs entries are visible only if related private feature is
3018c2ecf20Sopenharmony_ci	 * enumerated.
3028c2ecf20Sopenharmony_ci	 */
3038c2ecf20Sopenharmony_ci	if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR))
3048c2ecf20Sopenharmony_ci		return 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return attr->mode;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ciconst struct attribute_group fme_global_err_group = {
3108c2ecf20Sopenharmony_ci	.name       = "errors",
3118c2ecf20Sopenharmony_ci	.attrs      = fme_global_err_attrs,
3128c2ecf20Sopenharmony_ci	.is_visible = fme_global_err_attrs_visible,
3138c2ecf20Sopenharmony_ci};
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic void fme_err_mask(struct device *dev, bool mask)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
3188c2ecf20Sopenharmony_ci	void __iomem *base;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mutex_lock(&pdata->lock);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* Workaround: keep MBP_ERROR always masked if revision is 0 */
3258c2ecf20Sopenharmony_ci	if (dfl_feature_revision(base))
3268c2ecf20Sopenharmony_ci		writeq(mask ? ERROR_MASK : 0, base + FME_ERROR_MASK);
3278c2ecf20Sopenharmony_ci	else
3288c2ecf20Sopenharmony_ci		writeq(mask ? ERROR_MASK : MBP_ERROR, base + FME_ERROR_MASK);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	writeq(mask ? ERROR_MASK : 0, base + PCIE0_ERROR_MASK);
3318c2ecf20Sopenharmony_ci	writeq(mask ? ERROR_MASK : 0, base + PCIE1_ERROR_MASK);
3328c2ecf20Sopenharmony_ci	writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK);
3338c2ecf20Sopenharmony_ci	writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	mutex_unlock(&pdata->lock);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int fme_global_err_init(struct platform_device *pdev,
3398c2ecf20Sopenharmony_ci			       struct dfl_feature *feature)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	fme_err_mask(&pdev->dev, false);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return 0;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void fme_global_err_uinit(struct platform_device *pdev,
3478c2ecf20Sopenharmony_ci				 struct dfl_feature *feature)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	fme_err_mask(&pdev->dev, true);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic long
3538c2ecf20Sopenharmony_cifme_global_error_ioctl(struct platform_device *pdev,
3548c2ecf20Sopenharmony_ci		       struct dfl_feature *feature,
3558c2ecf20Sopenharmony_ci		       unsigned int cmd, unsigned long arg)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	switch (cmd) {
3588c2ecf20Sopenharmony_ci	case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
3598c2ecf20Sopenharmony_ci		return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
3608c2ecf20Sopenharmony_ci	case DFL_FPGA_FME_ERR_SET_IRQ:
3618c2ecf20Sopenharmony_ci		return dfl_feature_ioctl_set_irq(pdev, feature, arg);
3628c2ecf20Sopenharmony_ci	default:
3638c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
3648c2ecf20Sopenharmony_ci		return -ENODEV;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ciconst struct dfl_feature_id fme_global_err_id_table[] = {
3698c2ecf20Sopenharmony_ci	{.id = FME_FEATURE_ID_GLOBAL_ERR,},
3708c2ecf20Sopenharmony_ci	{0,}
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ciconst struct dfl_feature_ops fme_global_err_ops = {
3748c2ecf20Sopenharmony_ci	.init = fme_global_err_init,
3758c2ecf20Sopenharmony_ci	.uinit = fme_global_err_uinit,
3768c2ecf20Sopenharmony_ci	.ioctl = fme_global_error_ioctl,
3778c2ecf20Sopenharmony_ci};
378