16
16
17
17
#include <linux/kernel.h>
18
18
#include <linux/module.h>
19
+ #include <linux/uaccess.h>
19
20
#include <linux/fpga-dfl.h>
20
21
21
- #include "dfl.h"
22
+ #include "dfl-afu .h"
22
23
23
24
/**
24
25
* port_enable - enable a port
25
26
* @pdev: port platform device.
26
27
*
27
28
* Enable Port by clear the port soft reset bit, which is set by default.
28
- * The User AFU is unable to respond to any MMIO access while in reset.
29
- * port_enable function should only be used after port_disable
30
- * function.
29
+ * 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.
31
31
*/
32
32
static void port_enable (struct platform_device * pdev )
33
33
{
@@ -191,11 +191,74 @@ static const struct dfl_feature_ops port_hdr_ops = {
191
191
.ioctl = port_hdr_ioctl ,
192
192
};
193
193
194
+ static ssize_t
195
+ afu_id_show (struct device * dev , struct device_attribute * attr , char * buf )
196
+ {
197
+ struct dfl_feature_platform_data * pdata = dev_get_platdata (dev );
198
+ void __iomem * base ;
199
+ u64 guidl , guidh ;
200
+
201
+ base = dfl_get_feature_ioaddr_by_id (dev , PORT_FEATURE_ID_AFU );
202
+
203
+ mutex_lock (& pdata -> lock );
204
+ if (pdata -> disable_count ) {
205
+ mutex_unlock (& pdata -> lock );
206
+ return - EBUSY ;
207
+ }
208
+
209
+ guidl = readq (base + GUID_L );
210
+ guidh = readq (base + GUID_H );
211
+ mutex_unlock (& pdata -> lock );
212
+
213
+ return scnprintf (buf , PAGE_SIZE , "%016llx%016llx\n" , guidh , guidl );
214
+ }
215
+ static DEVICE_ATTR_RO (afu_id );
216
+
217
+ static const struct attribute * port_afu_attrs [] = {
218
+ & dev_attr_afu_id .attr ,
219
+ NULL
220
+ };
221
+
222
+ static int port_afu_init (struct platform_device * pdev ,
223
+ struct dfl_feature * feature )
224
+ {
225
+ struct resource * res = & pdev -> resource [feature -> resource_index ];
226
+ int ret ;
227
+
228
+ dev_dbg (& pdev -> dev , "PORT AFU Init.\n" );
229
+
230
+ ret = afu_mmio_region_add (dev_get_platdata (& pdev -> dev ),
231
+ DFL_PORT_REGION_INDEX_AFU , resource_size (res ),
232
+ res -> start , DFL_PORT_REGION_READ |
233
+ DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP );
234
+ if (ret )
235
+ return ret ;
236
+
237
+ return sysfs_create_files (& pdev -> dev .kobj , port_afu_attrs );
238
+ }
239
+
240
+ static void port_afu_uinit (struct platform_device * pdev ,
241
+ struct dfl_feature * feature )
242
+ {
243
+ dev_dbg (& pdev -> dev , "PORT AFU UInit.\n" );
244
+
245
+ sysfs_remove_files (& pdev -> dev .kobj , port_afu_attrs );
246
+ }
247
+
248
+ static const struct dfl_feature_ops port_afu_ops = {
249
+ .init = port_afu_init ,
250
+ .uinit = port_afu_uinit ,
251
+ };
252
+
194
253
static struct dfl_feature_driver port_feature_drvs [] = {
195
254
{
196
255
.id = PORT_FEATURE_ID_HEADER ,
197
256
.ops = & port_hdr_ops ,
198
257
},
258
+ {
259
+ .id = PORT_FEATURE_ID_AFU ,
260
+ .ops = & port_afu_ops ,
261
+ },
199
262
{
200
263
.ops = NULL ,
201
264
}
@@ -243,6 +306,64 @@ static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
243
306
return 0 ;
244
307
}
245
308
309
+ static long
310
+ afu_ioctl_get_info (struct dfl_feature_platform_data * pdata , void __user * arg )
311
+ {
312
+ struct dfl_fpga_port_info info ;
313
+ struct dfl_afu * afu ;
314
+ unsigned long minsz ;
315
+
316
+ minsz = offsetofend (struct dfl_fpga_port_info , num_umsgs );
317
+
318
+ if (copy_from_user (& info , arg , minsz ))
319
+ return - EFAULT ;
320
+
321
+ if (info .argsz < minsz )
322
+ return - EINVAL ;
323
+
324
+ mutex_lock (& pdata -> lock );
325
+ afu = dfl_fpga_pdata_get_private (pdata );
326
+ info .flags = 0 ;
327
+ info .num_regions = afu -> num_regions ;
328
+ info .num_umsgs = afu -> num_umsgs ;
329
+ mutex_unlock (& pdata -> lock );
330
+
331
+ if (copy_to_user (arg , & info , sizeof (info )))
332
+ return - EFAULT ;
333
+
334
+ return 0 ;
335
+ }
336
+
337
+ static long afu_ioctl_get_region_info (struct dfl_feature_platform_data * pdata ,
338
+ void __user * arg )
339
+ {
340
+ struct dfl_fpga_port_region_info rinfo ;
341
+ struct dfl_afu_mmio_region region ;
342
+ unsigned long minsz ;
343
+ long ret ;
344
+
345
+ minsz = offsetofend (struct dfl_fpga_port_region_info , offset );
346
+
347
+ if (copy_from_user (& rinfo , arg , minsz ))
348
+ return - EFAULT ;
349
+
350
+ if (rinfo .argsz < minsz || rinfo .padding )
351
+ return - EINVAL ;
352
+
353
+ ret = afu_mmio_region_get_by_index (pdata , rinfo .index , & region );
354
+ if (ret )
355
+ return ret ;
356
+
357
+ rinfo .flags = region .flags ;
358
+ rinfo .size = region .size ;
359
+ rinfo .offset = region .offset ;
360
+
361
+ if (copy_to_user (arg , & rinfo , sizeof (rinfo )))
362
+ return - EFAULT ;
363
+
364
+ return 0 ;
365
+ }
366
+
246
367
static long afu_ioctl (struct file * filp , unsigned int cmd , unsigned long arg )
247
368
{
248
369
struct platform_device * pdev = filp -> private_data ;
@@ -259,6 +380,10 @@ static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
259
380
return DFL_FPGA_API_VERSION ;
260
381
case DFL_FPGA_CHECK_EXTENSION :
261
382
return afu_ioctl_check_extension (pdata , arg );
383
+ case DFL_FPGA_PORT_GET_INFO :
384
+ return afu_ioctl_get_info (pdata , (void __user * )arg );
385
+ case DFL_FPGA_PORT_GET_REGION_INFO :
386
+ return afu_ioctl_get_region_info (pdata , (void __user * )arg );
262
387
default :
263
388
/*
264
389
* Let sub-feature's ioctl function to handle the cmd
@@ -277,13 +402,83 @@ static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
277
402
return - EINVAL ;
278
403
}
279
404
405
+ static int afu_mmap (struct file * filp , struct vm_area_struct * vma )
406
+ {
407
+ struct platform_device * pdev = filp -> private_data ;
408
+ struct dfl_feature_platform_data * pdata ;
409
+ u64 size = vma -> vm_end - vma -> vm_start ;
410
+ struct dfl_afu_mmio_region region ;
411
+ u64 offset ;
412
+ int ret ;
413
+
414
+ if (!(vma -> vm_flags & VM_SHARED ))
415
+ return - EINVAL ;
416
+
417
+ pdata = dev_get_platdata (& pdev -> dev );
418
+
419
+ offset = vma -> vm_pgoff << PAGE_SHIFT ;
420
+ ret = afu_mmio_region_get_by_offset (pdata , offset , size , & region );
421
+ if (ret )
422
+ return ret ;
423
+
424
+ if (!(region .flags & DFL_PORT_REGION_MMAP ))
425
+ return - EINVAL ;
426
+
427
+ if ((vma -> vm_flags & VM_READ ) && !(region .flags & DFL_PORT_REGION_READ ))
428
+ return - EPERM ;
429
+
430
+ if ((vma -> vm_flags & VM_WRITE ) &&
431
+ !(region .flags & DFL_PORT_REGION_WRITE ))
432
+ return - EPERM ;
433
+
434
+ vma -> vm_page_prot = pgprot_noncached (vma -> vm_page_prot );
435
+
436
+ return remap_pfn_range (vma , vma -> vm_start ,
437
+ (region .phys + (offset - region .offset )) >> PAGE_SHIFT ,
438
+ size , vma -> vm_page_prot );
439
+ }
440
+
280
441
static const struct file_operations afu_fops = {
281
442
.owner = THIS_MODULE ,
282
443
.open = afu_open ,
283
444
.release = afu_release ,
284
445
.unlocked_ioctl = afu_ioctl ,
446
+ .mmap = afu_mmap ,
285
447
};
286
448
449
+ static int afu_dev_init (struct platform_device * pdev )
450
+ {
451
+ struct dfl_feature_platform_data * pdata = dev_get_platdata (& pdev -> dev );
452
+ struct dfl_afu * afu ;
453
+
454
+ afu = devm_kzalloc (& pdev -> dev , sizeof (* afu ), GFP_KERNEL );
455
+ if (!afu )
456
+ return - ENOMEM ;
457
+
458
+ afu -> pdata = pdata ;
459
+
460
+ mutex_lock (& pdata -> lock );
461
+ dfl_fpga_pdata_set_private (pdata , afu );
462
+ afu_mmio_region_init (pdata );
463
+ mutex_unlock (& pdata -> lock );
464
+
465
+ return 0 ;
466
+ }
467
+
468
+ static int afu_dev_destroy (struct platform_device * pdev )
469
+ {
470
+ struct dfl_feature_platform_data * pdata = dev_get_platdata (& pdev -> dev );
471
+ struct dfl_afu * afu ;
472
+
473
+ mutex_lock (& pdata -> lock );
474
+ afu = dfl_fpga_pdata_get_private (pdata );
475
+ afu_mmio_region_destroy (pdata );
476
+ dfl_fpga_pdata_set_private (pdata , NULL );
477
+ mutex_unlock (& pdata -> lock );
478
+
479
+ return 0 ;
480
+ }
481
+
287
482
static int port_enable_set (struct platform_device * pdev , bool enable )
288
483
{
289
484
struct dfl_feature_platform_data * pdata = dev_get_platdata (& pdev -> dev );
@@ -312,14 +507,25 @@ static int afu_probe(struct platform_device *pdev)
312
507
313
508
dev_dbg (& pdev -> dev , "%s\n" , __func__ );
314
509
510
+ ret = afu_dev_init (pdev );
511
+ if (ret )
512
+ goto exit ;
513
+
315
514
ret = dfl_fpga_dev_feature_init (pdev , port_feature_drvs );
316
515
if (ret )
317
- return ret ;
516
+ goto dev_destroy ;
318
517
319
518
ret = dfl_fpga_dev_ops_register (pdev , & afu_fops , THIS_MODULE );
320
- if (ret )
519
+ if (ret ) {
321
520
dfl_fpga_dev_feature_uinit (pdev );
521
+ goto dev_destroy ;
522
+ }
523
+
524
+ return 0 ;
322
525
526
+ dev_destroy :
527
+ afu_dev_destroy (pdev );
528
+ exit :
323
529
return ret ;
324
530
}
325
531
@@ -329,6 +535,7 @@ static int afu_remove(struct platform_device *pdev)
329
535
330
536
dfl_fpga_dev_ops_unregister (pdev );
331
537
dfl_fpga_dev_feature_uinit (pdev );
538
+ afu_dev_destroy (pdev );
332
539
333
540
return 0 ;
334
541
}
0 commit comments