]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/dc/basics/logger.c
Merge branch 'linus' into locking/core, to pick up fixes
[linux.git] / drivers / gpu / drm / amd / display / dc / basics / logger.c
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
32 static 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 ----------- */
68 static 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
94 static 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
102 struct 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
118 uint32_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
132 static 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
142 static 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*/
162 void 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
182 static 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
231 static 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
244 static 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  */
266 void 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  */
310 void 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
322 void 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
353 void 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
377 void 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
396 cleanup:
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 }
This page took 0.069203 seconds and 4 git commands to generate.