hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/fpga/dfl-afu-main.c
....@@ -22,14 +22,17 @@
2222 #include "dfl-afu.h"
2323
2424 /**
25
- * port_enable - enable a port
25
+ * __afu_port_enable - enable a port by clear reset
2626 * @pdev: port platform device.
2727 *
2828 * Enable Port by clear the port soft reset bit, which is set by default.
2929 * The AFU is unable to respond to any MMIO access while in reset.
30
- * port_enable function should only be used after port_disable function.
30
+ * __afu_port_enable function should only be used after __afu_port_disable
31
+ * function.
32
+ *
33
+ * The caller needs to hold lock for protection.
3134 */
32
-static void port_enable(struct platform_device *pdev)
35
+void __afu_port_enable(struct platform_device *pdev)
3336 {
3437 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
3538 void __iomem *base;
....@@ -52,13 +55,14 @@
5255 #define RST_POLL_TIMEOUT 1000 /* us */
5356
5457 /**
55
- * port_disable - disable a port
58
+ * __afu_port_disable - disable a port by hold reset
5659 * @pdev: port platform device.
5760 *
58
- * Disable Port by setting the port soft reset bit, it puts the port into
59
- * reset.
61
+ * Disable Port by setting the port soft reset bit, it puts the port into reset.
62
+ *
63
+ * The caller needs to hold lock for protection.
6064 */
61
-static int port_disable(struct platform_device *pdev)
65
+int __afu_port_disable(struct platform_device *pdev)
6266 {
6367 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
6468 void __iomem *base;
....@@ -105,9 +109,9 @@
105109 {
106110 int ret;
107111
108
- ret = port_disable(pdev);
112
+ ret = __afu_port_disable(pdev);
109113 if (!ret)
110
- port_enable(pdev);
114
+ __afu_port_enable(pdev);
111115
112116 return ret;
113117 }
....@@ -142,27 +146,267 @@
142146 }
143147 static DEVICE_ATTR_RO(id);
144148
145
-static const struct attribute *port_hdr_attrs[] = {
149
+static ssize_t
150
+ltr_show(struct device *dev, struct device_attribute *attr, char *buf)
151
+{
152
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
153
+ void __iomem *base;
154
+ u64 v;
155
+
156
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
157
+
158
+ mutex_lock(&pdata->lock);
159
+ v = readq(base + PORT_HDR_CTRL);
160
+ mutex_unlock(&pdata->lock);
161
+
162
+ return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v));
163
+}
164
+
165
+static ssize_t
166
+ltr_store(struct device *dev, struct device_attribute *attr,
167
+ const char *buf, size_t count)
168
+{
169
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
170
+ void __iomem *base;
171
+ bool ltr;
172
+ u64 v;
173
+
174
+ if (kstrtobool(buf, &ltr))
175
+ return -EINVAL;
176
+
177
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
178
+
179
+ mutex_lock(&pdata->lock);
180
+ v = readq(base + PORT_HDR_CTRL);
181
+ v &= ~PORT_CTRL_LATENCY;
182
+ v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0);
183
+ writeq(v, base + PORT_HDR_CTRL);
184
+ mutex_unlock(&pdata->lock);
185
+
186
+ return count;
187
+}
188
+static DEVICE_ATTR_RW(ltr);
189
+
190
+static ssize_t
191
+ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf)
192
+{
193
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
194
+ void __iomem *base;
195
+ u64 v;
196
+
197
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
198
+
199
+ mutex_lock(&pdata->lock);
200
+ v = readq(base + PORT_HDR_STS);
201
+ mutex_unlock(&pdata->lock);
202
+
203
+ return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v));
204
+}
205
+
206
+static ssize_t
207
+ap1_event_store(struct device *dev, struct device_attribute *attr,
208
+ const char *buf, size_t count)
209
+{
210
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
211
+ void __iomem *base;
212
+ bool clear;
213
+
214
+ if (kstrtobool(buf, &clear) || !clear)
215
+ return -EINVAL;
216
+
217
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
218
+
219
+ mutex_lock(&pdata->lock);
220
+ writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS);
221
+ mutex_unlock(&pdata->lock);
222
+
223
+ return count;
224
+}
225
+static DEVICE_ATTR_RW(ap1_event);
226
+
227
+static ssize_t
228
+ap2_event_show(struct device *dev, struct device_attribute *attr,
229
+ char *buf)
230
+{
231
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
232
+ void __iomem *base;
233
+ u64 v;
234
+
235
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
236
+
237
+ mutex_lock(&pdata->lock);
238
+ v = readq(base + PORT_HDR_STS);
239
+ mutex_unlock(&pdata->lock);
240
+
241
+ return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v));
242
+}
243
+
244
+static ssize_t
245
+ap2_event_store(struct device *dev, struct device_attribute *attr,
246
+ const char *buf, size_t count)
247
+{
248
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
249
+ void __iomem *base;
250
+ bool clear;
251
+
252
+ if (kstrtobool(buf, &clear) || !clear)
253
+ return -EINVAL;
254
+
255
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
256
+
257
+ mutex_lock(&pdata->lock);
258
+ writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS);
259
+ mutex_unlock(&pdata->lock);
260
+
261
+ return count;
262
+}
263
+static DEVICE_ATTR_RW(ap2_event);
264
+
265
+static ssize_t
266
+power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
267
+{
268
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
269
+ void __iomem *base;
270
+ u64 v;
271
+
272
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
273
+
274
+ mutex_lock(&pdata->lock);
275
+ v = readq(base + PORT_HDR_STS);
276
+ mutex_unlock(&pdata->lock);
277
+
278
+ return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v));
279
+}
280
+static DEVICE_ATTR_RO(power_state);
281
+
282
+static ssize_t
283
+userclk_freqcmd_store(struct device *dev, struct device_attribute *attr,
284
+ const char *buf, size_t count)
285
+{
286
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
287
+ u64 userclk_freq_cmd;
288
+ void __iomem *base;
289
+
290
+ if (kstrtou64(buf, 0, &userclk_freq_cmd))
291
+ return -EINVAL;
292
+
293
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
294
+
295
+ mutex_lock(&pdata->lock);
296
+ writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0);
297
+ mutex_unlock(&pdata->lock);
298
+
299
+ return count;
300
+}
301
+static DEVICE_ATTR_WO(userclk_freqcmd);
302
+
303
+static ssize_t
304
+userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr,
305
+ const char *buf, size_t count)
306
+{
307
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
308
+ u64 userclk_freqcntr_cmd;
309
+ void __iomem *base;
310
+
311
+ if (kstrtou64(buf, 0, &userclk_freqcntr_cmd))
312
+ return -EINVAL;
313
+
314
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
315
+
316
+ mutex_lock(&pdata->lock);
317
+ writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1);
318
+ mutex_unlock(&pdata->lock);
319
+
320
+ return count;
321
+}
322
+static DEVICE_ATTR_WO(userclk_freqcntrcmd);
323
+
324
+static ssize_t
325
+userclk_freqsts_show(struct device *dev, struct device_attribute *attr,
326
+ char *buf)
327
+{
328
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
329
+ u64 userclk_freqsts;
330
+ void __iomem *base;
331
+
332
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
333
+
334
+ mutex_lock(&pdata->lock);
335
+ userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0);
336
+ mutex_unlock(&pdata->lock);
337
+
338
+ return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts);
339
+}
340
+static DEVICE_ATTR_RO(userclk_freqsts);
341
+
342
+static ssize_t
343
+userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr,
344
+ char *buf)
345
+{
346
+ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
347
+ u64 userclk_freqcntrsts;
348
+ void __iomem *base;
349
+
350
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
351
+
352
+ mutex_lock(&pdata->lock);
353
+ userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1);
354
+ mutex_unlock(&pdata->lock);
355
+
356
+ return sprintf(buf, "0x%llx\n",
357
+ (unsigned long long)userclk_freqcntrsts);
358
+}
359
+static DEVICE_ATTR_RO(userclk_freqcntrsts);
360
+
361
+static struct attribute *port_hdr_attrs[] = {
146362 &dev_attr_id.attr,
363
+ &dev_attr_ltr.attr,
364
+ &dev_attr_ap1_event.attr,
365
+ &dev_attr_ap2_event.attr,
366
+ &dev_attr_power_state.attr,
367
+ &dev_attr_userclk_freqcmd.attr,
368
+ &dev_attr_userclk_freqcntrcmd.attr,
369
+ &dev_attr_userclk_freqsts.attr,
370
+ &dev_attr_userclk_freqcntrsts.attr,
147371 NULL,
372
+};
373
+
374
+static umode_t port_hdr_attrs_visible(struct kobject *kobj,
375
+ struct attribute *attr, int n)
376
+{
377
+ struct device *dev = kobj_to_dev(kobj);
378
+ umode_t mode = attr->mode;
379
+ void __iomem *base;
380
+
381
+ base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
382
+
383
+ if (dfl_feature_revision(base) > 0) {
384
+ /*
385
+ * userclk sysfs interfaces are only visible in case port
386
+ * revision is 0, as hardware with revision >0 doesn't
387
+ * support this.
388
+ */
389
+ if (attr == &dev_attr_userclk_freqcmd.attr ||
390
+ attr == &dev_attr_userclk_freqcntrcmd.attr ||
391
+ attr == &dev_attr_userclk_freqsts.attr ||
392
+ attr == &dev_attr_userclk_freqcntrsts.attr)
393
+ mode = 0;
394
+ }
395
+
396
+ return mode;
397
+}
398
+
399
+static const struct attribute_group port_hdr_group = {
400
+ .attrs = port_hdr_attrs,
401
+ .is_visible = port_hdr_attrs_visible,
148402 };
149403
150404 static int port_hdr_init(struct platform_device *pdev,
151405 struct dfl_feature *feature)
152406 {
153
- dev_dbg(&pdev->dev, "PORT HDR Init.\n");
154
-
155407 port_reset(pdev);
156408
157
- return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs);
158
-}
159
-
160
-static void port_hdr_uinit(struct platform_device *pdev,
161
- struct dfl_feature *feature)
162
-{
163
- dev_dbg(&pdev->dev, "PORT HDR UInit.\n");
164
-
165
- sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs);
409
+ return 0;
166410 }
167411
168412 static long
....@@ -186,9 +430,13 @@
186430 return ret;
187431 }
188432
433
+static const struct dfl_feature_id port_hdr_id_table[] = {
434
+ {.id = PORT_FEATURE_ID_HEADER,},
435
+ {0,}
436
+};
437
+
189438 static const struct dfl_feature_ops port_hdr_ops = {
190439 .init = port_hdr_init,
191
- .uinit = port_hdr_uinit,
192440 .ioctl = port_hdr_ioctl,
193441 };
194442
....@@ -215,50 +463,117 @@
215463 }
216464 static DEVICE_ATTR_RO(afu_id);
217465
218
-static const struct attribute *port_afu_attrs[] = {
466
+static struct attribute *port_afu_attrs[] = {
219467 &dev_attr_afu_id.attr,
220468 NULL
469
+};
470
+
471
+static umode_t port_afu_attrs_visible(struct kobject *kobj,
472
+ struct attribute *attr, int n)
473
+{
474
+ struct device *dev = kobj_to_dev(kobj);
475
+
476
+ /*
477
+ * sysfs entries are visible only if related private feature is
478
+ * enumerated.
479
+ */
480
+ if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU))
481
+ return 0;
482
+
483
+ return attr->mode;
484
+}
485
+
486
+static const struct attribute_group port_afu_group = {
487
+ .attrs = port_afu_attrs,
488
+ .is_visible = port_afu_attrs_visible,
221489 };
222490
223491 static int port_afu_init(struct platform_device *pdev,
224492 struct dfl_feature *feature)
225493 {
226494 struct resource *res = &pdev->resource[feature->resource_index];
227
- int ret;
228495
229
- dev_dbg(&pdev->dev, "PORT AFU Init.\n");
230
-
231
- ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev),
232
- DFL_PORT_REGION_INDEX_AFU, resource_size(res),
233
- res->start, DFL_PORT_REGION_READ |
234
- DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP);
235
- if (ret)
236
- return ret;
237
-
238
- return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs);
496
+ return afu_mmio_region_add(dev_get_platdata(&pdev->dev),
497
+ DFL_PORT_REGION_INDEX_AFU,
498
+ resource_size(res), res->start,
499
+ DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ |
500
+ DFL_PORT_REGION_WRITE);
239501 }
240502
241
-static void port_afu_uinit(struct platform_device *pdev,
242
- struct dfl_feature *feature)
243
-{
244
- dev_dbg(&pdev->dev, "PORT AFU UInit.\n");
245
-
246
- sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs);
247
-}
503
+static const struct dfl_feature_id port_afu_id_table[] = {
504
+ {.id = PORT_FEATURE_ID_AFU,},
505
+ {0,}
506
+};
248507
249508 static const struct dfl_feature_ops port_afu_ops = {
250509 .init = port_afu_init,
251
- .uinit = port_afu_uinit,
510
+};
511
+
512
+static int port_stp_init(struct platform_device *pdev,
513
+ struct dfl_feature *feature)
514
+{
515
+ struct resource *res = &pdev->resource[feature->resource_index];
516
+
517
+ return afu_mmio_region_add(dev_get_platdata(&pdev->dev),
518
+ DFL_PORT_REGION_INDEX_STP,
519
+ resource_size(res), res->start,
520
+ DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ |
521
+ DFL_PORT_REGION_WRITE);
522
+}
523
+
524
+static const struct dfl_feature_id port_stp_id_table[] = {
525
+ {.id = PORT_FEATURE_ID_STP,},
526
+ {0,}
527
+};
528
+
529
+static const struct dfl_feature_ops port_stp_ops = {
530
+ .init = port_stp_init,
531
+};
532
+
533
+static long
534
+port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
535
+ unsigned int cmd, unsigned long arg)
536
+{
537
+ switch (cmd) {
538
+ case DFL_FPGA_PORT_UINT_GET_IRQ_NUM:
539
+ return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
540
+ case DFL_FPGA_PORT_UINT_SET_IRQ:
541
+ return dfl_feature_ioctl_set_irq(pdev, feature, arg);
542
+ default:
543
+ dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
544
+ return -ENODEV;
545
+ }
546
+}
547
+
548
+static const struct dfl_feature_id port_uint_id_table[] = {
549
+ {.id = PORT_FEATURE_ID_UINT,},
550
+ {0,}
551
+};
552
+
553
+static const struct dfl_feature_ops port_uint_ops = {
554
+ .ioctl = port_uint_ioctl,
252555 };
253556
254557 static struct dfl_feature_driver port_feature_drvs[] = {
255558 {
256
- .id = PORT_FEATURE_ID_HEADER,
559
+ .id_table = port_hdr_id_table,
257560 .ops = &port_hdr_ops,
258561 },
259562 {
260
- .id = PORT_FEATURE_ID_AFU,
563
+ .id_table = port_afu_id_table,
261564 .ops = &port_afu_ops,
565
+ },
566
+ {
567
+ .id_table = port_err_id_table,
568
+ .ops = &port_err_ops,
569
+ },
570
+ {
571
+ .id_table = port_stp_id_table,
572
+ .ops = &port_stp_ops,
573
+ },
574
+ {
575
+ .id_table = port_uint_id_table,
576
+ .ops = &port_uint_ops,
262577 },
263578 {
264579 .ops = NULL,
....@@ -275,31 +590,39 @@
275590 if (WARN_ON(!pdata))
276591 return -ENODEV;
277592
278
- ret = dfl_feature_dev_use_begin(pdata);
279
- if (ret)
280
- return ret;
593
+ mutex_lock(&pdata->lock);
594
+ ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL);
595
+ if (!ret) {
596
+ dev_dbg(&fdev->dev, "Device File Opened %d Times\n",
597
+ dfl_feature_dev_use_count(pdata));
598
+ filp->private_data = fdev;
599
+ }
600
+ mutex_unlock(&pdata->lock);
281601
282
- dev_dbg(&fdev->dev, "Device File Open\n");
283
- filp->private_data = fdev;
284
-
285
- return 0;
602
+ return ret;
286603 }
287604
288605 static int afu_release(struct inode *inode, struct file *filp)
289606 {
290607 struct platform_device *pdev = filp->private_data;
291608 struct dfl_feature_platform_data *pdata;
609
+ struct dfl_feature *feature;
292610
293611 dev_dbg(&pdev->dev, "Device File Release\n");
294612
295613 pdata = dev_get_platdata(&pdev->dev);
296614
297615 mutex_lock(&pdata->lock);
298
- __port_reset(pdev);
299
- afu_dma_region_destroy(pdata);
300
- mutex_unlock(&pdata->lock);
301
-
302616 dfl_feature_dev_use_end(pdata);
617
+
618
+ if (!dfl_feature_dev_use_count(pdata)) {
619
+ dfl_fpga_dev_for_each_feature(pdata, feature)
620
+ dfl_fpga_set_irq_triggers(feature, 0,
621
+ feature->nr_irqs, NULL);
622
+ __port_reset(pdev);
623
+ afu_dma_region_destroy(pdata);
624
+ }
625
+ mutex_unlock(&pdata->lock);
303626
304627 return 0;
305628 }
....@@ -460,6 +783,12 @@
460783 return -EINVAL;
461784 }
462785
786
+static const struct vm_operations_struct afu_vma_ops = {
787
+#ifdef CONFIG_HAVE_IOREMAP_PROT
788
+ .access = generic_access_phys,
789
+#endif
790
+};
791
+
463792 static int afu_mmap(struct file *filp, struct vm_area_struct *vma)
464793 {
465794 struct platform_device *pdev = filp->private_data;
....@@ -488,6 +817,9 @@
488817 if ((vma->vm_flags & VM_WRITE) &&
489818 !(region.flags & DFL_PORT_REGION_WRITE))
490819 return -EPERM;
820
+
821
+ /* Support debug access to the mapping */
822
+ vma->vm_ops = &afu_vma_ops;
491823
492824 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
493825
....@@ -527,10 +859,8 @@
527859 static int afu_dev_destroy(struct platform_device *pdev)
528860 {
529861 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
530
- struct dfl_afu *afu;
531862
532863 mutex_lock(&pdata->lock);
533
- afu = dfl_fpga_pdata_get_private(pdata);
534864 afu_mmio_region_destroy(pdata);
535865 afu_dma_region_destroy(pdata);
536866 dfl_fpga_pdata_set_private(pdata, NULL);
....@@ -546,9 +876,9 @@
546876
547877 mutex_lock(&pdata->lock);
548878 if (enable)
549
- port_enable(pdev);
879
+ __afu_port_enable(pdev);
550880 else
551
- ret = port_disable(pdev);
881
+ ret = __afu_port_disable(pdev);
552882 mutex_unlock(&pdata->lock);
553883
554884 return ret;
....@@ -600,9 +930,17 @@
600930 return 0;
601931 }
602932
933
+static const struct attribute_group *afu_dev_groups[] = {
934
+ &port_hdr_group,
935
+ &port_afu_group,
936
+ &port_err_group,
937
+ NULL
938
+};
939
+
603940 static struct platform_driver afu_driver = {
604941 .driver = {
605
- .name = DFL_FPGA_FEATURE_DEV_PORT,
942
+ .name = DFL_FPGA_FEATURE_DEV_PORT,
943
+ .dev_groups = afu_dev_groups,
606944 },
607945 .probe = afu_probe,
608946 .remove = afu_remove,