1 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2 /*
3 *
4 * (C) COPYRIGHT 2019-2022 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 /*
23 * mali_kbase_kinstr_jm.h
24 * Kernel driver public interface to job manager atom tracing. This API provides
25 * a method to get the atom state changes into user space.
26 *
27 * The flow of operation is:
28 *
29 * | kernel | user |
30 * | ----------------------------------- | ----------------------------------- |
31 * | Initialize API with | |
32 * | kbase_kinstr_jm_init() | |
33 * | | |
34 * | Kernel code injects states with | |
35 * | kbase_kinstr_jm_atom_state_*() APIs | |
36 * | | Call ioctl() to get file descriptor |
37 * | | via KBASE_IOCTL_KINSTR_JM_FD |
38 * | Allocates a reader attached to FD | |
39 * | Allocates circular buffer and | |
40 * | patches, via ASM goto, the | |
41 * | kbase_kinstr_jm_atom_state_*() | |
42 * | | loop: |
43 * | | Call poll() on FD for POLLIN |
44 * | When threshold of changes is hit, | |
45 * | the poll is interrupted with | |
46 * | POLLIN. If circular buffer is | |
47 * | full then store the missed count | |
48 * | and interrupt poll | Call read() to get data from |
49 * | | circular buffer via the fd |
50 * | Kernel advances tail of circular | |
51 * | buffer | |
52 * | | Close file descriptor |
53 * | Deallocates circular buffer | |
54 * | | |
55 * | Terminate API with | |
56 * | kbase_kinstr_jm_term() | |
57 *
58 * All tracepoints are guarded on a static key. The static key is activated when
59 * a user space reader gets created. This means that there is negligible cost
60 * inserting the tracepoints into code when there are no readers.
61 */
62
63 #ifndef _KBASE_KINSTR_JM_H_
64 #define _KBASE_KINSTR_JM_H_
65
66 #include <uapi/gpu/arm/bifrost/mali_kbase_kinstr_jm_reader.h>
67
68 #ifdef __KERNEL__
69 #include <linux/version.h>
70 #include <linux/static_key.h>
71 #else
72 /* empty wrapper macros for userspace */
73 #define static_branch_unlikely(key) (1)
74 #endif /* __KERNEL__ */
75
76 /* Forward declarations */
77 struct kbase_context;
78 struct kbase_kinstr_jm;
79 struct kbase_jd_atom;
80 union kbase_kinstr_jm_fd;
81
82 /**
83 * kbase_kinstr_jm_init() - Initialise an instrumentation job manager context.
84 * @ctx: Non-NULL pointer to where the pointer to the created context will
85 * be stored on success.
86 *
87 * Return: 0 on success, else error code.
88 */
89 int kbase_kinstr_jm_init(struct kbase_kinstr_jm **ctx);
90
91 /**
92 * kbase_kinstr_jm_term() - Terminate an instrumentation job manager context.
93 * @ctx: Pointer to context to be terminated.
94 */
95 void kbase_kinstr_jm_term(struct kbase_kinstr_jm *ctx);
96
97 /**
98 * kbase_kinstr_jm_get_fd() - Retrieves a file descriptor that can be used to
99 * read the atom state changes from userspace
100 *
101 * @ctx: Pointer to the initialized context
102 * @jm_fd_arg: Pointer to the union containing the in/out params
103 * Return: -1 on failure, valid file descriptor on success
104 */
105 int kbase_kinstr_jm_get_fd(struct kbase_kinstr_jm *const ctx,
106 union kbase_kinstr_jm_fd *jm_fd_arg);
107
108 /**
109 * kbasep_kinstr_jm_atom_state() - Signifies that an atom has changed state
110 * @atom: The atom that has changed state
111 * @state: The new state of the atom
112 *
113 * This performs the actual storage of the state ready for user space to
114 * read the data. It is only called when the static key is enabled from
115 * kbase_kinstr_jm_atom_state(). There is almost never a need to invoke this
116 * function directly.
117 */
118 void kbasep_kinstr_jm_atom_state(
119 struct kbase_jd_atom *const atom,
120 const enum kbase_kinstr_jm_reader_atom_state state);
121
122 /* Allows ASM goto patching to reduce tracing overhead. This is
123 * incremented/decremented when readers are created and terminated. This really
124 * shouldn't be changed externally, but if you do, make sure you use
125 * a static_key_inc()/static_key_dec() pair.
126 */
127 extern struct static_key_false basep_kinstr_jm_reader_static_key;
128
129 /**
130 * kbase_kinstr_jm_atom_state() - Signifies that an atom has changed state
131 * @atom: The atom that has changed state
132 * @state: The new state of the atom
133 *
134 * This uses a static key to reduce overhead when tracing is disabled
135 */
kbase_kinstr_jm_atom_state(struct kbase_jd_atom * const atom,const enum kbase_kinstr_jm_reader_atom_state state)136 static inline void kbase_kinstr_jm_atom_state(
137 struct kbase_jd_atom *const atom,
138 const enum kbase_kinstr_jm_reader_atom_state state)
139 {
140 if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key))
141 kbasep_kinstr_jm_atom_state(atom, state);
142 }
143
144 /**
145 * kbase_kinstr_jm_atom_state_queue() - Signifies that an atom has entered a
146 * hardware or software queue.
147 * @atom: The atom that has changed state
148 */
kbase_kinstr_jm_atom_state_queue(struct kbase_jd_atom * const atom)149 static inline void kbase_kinstr_jm_atom_state_queue(
150 struct kbase_jd_atom *const atom)
151 {
152 kbase_kinstr_jm_atom_state(
153 atom, KBASE_KINSTR_JM_READER_ATOM_STATE_QUEUE);
154 }
155
156 /**
157 * kbase_kinstr_jm_atom_state_start() - Signifies that work has started on an
158 * atom
159 * @atom: The atom that has changed state
160 */
kbase_kinstr_jm_atom_state_start(struct kbase_jd_atom * const atom)161 static inline void kbase_kinstr_jm_atom_state_start(
162 struct kbase_jd_atom *const atom)
163 {
164 kbase_kinstr_jm_atom_state(
165 atom, KBASE_KINSTR_JM_READER_ATOM_STATE_START);
166 }
167
168 /**
169 * kbase_kinstr_jm_atom_state_stop() - Signifies that work has stopped on an
170 * atom
171 * @atom: The atom that has changed state
172 */
kbase_kinstr_jm_atom_state_stop(struct kbase_jd_atom * const atom)173 static inline void kbase_kinstr_jm_atom_state_stop(
174 struct kbase_jd_atom *const atom)
175 {
176 kbase_kinstr_jm_atom_state(
177 atom, KBASE_KINSTR_JM_READER_ATOM_STATE_STOP);
178 }
179
180 /**
181 * kbase_kinstr_jm_atom_state_complete() - Signifies that all work has completed
182 * on an atom
183 * @atom: The atom that has changed state
184 */
kbase_kinstr_jm_atom_state_complete(struct kbase_jd_atom * const atom)185 static inline void kbase_kinstr_jm_atom_state_complete(
186 struct kbase_jd_atom *const atom)
187 {
188 kbase_kinstr_jm_atom_state(
189 atom, KBASE_KINSTR_JM_READER_ATOM_STATE_COMPLETE);
190 }
191
192 /**
193 * kbase_kinstr_jm_atom_queue() - A software *or* hardware atom is queued for
194 * execution
195 * @atom: The atom that has changed state
196 */
kbase_kinstr_jm_atom_queue(struct kbase_jd_atom * const atom)197 static inline void kbase_kinstr_jm_atom_queue(struct kbase_jd_atom *const atom)
198 {
199 kbase_kinstr_jm_atom_state_queue(atom);
200 }
201
202 /**
203 * kbase_kinstr_jm_atom_complete() - A software *or* hardware atom is fully
204 * completed
205 * @atom: The atom that has changed state
206 */
kbase_kinstr_jm_atom_complete(struct kbase_jd_atom * const atom)207 static inline void kbase_kinstr_jm_atom_complete(
208 struct kbase_jd_atom *const atom)
209 {
210 kbase_kinstr_jm_atom_state_complete(atom);
211 }
212
213 /**
214 * kbase_kinstr_jm_atom_sw_start() - A software atom has started work
215 * @atom: The atom that has changed state
216 */
kbase_kinstr_jm_atom_sw_start(struct kbase_jd_atom * const atom)217 static inline void kbase_kinstr_jm_atom_sw_start(
218 struct kbase_jd_atom *const atom)
219 {
220 kbase_kinstr_jm_atom_state_start(atom);
221 }
222
223 /**
224 * kbase_kinstr_jm_atom_sw_stop() - A software atom has stopped work
225 * @atom: The atom that has changed state
226 */
kbase_kinstr_jm_atom_sw_stop(struct kbase_jd_atom * const atom)227 static inline void kbase_kinstr_jm_atom_sw_stop(
228 struct kbase_jd_atom *const atom)
229 {
230 kbase_kinstr_jm_atom_state_stop(atom);
231 }
232
233 /**
234 * kbasep_kinstr_jm_atom_hw_submit() - A hardware atom has been submitted
235 * @atom: The atom that has been submitted
236 *
237 * This private implementation should not be called directly, it is protected
238 * by a static key in kbase_kinstr_jm_atom_hw_submit(). Use that instead.
239 */
240 void kbasep_kinstr_jm_atom_hw_submit(struct kbase_jd_atom *const atom);
241
242 /**
243 * kbase_kinstr_jm_atom_hw_submit() - A hardware atom has been submitted
244 * @atom: The atom that has been submitted
245 */
kbase_kinstr_jm_atom_hw_submit(struct kbase_jd_atom * const atom)246 static inline void kbase_kinstr_jm_atom_hw_submit(
247 struct kbase_jd_atom *const atom)
248 {
249 if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key))
250 kbasep_kinstr_jm_atom_hw_submit(atom);
251 }
252
253 /**
254 * kbasep_kinstr_jm_atom_hw_release() - A hardware atom has been released
255 * @atom: The atom that has been released
256 *
257 * This private implementation should not be called directly, it is protected
258 * by a static key in kbase_kinstr_jm_atom_hw_release(). Use that instead.
259 */
260 void kbasep_kinstr_jm_atom_hw_release(struct kbase_jd_atom *const atom);
261
262 /**
263 * kbase_kinstr_jm_atom_hw_release() - A hardware atom has been released
264 * @atom: The atom that has been released
265 */
kbase_kinstr_jm_atom_hw_release(struct kbase_jd_atom * const atom)266 static inline void kbase_kinstr_jm_atom_hw_release(
267 struct kbase_jd_atom *const atom)
268 {
269 if (static_branch_unlikely(&basep_kinstr_jm_reader_static_key))
270 kbasep_kinstr_jm_atom_hw_release(atom);
271 }
272
273 #endif /* _KBASE_KINSTR_JM_H_ */
274