Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Sync File validation framework and debug information
0004  *
0005  * Copyright (C) 2012 Google, Inc.
0006  */
0007 
0008 #include <linux/debugfs.h>
0009 #include "sync_debug.h"
0010 
0011 static struct dentry *dbgfs;
0012 
0013 static LIST_HEAD(sync_timeline_list_head);
0014 static DEFINE_SPINLOCK(sync_timeline_list_lock);
0015 static LIST_HEAD(sync_file_list_head);
0016 static DEFINE_SPINLOCK(sync_file_list_lock);
0017 
0018 void sync_timeline_debug_add(struct sync_timeline *obj)
0019 {
0020     unsigned long flags;
0021 
0022     spin_lock_irqsave(&sync_timeline_list_lock, flags);
0023     list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
0024     spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
0025 }
0026 
0027 void sync_timeline_debug_remove(struct sync_timeline *obj)
0028 {
0029     unsigned long flags;
0030 
0031     spin_lock_irqsave(&sync_timeline_list_lock, flags);
0032     list_del(&obj->sync_timeline_list);
0033     spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
0034 }
0035 
0036 void sync_file_debug_add(struct sync_file *sync_file)
0037 {
0038     unsigned long flags;
0039 
0040     spin_lock_irqsave(&sync_file_list_lock, flags);
0041     list_add_tail(&sync_file->sync_file_list, &sync_file_list_head);
0042     spin_unlock_irqrestore(&sync_file_list_lock, flags);
0043 }
0044 
0045 void sync_file_debug_remove(struct sync_file *sync_file)
0046 {
0047     unsigned long flags;
0048 
0049     spin_lock_irqsave(&sync_file_list_lock, flags);
0050     list_del(&sync_file->sync_file_list);
0051     spin_unlock_irqrestore(&sync_file_list_lock, flags);
0052 }
0053 
0054 static const char *sync_status_str(int status)
0055 {
0056     if (status < 0)
0057         return "error";
0058 
0059     if (status > 0)
0060         return "signaled";
0061 
0062     return "active";
0063 }
0064 
0065 static void sync_print_fence(struct seq_file *s,
0066                  struct dma_fence *fence, bool show)
0067 {
0068     struct sync_timeline *parent = dma_fence_parent(fence);
0069     int status;
0070 
0071     status = dma_fence_get_status_locked(fence);
0072 
0073     seq_printf(s, "  %s%sfence %s",
0074            show ? parent->name : "",
0075            show ? "_" : "",
0076            sync_status_str(status));
0077 
0078     if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) {
0079         struct timespec64 ts64 =
0080             ktime_to_timespec64(fence->timestamp);
0081 
0082         seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
0083     }
0084 
0085     if (fence->ops->timeline_value_str &&
0086         fence->ops->fence_value_str) {
0087         char value[64];
0088         bool success;
0089 
0090         fence->ops->fence_value_str(fence, value, sizeof(value));
0091         success = strlen(value);
0092 
0093         if (success) {
0094             seq_printf(s, ": %s", value);
0095 
0096             fence->ops->timeline_value_str(fence, value,
0097                                sizeof(value));
0098 
0099             if (strlen(value))
0100                 seq_printf(s, " / %s", value);
0101         }
0102     }
0103 
0104     seq_putc(s, '\n');
0105 }
0106 
0107 static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
0108 {
0109     struct list_head *pos;
0110 
0111     seq_printf(s, "%s: %d\n", obj->name, obj->value);
0112 
0113     spin_lock_irq(&obj->lock);
0114     list_for_each(pos, &obj->pt_list) {
0115         struct sync_pt *pt = container_of(pos, struct sync_pt, link);
0116         sync_print_fence(s, &pt->base, false);
0117     }
0118     spin_unlock_irq(&obj->lock);
0119 }
0120 
0121 static void sync_print_sync_file(struct seq_file *s,
0122                   struct sync_file *sync_file)
0123 {
0124     char buf[128];
0125     int i;
0126 
0127     seq_printf(s, "[%p] %s: %s\n", sync_file,
0128            sync_file_get_name(sync_file, buf, sizeof(buf)),
0129            sync_status_str(dma_fence_get_status(sync_file->fence)));
0130 
0131     if (dma_fence_is_array(sync_file->fence)) {
0132         struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
0133 
0134         for (i = 0; i < array->num_fences; ++i)
0135             sync_print_fence(s, array->fences[i], true);
0136     } else {
0137         sync_print_fence(s, sync_file->fence, true);
0138     }
0139 }
0140 
0141 static int sync_info_debugfs_show(struct seq_file *s, void *unused)
0142 {
0143     struct list_head *pos;
0144 
0145     seq_puts(s, "objs:\n--------------\n");
0146 
0147     spin_lock_irq(&sync_timeline_list_lock);
0148     list_for_each(pos, &sync_timeline_list_head) {
0149         struct sync_timeline *obj =
0150             container_of(pos, struct sync_timeline,
0151                      sync_timeline_list);
0152 
0153         sync_print_obj(s, obj);
0154         seq_putc(s, '\n');
0155     }
0156     spin_unlock_irq(&sync_timeline_list_lock);
0157 
0158     seq_puts(s, "fences:\n--------------\n");
0159 
0160     spin_lock_irq(&sync_file_list_lock);
0161     list_for_each(pos, &sync_file_list_head) {
0162         struct sync_file *sync_file =
0163             container_of(pos, struct sync_file, sync_file_list);
0164 
0165         sync_print_sync_file(s, sync_file);
0166         seq_putc(s, '\n');
0167     }
0168     spin_unlock_irq(&sync_file_list_lock);
0169     return 0;
0170 }
0171 
0172 DEFINE_SHOW_ATTRIBUTE(sync_info_debugfs);
0173 
0174 static __init int sync_debugfs_init(void)
0175 {
0176     dbgfs = debugfs_create_dir("sync", NULL);
0177 
0178     /*
0179      * The debugfs files won't ever get removed and thus, there is
0180      * no need to protect it against removal races. The use of
0181      * debugfs_create_file_unsafe() is actually safe here.
0182      */
0183     debugfs_create_file_unsafe("info", 0444, dbgfs, NULL,
0184                    &sync_info_debugfs_fops);
0185     debugfs_create_file_unsafe("sw_sync", 0644, dbgfs, NULL,
0186                    &sw_sync_debugfs_fops);
0187 
0188     return 0;
0189 }
0190 late_initcall(sync_debugfs_init);