1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include "mali_kbase_csf_kcpu_debugfs.h"
23 #include <mali_kbase.h>
24 #include <linux/seq_file.h>
25
26 #if IS_ENABLED(CONFIG_SYNC_FILE)
27 #include "mali_kbase_sync.h"
28 #endif
29
30 #if IS_ENABLED(CONFIG_DEBUG_FS)
31
32 /**
33 * kbasep_csf_kcpu_debugfs_print_queue() - Print additional info for KCPU
34 * queues blocked on CQS wait commands.
35 *
36 * @file: The seq_file to print to
37 * @kctx: The context of the KCPU queue
38 * @waits: Pointer to the KCPU CQS wait command info
39 */
kbasep_csf_kcpu_debugfs_print_cqs_waits(struct seq_file * file,struct kbase_context * kctx,struct kbase_kcpu_command_cqs_wait_info * waits)40 static void kbasep_csf_kcpu_debugfs_print_cqs_waits(struct seq_file *file,
41 struct kbase_context *kctx,
42 struct kbase_kcpu_command_cqs_wait_info *waits)
43 {
44 unsigned int i;
45
46 for (i = 0; i < waits->nr_objs; i++) {
47 struct kbase_vmap_struct *mapping;
48 u32 val;
49 char const *msg;
50 u32 *const cpu_ptr = (u32 *)kbase_phy_alloc_mapping_get(kctx,
51 waits->objs[i].addr, &mapping);
52
53 if (!cpu_ptr)
54 return;
55
56 val = *cpu_ptr;
57
58 kbase_phy_alloc_mapping_put(kctx, mapping);
59
60 msg = (waits->inherit_err_flags && (1U << i)) ? "true" :
61 "false";
62 seq_printf(file, " %llx(%u > %u, inherit_err: %s), ",
63 waits->objs[i].addr, val, waits->objs[i].val, msg);
64 }
65 }
66
67 /**
68 * kbasep_csf_kcpu_debugfs_print_queue() - Print debug data for a KCPU queue
69 *
70 * @file: The seq_file to print to
71 * @kctx: The context of the KCPU queue
72 * @queue: Pointer to the KCPU queue
73 */
kbasep_csf_kcpu_debugfs_print_queue(struct seq_file * file,struct kbase_context * kctx,struct kbase_kcpu_command_queue * queue)74 static void kbasep_csf_kcpu_debugfs_print_queue(struct seq_file *file,
75 struct kbase_context *kctx,
76 struct kbase_kcpu_command_queue *queue)
77 {
78 if (WARN_ON(!queue))
79 return;
80
81 lockdep_assert_held(&kctx->csf.kcpu_queues.lock);
82
83 seq_printf(file, "%16u, %11u, %7u, %13llu %8u",
84 queue->num_pending_cmds, queue->enqueue_failed,
85 queue->command_started ? 1 : 0,
86 queue->fence_context, queue->fence_seqno);
87
88 if (queue->command_started) {
89 struct kbase_kcpu_command *cmd =
90 &queue->commands[queue->start_offset];
91 switch (cmd->type) {
92 #if IS_ENABLED(CONFIG_SYNC_FILE)
93 case BASE_KCPU_COMMAND_TYPE_FENCE_WAIT:
94 {
95 struct kbase_sync_fence_info info;
96
97 kbase_sync_fence_info_get(cmd->info.fence.fence, &info);
98 seq_printf(file, ", Fence %pK %s %s",
99 info.fence, info.name,
100 kbase_sync_status_string(info.status));
101 break;
102 }
103 #endif
104 case BASE_KCPU_COMMAND_TYPE_CQS_WAIT:
105 seq_puts(file, ", CQS ");
106 kbasep_csf_kcpu_debugfs_print_cqs_waits(file, kctx,
107 &cmd->info.cqs_wait);
108 break;
109 default:
110 seq_puts(file, ", U, Unknown blocking command");
111 break;
112 }
113 }
114
115 seq_puts(file, "\n");
116 }
117
118 /**
119 * kbasep_csf_kcpu_debugfs_show() - Print the KCPU queues debug information
120 *
121 * @file: The seq_file for printing to
122 * @data: The debugfs dentry private data, a pointer to kbase_context
123 *
124 * Return: Negative error code or 0 on success.
125 */
kbasep_csf_kcpu_debugfs_show(struct seq_file * file,void * data)126 static int kbasep_csf_kcpu_debugfs_show(struct seq_file *file, void *data)
127 {
128 struct kbase_context *kctx = file->private;
129 unsigned long idx;
130
131 seq_printf(file, "MALI_CSF_KCPU_DEBUGFS_VERSION: v%u\n", MALI_CSF_KCPU_DEBUGFS_VERSION);
132 seq_puts(file, "Queue Idx(err-mode), Pending Commands, Enqueue err, Blocked, Fence context & seqno, (Wait Type, Additional info)\n");
133 mutex_lock(&kctx->csf.kcpu_queues.lock);
134
135 idx = find_first_bit(kctx->csf.kcpu_queues.in_use,
136 KBASEP_MAX_KCPU_QUEUES);
137
138 while (idx < KBASEP_MAX_KCPU_QUEUES) {
139 struct kbase_kcpu_command_queue *queue =
140 kctx->csf.kcpu_queues.array[idx];
141
142 seq_printf(file, "%9lu( %s ), ", idx,
143 queue->has_error ? "InErr" : "NoErr");
144 kbasep_csf_kcpu_debugfs_print_queue(file, kctx,
145 kctx->csf.kcpu_queues.array[idx]);
146
147 idx = find_next_bit(kctx->csf.kcpu_queues.in_use,
148 KBASEP_MAX_KCPU_QUEUES, idx + 1);
149 }
150
151 mutex_unlock(&kctx->csf.kcpu_queues.lock);
152 return 0;
153 }
154
kbasep_csf_kcpu_debugfs_open(struct inode * in,struct file * file)155 static int kbasep_csf_kcpu_debugfs_open(struct inode *in, struct file *file)
156 {
157 return single_open(file, kbasep_csf_kcpu_debugfs_show, in->i_private);
158 }
159
160 static const struct file_operations kbasep_csf_kcpu_debugfs_fops = {
161 .open = kbasep_csf_kcpu_debugfs_open,
162 .read = seq_read,
163 .llseek = seq_lseek,
164 .release = single_release,
165 };
166
kbase_csf_kcpu_debugfs_init(struct kbase_context * kctx)167 void kbase_csf_kcpu_debugfs_init(struct kbase_context *kctx)
168 {
169 struct dentry *file;
170 #if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
171 const mode_t mode = 0444;
172 #else
173 const mode_t mode = 0400;
174 #endif
175
176 if (WARN_ON(!kctx || IS_ERR_OR_NULL(kctx->kctx_dentry)))
177 return;
178
179 file = debugfs_create_file("kcpu_queues", mode, kctx->kctx_dentry,
180 kctx, &kbasep_csf_kcpu_debugfs_fops);
181
182 if (IS_ERR_OR_NULL(file)) {
183 dev_warn(kctx->kbdev->dev,
184 "Unable to create KCPU debugfs entry");
185 }
186 }
187
188
189 #else
190 /*
191 * Stub functions for when debugfs is disabled
192 */
kbase_csf_kcpu_debugfs_init(struct kbase_context * kctx)193 void kbase_csf_kcpu_debugfs_init(struct kbase_context *kctx)
194 {
195 }
196
197 #endif /* CONFIG_DEBUG_FS */
198