Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anthony Koo and committed by
Alex Deucher
a3e1737e e18d3086

+510 -31
+2 -1
drivers/gpu/drm/amd/display/dc/basics/logger.c
··· 60 60 {LOG_EVENT_LINK_LOSS, "LinkLoss"}, 61 61 {LOG_EVENT_UNDERFLOW, "Underflow"}, 62 62 {LOG_IF_TRACE, "InterfaceTrace"}, 63 - {LOG_DTN, "DTN"} 63 + {LOG_DTN, "DTN"}, 64 + {LOG_PROFILING, "Profiling"} 64 65 }; 65 66 66 67
+1
drivers/gpu/drm/amd/display/include/logger_types.h
··· 98 98 LOG_EVENT_UNDERFLOW, 99 99 LOG_IF_TRACE, 100 100 LOG_PERF_TRACE, 101 + LOG_PROFILING, 101 102 102 103 LOG_SECTION_TOTAL_COUNT 103 104 };
+99 -30
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
··· 33 33 /* Refresh rate ramp at a fixed rate of 65 Hz/second */ 34 34 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) 35 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 37 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ 38 38 #define BTR_EXIT_MARGIN 2000 39 39 /* Number of consecutive frames to check before entering/exiting fixed refresh*/ ··· 52 52 unsigned int ramp_current_frame_duration_in_ns; 53 53 }; 54 54 55 - struct time_cache { 55 + struct freesync_time { 56 56 /* video (48Hz feature) related */ 57 57 unsigned int update_duration_in_ns; 58 58 ··· 64 64 65 65 unsigned int render_times_index; 66 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 72 struct below_the_range { ··· 101 98 bool static_screen; 102 99 bool video; 103 100 101 + unsigned int vmin; 102 + unsigned int vmax; 103 + 104 + struct freesync_time time; 105 + 104 106 unsigned int nominal_refresh_rate_in_micro_hz; 105 107 bool windowed_fullscreen; 106 - 107 - struct time_cache time; 108 108 109 109 struct gradual_static_ramp static_ramp; 110 110 struct below_the_range btr; ··· 130 124 struct core_freesync { 131 125 struct mod_freesync public; 132 126 struct dc *dc; 127 + struct freesync_registry_options opts; 133 128 struct freesync_entity *map; 134 129 int num_entities; 135 - struct freesync_registry_options opts; 136 130 }; 137 131 138 132 #define MOD_FREESYNC_TO_CORE(mod_freesync)\ ··· 152 146 goto fail_alloc_context; 153 147 154 148 core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, 155 - GFP_KERNEL); 149 + GFP_KERNEL); 156 150 157 151 if (core_freesync->map == NULL) 158 152 goto fail_alloc_map; ··· 335 329 core_freesync->num_entities--; 336 330 return true; 337 331 } 332 + 333 + static void adjust_vmin_vmax(struct core_freesync *core_freesync, 334 + struct dc_stream_state **streams, 335 + int num_streams, 336 + int map_index, 337 + unsigned int v_total_min, 338 + unsigned int v_total_max) 339 + { 340 + if (num_streams == 0 || streams == NULL || num_streams > 1) 341 + return; 342 + 343 + core_freesync->map[map_index].state.vmin = v_total_min; 344 + core_freesync->map[map_index].state.vmax = v_total_max; 345 + 346 + dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 347 + num_streams, v_total_min, 348 + v_total_max); 349 + } 350 + 338 351 339 352 static void update_stream_freesync_context(struct core_freesync *core_freesync, 340 353 struct dc_stream_state *stream) ··· 613 588 update_stream_freesync_context(core_freesync, 614 589 streams[stream_idx]); 615 590 616 - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 617 - num_streams, v_total_min, 618 - v_total_max); 591 + adjust_vmin_vmax(core_freesync, streams, 592 + num_streams, map_index, 593 + v_total_min, 594 + v_total_max); 619 595 620 596 return true; 621 597 ··· 639 613 core_freesync, 640 614 streams[stream_idx]); 641 615 642 - dc_stream_adjust_vmin_vmax( 643 - core_freesync->dc, streams, 644 - num_streams, v_total_nominal, 616 + adjust_vmin_vmax( 617 + core_freesync, streams, 618 + num_streams, map_index, 619 + v_total_nominal, 645 620 v_total_nominal); 646 621 } 647 622 return true; ··· 659 632 core_freesync, 660 633 streams[stream_idx]); 661 634 662 - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 663 - num_streams, v_total_nominal, 664 - v_total_nominal); 635 + adjust_vmin_vmax(core_freesync, streams, 636 + num_streams, map_index, 637 + v_total_nominal, 638 + v_total_nominal); 665 639 666 640 /* Reset the cached variables */ 667 641 reset_freesync_state_variables(state); ··· 678 650 * not support freesync because a former stream has 679 651 * be programmed 680 652 */ 681 - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 682 - num_streams, v_total_nominal, 683 - v_total_nominal); 653 + adjust_vmin_vmax(core_freesync, streams, 654 + num_streams, map_index, 655 + v_total_nominal, 656 + v_total_nominal); 684 657 /* Reset the cached variables */ 685 658 reset_freesync_state_variables(state); 686 659 } ··· 798 769 vmin = inserted_frame_v_total; 799 770 800 771 /* Program V_TOTAL */ 801 - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 802 - num_streams, vmin, vmax); 772 + adjust_vmin_vmax(core_freesync, streams, 773 + num_streams, index, 774 + vmin, vmax); 803 775 } 804 776 805 777 if (state->btr.frame_counter > 0) ··· 834 804 update_stream_freesync_context(core_freesync, streams[0]); 835 805 836 806 /* Program static screen ramp values */ 837 - dc_stream_adjust_vmin_vmax(core_freesync->dc, streams, 838 - num_streams, v_total, 839 - v_total); 807 + adjust_vmin_vmax(core_freesync, streams, 808 + num_streams, index, 809 + v_total, 810 + v_total); 840 811 841 812 triggers.overlay_update = true; 842 813 triggers.surface_update = true; ··· 1094 1063 max_refresh); 1095 1064 1096 1065 /* Program vtotal min/max */ 1097 - dc_stream_adjust_vmin_vmax(core_freesync->dc, &streams, 1, 1098 - state->freesync_range.vmin, 1099 - state->freesync_range.vmax); 1066 + adjust_vmin_vmax(core_freesync, &streams, 1, index, 1067 + state->freesync_range.vmin, 1068 + state->freesync_range.vmax); 1100 1069 } 1101 1070 1102 1071 if (min_refresh != 0 && ··· 1430 1399 } else { 1431 1400 1432 1401 vmin = state->freesync_range.vmin; 1433 - 1434 1402 vmax = vmin; 1435 - 1436 - dc_stream_adjust_vmin_vmax(core_freesync->dc, &stream, 1437 - 1, vmin, vmax); 1403 + adjust_vmin_vmax(core_freesync, &stream, map_index, 1404 + 1, vmin, vmax); 1438 1405 } 1439 1406 } 1440 1407 ··· 1486 1457 1487 1458 } 1488 1459 } 1460 + 1461 + void mod_freesync_get_settings(struct mod_freesync *mod_freesync, 1462 + struct dc_stream_state **streams, int num_streams, 1463 + unsigned int *v_total_min, unsigned int *v_total_max, 1464 + unsigned int *event_triggers, 1465 + unsigned int *window_min, unsigned int *window_max, 1466 + unsigned int *lfc_mid_point_in_us, 1467 + unsigned int *inserted_frames, 1468 + unsigned int *inserted_duration_in_us) 1469 + { 1470 + unsigned int stream_index, map_index; 1471 + struct core_freesync *core_freesync = NULL; 1472 + 1473 + if (mod_freesync == NULL) 1474 + return; 1475 + 1476 + core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1477 + 1478 + for (stream_index = 0; stream_index < num_streams; stream_index++) { 1479 + 1480 + map_index = map_index_from_stream(core_freesync, 1481 + streams[stream_index]); 1482 + 1483 + if (core_freesync->map[map_index].caps->supported) { 1484 + struct freesync_state state = 1485 + core_freesync->map[map_index].state; 1486 + *v_total_min = state.vmin; 1487 + *v_total_max = state.vmax; 1488 + *event_triggers = 0; 1489 + *window_min = state.time.min_window; 1490 + *window_max = state.time.max_window; 1491 + *lfc_mid_point_in_us = state.btr.mid_point_in_us; 1492 + *inserted_frames = state.btr.frames_to_insert; 1493 + *inserted_duration_in_us = 1494 + state.btr.inserted_frame_duration_in_us; 1495 + } 1496 + 1497 + } 1498 + } 1499 +
+9
drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
··· 164 164 struct dc_stream_state **streams, int num_streams, 165 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 176 #endif
+65
drivers/gpu/drm/amd/display/modules/inc/mod_stats.h
··· 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_ */
+334
drivers/gpu/drm/amd/display/modules/stats/stats.c
··· 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 + &reg_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 + &reg_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 +