treewide: kzalloc() -> kcalloc()
[linux-2.6-block.git] / drivers / gpu / drm / amd / display / modules / stats / stats.c
CommitLineData
a3e1737e
AK
1/*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "mod_stats.h"
27#include "dm_services.h"
28#include "dc.h"
29#include "core_types.h"
30
31#define DAL_STATS_ENABLE_REGKEY "DalStatsEnable"
32#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000001
33#define DAL_STATS_ENABLE_REGKEY_ENABLED 0x00000001
34
35#define DAL_STATS_ENTRIES_REGKEY "DalStatsEntries"
36#define DAL_STATS_ENTRIES_REGKEY_DEFAULT 0x00350000
37#define DAL_STATS_ENTRIES_REGKEY_MAX 0x01000000
38
6474b282
AK
39#define DAL_STATS_EVENT_ENTRIES_DEFAULT 0x00000100
40
a3e1737e 41#define MOD_STATS_NUM_VSYNCS 5
6474b282 42#define MOD_STATS_EVENT_STRING_MAX 512
a3e1737e
AK
43
44struct stats_time_cache {
6474b282
AK
45 unsigned int entry_id;
46
a3e1737e
AK
47 unsigned long flip_timestamp_in_ns;
48 unsigned long vupdate_timestamp_in_ns;
49
50 unsigned int render_time_in_us;
51 unsigned int avg_render_time_in_us_last_ten;
52 unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS];
53 unsigned int num_vsync_between_flips;
54
55 unsigned int flip_to_vsync_time_in_us;
56 unsigned int vsync_to_flip_time_in_us;
57
58 unsigned int min_window;
59 unsigned int max_window;
60 unsigned int v_total_min;
61 unsigned int v_total_max;
62 unsigned int event_triggers;
63
64 unsigned int lfc_mid_point_in_us;
65 unsigned int num_frames_inserted;
66 unsigned int inserted_duration_in_us;
67
68 unsigned int flags;
69};
70
6474b282
AK
71struct stats_event_cache {
72 unsigned int entry_id;
73 char event_string[MOD_STATS_EVENT_STRING_MAX];
74};
75
a3e1737e
AK
76struct core_stats {
77 struct mod_stats public;
78 struct dc *dc;
79
6474b282
AK
80 bool enabled;
81 unsigned int entries;
82 unsigned int event_entries;
83 unsigned int entry_id;
84
a3e1737e
AK
85 struct stats_time_cache *time;
86 unsigned int index;
87
6474b282
AK
88 struct stats_event_cache *events;
89 unsigned int event_index;
90
a3e1737e
AK
91};
92
93#define MOD_STATS_TO_CORE(mod_stats)\
94 container_of(mod_stats, struct core_stats, public)
95
96bool mod_stats_init(struct mod_stats *mod_stats)
97{
98 bool result = false;
99 struct core_stats *core_stats = NULL;
100 struct dc *dc = NULL;
101
102 if (mod_stats == NULL)
103 return false;
104
105 core_stats = MOD_STATS_TO_CORE(mod_stats);
106 dc = core_stats->dc;
107
108 return result;
109}
110
111struct mod_stats *mod_stats_create(struct dc *dc)
112{
113 struct core_stats *core_stats = NULL;
114 struct persistent_data_flag flag;
115 unsigned int reg_data;
116 int i = 0;
117
9fcab85c
AK
118 if (dc == NULL)
119 goto fail_construct;
120
a3e1737e
AK
121 core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL);
122
123 if (core_stats == NULL)
a3e1737e
AK
124 goto fail_construct;
125
126 core_stats->dc = dc;
127
128 core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT;
129 if (dm_read_persistent_data(dc->ctx, NULL, NULL,
130 DAL_STATS_ENABLE_REGKEY,
131 &reg_data, sizeof(unsigned int), &flag))
132 core_stats->enabled = reg_data;
133
c4b0faae
AK
134 if (core_stats->enabled) {
135 core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT;
136 if (dm_read_persistent_data(dc->ctx, NULL, NULL,
137 DAL_STATS_ENTRIES_REGKEY,
138 &reg_data, sizeof(unsigned int), &flag)) {
139 if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX)
140 core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX;
141 else
142 core_stats->entries = reg_data;
143 }
6396bb22
KC
144 core_stats->time = kcalloc(core_stats->entries,
145 sizeof(struct stats_time_cache),
6474b282 146 GFP_KERNEL);
c4b0faae 147
9fcab85c
AK
148 if (core_stats->time == NULL)
149 goto fail_construct_time;
6474b282
AK
150
151 core_stats->event_entries = DAL_STATS_EVENT_ENTRIES_DEFAULT;
6396bb22
KC
152 core_stats->events = kcalloc(core_stats->event_entries,
153 sizeof(struct stats_event_cache),
154 GFP_KERNEL);
6474b282 155
9fcab85c
AK
156 if (core_stats->events == NULL)
157 goto fail_construct_events;
158
c4b0faae
AK
159 } else {
160 core_stats->entries = 0;
a3e1737e
AK
161 }
162
a3e1737e
AK
163 /* Purposely leave index 0 unused so we don't need special logic to
164 * handle calculation cases that depend on previous flip data.
165 */
166 core_stats->index = 1;
6474b282
AK
167 core_stats->event_index = 0;
168
169 // Keeps track of ordering within the different stats structures
170 core_stats->entry_id = 0;
a3e1737e
AK
171
172 return &core_stats->public;
173
9fcab85c
AK
174fail_construct_events:
175 kfree(core_stats->time);
176
177fail_construct_time:
a3e1737e
AK
178 kfree(core_stats);
179
9fcab85c 180fail_construct:
a3e1737e
AK
181 return NULL;
182}
183
184void mod_stats_destroy(struct mod_stats *mod_stats)
185{
186 if (mod_stats != NULL) {
187 struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats);
188
189 if (core_stats->time != NULL)
190 kfree(core_stats->time);
191
9fcab85c
AK
192 if (core_stats->events != NULL)
193 kfree(core_stats->events);
194
a3e1737e
AK
195 kfree(core_stats);
196 }
197}
198
199void mod_stats_dump(struct mod_stats *mod_stats)
200{
201 struct dc *dc = NULL;
202 struct dal_logger *logger = NULL;
203 struct core_stats *core_stats = NULL;
204 struct stats_time_cache *time = NULL;
6474b282
AK
205 struct stats_event_cache *events = NULL;
206 unsigned int time_index = 1;
207 unsigned int event_index = 0;
a3e1737e 208 unsigned int index = 0;
66dec27a 209 struct log_entry log_entry;
a3e1737e
AK
210
211 if (mod_stats == NULL)
212 return;
213
214 core_stats = MOD_STATS_TO_CORE(mod_stats);
215 dc = core_stats->dc;
216 logger = dc->ctx->logger;
217 time = core_stats->time;
6474b282 218 events = core_stats->events;
a3e1737e 219
5103c568 220 DISPLAY_STATS_BEGIN(log_entry);
e8838df1 221
5103c568 222 DISPLAY_STATS("==Display Caps==\n");
e8838df1 223
5103c568 224 DISPLAY_STATS("==Display Stats==\n");
66dec27a 225
5103c568 226 DISPLAY_STATS("%10s %10s %10s %10s %10s"
e8838df1
AK
227 " %11s %11s %17s %10s %14s"
228 " %10s %10s %10s %10s %10s"
66dec27a 229 " %10s %10s %10s %10s\n",
e8838df1
AK
230 "render", "avgRender",
231 "minWindow", "midPoint", "maxWindow",
232 "vsyncToFlip", "flipToVsync", "vsyncsBetweenFlip",
233 "numFrame", "insertDuration",
234 "vTotalMin", "vTotalMax", "eventTrigs",
235 "vSyncTime1", "vSyncTime2", "vSyncTime3",
236 "vSyncTime4", "vSyncTime5", "flags");
237
6474b282
AK
238 for (int i = 0; i < core_stats->entry_id; i++) {
239 if (event_index < core_stats->event_index &&
240 i == events[event_index].entry_id) {
241 DISPLAY_STATS("%s\n", events[event_index].event_string);
242 event_index++;
243 } else if (time_index < core_stats->index &&
244 i == time[time_index].entry_id) {
245 DISPLAY_STATS("%10u %10u %10u %10u %10u"
246 " %11u %11u %17u %10u %14u"
247 " %10u %10u %10u %10u %10u"
248 " %10u %10u %10u %10u\n",
249 time[time_index].render_time_in_us,
250 time[time_index].avg_render_time_in_us_last_ten,
251 time[time_index].min_window,
252 time[time_index].lfc_mid_point_in_us,
253 time[time_index].max_window,
254 time[time_index].vsync_to_flip_time_in_us,
255 time[time_index].flip_to_vsync_time_in_us,
256 time[time_index].num_vsync_between_flips,
257 time[time_index].num_frames_inserted,
258 time[time_index].inserted_duration_in_us,
259 time[time_index].v_total_min,
260 time[time_index].v_total_max,
261 time[time_index].event_triggers,
262 time[time_index].v_sync_time_in_us[0],
263 time[time_index].v_sync_time_in_us[1],
264 time[time_index].v_sync_time_in_us[2],
265 time[time_index].v_sync_time_in_us[3],
266 time[time_index].v_sync_time_in_us[4],
267 time[time_index].flags);
268
269 time_index++;
270 }
a3e1737e 271 }
66dec27a 272
5103c568 273 DISPLAY_STATS_END(log_entry);
a3e1737e
AK
274}
275
276void mod_stats_reset_data(struct mod_stats *mod_stats)
277{
278 struct core_stats *core_stats = NULL;
279 struct stats_time_cache *time = NULL;
280 unsigned int index = 0;
281
282 if (mod_stats == NULL)
283 return;
284
285 core_stats = MOD_STATS_TO_CORE(mod_stats);
286
287 memset(core_stats->time, 0,
288 sizeof(struct stats_time_cache) * core_stats->entries);
289
6474b282
AK
290 memset(core_stats->events, 0,
291 sizeof(struct stats_event_cache) * core_stats->event_entries);
292
f412e830 293 core_stats->index = 1;
6474b282
AK
294 core_stats->event_index = 0;
295
296 // Keeps track of ordering within the different stats structures
297 core_stats->entry_id = 0;
298}
299
300void mod_stats_update_event(struct mod_stats *mod_stats,
301 char *event_string,
302 unsigned int length)
303{
304 struct core_stats *core_stats = NULL;
305 struct stats_event_cache *events = NULL;
306 unsigned int index = 0;
307 unsigned int copy_length = 0;
308
309 if (mod_stats == NULL)
310 return;
311
312 core_stats = MOD_STATS_TO_CORE(mod_stats);
313
dab911d5 314 if (core_stats->event_index >= core_stats->event_entries)
6474b282
AK
315 return;
316
317 events = core_stats->events;
318 index = core_stats->event_index;
319
320 copy_length = length;
321 if (length > MOD_STATS_EVENT_STRING_MAX)
322 copy_length = MOD_STATS_EVENT_STRING_MAX;
323
324 memcpy(&events[index].event_string, event_string, copy_length);
325 events[index].event_string[copy_length - 1] = '\0';
326
327 events[index].entry_id = core_stats->entry_id;
328 core_stats->event_index++;
329 core_stats->entry_id++;
a3e1737e
AK
330}
331
332void mod_stats_update_flip(struct mod_stats *mod_stats,
333 unsigned long timestamp_in_ns)
334{
335 struct core_stats *core_stats = NULL;
336 struct stats_time_cache *time = NULL;
337 unsigned int index = 0;
338
339 if (mod_stats == NULL)
340 return;
341
342 core_stats = MOD_STATS_TO_CORE(mod_stats);
343
344 if (core_stats->index >= core_stats->entries)
345 return;
346
347 time = core_stats->time;
348 index = core_stats->index;
349
350 time[index].flip_timestamp_in_ns = timestamp_in_ns;
351 time[index].render_time_in_us =
f412e830 352 (timestamp_in_ns - time[index - 1].flip_timestamp_in_ns) / 1000;
a3e1737e
AK
353
354 if (index >= 10) {
355 for (unsigned int i = 0; i < 10; i++)
356 time[index].avg_render_time_in_us_last_ten +=
357 time[index - i].render_time_in_us;
358 time[index].avg_render_time_in_us_last_ten /= 10;
359 }
360
361 if (time[index].num_vsync_between_flips > 0)
362 time[index].vsync_to_flip_time_in_us =
f412e830
AK
363 (timestamp_in_ns -
364 time[index].vupdate_timestamp_in_ns) / 1000;
a3e1737e
AK
365 else
366 time[index].vsync_to_flip_time_in_us =
f412e830
AK
367 (timestamp_in_ns -
368 time[index - 1].vupdate_timestamp_in_ns) / 1000;
a3e1737e 369
6474b282 370 time[index].entry_id = core_stats->entry_id;
a3e1737e 371 core_stats->index++;
6474b282 372 core_stats->entry_id++;
a3e1737e
AK
373}
374
375void mod_stats_update_vupdate(struct mod_stats *mod_stats,
376 unsigned long timestamp_in_ns)
377{
378 struct core_stats *core_stats = NULL;
379 struct stats_time_cache *time = NULL;
380 unsigned int index = 0;
f412e830
AK
381 unsigned int num_vsyncs = 0;
382 unsigned int prev_vsync_in_ns = 0;
a3e1737e
AK
383
384 if (mod_stats == NULL)
385 return;
386
387 core_stats = MOD_STATS_TO_CORE(mod_stats);
388
389 if (core_stats->index >= core_stats->entries)
390 return;
391
392 time = core_stats->time;
393 index = core_stats->index;
f412e830
AK
394 num_vsyncs = time[index].num_vsync_between_flips;
395
396 if (num_vsyncs < MOD_STATS_NUM_VSYNCS) {
397 if (num_vsyncs == 0) {
398 prev_vsync_in_ns =
399 time[index - 1].vupdate_timestamp_in_ns;
400
401 time[index].flip_to_vsync_time_in_us =
402 (timestamp_in_ns -
403 time[index - 1].flip_timestamp_in_ns) /
404 1000;
405 } else {
406 prev_vsync_in_ns =
407 time[index].vupdate_timestamp_in_ns;
408 }
a3e1737e 409
f412e830
AK
410 time[index].v_sync_time_in_us[num_vsyncs] =
411 (timestamp_in_ns - prev_vsync_in_ns) / 1000;
412 }
a3e1737e 413
f412e830 414 time[index].vupdate_timestamp_in_ns = timestamp_in_ns;
a3e1737e
AK
415 time[index].num_vsync_between_flips++;
416}
417
418void mod_stats_update_freesync(struct mod_stats *mod_stats,
419 unsigned int v_total_min,
420 unsigned int v_total_max,
421 unsigned int event_triggers,
422 unsigned int window_min,
423 unsigned int window_max,
424 unsigned int lfc_mid_point_in_us,
425 unsigned int inserted_frames,
426 unsigned int inserted_duration_in_us)
427{
428 struct core_stats *core_stats = NULL;
429 struct stats_time_cache *time = NULL;
430 unsigned int index = 0;
431
432 if (mod_stats == NULL)
433 return;
434
435 core_stats = MOD_STATS_TO_CORE(mod_stats);
436
437 if (core_stats->index >= core_stats->entries)
438 return;
439
440 time = core_stats->time;
441 index = core_stats->index;
442
443 time[index].v_total_min = v_total_min;
444 time[index].v_total_max = v_total_max;
445 time[index].event_triggers = event_triggers;
446 time[index].min_window = window_min;
447 time[index].max_window = window_max;
448 time[index].lfc_mid_point_in_us = lfc_mid_point_in_us;
449 time[index].num_frames_inserted = inserted_frames;
450 time[index].inserted_duration_in_us = inserted_duration_in_us;
451}
452