File Index
Files and directories
Sign in
FILE

dfl-fme-error.c

File preview with syntax highlighting.

linux-6.19.14/drivers/fpga/dfl-fme-error.c C
  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_dev_data *fdata = to_dfl_feature_dev_data(dev);
 46	void __iomem *base;
 47	u64 value;
 48
 49	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
 50
 51	mutex_lock(&fdata->lock);
 52	value = readq(base + PCIE0_ERROR);
 53	mutex_unlock(&fdata->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_dev_data *fdata = to_dfl_feature_dev_data(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(fdata, FME_FEATURE_ID_GLOBAL_ERR);
 71
 72	mutex_lock(&fdata->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(&fdata->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_dev_data *fdata = to_dfl_feature_dev_data(dev);
 91	void __iomem *base;
 92	u64 value;
 93
 94	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
 95
 96	mutex_lock(&fdata->lock);
 97	value = readq(base + PCIE1_ERROR);
 98	mutex_unlock(&fdata->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_dev_data *fdata = to_dfl_feature_dev_data(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(fdata, FME_FEATURE_ID_GLOBAL_ERR);
116
117	mutex_lock(&fdata->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(&fdata->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	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
136	void __iomem *base;
137
138	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
139
140	return sprintf(buf, "0x%llx\n",
141		       (unsigned long long)readq(base + RAS_NONFAT_ERROR));
142}
143static DEVICE_ATTR_RO(nonfatal_errors);
144
145static ssize_t catfatal_errors_show(struct device *dev,
146				    struct device_attribute *attr, char *buf)
147{
148	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
149	void __iomem *base;
150
151	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
152
153	return sprintf(buf, "0x%llx\n",
154		       (unsigned long long)readq(base + RAS_CATFAT_ERROR));
155}
156static DEVICE_ATTR_RO(catfatal_errors);
157
158static ssize_t inject_errors_show(struct device *dev,
159				  struct device_attribute *attr, char *buf)
160{
161	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
162	void __iomem *base;
163	u64 v;
164
165	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
166
167	mutex_lock(&fdata->lock);
168	v = readq(base + RAS_ERROR_INJECT);
169	mutex_unlock(&fdata->lock);
170
171	return sprintf(buf, "0x%llx\n",
172		       (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v));
173}
174
175static ssize_t inject_errors_store(struct device *dev,
176				   struct device_attribute *attr,
177				   const char *buf, size_t count)
178{
179	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
180	void __iomem *base;
181	u8 inject_error;
182	u64 v;
183
184	if (kstrtou8(buf, 0, &inject_error))
185		return -EINVAL;
186
187	if (inject_error & ~INJECT_ERROR_MASK)
188		return -EINVAL;
189
190	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
191
192	mutex_lock(&fdata->lock);
193	v = readq(base + RAS_ERROR_INJECT);
194	v &= ~INJECT_ERROR_MASK;
195	v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error);
196	writeq(v, base + RAS_ERROR_INJECT);
197	mutex_unlock(&fdata->lock);
198
199	return count;
200}
201static DEVICE_ATTR_RW(inject_errors);
202
203static ssize_t fme_errors_show(struct device *dev,
204			       struct device_attribute *attr, char *buf)
205{
206	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
207	void __iomem *base;
208	u64 value;
209
210	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
211
212	mutex_lock(&fdata->lock);
213	value = readq(base + FME_ERROR);
214	mutex_unlock(&fdata->lock);
215
216	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
217}
218
219static ssize_t fme_errors_store(struct device *dev,
220				struct device_attribute *attr,
221				const char *buf, size_t count)
222{
223	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
224	void __iomem *base;
225	u64 v, val;
226	int ret = 0;
227
228	if (kstrtou64(buf, 0, &val))
229		return -EINVAL;
230
231	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
232
233	mutex_lock(&fdata->lock);
234	writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK);
235
236	v = readq(base + FME_ERROR);
237	if (val == v)
238		writeq(v, base + FME_ERROR);
239	else
240		ret = -EINVAL;
241
242	/* Workaround: disable MBP_ERROR if feature revision is 0 */
243	writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR,
244	       base + FME_ERROR_MASK);
245	mutex_unlock(&fdata->lock);
246	return ret ? ret : count;
247}
248static DEVICE_ATTR_RW(fme_errors);
249
250static ssize_t first_error_show(struct device *dev,
251				struct device_attribute *attr, char *buf)
252{
253	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
254	void __iomem *base;
255	u64 value;
256
257	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
258
259	mutex_lock(&fdata->lock);
260	value = readq(base + FME_FIRST_ERROR);
261	mutex_unlock(&fdata->lock);
262
263	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
264}
265static DEVICE_ATTR_RO(first_error);
266
267static ssize_t next_error_show(struct device *dev,
268			       struct device_attribute *attr, char *buf)
269{
270	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
271	void __iomem *base;
272	u64 value;
273
274	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
275
276	mutex_lock(&fdata->lock);
277	value = readq(base + FME_NEXT_ERROR);
278	mutex_unlock(&fdata->lock);
279
280	return sprintf(buf, "0x%llx\n", (unsigned long long)value);
281}
282static DEVICE_ATTR_RO(next_error);
283
284static struct attribute *fme_global_err_attrs[] = {
285	&dev_attr_pcie0_errors.attr,
286	&dev_attr_pcie1_errors.attr,
287	&dev_attr_nonfatal_errors.attr,
288	&dev_attr_catfatal_errors.attr,
289	&dev_attr_inject_errors.attr,
290	&dev_attr_fme_errors.attr,
291	&dev_attr_first_error.attr,
292	&dev_attr_next_error.attr,
293	NULL,
294};
295
296static umode_t fme_global_err_attrs_visible(struct kobject *kobj,
297					    struct attribute *attr, int n)
298{
299	struct device *dev = kobj_to_dev(kobj);
300	struct dfl_feature_dev_data *fdata;
301
302	fdata = to_dfl_feature_dev_data(dev);
303	/*
304	 * sysfs entries are visible only if related private feature is
305	 * enumerated.
306	 */
307	if (!dfl_get_feature_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR))
308		return 0;
309
310	return attr->mode;
311}
312
313const struct attribute_group fme_global_err_group = {
314	.name       = "errors",
315	.attrs      = fme_global_err_attrs,
316	.is_visible = fme_global_err_attrs_visible,
317};
318
319static void fme_err_mask(struct device *dev, bool mask)
320{
321	struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev);
322	void __iomem *base;
323
324	base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR);
325
326	mutex_lock(&fdata->lock);
327
328	/* Workaround: keep MBP_ERROR always masked if revision is 0 */
329	if (dfl_feature_revision(base))
330		writeq(mask ? ERROR_MASK : 0, base + FME_ERROR_MASK);
331	else
332		writeq(mask ? ERROR_MASK : MBP_ERROR, base + FME_ERROR_MASK);
333
334	writeq(mask ? ERROR_MASK : 0, base + PCIE0_ERROR_MASK);
335	writeq(mask ? ERROR_MASK : 0, base + PCIE1_ERROR_MASK);
336	writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK);
337	writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK);
338
339	mutex_unlock(&fdata->lock);
340}
341
342static int fme_global_err_init(struct platform_device *pdev,
343			       struct dfl_feature *feature)
344{
345	fme_err_mask(&pdev->dev, false);
346
347	return 0;
348}
349
350static void fme_global_err_uinit(struct platform_device *pdev,
351				 struct dfl_feature *feature)
352{
353	fme_err_mask(&pdev->dev, true);
354}
355
356static long
357fme_global_error_ioctl(struct platform_device *pdev,
358		       struct dfl_feature *feature,
359		       unsigned int cmd, unsigned long arg)
360{
361	switch (cmd) {
362	case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
363		return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
364	case DFL_FPGA_FME_ERR_SET_IRQ:
365		return dfl_feature_ioctl_set_irq(pdev, feature, arg);
366	default:
367		dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
368		return -ENODEV;
369	}
370}
371
372const struct dfl_feature_id fme_global_err_id_table[] = {
373	{.id = FME_FEATURE_ID_GLOBAL_ERR,},
374	{0,}
375};
376
377const struct dfl_feature_ops fme_global_err_ops = {
378	.init = fme_global_err_init,
379	.uinit = fme_global_err_uinit,
380	.ioctl = fme_global_error_ioctl,
381};
~/ Read-only file preview.