@@ -320,3 +320,227 @@ void vgic_debug_init(struct kvm *kvm)
320
320
void vgic_debug_destroy (struct kvm * kvm )
321
321
{
322
322
}
323
+
324
+ /**
325
+ * struct vgic_its_iter - Iterator for traversing VGIC ITS device tables.
326
+ * @dev: Pointer to the current its_device being processed.
327
+ * @ite: Pointer to the current its_ite within the device being processed.
328
+ *
329
+ * This structure is used to maintain the current position during iteration
330
+ * over the ITS device tables. It holds pointers to both the current device
331
+ * and the current ITE within that device.
332
+ */
333
+ struct vgic_its_iter {
334
+ struct its_device * dev ;
335
+ struct its_ite * ite ;
336
+ };
337
+
338
+ /**
339
+ * end_of_iter - Checks if the iterator has reached the end.
340
+ * @iter: The iterator to check.
341
+ *
342
+ * When the iterator completed processing the final ITE in the last device
343
+ * table, it was marked to indicate the end of iteration by setting its
344
+ * device and ITE pointers to NULL.
345
+ * This function checks whether the iterator was marked as end.
346
+ *
347
+ * Return: True if the iterator is marked as end, false otherwise.
348
+ */
349
+ static inline bool end_of_iter (struct vgic_its_iter * iter )
350
+ {
351
+ return !iter -> dev && !iter -> ite ;
352
+ }
353
+
354
+ /**
355
+ * vigc_its_iter_next - Advances the iterator to the next entry in the ITS tables.
356
+ * @its: The VGIC ITS structure.
357
+ * @iter: The iterator to advance.
358
+ *
359
+ * This function moves the iterator to the next ITE within the current device,
360
+ * or to the first ITE of the next device if the current ITE is the last in
361
+ * the device. If the current device is the last device, the iterator is set
362
+ * to indicate the end of iteration.
363
+ */
364
+ static void vgic_its_iter_next (struct vgic_its * its , struct vgic_its_iter * iter )
365
+ {
366
+ struct its_device * dev = iter -> dev ;
367
+ struct its_ite * ite = iter -> ite ;
368
+
369
+ if (!ite || list_is_last (& ite -> ite_list , & dev -> itt_head )) {
370
+ if (list_is_last (& dev -> dev_list , & its -> device_list )) {
371
+ dev = NULL ;
372
+ ite = NULL ;
373
+ } else {
374
+ dev = list_next_entry (dev , dev_list );
375
+ ite = list_first_entry_or_null (& dev -> itt_head ,
376
+ struct its_ite ,
377
+ ite_list );
378
+ }
379
+ } else {
380
+ ite = list_next_entry (ite , ite_list );
381
+ }
382
+
383
+ iter -> dev = dev ;
384
+ iter -> ite = ite ;
385
+ }
386
+
387
+ /**
388
+ * vgic_its_debug_start - Start function for the seq_file interface.
389
+ * @s: The seq_file structure.
390
+ * @pos: The starting position (offset).
391
+ *
392
+ * This function initializes the iterator to the beginning of the ITS tables
393
+ * and advances it to the specified position. It acquires the its_lock mutex
394
+ * to protect shared data.
395
+ *
396
+ * Return: An iterator pointer on success, NULL if no devices are found or
397
+ * the end of the list is reached, or ERR_PTR(-ENOMEM) on memory
398
+ * allocation failure.
399
+ */
400
+ static void * vgic_its_debug_start (struct seq_file * s , loff_t * pos )
401
+ {
402
+ struct vgic_its * its = s -> private ;
403
+ struct vgic_its_iter * iter ;
404
+ struct its_device * dev ;
405
+ loff_t offset = * pos ;
406
+
407
+ mutex_lock (& its -> its_lock );
408
+
409
+ dev = list_first_entry_or_null (& its -> device_list ,
410
+ struct its_device , dev_list );
411
+ if (!dev )
412
+ return NULL ;
413
+
414
+ iter = kmalloc (sizeof (* iter ), GFP_KERNEL );
415
+ if (!iter )
416
+ return ERR_PTR (- ENOMEM );
417
+
418
+ iter -> dev = dev ;
419
+ iter -> ite = list_first_entry_or_null (& dev -> itt_head ,
420
+ struct its_ite , ite_list );
421
+
422
+ while (!end_of_iter (iter ) && offset -- )
423
+ vgic_its_iter_next (its , iter );
424
+
425
+ if (end_of_iter (iter )) {
426
+ kfree (iter );
427
+ return NULL ;
428
+ }
429
+
430
+ return iter ;
431
+ }
432
+
433
+ /**
434
+ * vgic_its_debug_next - Next function for the seq_file interface.
435
+ * @s: The seq_file structure.
436
+ * @v: The current iterator.
437
+ * @pos: The current position (offset).
438
+ *
439
+ * This function advances the iterator to the next entry and increments the
440
+ * position.
441
+ *
442
+ * Return: An iterator pointer on success, or NULL if the end of the list is
443
+ * reached.
444
+ */
445
+ static void * vgic_its_debug_next (struct seq_file * s , void * v , loff_t * pos )
446
+ {
447
+ struct vgic_its * its = s -> private ;
448
+ struct vgic_its_iter * iter = v ;
449
+
450
+ ++ * pos ;
451
+ vgic_its_iter_next (its , iter );
452
+
453
+ if (end_of_iter (iter )) {
454
+ kfree (iter );
455
+ return NULL ;
456
+ }
457
+ return iter ;
458
+ }
459
+
460
+ /**
461
+ * vgic_its_debug_stop - Stop function for the seq_file interface.
462
+ * @s: The seq_file structure.
463
+ * @v: The current iterator.
464
+ *
465
+ * This function frees the iterator and releases the its_lock mutex.
466
+ */
467
+ static void vgic_its_debug_stop (struct seq_file * s , void * v )
468
+ {
469
+ struct vgic_its * its = s -> private ;
470
+ struct vgic_its_iter * iter = v ;
471
+
472
+ if (!IS_ERR_OR_NULL (iter ))
473
+ kfree (iter );
474
+ mutex_unlock (& its -> its_lock );
475
+ }
476
+
477
+ /**
478
+ * vgic_its_debug_show - Show function for the seq_file interface.
479
+ * @s: The seq_file structure.
480
+ * @v: The current iterator.
481
+ *
482
+ * This function formats and prints the ITS table entry information to the
483
+ * seq_file output.
484
+ *
485
+ * Return: 0 on success.
486
+ */
487
+ static int vgic_its_debug_show (struct seq_file * s , void * v )
488
+ {
489
+ struct vgic_its_iter * iter = v ;
490
+ struct its_device * dev = iter -> dev ;
491
+ struct its_ite * ite = iter -> ite ;
492
+
493
+ if (list_is_first (& ite -> ite_list , & dev -> itt_head )) {
494
+ seq_printf (s , "\n" );
495
+ seq_printf (s , "Device ID: 0x%x, Event ID Range: [0 - %llu]\n" ,
496
+ dev -> device_id , BIT_ULL (dev -> num_eventid_bits ) - 1 );
497
+ seq_printf (s , "EVENT_ID INTID HWINTID TARGET COL_ID HW\n" );
498
+ seq_printf (s , "-----------------------------------------------\n" );
499
+ }
500
+
501
+ if (ite && ite -> irq && ite -> collection ) {
502
+ seq_printf (s , "%8u %8u %8u %8u %8u %2d\n" ,
503
+ ite -> event_id , ite -> irq -> intid , ite -> irq -> hwintid ,
504
+ ite -> collection -> target_addr ,
505
+ ite -> collection -> collection_id , ite -> irq -> hw );
506
+ }
507
+
508
+ return 0 ;
509
+ }
510
+
511
+ static const struct seq_operations vgic_its_debug_sops = {
512
+ .start = vgic_its_debug_start ,
513
+ .next = vgic_its_debug_next ,
514
+ .stop = vgic_its_debug_stop ,
515
+ .show = vgic_its_debug_show
516
+ };
517
+
518
+ DEFINE_SEQ_ATTRIBUTE (vgic_its_debug );
519
+
520
+ /**
521
+ * vgic_its_debug_init - Initializes the debugfs interface for VGIC ITS.
522
+ * @dev: The KVM device structure.
523
+ *
524
+ * This function creates a debugfs file named "vgic-its-state@%its_base"
525
+ * to expose the ITS table information.
526
+ *
527
+ * Return: 0 on success.
528
+ */
529
+ int vgic_its_debug_init (struct kvm_device * dev )
530
+ {
531
+ struct vgic_its * its = dev -> private ;
532
+ char * name ;
533
+
534
+ name = kasprintf (GFP_KERNEL , "vgic-its-state@%llx" , (u64 )its -> vgic_its_base );
535
+ if (!name )
536
+ return - ENOMEM ;
537
+
538
+ debugfs_create_file (name , 0444 , dev -> kvm -> debugfs_dentry , its , & vgic_its_debug_fops );
539
+
540
+ kfree (name );
541
+ return 0 ;
542
+ }
543
+
544
+ void vgic_its_debug_destroy (struct kvm_device * dev )
545
+ {
546
+ }
0 commit comments