hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/fpga/dfl-fme-main.c
....@@ -14,8 +14,11 @@
1414 * Henry Mitchel <henry.mitchel@intel.com>
1515 */
1616
17
+#include <linux/hwmon.h>
18
+#include <linux/hwmon-sysfs.h>
1719 #include <linux/kernel.h>
1820 #include <linux/module.h>
21
+#include <linux/uaccess.h>
1922 #include <linux/fpga-dfl.h>
2023
2124 #include "dfl.h"
....@@ -72,50 +75,513 @@
7275 }
7376 static DEVICE_ATTR_RO(bitstream_metadata);
7477
75
-static const struct attribute *fme_hdr_attrs[] = {
78
+static ssize_t cache_size_show(struct device *dev,
79
+ struct device_attribute *attr, char *buf)
80
+{
81
+ void __iomem *base;
82
+ u64 v;
83
+
84
+ base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
85
+
86
+ v = readq(base + FME_HDR_CAP);
87
+
88
+ return sprintf(buf, "%u\n",
89
+ (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v));
90
+}
91
+static DEVICE_ATTR_RO(cache_size);
92
+
93
+static ssize_t fabric_version_show(struct device *dev,
94
+ struct device_attribute *attr, char *buf)
95
+{
96
+ void __iomem *base;
97
+ u64 v;
98
+
99
+ base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
100
+
101
+ v = readq(base + FME_HDR_CAP);
102
+
103
+ return sprintf(buf, "%u\n",
104
+ (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v));
105
+}
106
+static DEVICE_ATTR_RO(fabric_version);
107
+
108
+static ssize_t socket_id_show(struct device *dev,
109
+ struct device_attribute *attr, char *buf)
110
+{
111
+ void __iomem *base;
112
+ u64 v;
113
+
114
+ base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
115
+
116
+ v = readq(base + FME_HDR_CAP);
117
+
118
+ return sprintf(buf, "%u\n",
119
+ (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v));
120
+}
121
+static DEVICE_ATTR_RO(socket_id);
122
+
123
+static struct attribute *fme_hdr_attrs[] = {
76124 &dev_attr_ports_num.attr,
77125 &dev_attr_bitstream_id.attr,
78126 &dev_attr_bitstream_metadata.attr,
127
+ &dev_attr_cache_size.attr,
128
+ &dev_attr_fabric_version.attr,
129
+ &dev_attr_socket_id.attr,
79130 NULL,
80131 };
81132
82
-static int fme_hdr_init(struct platform_device *pdev,
83
- struct dfl_feature *feature)
133
+static const struct attribute_group fme_hdr_group = {
134
+ .attrs = fme_hdr_attrs,
135
+};
136
+
137
+static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
138
+ unsigned long arg)
84139 {
85
- void __iomem *base = feature->ioaddr;
86
- int ret;
140
+ struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
141
+ int port_id;
87142
88
- dev_dbg(&pdev->dev, "FME HDR Init.\n");
89
- dev_dbg(&pdev->dev, "FME cap %llx.\n",
90
- (unsigned long long)readq(base + FME_HDR_CAP));
143
+ if (get_user(port_id, (int __user *)arg))
144
+ return -EFAULT;
91145
92
- ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs);
93
- if (ret)
94
- return ret;
146
+ return dfl_fpga_cdev_release_port(cdev, port_id);
147
+}
148
+
149
+static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata,
150
+ unsigned long arg)
151
+{
152
+ struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
153
+ int port_id;
154
+
155
+ if (get_user(port_id, (int __user *)arg))
156
+ return -EFAULT;
157
+
158
+ return dfl_fpga_cdev_assign_port(cdev, port_id);
159
+}
160
+
161
+static long fme_hdr_ioctl(struct platform_device *pdev,
162
+ struct dfl_feature *feature,
163
+ unsigned int cmd, unsigned long arg)
164
+{
165
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
166
+
167
+ switch (cmd) {
168
+ case DFL_FPGA_FME_PORT_RELEASE:
169
+ return fme_hdr_ioctl_release_port(pdata, arg);
170
+ case DFL_FPGA_FME_PORT_ASSIGN:
171
+ return fme_hdr_ioctl_assign_port(pdata, arg);
172
+ }
173
+
174
+ return -ENODEV;
175
+}
176
+
177
+static const struct dfl_feature_id fme_hdr_id_table[] = {
178
+ {.id = FME_FEATURE_ID_HEADER,},
179
+ {0,}
180
+};
181
+
182
+static const struct dfl_feature_ops fme_hdr_ops = {
183
+ .ioctl = fme_hdr_ioctl,
184
+};
185
+
186
+#define FME_THERM_THRESHOLD 0x8
187
+#define TEMP_THRESHOLD1 GENMASK_ULL(6, 0)
188
+#define TEMP_THRESHOLD1_EN BIT_ULL(7)
189
+#define TEMP_THRESHOLD2 GENMASK_ULL(14, 8)
190
+#define TEMP_THRESHOLD2_EN BIT_ULL(15)
191
+#define TRIP_THRESHOLD GENMASK_ULL(30, 24)
192
+#define TEMP_THRESHOLD1_STATUS BIT_ULL(32) /* threshold1 reached */
193
+#define TEMP_THRESHOLD2_STATUS BIT_ULL(33) /* threshold2 reached */
194
+/* threshold1 policy: 0 - AP2 (90% throttle) / 1 - AP1 (50% throttle) */
195
+#define TEMP_THRESHOLD1_POLICY BIT_ULL(44)
196
+
197
+#define FME_THERM_RDSENSOR_FMT1 0x10
198
+#define FPGA_TEMPERATURE GENMASK_ULL(6, 0)
199
+
200
+#define FME_THERM_CAP 0x20
201
+#define THERM_NO_THROTTLE BIT_ULL(0)
202
+
203
+#define MD_PRE_DEG
204
+
205
+static bool fme_thermal_throttle_support(void __iomem *base)
206
+{
207
+ u64 v = readq(base + FME_THERM_CAP);
208
+
209
+ return FIELD_GET(THERM_NO_THROTTLE, v) ? false : true;
210
+}
211
+
212
+static umode_t thermal_hwmon_attrs_visible(const void *drvdata,
213
+ enum hwmon_sensor_types type,
214
+ u32 attr, int channel)
215
+{
216
+ const struct dfl_feature *feature = drvdata;
217
+
218
+ /* temperature is always supported, and check hardware cap for others */
219
+ if (attr == hwmon_temp_input)
220
+ return 0444;
221
+
222
+ return fme_thermal_throttle_support(feature->ioaddr) ? 0444 : 0;
223
+}
224
+
225
+static int thermal_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
226
+ u32 attr, int channel, long *val)
227
+{
228
+ struct dfl_feature *feature = dev_get_drvdata(dev);
229
+ u64 v;
230
+
231
+ switch (attr) {
232
+ case hwmon_temp_input:
233
+ v = readq(feature->ioaddr + FME_THERM_RDSENSOR_FMT1);
234
+ *val = (long)(FIELD_GET(FPGA_TEMPERATURE, v) * 1000);
235
+ break;
236
+ case hwmon_temp_max:
237
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
238
+ *val = (long)(FIELD_GET(TEMP_THRESHOLD1, v) * 1000);
239
+ break;
240
+ case hwmon_temp_crit:
241
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
242
+ *val = (long)(FIELD_GET(TEMP_THRESHOLD2, v) * 1000);
243
+ break;
244
+ case hwmon_temp_emergency:
245
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
246
+ *val = (long)(FIELD_GET(TRIP_THRESHOLD, v) * 1000);
247
+ break;
248
+ case hwmon_temp_max_alarm:
249
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
250
+ *val = (long)FIELD_GET(TEMP_THRESHOLD1_STATUS, v);
251
+ break;
252
+ case hwmon_temp_crit_alarm:
253
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
254
+ *val = (long)FIELD_GET(TEMP_THRESHOLD2_STATUS, v);
255
+ break;
256
+ default:
257
+ return -EOPNOTSUPP;
258
+ }
95259
96260 return 0;
97261 }
98262
99
-static void fme_hdr_uinit(struct platform_device *pdev,
100
- struct dfl_feature *feature)
263
+static const struct hwmon_ops thermal_hwmon_ops = {
264
+ .is_visible = thermal_hwmon_attrs_visible,
265
+ .read = thermal_hwmon_read,
266
+};
267
+
268
+static const struct hwmon_channel_info *thermal_hwmon_info[] = {
269
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_EMERGENCY |
270
+ HWMON_T_MAX | HWMON_T_MAX_ALARM |
271
+ HWMON_T_CRIT | HWMON_T_CRIT_ALARM),
272
+ NULL
273
+};
274
+
275
+static const struct hwmon_chip_info thermal_hwmon_chip_info = {
276
+ .ops = &thermal_hwmon_ops,
277
+ .info = thermal_hwmon_info,
278
+};
279
+
280
+static ssize_t temp1_max_policy_show(struct device *dev,
281
+ struct device_attribute *attr, char *buf)
101282 {
102
- dev_dbg(&pdev->dev, "FME HDR UInit.\n");
103
- sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs);
283
+ struct dfl_feature *feature = dev_get_drvdata(dev);
284
+ u64 v;
285
+
286
+ v = readq(feature->ioaddr + FME_THERM_THRESHOLD);
287
+
288
+ return sprintf(buf, "%u\n",
289
+ (unsigned int)FIELD_GET(TEMP_THRESHOLD1_POLICY, v));
104290 }
105291
106
-static const struct dfl_feature_ops fme_hdr_ops = {
107
- .init = fme_hdr_init,
108
- .uinit = fme_hdr_uinit,
292
+static DEVICE_ATTR_RO(temp1_max_policy);
293
+
294
+static struct attribute *thermal_extra_attrs[] = {
295
+ &dev_attr_temp1_max_policy.attr,
296
+ NULL,
297
+};
298
+
299
+static umode_t thermal_extra_attrs_visible(struct kobject *kobj,
300
+ struct attribute *attr, int index)
301
+{
302
+ struct device *dev = kobj_to_dev(kobj);
303
+ struct dfl_feature *feature = dev_get_drvdata(dev);
304
+
305
+ return fme_thermal_throttle_support(feature->ioaddr) ? attr->mode : 0;
306
+}
307
+
308
+static const struct attribute_group thermal_extra_group = {
309
+ .attrs = thermal_extra_attrs,
310
+ .is_visible = thermal_extra_attrs_visible,
311
+};
312
+__ATTRIBUTE_GROUPS(thermal_extra);
313
+
314
+static int fme_thermal_mgmt_init(struct platform_device *pdev,
315
+ struct dfl_feature *feature)
316
+{
317
+ struct device *hwmon;
318
+
319
+ /*
320
+ * create hwmon to allow userspace monitoring temperature and other
321
+ * threshold information.
322
+ *
323
+ * temp1_input -> FPGA device temperature
324
+ * temp1_max -> hardware threshold 1 -> 50% or 90% throttling
325
+ * temp1_crit -> hardware threshold 2 -> 100% throttling
326
+ * temp1_emergency -> hardware trip_threshold to shutdown FPGA
327
+ * temp1_max_alarm -> hardware threshold 1 alarm
328
+ * temp1_crit_alarm -> hardware threshold 2 alarm
329
+ *
330
+ * create device specific sysfs interfaces, e.g. read temp1_max_policy
331
+ * to understand the actual hardware throttling action (50% vs 90%).
332
+ *
333
+ * If hardware doesn't support automatic throttling per thresholds,
334
+ * then all above sysfs interfaces are not visible except temp1_input
335
+ * for temperature.
336
+ */
337
+ hwmon = devm_hwmon_device_register_with_info(&pdev->dev,
338
+ "dfl_fme_thermal", feature,
339
+ &thermal_hwmon_chip_info,
340
+ thermal_extra_groups);
341
+ if (IS_ERR(hwmon)) {
342
+ dev_err(&pdev->dev, "Fail to register thermal hwmon\n");
343
+ return PTR_ERR(hwmon);
344
+ }
345
+
346
+ return 0;
347
+}
348
+
349
+static const struct dfl_feature_id fme_thermal_mgmt_id_table[] = {
350
+ {.id = FME_FEATURE_ID_THERMAL_MGMT,},
351
+ {0,}
352
+};
353
+
354
+static const struct dfl_feature_ops fme_thermal_mgmt_ops = {
355
+ .init = fme_thermal_mgmt_init,
356
+};
357
+
358
+#define FME_PWR_STATUS 0x8
359
+#define FME_LATENCY_TOLERANCE BIT_ULL(18)
360
+#define PWR_CONSUMED GENMASK_ULL(17, 0)
361
+
362
+#define FME_PWR_THRESHOLD 0x10
363
+#define PWR_THRESHOLD1 GENMASK_ULL(6, 0) /* in Watts */
364
+#define PWR_THRESHOLD2 GENMASK_ULL(14, 8) /* in Watts */
365
+#define PWR_THRESHOLD_MAX 0x7f /* in Watts */
366
+#define PWR_THRESHOLD1_STATUS BIT_ULL(16)
367
+#define PWR_THRESHOLD2_STATUS BIT_ULL(17)
368
+
369
+#define FME_PWR_XEON_LIMIT 0x18
370
+#define XEON_PWR_LIMIT GENMASK_ULL(14, 0) /* in 0.1 Watts */
371
+#define XEON_PWR_EN BIT_ULL(15)
372
+#define FME_PWR_FPGA_LIMIT 0x20
373
+#define FPGA_PWR_LIMIT GENMASK_ULL(14, 0) /* in 0.1 Watts */
374
+#define FPGA_PWR_EN BIT_ULL(15)
375
+
376
+static int power_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
377
+ u32 attr, int channel, long *val)
378
+{
379
+ struct dfl_feature *feature = dev_get_drvdata(dev);
380
+ u64 v;
381
+
382
+ switch (attr) {
383
+ case hwmon_power_input:
384
+ v = readq(feature->ioaddr + FME_PWR_STATUS);
385
+ *val = (long)(FIELD_GET(PWR_CONSUMED, v) * 1000000);
386
+ break;
387
+ case hwmon_power_max:
388
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
389
+ *val = (long)(FIELD_GET(PWR_THRESHOLD1, v) * 1000000);
390
+ break;
391
+ case hwmon_power_crit:
392
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
393
+ *val = (long)(FIELD_GET(PWR_THRESHOLD2, v) * 1000000);
394
+ break;
395
+ case hwmon_power_max_alarm:
396
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
397
+ *val = (long)FIELD_GET(PWR_THRESHOLD1_STATUS, v);
398
+ break;
399
+ case hwmon_power_crit_alarm:
400
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
401
+ *val = (long)FIELD_GET(PWR_THRESHOLD2_STATUS, v);
402
+ break;
403
+ default:
404
+ return -EOPNOTSUPP;
405
+ }
406
+
407
+ return 0;
408
+}
409
+
410
+static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
411
+ u32 attr, int channel, long val)
412
+{
413
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev->parent);
414
+ struct dfl_feature *feature = dev_get_drvdata(dev);
415
+ int ret = 0;
416
+ u64 v;
417
+
418
+ val = clamp_val(val / 1000000, 0, PWR_THRESHOLD_MAX);
419
+
420
+ mutex_lock(&pdata->lock);
421
+
422
+ switch (attr) {
423
+ case hwmon_power_max:
424
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
425
+ v &= ~PWR_THRESHOLD1;
426
+ v |= FIELD_PREP(PWR_THRESHOLD1, val);
427
+ writeq(v, feature->ioaddr + FME_PWR_THRESHOLD);
428
+ break;
429
+ case hwmon_power_crit:
430
+ v = readq(feature->ioaddr + FME_PWR_THRESHOLD);
431
+ v &= ~PWR_THRESHOLD2;
432
+ v |= FIELD_PREP(PWR_THRESHOLD2, val);
433
+ writeq(v, feature->ioaddr + FME_PWR_THRESHOLD);
434
+ break;
435
+ default:
436
+ ret = -EOPNOTSUPP;
437
+ break;
438
+ }
439
+
440
+ mutex_unlock(&pdata->lock);
441
+
442
+ return ret;
443
+}
444
+
445
+static umode_t power_hwmon_attrs_visible(const void *drvdata,
446
+ enum hwmon_sensor_types type,
447
+ u32 attr, int channel)
448
+{
449
+ switch (attr) {
450
+ case hwmon_power_input:
451
+ case hwmon_power_max_alarm:
452
+ case hwmon_power_crit_alarm:
453
+ return 0444;
454
+ case hwmon_power_max:
455
+ case hwmon_power_crit:
456
+ return 0644;
457
+ }
458
+
459
+ return 0;
460
+}
461
+
462
+static const struct hwmon_ops power_hwmon_ops = {
463
+ .is_visible = power_hwmon_attrs_visible,
464
+ .read = power_hwmon_read,
465
+ .write = power_hwmon_write,
466
+};
467
+
468
+static const struct hwmon_channel_info *power_hwmon_info[] = {
469
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT |
470
+ HWMON_P_MAX | HWMON_P_MAX_ALARM |
471
+ HWMON_P_CRIT | HWMON_P_CRIT_ALARM),
472
+ NULL
473
+};
474
+
475
+static const struct hwmon_chip_info power_hwmon_chip_info = {
476
+ .ops = &power_hwmon_ops,
477
+ .info = power_hwmon_info,
478
+};
479
+
480
+static ssize_t power1_xeon_limit_show(struct device *dev,
481
+ struct device_attribute *attr, char *buf)
482
+{
483
+ struct dfl_feature *feature = dev_get_drvdata(dev);
484
+ u16 xeon_limit = 0;
485
+ u64 v;
486
+
487
+ v = readq(feature->ioaddr + FME_PWR_XEON_LIMIT);
488
+
489
+ if (FIELD_GET(XEON_PWR_EN, v))
490
+ xeon_limit = FIELD_GET(XEON_PWR_LIMIT, v);
491
+
492
+ return sprintf(buf, "%u\n", xeon_limit * 100000);
493
+}
494
+
495
+static ssize_t power1_fpga_limit_show(struct device *dev,
496
+ struct device_attribute *attr, char *buf)
497
+{
498
+ struct dfl_feature *feature = dev_get_drvdata(dev);
499
+ u16 fpga_limit = 0;
500
+ u64 v;
501
+
502
+ v = readq(feature->ioaddr + FME_PWR_FPGA_LIMIT);
503
+
504
+ if (FIELD_GET(FPGA_PWR_EN, v))
505
+ fpga_limit = FIELD_GET(FPGA_PWR_LIMIT, v);
506
+
507
+ return sprintf(buf, "%u\n", fpga_limit * 100000);
508
+}
509
+
510
+static ssize_t power1_ltr_show(struct device *dev,
511
+ struct device_attribute *attr, char *buf)
512
+{
513
+ struct dfl_feature *feature = dev_get_drvdata(dev);
514
+ u64 v;
515
+
516
+ v = readq(feature->ioaddr + FME_PWR_STATUS);
517
+
518
+ return sprintf(buf, "%u\n",
519
+ (unsigned int)FIELD_GET(FME_LATENCY_TOLERANCE, v));
520
+}
521
+
522
+static DEVICE_ATTR_RO(power1_xeon_limit);
523
+static DEVICE_ATTR_RO(power1_fpga_limit);
524
+static DEVICE_ATTR_RO(power1_ltr);
525
+
526
+static struct attribute *power_extra_attrs[] = {
527
+ &dev_attr_power1_xeon_limit.attr,
528
+ &dev_attr_power1_fpga_limit.attr,
529
+ &dev_attr_power1_ltr.attr,
530
+ NULL
531
+};
532
+
533
+ATTRIBUTE_GROUPS(power_extra);
534
+
535
+static int fme_power_mgmt_init(struct platform_device *pdev,
536
+ struct dfl_feature *feature)
537
+{
538
+ struct device *hwmon;
539
+
540
+ hwmon = devm_hwmon_device_register_with_info(&pdev->dev,
541
+ "dfl_fme_power", feature,
542
+ &power_hwmon_chip_info,
543
+ power_extra_groups);
544
+ if (IS_ERR(hwmon)) {
545
+ dev_err(&pdev->dev, "Fail to register power hwmon\n");
546
+ return PTR_ERR(hwmon);
547
+ }
548
+
549
+ return 0;
550
+}
551
+
552
+static const struct dfl_feature_id fme_power_mgmt_id_table[] = {
553
+ {.id = FME_FEATURE_ID_POWER_MGMT,},
554
+ {0,}
555
+};
556
+
557
+static const struct dfl_feature_ops fme_power_mgmt_ops = {
558
+ .init = fme_power_mgmt_init,
109559 };
110560
111561 static struct dfl_feature_driver fme_feature_drvs[] = {
112562 {
113
- .id = FME_FEATURE_ID_HEADER,
563
+ .id_table = fme_hdr_id_table,
114564 .ops = &fme_hdr_ops,
115565 },
116566 {
117
- .id = FME_FEATURE_ID_PR_MGMT,
118
- .ops = &pr_mgmt_ops,
567
+ .id_table = fme_pr_mgmt_id_table,
568
+ .ops = &fme_pr_mgmt_ops,
569
+ },
570
+ {
571
+ .id_table = fme_global_err_id_table,
572
+ .ops = &fme_global_err_ops,
573
+ },
574
+ {
575
+ .id_table = fme_thermal_mgmt_id_table,
576
+ .ops = &fme_thermal_mgmt_ops,
577
+ },
578
+ {
579
+ .id_table = fme_power_mgmt_id_table,
580
+ .ops = &fme_power_mgmt_ops,
581
+ },
582
+ {
583
+ .id_table = fme_perf_id_table,
584
+ .ops = &fme_perf_ops,
119585 },
120586 {
121587 .ops = NULL,
....@@ -138,23 +604,34 @@
138604 if (WARN_ON(!pdata))
139605 return -ENODEV;
140606
141
- ret = dfl_feature_dev_use_begin(pdata);
142
- if (ret)
143
- return ret;
607
+ mutex_lock(&pdata->lock);
608
+ ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL);
609
+ if (!ret) {
610
+ dev_dbg(&fdev->dev, "Device File Opened %d Times\n",
611
+ dfl_feature_dev_use_count(pdata));
612
+ filp->private_data = pdata;
613
+ }
614
+ mutex_unlock(&pdata->lock);
144615
145
- dev_dbg(&fdev->dev, "Device File Open\n");
146
- filp->private_data = pdata;
147
-
148
- return 0;
616
+ return ret;
149617 }
150618
151619 static int fme_release(struct inode *inode, struct file *filp)
152620 {
153621 struct dfl_feature_platform_data *pdata = filp->private_data;
154622 struct platform_device *pdev = pdata->dev;
623
+ struct dfl_feature *feature;
155624
156625 dev_dbg(&pdev->dev, "Device File Release\n");
626
+
627
+ mutex_lock(&pdata->lock);
157628 dfl_feature_dev_use_end(pdata);
629
+
630
+ if (!dfl_feature_dev_use_count(pdata))
631
+ dfl_fpga_dev_for_each_feature(pdata, feature)
632
+ dfl_fpga_set_irq_triggers(feature, 0,
633
+ feature->nr_irqs, NULL);
634
+ mutex_unlock(&pdata->lock);
158635
159636 return 0;
160637 }
....@@ -213,10 +690,8 @@
213690 static void fme_dev_destroy(struct platform_device *pdev)
214691 {
215692 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
216
- struct dfl_fme *fme;
217693
218694 mutex_lock(&pdata->lock);
219
- fme = dfl_fpga_pdata_get_private(pdata);
220695 dfl_fpga_pdata_set_private(pdata, NULL);
221696 mutex_unlock(&pdata->lock);
222697 }
....@@ -263,9 +738,16 @@
263738 return 0;
264739 }
265740
741
+static const struct attribute_group *fme_dev_groups[] = {
742
+ &fme_hdr_group,
743
+ &fme_global_err_group,
744
+ NULL
745
+};
746
+
266747 static struct platform_driver fme_driver = {
267748 .driver = {
268
- .name = DFL_FPGA_FEATURE_DEV_FME,
749
+ .name = DFL_FPGA_FEATURE_DEV_FME,
750
+ .dev_groups = fme_dev_groups,
269751 },
270752 .probe = fme_probe,
271753 .remove = fme_remove,