Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fpga/dfl-fme-error.c
26378 views
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 <[email protected]>
9
* Xiao Guangrong <[email protected]>
10
* Wu Hao <[email protected]>
11
* Joseph Grecco <[email protected]>
12
* Enno Luebbers <[email protected]>
13
* Tim Whisonant <[email protected]>
14
* Ananda Ravuri <[email protected]>
15
* Mitchel, Henry <[email protected]>
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
42
static 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
58
static 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
}
85
static DEVICE_ATTR_RW(pcie0_errors);
86
87
static 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
103
static 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
}
130
static DEVICE_ATTR_RW(pcie1_errors);
131
132
static 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
}
143
static DEVICE_ATTR_RO(nonfatal_errors);
144
145
static 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
}
156
static DEVICE_ATTR_RO(catfatal_errors);
157
158
static 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
175
static 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
}
201
static DEVICE_ATTR_RW(inject_errors);
202
203
static 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
219
static 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
}
248
static DEVICE_ATTR_RW(fme_errors);
249
250
static 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
}
265
static DEVICE_ATTR_RO(first_error);
266
267
static 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
}
282
static DEVICE_ATTR_RO(next_error);
283
284
static 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
296
static 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
313
const 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
319
static 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
342
static 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
350
static void fme_global_err_uinit(struct platform_device *pdev,
351
struct dfl_feature *feature)
352
{
353
fme_err_mask(&pdev->dev, true);
354
}
355
356
static long
357
fme_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
372
const struct dfl_feature_id fme_global_err_id_table[] = {
373
{.id = FME_FEATURE_ID_GLOBAL_ERR,},
374
{0,}
375
};
376
377
const 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
};
382
383