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