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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16 403 lines 10 kB view raw
1/* 2 * Copyright 2012-15 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#include "dm_services.h" 26#include "include/logger_interface.h" 27#include "logger.h" 28 29 30#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) 31 32static const struct dc_log_type_info log_type_info_tbl[] = { 33 {LOG_ERROR, "Error"}, 34 {LOG_WARNING, "Warning"}, 35 {LOG_DEBUG, "Debug"}, 36 {LOG_DC, "DC_Interface"}, 37 {LOG_SURFACE, "Surface"}, 38 {LOG_HW_HOTPLUG, "HW_Hotplug"}, 39 {LOG_HW_LINK_TRAINING, "HW_LKTN"}, 40 {LOG_HW_SET_MODE, "HW_Mode"}, 41 {LOG_HW_RESUME_S3, "HW_Resume"}, 42 {LOG_HW_AUDIO, "HW_Audio"}, 43 {LOG_HW_HPD_IRQ, "HW_HPDIRQ"}, 44 {LOG_MST, "MST"}, 45 {LOG_SCALER, "Scaler"}, 46 {LOG_BIOS, "BIOS"}, 47 {LOG_BANDWIDTH_CALCS, "BWCalcs"}, 48 {LOG_BANDWIDTH_VALIDATION, "BWValidation"}, 49 {LOG_I2C_AUX, "I2C_AUX"}, 50 {LOG_SYNC, "Sync"}, 51 {LOG_BACKLIGHT, "Backlight"}, 52 {LOG_FEATURE_OVERRIDE, "Override"}, 53 {LOG_DETECTION_EDID_PARSER, "Edid"}, 54 {LOG_DETECTION_DP_CAPS, "DP_Caps"}, 55 {LOG_RESOURCE, "Resource"}, 56 {LOG_DML, "DML"}, 57 {LOG_EVENT_MODE_SET, "Mode"}, 58 {LOG_EVENT_DETECTION, "Detect"}, 59 {LOG_EVENT_LINK_TRAINING, "LKTN"}, 60 {LOG_EVENT_LINK_LOSS, "LinkLoss"}, 61 {LOG_EVENT_UNDERFLOW, "Underflow"}, 62 {LOG_IF_TRACE, "InterfaceTrace"}, 63 {LOG_DTN, "DTN"} 64}; 65 66 67/* ----------- Object init and destruction ----------- */ 68static bool construct(struct dc_context *ctx, struct dal_logger *logger, 69 uint32_t log_mask) 70{ 71 /* malloc buffer and init offsets */ 72 logger->log_buffer_size = DAL_LOGGER_BUFFER_MAX_SIZE; 73 logger->log_buffer = kcalloc(logger->log_buffer_size, sizeof(char), 74 GFP_KERNEL); 75 if (!logger->log_buffer) 76 return false; 77 78 /* Initialize both offsets to start of buffer (empty) */ 79 logger->buffer_read_offset = 0; 80 logger->buffer_write_offset = 0; 81 82 logger->open_count = 0; 83 84 logger->flags.bits.ENABLE_CONSOLE = 1; 85 logger->flags.bits.ENABLE_BUFFER = 0; 86 87 logger->ctx = ctx; 88 89 logger->mask = log_mask; 90 91 return true; 92} 93 94static void destruct(struct dal_logger *logger) 95{ 96 if (logger->log_buffer) { 97 kfree(logger->log_buffer); 98 logger->log_buffer = NULL; 99 } 100} 101 102struct dal_logger *dal_logger_create(struct dc_context *ctx, uint32_t log_mask) 103{ 104 /* malloc struct */ 105 struct dal_logger *logger = kzalloc(sizeof(struct dal_logger), 106 GFP_KERNEL); 107 108 if (!logger) 109 return NULL; 110 if (!construct(ctx, logger, log_mask)) { 111 kfree(logger); 112 return NULL; 113 } 114 115 return logger; 116} 117 118uint32_t dal_logger_destroy(struct dal_logger **logger) 119{ 120 if (logger == NULL || *logger == NULL) 121 return 1; 122 destruct(*logger); 123 kfree(*logger); 124 *logger = NULL; 125 126 return 0; 127} 128 129/* ------------------------------------------------------------------------ */ 130 131 132static bool dal_logger_should_log( 133 struct dal_logger *logger, 134 enum dc_log_type log_type) 135{ 136 if (logger->mask & (1 << log_type)) 137 return true; 138 139 return false; 140} 141 142static void log_to_debug_console(struct log_entry *entry) 143{ 144 struct dal_logger *logger = entry->logger; 145 146 if (logger->flags.bits.ENABLE_CONSOLE == 0) 147 return; 148 149 if (entry->buf_offset) { 150 switch (entry->type) { 151 case LOG_ERROR: 152 dm_error("%s", entry->buf); 153 break; 154 default: 155 dm_output_to_console("%s", entry->buf); 156 break; 157 } 158 } 159} 160 161/* Print everything unread existing in log_buffer to debug console*/ 162void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn) 163{ 164 char *string_start = &logger->log_buffer[logger->buffer_read_offset]; 165 166 if (should_warn) 167 dm_output_to_console( 168 "---------------- FLUSHING LOG BUFFER ----------------\n"); 169 while (logger->buffer_read_offset < logger->buffer_write_offset) { 170 171 if (logger->log_buffer[logger->buffer_read_offset] == '\0') { 172 dm_output_to_console("%s", string_start); 173 string_start = logger->log_buffer + logger->buffer_read_offset + 1; 174 } 175 logger->buffer_read_offset++; 176 } 177 if (should_warn) 178 dm_output_to_console( 179 "-------------- END FLUSHING LOG BUFFER --------------\n\n"); 180} 181 182static void log_to_internal_buffer(struct log_entry *entry) 183{ 184 185 uint32_t size = entry->buf_offset; 186 struct dal_logger *logger = entry->logger; 187 188 if (logger->flags.bits.ENABLE_BUFFER == 0) 189 return; 190 191 if (logger->log_buffer == NULL) 192 return; 193 194 if (size > 0 && size < logger->log_buffer_size) { 195 196 int buffer_space = logger->log_buffer_size - 197 logger->buffer_write_offset; 198 199 if (logger->buffer_write_offset == logger->buffer_read_offset) { 200 /* Buffer is empty, start writing at beginning */ 201 buffer_space = logger->log_buffer_size; 202 logger->buffer_write_offset = 0; 203 logger->buffer_read_offset = 0; 204 } 205 206 if (buffer_space > size) { 207 /* No wrap around, copy 'size' bytes 208 * from 'entry->buf' to 'log_buffer' 209 */ 210 memmove(logger->log_buffer + 211 logger->buffer_write_offset, 212 entry->buf, size); 213 logger->buffer_write_offset += size; 214 215 } else { 216 /* Not enough room remaining, we should flush 217 * existing logs */ 218 219 /* Flush existing unread logs to console */ 220 dm_logger_flush_buffer(logger, true); 221 222 /* Start writing to beginning of buffer */ 223 memmove(logger->log_buffer, entry->buf, size); 224 logger->buffer_write_offset = size; 225 logger->buffer_read_offset = 0; 226 } 227 228 } 229} 230 231static void log_heading(struct log_entry *entry) 232{ 233 int j; 234 235 for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) { 236 237 const struct dc_log_type_info *info = &log_type_info_tbl[j]; 238 239 if (info->type == entry->type) 240 dm_logger_append(entry, "[%s]\t", info->name); 241 } 242} 243 244static void append_entry( 245 struct log_entry *entry, 246 char *buffer, 247 uint32_t buf_size) 248{ 249 if (!entry->buf || 250 entry->buf_offset + buf_size > entry->max_buf_bytes 251 ) { 252 BREAK_TO_DEBUGGER(); 253 return; 254 } 255 256 /* Todo: check if off by 1 byte due to \0 anywhere */ 257 memmove(entry->buf + entry->buf_offset, buffer, buf_size); 258 entry->buf_offset += buf_size; 259} 260 261/* ------------------------------------------------------------------------ */ 262 263/* Warning: Be careful that 'msg' is null terminated and the total size is 264 * less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0' 265 */ 266void dm_logger_write( 267 struct dal_logger *logger, 268 enum dc_log_type log_type, 269 const char *msg, 270 ...) 271{ 272 if (logger && dal_logger_should_log(logger, log_type)) { 273 uint32_t size; 274 va_list args; 275 char buffer[LOG_MAX_LINE_SIZE]; 276 struct log_entry entry; 277 278 va_start(args, msg); 279 280 entry.logger = logger; 281 282 entry.buf = buffer; 283 284 entry.buf_offset = 0; 285 entry.max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); 286 287 entry.type = log_type; 288 289 log_heading(&entry); 290 291 size = dm_log_to_buffer( 292 buffer, LOG_MAX_LINE_SIZE - 1, msg, args); 293 294 buffer[entry.buf_offset + size] = '\0'; 295 entry.buf_offset += size + 1; 296 297 /* --Flush log_entry buffer-- */ 298 /* print to kernel console */ 299 log_to_debug_console(&entry); 300 /* log internally for dsat */ 301 log_to_internal_buffer(&entry); 302 303 va_end(args); 304 } 305} 306 307/* Same as dm_logger_write, except without open() and close(), which must 308 * be done separately. 309 */ 310void dm_logger_append( 311 struct log_entry *entry, 312 const char *msg, 313 ...) 314{ 315 va_list args; 316 317 va_start(args, msg); 318 dm_logger_append_va(entry, msg, args); 319 va_end(args); 320} 321 322void dm_logger_append_va( 323 struct log_entry *entry, 324 const char *msg, 325 va_list args) 326{ 327 struct dal_logger *logger; 328 329 if (!entry) { 330 BREAK_TO_DEBUGGER(); 331 return; 332 } 333 334 logger = entry->logger; 335 336 if (logger && logger->open_count > 0 && 337 dal_logger_should_log(logger, entry->type)) { 338 339 uint32_t size; 340 char buffer[LOG_MAX_LINE_SIZE]; 341 342 size = dm_log_to_buffer( 343 buffer, LOG_MAX_LINE_SIZE, msg, args); 344 345 if (size < LOG_MAX_LINE_SIZE - 1) { 346 append_entry(entry, buffer, size); 347 } else { 348 append_entry(entry, "LOG_ERROR, line too long\n", 27); 349 } 350 } 351} 352 353void dm_logger_open( 354 struct dal_logger *logger, 355 struct log_entry *entry, /* out */ 356 enum dc_log_type log_type) 357{ 358 if (!entry) { 359 BREAK_TO_DEBUGGER(); 360 return; 361 } 362 363 entry->type = log_type; 364 entry->logger = logger; 365 366 entry->buf = kzalloc(DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char), 367 GFP_KERNEL); 368 369 entry->buf_offset = 0; 370 entry->max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); 371 372 logger->open_count++; 373 374 log_heading(entry); 375} 376 377void dm_logger_close(struct log_entry *entry) 378{ 379 struct dal_logger *logger = entry->logger; 380 381 if (logger && logger->open_count > 0) { 382 logger->open_count--; 383 } else { 384 BREAK_TO_DEBUGGER(); 385 goto cleanup; 386 } 387 388 /* --Flush log_entry buffer-- */ 389 /* print to kernel console */ 390 log_to_debug_console(entry); 391 /* log internally for dsat */ 392 log_to_internal_buffer(entry); 393 394 /* TODO: Write end heading */ 395 396cleanup: 397 if (entry->buf) { 398 kfree(entry->buf); 399 entry->buf = NULL; 400 entry->buf_offset = 0; 401 entry->max_buf_bytes = 0; 402 } 403}