@@ -320,3 +320,227 @@ void vgic_debug_init(struct kvm *kvm)
320320void vgic_debug_destroy (struct kvm * kvm )
321321{
322322}
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