diff options
author | Anthony Koo <Anthony.Koo@amd.com> | 2018-02-22 09:50:25 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2018-03-14 16:08:47 -0400 |
commit | a3e1737ed61c8b6ea078f477eee612e26f9d2561 (patch) | |
tree | 479253ee203048b79487c05160626b6277241eb3 /drivers/gpu/drm/amd/display/modules | |
parent | e18d3086733bd150f87594a754ae983329fb0ba1 (diff) |
drm/amd/display: Implement stats logging
Stats will be used for debug purposes
Signed-off-by: Anthony Koo <Anthony.Koo@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/modules')
4 files changed, 507 insertions, 30 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index b4723af368a5..e849b704f2f6 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c | |||
@@ -33,7 +33,7 @@ | |||
33 | /* Refresh rate ramp at a fixed rate of 65 Hz/second */ | 33 | /* Refresh rate ramp at a fixed rate of 65 Hz/second */ |
34 | #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) | 34 | #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) |
35 | /* Number of elements in the render times cache array */ | 35 | /* Number of elements in the render times cache array */ |
36 | #define RENDER_TIMES_MAX_COUNT 20 | 36 | #define RENDER_TIMES_MAX_COUNT 10 |
37 | /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ | 37 | /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ |
38 | #define BTR_EXIT_MARGIN 2000 | 38 | #define BTR_EXIT_MARGIN 2000 |
39 | /* Number of consecutive frames to check before entering/exiting fixed refresh*/ | 39 | /* Number of consecutive frames to check before entering/exiting fixed refresh*/ |
@@ -52,7 +52,7 @@ struct gradual_static_ramp { | |||
52 | unsigned int ramp_current_frame_duration_in_ns; | 52 | unsigned int ramp_current_frame_duration_in_ns; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct time_cache { | 55 | struct freesync_time { |
56 | /* video (48Hz feature) related */ | 56 | /* video (48Hz feature) related */ |
57 | unsigned int update_duration_in_ns; | 57 | unsigned int update_duration_in_ns; |
58 | 58 | ||
@@ -64,6 +64,9 @@ struct time_cache { | |||
64 | 64 | ||
65 | unsigned int render_times_index; | 65 | unsigned int render_times_index; |
66 | unsigned int render_times[RENDER_TIMES_MAX_COUNT]; | 66 | unsigned int render_times[RENDER_TIMES_MAX_COUNT]; |
67 | |||
68 | unsigned int min_window; | ||
69 | unsigned int max_window; | ||
67 | }; | 70 | }; |
68 | 71 | ||
69 | struct below_the_range { | 72 | struct below_the_range { |
@@ -98,11 +101,14 @@ struct freesync_state { | |||
98 | bool static_screen; | 101 | bool static_screen; |
99 | bool video; | 102 | bool video; |
100 | 103 | ||
104 | unsigned int vmin; | ||
105 | unsigned int vmax; | ||
106 | |||
107 | struct freesync_time time; | ||
108 | |||
101 | unsigned int nominal_refresh_rate_in_micro_hz; | 109 | unsigned int nominal_refresh_rate_in_micro_hz; |
102 | bool windowed_fullscreen; | 110 | bool windowed_fullscreen; |
103 | 111 | ||
104 | struct time_cache time; | ||
105 | |||
106 | struct gradual_static_ramp static_ramp; | 112 | struct gradual_static_ramp static_ramp; |
107 | struct below_the_range btr; | 113 | struct below_the_range btr; |
108 | struct fixed_refresh fixed_refresh; | 114 | struct fixed_refresh fixed_refresh; |
@@ -124,9 +130,9 @@ struct freesync_registry_options { | |||
124 | struct core_freesync { | 130 | struct core_freesync { |
125 | struct mod_freesync public; | 131 | struct mod_freesync public; |
126 | struct dc *dc; | 132 | struct dc *dc; |
133 | struct freesync_registry_options opts; | ||
127 | struct freesync_entity *map; | 134 | struct freesync_entity *map; |
128 | int num_entities; | 135 | int num_entities; |
129 | struct freesync_registry_options opts; | ||
130 | }; | 136 | }; |
131 | 137 | ||
132 | #define MOD_FREESYNC_TO_CORE(mod_freesync)\ | 138 | #define MOD_FREESYNC_TO_CORE(mod_freesync)\ |
@@ -146,7 +152,7 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) | |||
146 | goto fail_alloc_context; | 152 | goto fail_alloc_context; |
147 | 153 | ||
148 | core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, | 154 | core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, |
149 | GFP_KERNEL); | 155 | GFP_KERNEL); |
150 | 156 | ||
151 | if (core_freesync->map == NULL) | 157 | if (core_freesync->map == NULL) |
152 | goto fail_alloc_map; | 158 | goto fail_alloc_map; |
@@ -330,6 +336,25 @@ bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, | |||
330 | return true; | 336 | return true; |
331 | } | 337 | } |
332 | 338 | ||
339 | static void adjust_vmin_vmax(struct core_freesync *core_freesync, | ||
340 | struct dc_stream_state **streams, | ||
341 | int num_streams, | ||
342 | int map_index, | ||
343 | unsigned int v_total_min, | ||
344 | unsigned int v_total_max) | ||
345 | { | ||
346 | if (num_streams == 0 || streams == NULL || num_streams > 1) | ||
347 | return; | ||
348 | |||
349 | core_freesync->map[map_index].state.vmin = v_total_min; | ||
350 | core_freesync->map[map_index].state.vmax = v_total_max; | ||
351 | |||
352 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | ||
353 | num_streams, v_total_min, | ||
354 | v_total_max); | ||
355 | } | ||
356 | |||
357 | |||
333 | static void update_stream_freesync_context(struct core_freesync *core_freesync, | 358 | static void update_stream_freesync_context(struct core_freesync *core_freesync, |
334 | struct dc_stream_state *stream) | 359 | struct dc_stream_state *stream) |
335 | { | 360 | { |
@@ -588,9 +613,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
588 | update_stream_freesync_context(core_freesync, | 613 | update_stream_freesync_context(core_freesync, |
589 | streams[stream_idx]); | 614 | streams[stream_idx]); |
590 | 615 | ||
591 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 616 | adjust_vmin_vmax(core_freesync, streams, |
592 | num_streams, v_total_min, | 617 | num_streams, map_index, |
593 | v_total_max); | 618 | v_total_min, |
619 | v_total_max); | ||
594 | 620 | ||
595 | return true; | 621 | return true; |
596 | 622 | ||
@@ -613,9 +639,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
613 | core_freesync, | 639 | core_freesync, |
614 | streams[stream_idx]); | 640 | streams[stream_idx]); |
615 | 641 | ||
616 | dc_stream_adjust_vmin_vmax( | 642 | adjust_vmin_vmax( |
617 | core_freesync->dc, streams, | 643 | core_freesync, streams, |
618 | num_streams, v_total_nominal, | 644 | num_streams, map_index, |
645 | v_total_nominal, | ||
619 | v_total_nominal); | 646 | v_total_nominal); |
620 | } | 647 | } |
621 | return true; | 648 | return true; |
@@ -632,9 +659,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
632 | core_freesync, | 659 | core_freesync, |
633 | streams[stream_idx]); | 660 | streams[stream_idx]); |
634 | 661 | ||
635 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 662 | adjust_vmin_vmax(core_freesync, streams, |
636 | num_streams, v_total_nominal, | 663 | num_streams, map_index, |
637 | v_total_nominal); | 664 | v_total_nominal, |
665 | v_total_nominal); | ||
638 | 666 | ||
639 | /* Reset the cached variables */ | 667 | /* Reset the cached variables */ |
640 | reset_freesync_state_variables(state); | 668 | reset_freesync_state_variables(state); |
@@ -650,9 +678,10 @@ static bool set_freesync_on_streams(struct core_freesync *core_freesync, | |||
650 | * not support freesync because a former stream has | 678 | * not support freesync because a former stream has |
651 | * be programmed | 679 | * be programmed |
652 | */ | 680 | */ |
653 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 681 | adjust_vmin_vmax(core_freesync, streams, |
654 | num_streams, v_total_nominal, | 682 | num_streams, map_index, |
655 | v_total_nominal); | 683 | v_total_nominal, |
684 | v_total_nominal); | ||
656 | /* Reset the cached variables */ | 685 | /* Reset the cached variables */ |
657 | reset_freesync_state_variables(state); | 686 | reset_freesync_state_variables(state); |
658 | } | 687 | } |
@@ -769,8 +798,9 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, | |||
769 | vmin = inserted_frame_v_total; | 798 | vmin = inserted_frame_v_total; |
770 | 799 | ||
771 | /* Program V_TOTAL */ | 800 | /* Program V_TOTAL */ |
772 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 801 | adjust_vmin_vmax(core_freesync, streams, |
773 | num_streams, vmin, vmax); | 802 | num_streams, index, |
803 | vmin, vmax); | ||
774 | } | 804 | } |
775 | 805 | ||
776 | if (state->btr.frame_counter > 0) | 806 | if (state->btr.frame_counter > 0) |
@@ -804,9 +834,10 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, | |||
804 | update_stream_freesync_context(core_freesync, streams[0]); | 834 | update_stream_freesync_context(core_freesync, streams[0]); |
805 | 835 | ||
806 | /* Program static screen ramp values */ | 836 | /* Program static screen ramp values */ |
807 | dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, | 837 | adjust_vmin_vmax(core_freesync, streams, |
808 | num_streams, v_total, | 838 | num_streams, index, |
809 | v_total); | 839 | v_total, |
840 | v_total); | ||
810 | 841 | ||
811 | triggers.overlay_update = true; | 842 | triggers.overlay_update = true; |
812 | triggers.surface_update = true; | 843 | triggers.surface_update = true; |
@@ -1063,9 +1094,9 @@ bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, | |||
1063 | max_refresh); | 1094 | max_refresh); |
1064 | 1095 | ||
1065 | /* Program vtotal min/max */ | 1096 | /* Program vtotal min/max */ |
1066 | dc_stream_adjust_vmin_vmax(core_freesync->dc, &streams, 1, | 1097 | adjust_vmin_vmax(core_freesync, &streams, 1, index, |
1067 | state->freesync_range.vmin, | 1098 | state->freesync_range.vmin, |
1068 | state->freesync_range.vmax); | 1099 | state->freesync_range.vmax); |
1069 | } | 1100 | } |
1070 | 1101 | ||
1071 | if (min_refresh != 0 && | 1102 | if (min_refresh != 0 && |
@@ -1399,11 +1430,9 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync, | |||
1399 | } else { | 1430 | } else { |
1400 | 1431 | ||
1401 | vmin = state->freesync_range.vmin; | 1432 | vmin = state->freesync_range.vmin; |
1402 | |||
1403 | vmax = vmin; | 1433 | vmax = vmin; |
1404 | 1434 | adjust_vmin_vmax(core_freesync, &stream, map_index, | |
1405 | dc_stream_adjust_vmin_vmax(core_freesync->dc, &stream, | 1435 | 1, vmin, vmax); |
1406 | 1, vmin, vmax); | ||
1407 | } | 1436 | } |
1408 | } | 1437 | } |
1409 | 1438 | ||
@@ -1457,3 +1486,43 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, | |||
1457 | 1486 | ||
1458 | } | 1487 | } |
1459 | } | 1488 | } |
1489 | |||
1490 | void mod_freesync_get_settings(struct mod_freesync *mod_freesync, | ||
1491 | struct dc_stream_state **streams, int num_streams, | ||
1492 | unsigned int *v_total_min, unsigned int *v_total_max, | ||
1493 | unsigned int *event_triggers, | ||
1494 | unsigned int *window_min, unsigned int *window_max, | ||
1495 | unsigned int *lfc_mid_point_in_us, | ||
1496 | unsigned int *inserted_frames, | ||
1497 | unsigned int *inserted_duration_in_us) | ||
1498 | { | ||
1499 | unsigned int stream_index, map_index; | ||
1500 | struct core_freesync *core_freesync = NULL; | ||
1501 | |||
1502 | if (mod_freesync == NULL) | ||
1503 | return; | ||
1504 | |||
1505 | core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); | ||
1506 | |||
1507 | for (stream_index = 0; stream_index < num_streams; stream_index++) { | ||
1508 | |||
1509 | map_index = map_index_from_stream(core_freesync, | ||
1510 | streams[stream_index]); | ||
1511 | |||
1512 | if (core_freesync->map[map_index].caps->supported) { | ||
1513 | struct freesync_state state = | ||
1514 | core_freesync->map[map_index].state; | ||
1515 | *v_total_min = state.vmin; | ||
1516 | *v_total_max = state.vmax; | ||
1517 | *event_triggers = 0; | ||
1518 | *window_min = state.time.min_window; | ||
1519 | *window_max = state.time.max_window; | ||
1520 | *lfc_mid_point_in_us = state.btr.mid_point_in_us; | ||
1521 | *inserted_frames = state.btr.frames_to_insert; | ||
1522 | *inserted_duration_in_us = | ||
1523 | state.btr.inserted_frame_duration_in_us; | ||
1524 | } | ||
1525 | |||
1526 | } | ||
1527 | } | ||
1528 | |||
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index 84b53425f2c8..f083e1619dbe 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h | |||
@@ -164,4 +164,13 @@ void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, | |||
164 | struct dc_stream_state **streams, int num_streams, | 164 | struct dc_stream_state **streams, int num_streams, |
165 | unsigned int curr_time_stamp); | 165 | unsigned int curr_time_stamp); |
166 | 166 | ||
167 | void mod_freesync_get_settings(struct mod_freesync *mod_freesync, | ||
168 | struct dc_stream_state **streams, int num_streams, | ||
169 | unsigned int *v_total_min, unsigned int *v_total_max, | ||
170 | unsigned int *event_triggers, | ||
171 | unsigned int *window_min, unsigned int *window_max, | ||
172 | unsigned int *lfc_mid_point_in_us, | ||
173 | unsigned int *inserted_frames, | ||
174 | unsigned int *inserted_duration_in_us); | ||
175 | |||
167 | #endif | 176 | #endif |
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h new file mode 100644 index 000000000000..3230e2adb870 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_stats.h | |||
@@ -0,0 +1,65 @@ | |||
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 | #ifndef MODULES_INC_MOD_STATS_H_ | ||
27 | #define MODULES_INC_MOD_STATS_H_ | ||
28 | |||
29 | #include "dm_services.h" | ||
30 | |||
31 | struct mod_stats { | ||
32 | int dummy; | ||
33 | }; | ||
34 | |||
35 | struct mod_stats_caps { | ||
36 | bool dummy; | ||
37 | }; | ||
38 | |||
39 | struct mod_stats *mod_stats_create(struct dc *dc); | ||
40 | |||
41 | void mod_stats_destroy(struct mod_stats *mod_stats); | ||
42 | |||
43 | bool mod_stats_init(struct mod_stats *mod_stats); | ||
44 | |||
45 | void mod_stats_dump(struct mod_stats *mod_stats); | ||
46 | |||
47 | void mod_stats_reset_data(struct mod_stats *mod_stats); | ||
48 | |||
49 | void mod_stats_update_flip(struct mod_stats *mod_stats, | ||
50 | unsigned long timestamp_in_ns); | ||
51 | |||
52 | void mod_stats_update_vupdate(struct mod_stats *mod_stats, | ||
53 | unsigned long timestamp_in_ns); | ||
54 | |||
55 | void mod_stats_update_freesync(struct mod_stats *mod_stats, | ||
56 | unsigned int v_total_min, | ||
57 | unsigned int v_total_max, | ||
58 | unsigned int event_triggers, | ||
59 | unsigned int window_min, | ||
60 | unsigned int window_max, | ||
61 | unsigned int lfc_mid_point_in_us, | ||
62 | unsigned int inserted_frames, | ||
63 | unsigned int inserted_frame_duration_in_us); | ||
64 | |||
65 | #endif /* MODULES_INC_MOD_STATS_H_ */ | ||
diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c new file mode 100644 index 000000000000..041f87b73d5f --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c | |||
@@ -0,0 +1,334 @@ | |||
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 | |||
39 | #define MOD_STATS_NUM_VSYNCS 5 | ||
40 | |||
41 | struct stats_time_cache { | ||
42 | unsigned long flip_timestamp_in_ns; | ||
43 | unsigned long vupdate_timestamp_in_ns; | ||
44 | |||
45 | unsigned int render_time_in_us; | ||
46 | unsigned int avg_render_time_in_us_last_ten; | ||
47 | unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS]; | ||
48 | unsigned int num_vsync_between_flips; | ||
49 | |||
50 | unsigned int flip_to_vsync_time_in_us; | ||
51 | unsigned int vsync_to_flip_time_in_us; | ||
52 | |||
53 | unsigned int min_window; | ||
54 | unsigned int max_window; | ||
55 | unsigned int v_total_min; | ||
56 | unsigned int v_total_max; | ||
57 | unsigned int event_triggers; | ||
58 | |||
59 | unsigned int lfc_mid_point_in_us; | ||
60 | unsigned int num_frames_inserted; | ||
61 | unsigned int inserted_duration_in_us; | ||
62 | |||
63 | unsigned int flags; | ||
64 | }; | ||
65 | |||
66 | struct core_stats { | ||
67 | struct mod_stats public; | ||
68 | struct dc *dc; | ||
69 | |||
70 | struct stats_time_cache *time; | ||
71 | unsigned int index; | ||
72 | |||
73 | bool enabled; | ||
74 | unsigned int entries; | ||
75 | }; | ||
76 | |||
77 | #define MOD_STATS_TO_CORE(mod_stats)\ | ||
78 | container_of(mod_stats, struct core_stats, public) | ||
79 | |||
80 | bool mod_stats_init(struct mod_stats *mod_stats) | ||
81 | { | ||
82 | bool result = false; | ||
83 | struct core_stats *core_stats = NULL; | ||
84 | struct dc *dc = NULL; | ||
85 | |||
86 | if (mod_stats == NULL) | ||
87 | return false; | ||
88 | |||
89 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
90 | dc = core_stats->dc; | ||
91 | |||
92 | return result; | ||
93 | } | ||
94 | |||
95 | struct mod_stats *mod_stats_create(struct dc *dc) | ||
96 | { | ||
97 | struct core_stats *core_stats = NULL; | ||
98 | struct persistent_data_flag flag; | ||
99 | unsigned int reg_data; | ||
100 | int i = 0; | ||
101 | |||
102 | core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL); | ||
103 | |||
104 | if (core_stats == NULL) | ||
105 | goto fail_alloc_context; | ||
106 | |||
107 | if (dc == NULL) | ||
108 | goto fail_construct; | ||
109 | |||
110 | core_stats->dc = dc; | ||
111 | |||
112 | core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT; | ||
113 | if (dm_read_persistent_data(dc->ctx, NULL, NULL, | ||
114 | DAL_STATS_ENABLE_REGKEY, | ||
115 | ®_data, sizeof(unsigned int), &flag)) | ||
116 | core_stats->enabled = reg_data; | ||
117 | |||
118 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT; | ||
119 | if (dm_read_persistent_data(dc->ctx, NULL, NULL, | ||
120 | DAL_STATS_ENTRIES_REGKEY, | ||
121 | ®_data, sizeof(unsigned int), &flag)) { | ||
122 | if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX) | ||
123 | core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX; | ||
124 | else | ||
125 | core_stats->entries = reg_data; | ||
126 | } | ||
127 | |||
128 | core_stats->time = kzalloc(sizeof(struct stats_time_cache) * core_stats->entries, | ||
129 | GFP_KERNEL); | ||
130 | |||
131 | if (core_stats->time == NULL) | ||
132 | goto fail_construct; | ||
133 | |||
134 | /* Purposely leave index 0 unused so we don't need special logic to | ||
135 | * handle calculation cases that depend on previous flip data. | ||
136 | */ | ||
137 | core_stats->index = 1; | ||
138 | |||
139 | return &core_stats->public; | ||
140 | |||
141 | fail_construct: | ||
142 | kfree(core_stats); | ||
143 | |||
144 | fail_alloc_context: | ||
145 | return NULL; | ||
146 | } | ||
147 | |||
148 | void mod_stats_destroy(struct mod_stats *mod_stats) | ||
149 | { | ||
150 | if (mod_stats != NULL) { | ||
151 | struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
152 | |||
153 | if (core_stats->time != NULL) | ||
154 | kfree(core_stats->time); | ||
155 | |||
156 | kfree(core_stats); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void mod_stats_dump(struct mod_stats *mod_stats) | ||
161 | { | ||
162 | struct dc *dc = NULL; | ||
163 | struct dal_logger *logger = NULL; | ||
164 | struct core_stats *core_stats = NULL; | ||
165 | struct stats_time_cache *time = NULL; | ||
166 | unsigned int index = 0; | ||
167 | |||
168 | if (mod_stats == NULL) | ||
169 | return; | ||
170 | |||
171 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
172 | dc = core_stats->dc; | ||
173 | logger = dc->ctx->logger; | ||
174 | time = core_stats->time; | ||
175 | |||
176 | //LogEntry* pLog = GetLog()->Open(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); | ||
177 | |||
178 | //if (!pLog->IsDummyEntry()) | ||
179 | { | ||
180 | dm_logger_write(logger, LOG_PROFILING, "==Display Caps==\n"); | ||
181 | dm_logger_write(logger, LOG_PROFILING, "\n"); | ||
182 | dm_logger_write(logger, LOG_PROFILING, "\n"); | ||
183 | |||
184 | dm_logger_write(logger, LOG_PROFILING, "==Stats==\n"); | ||
185 | dm_logger_write(logger, LOG_PROFILING, | ||
186 | "render avgRender minWindow midPoint maxWindow vsyncToFlip flipToVsync #vsyncBetweenFlip #frame insertDuration vTotalMin vTotalMax eventTrigs vSyncTime1 vSyncTime2 vSyncTime3 vSyncTime4 vSyncTime5 flags\n"); | ||
187 | |||
188 | for (int i = 0; i < core_stats->index && i < core_stats->entries; i++) { | ||
189 | dm_logger_write(logger, LOG_PROFILING, | ||
190 | "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n", | ||
191 | time[i].render_time_in_us, | ||
192 | time[i].avg_render_time_in_us_last_ten, | ||
193 | time[i].min_window, | ||
194 | time[i].lfc_mid_point_in_us, | ||
195 | time[i].max_window, | ||
196 | time[i].vsync_to_flip_time_in_us, | ||
197 | time[i].flip_to_vsync_time_in_us, | ||
198 | time[i].num_vsync_between_flips, | ||
199 | time[i].num_frames_inserted, | ||
200 | time[i].inserted_duration_in_us, | ||
201 | time[i].v_total_min, | ||
202 | time[i].v_total_max, | ||
203 | time[i].event_triggers, | ||
204 | time[i].v_sync_time_in_us[0], | ||
205 | time[i].v_sync_time_in_us[1], | ||
206 | time[i].v_sync_time_in_us[2], | ||
207 | time[i].v_sync_time_in_us[3], | ||
208 | time[i].v_sync_time_in_us[4], | ||
209 | time[i].flags); | ||
210 | } | ||
211 | } | ||
212 | //GetLog()->Close(pLog); | ||
213 | //GetLog()->UnSetLogMask(LogMajor_ISR, LogMinor_ISR_FreeSyncSW); | ||
214 | } | ||
215 | |||
216 | void mod_stats_reset_data(struct mod_stats *mod_stats) | ||
217 | { | ||
218 | struct core_stats *core_stats = NULL; | ||
219 | struct stats_time_cache *time = NULL; | ||
220 | unsigned int index = 0; | ||
221 | |||
222 | if (mod_stats == NULL) | ||
223 | return; | ||
224 | |||
225 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
226 | |||
227 | memset(core_stats->time, 0, | ||
228 | sizeof(struct stats_time_cache) * core_stats->entries); | ||
229 | |||
230 | core_stats->index = 0; | ||
231 | } | ||
232 | |||
233 | void mod_stats_update_flip(struct mod_stats *mod_stats, | ||
234 | unsigned long timestamp_in_ns) | ||
235 | { | ||
236 | struct core_stats *core_stats = NULL; | ||
237 | struct stats_time_cache *time = NULL; | ||
238 | unsigned int index = 0; | ||
239 | |||
240 | if (mod_stats == NULL) | ||
241 | return; | ||
242 | |||
243 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
244 | |||
245 | if (core_stats->index >= core_stats->entries) | ||
246 | return; | ||
247 | |||
248 | time = core_stats->time; | ||
249 | index = core_stats->index; | ||
250 | |||
251 | time[index].flip_timestamp_in_ns = timestamp_in_ns; | ||
252 | time[index].render_time_in_us = | ||
253 | timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; | ||
254 | |||
255 | if (index >= 10) { | ||
256 | for (unsigned int i = 0; i < 10; i++) | ||
257 | time[index].avg_render_time_in_us_last_ten += | ||
258 | time[index - i].render_time_in_us; | ||
259 | time[index].avg_render_time_in_us_last_ten /= 10; | ||
260 | } | ||
261 | |||
262 | if (time[index].num_vsync_between_flips > 0) | ||
263 | time[index].vsync_to_flip_time_in_us = | ||
264 | timestamp_in_ns - time[index].vupdate_timestamp_in_ns; | ||
265 | else | ||
266 | time[index].vsync_to_flip_time_in_us = | ||
267 | timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; | ||
268 | |||
269 | core_stats->index++; | ||
270 | } | ||
271 | |||
272 | void mod_stats_update_vupdate(struct mod_stats *mod_stats, | ||
273 | unsigned long timestamp_in_ns) | ||
274 | { | ||
275 | struct core_stats *core_stats = NULL; | ||
276 | struct stats_time_cache *time = NULL; | ||
277 | unsigned int index = 0; | ||
278 | |||
279 | if (mod_stats == NULL) | ||
280 | return; | ||
281 | |||
282 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
283 | |||
284 | if (core_stats->index >= core_stats->entries) | ||
285 | return; | ||
286 | |||
287 | time = core_stats->time; | ||
288 | index = core_stats->index; | ||
289 | |||
290 | time[index].vupdate_timestamp_in_ns = timestamp_in_ns; | ||
291 | if (time[index].num_vsync_between_flips < MOD_STATS_NUM_VSYNCS) | ||
292 | time[index].v_sync_time_in_us[time[index].num_vsync_between_flips] = | ||
293 | timestamp_in_ns - time[index - 1].vupdate_timestamp_in_ns; | ||
294 | time[index].flip_to_vsync_time_in_us = | ||
295 | timestamp_in_ns - time[index - 1].flip_timestamp_in_ns; | ||
296 | |||
297 | time[index].num_vsync_between_flips++; | ||
298 | } | ||
299 | |||
300 | void mod_stats_update_freesync(struct mod_stats *mod_stats, | ||
301 | unsigned int v_total_min, | ||
302 | unsigned int v_total_max, | ||
303 | unsigned int event_triggers, | ||
304 | unsigned int window_min, | ||
305 | unsigned int window_max, | ||
306 | unsigned int lfc_mid_point_in_us, | ||
307 | unsigned int inserted_frames, | ||
308 | unsigned int inserted_duration_in_us) | ||
309 | { | ||
310 | struct core_stats *core_stats = NULL; | ||
311 | struct stats_time_cache *time = NULL; | ||
312 | unsigned int index = 0; | ||
313 | |||
314 | if (mod_stats == NULL) | ||
315 | return; | ||
316 | |||
317 | core_stats = MOD_STATS_TO_CORE(mod_stats); | ||
318 | |||
319 | if (core_stats->index >= core_stats->entries) | ||
320 | return; | ||
321 | |||
322 | time = core_stats->time; | ||
323 | index = core_stats->index; | ||
324 | |||
325 | time[index].v_total_min = v_total_min; | ||
326 | time[index].v_total_max = v_total_max; | ||
327 | time[index].event_triggers = event_triggers; | ||
328 | time[index].min_window = window_min; | ||
329 | time[index].max_window = window_max; | ||
330 | time[index].lfc_mid_point_in_us = lfc_mid_point_in_us; | ||
331 | time[index].num_frames_inserted = inserted_frames; | ||
332 | time[index].inserted_duration_in_us = inserted_duration_in_us; | ||
333 | } | ||
334 | |||