1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #ifdef __HuaweiLite__
20 #include <pthread.h>
21 #include <shell.h>
22 #include <sys/prctl.h>
23 #include "linux/kernel.h"
24 #endif
25
26 #include "hi_osal.h"
27 #include "securec.h"
28
29 #include "hi_type.h"
30 #include "hi_debug.h"
31 #include "proc_ext.h"
32 #include "dev_ext.h"
33 #include "mod_ext.h"
34 #include "mkp_log.h"
35
36 static hi_s32 g_log_level[HI_ID_BUTT + 1] = {
37 [0 ... HI_ID_BUTT - 1] = HI_DBG_ERR
38 };
39 #define LOG_STATE_INIT 0
40 #define LOG_STATE_OPEN 1
41 #define LOG_STATE_READ 2
42 #define LOG_STATE_WRITE 3
43 #define LOG_STATE_CLOSE 4
44
45 static hi_u32 g_state = LOG_STATE_INIT;
46 static hi_bool g_wait_data = HI_TRUE;
47
48 #define LOG_BUFFER_LEN 64 /* unit is KB. the ring buffer's default length is 64KB */
49 #define LOG_MAX_ITEMLEN 512 /* unit is byte. suppose one log is short than 512 byte */
50
51 typedef struct {
52 hi_u32 max_len; /* the max length of ring buffer */
53 hi_char *addr; /* the address of ring buffer */
54 hi_u32 read_pos; /* the read pointer of ring buffer */
55 hi_u32 write_pos; /* the write pointer of ring buffer */
56 hi_u32 butt_pos; /* leave a blank for circle round */
57 osal_spinlock_t lock; /* the lock */
58 osal_wait_t block_wait; /* wait for read */
59 } log_buffer;
60
61 /* All the mode use the same one buffer. so the time order can be record. */
62 static log_buffer g_log_buf = {0};
63
search_mod(const char * s)64 static int search_mod(const char *s)
65 {
66 int i;
67 for (i = 0; i < HI_ID_BUTT; i++) {
68 hi_char *pa_name = cmpi_get_module_name(i);
69 if (pa_name && !osal_strcmp(pa_name, s)) {
70 return i;
71 }
72 }
73 return -1;
74 }
75
76 /* ate all blanks in a line */
strip_string(char * s,char * d,int len)77 static char *strip_string(char *s, char *d, int len)
78 {
79 int i = 0;
80 char *p = d;
81 do {
82 if (*s == '\n') {
83 *s = '\0';
84 }
85 if (*s != ' ') {
86 *p++ = *s;
87 }
88 i++;
89 } while ((*s++ != '\0') && (i < len));
90 return d;
91 }
92
separate_string(char * s,char ** left,char ** right)93 static int separate_string(char *s, char **left, char **right)
94 {
95 char *p = s;
96 /* find '=' */
97 while (*p != '\0' && *p++ != '=') {
98 };
99
100 if (*--p != '=') {
101 return -1;
102 }
103
104 /* separate left from right value by '=' */
105 *p = '\0';
106 *left = s;
107 *right = p + 1;
108 return 0;
109 }
110
hi_chk_log_level(hi_s32 level,hi_mod_id mod_id)111 hi_s32 hi_chk_log_level(hi_s32 level, hi_mod_id mod_id)
112 {
113 if ((mod_id >= HI_ID_BUTT) ||
114 (level > g_log_level[mod_id])) {
115 return 0;
116 }
117 return 1;
118 }
119
log_get_time(hi_void)120 static inline hi_u64 log_get_time(hi_void)
121 {
122 osal_timeval_t time;
123 osal_gettimeofday(&time);
124 return time.tv_sec * 1000000LLU + time.tv_usec;
125 }
126
log_write(hi_s32 level,hi_mod_id mod_id,const char * fmt,osal_va_list args)127 hi_s32 log_write(hi_s32 level, hi_mod_id mod_id, const char *fmt, osal_va_list args)
128 {
129 hi_s32 new_len;
130 hi_s32 tmp_len;
131 hi_u32 old_wp, old_rp, new_wp, new_rp;
132 hi_char *addr = NULL;
133 unsigned long lock_flag;
134 hi_char *mod_name = NULL;
135
136 if (g_log_buf.addr == NULL) {
137 return 0;
138 }
139 HI_ASSERT(g_log_buf.write_pos <= g_log_buf.max_len);
140 HI_ASSERT(g_log_buf.read_pos <= g_log_buf.max_len);
141
142 osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
143
144 old_wp = new_wp = g_log_buf.write_pos;
145 old_rp = new_rp = g_log_buf.read_pos;
146 mod_name = cmpi_get_module_name(mod_id);
147
148 if (g_log_buf.max_len - old_wp > LOG_MAX_ITEMLEN) {
149 addr = g_log_buf.addr + old_wp;
150 new_len = snprintf_s(addr, LOG_MAX_ITEMLEN, LOG_MAX_ITEMLEN - 1, "<%d>[%6s] ", level, mod_name);
151 new_len = (new_len < 0) ? 0 : new_len;
152 tmp_len = vsnprintf_s(addr + new_len, LOG_MAX_ITEMLEN - new_len, LOG_MAX_ITEMLEN - new_len - 1, fmt, args);
153 tmp_len = (tmp_len < 0) ? 0 : tmp_len;
154 new_len = new_len + tmp_len;
155
156 if (new_len >= LOG_MAX_ITEMLEN) {
157 osal_printk("[%6s]: log message is too long!!\n", mod_name);
158 } else {
159 new_wp = old_wp + new_len;
160 if ((new_wp >= old_rp) && (old_wp < old_rp)) {
161 new_rp = new_wp + 1;
162 }
163 }
164 } else {
165 g_log_buf.butt_pos = old_wp;
166 addr = g_log_buf.addr;
167 new_len = snprintf_s(addr, LOG_MAX_ITEMLEN, LOG_MAX_ITEMLEN - 1, "<%d>[%6s] ", level, mod_name);
168 new_len = (new_len < 0) ? 0 : new_len;
169 tmp_len = vsnprintf_s(addr + new_len, LOG_MAX_ITEMLEN - new_len, LOG_MAX_ITEMLEN - new_len - 1, fmt, args);
170 tmp_len = (tmp_len < 0) ? 0 : tmp_len;
171 new_len = new_len + tmp_len;
172
173 if (new_len >= LOG_MAX_ITEMLEN) {
174 osal_printk("[%6s]: log message is too long!!\n", mod_name);
175 } else {
176 new_wp = new_len;
177 if (!(((hi_u32)new_len < old_rp) && (old_wp >= old_rp))) {
178 new_rp = new_len + 1;
179 }
180 }
181 }
182
183 g_log_buf.write_pos = new_wp;
184 g_log_buf.read_pos = new_rp;
185
186 osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
187
188 osal_wakeup(&(g_log_buf.block_wait));
189
190 return new_len;
191 }
192
HI_LOG(hi_s32 level,hi_mod_id mod_id,const char * fmt,...)193 int HI_LOG(hi_s32 level, hi_mod_id mod_id, const char *fmt, ...)
194 {
195 osal_va_list args;
196 int r;
197 if (!hi_chk_log_level(level, mod_id)) {
198 return 0;
199 }
200
201 osal_va_start(args, fmt);
202 r = log_write(level, mod_id, fmt, args);
203 osal_va_end(args);
204 return r;
205 }
206
207 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
208 /* use the "cat /proc/umap/log" to get the debug level */
log_proc_read(struct osal_proc_dir_entry * s)209 static hi_s32 log_proc_read(struct osal_proc_dir_entry *s)
210 {
211 hi_u32 i;
212
213 osal_seq_printf(s, "-----LOG BUFFER STATE----------------------------------------------------------\n");
214 osal_seq_printf(s, "MaxLen ReadPos WritePos ButtPos\n");
215 osal_seq_printf(s, "%3d(KB) %7d %8d %7d\n",
216 g_log_buf.max_len >> 10, g_log_buf.read_pos, /* 10,width */
217 g_log_buf.write_pos, g_log_buf.butt_pos);
218 osal_seq_printf(s, "\n");
219
220 osal_seq_printf(s, "-----CURRENT LOG LEVEL---------------------------------------------------------\n");
221 for (i = 0; i < HI_ID_BUTT; i++) {
222 hi_char *pa_temp_name = cmpi_get_module_name(i);
223 if (pa_temp_name == NULL) {
224 continue;
225 }
226 osal_seq_printf(s, "%s\t: %d\n",
227 pa_temp_name, g_log_level[i]);
228 }
229
230 return 0;
231 }
232
233 /* use the "echo 'mode = level' > /proc/umap/log" to modify the debug level */
log_proc_write(struct osal_proc_dir_entry * s,const char * buf,int count,long long * ppos)234 static hi_s32 log_proc_write(struct osal_proc_dir_entry *s, const char *buf,
235 int count, long long *ppos)
236 {
237 #define TMP_BUF_LEN 32
238 char m[TMP_BUF_LEN] = {0};
239 char d[TMP_BUF_LEN] = { [0 ... TMP_BUF_LEN - 1] = '\0' };
240 int len = TMP_BUF_LEN;
241 char *left = NULL;
242 char *right = NULL;
243 int idx;
244 int level;
245
246 hi_unused(s);
247 if (*ppos >= TMP_BUF_LEN) {
248 return HI_FAILURE;
249 }
250
251 if (count <= 0) {
252 return HI_FAILURE;
253 }
254
255 len = osal_min(len, count);
256 if (osal_copy_from_user(m, buf, len) != 0) {
257 return HI_FAILURE;
258 }
259
260 m[len - 1] = '\0';
261 strip_string(m, d, len);
262 if (separate_string(d, &left, &right)) {
263 osal_printk("string is unknown!\n");
264 goto out;
265 }
266
267 level = osal_strtol(right, NULL, 10); /* 10,base */
268 if (!osal_strcmp("wait", left)) {
269 g_wait_data = level;
270 goto out;
271 }
272
273 if (!level && *right != '0') {
274 osal_printk("invalid value!\n");
275 goto out;
276 }
277
278 if (level > HI_DBG_DEBUG) {
279 osal_printk("level: %d illegal!\n", level);
280 }
281
282 if (!osal_strcmp("all", left)) {
283 int i = 0;
284 for (; i < HI_ID_BUTT; i++) {
285 g_log_level[i] = level;
286 }
287 goto out;
288 }
289 idx = search_mod(left);
290 if ((idx < 0) || (idx >= HI_ID_BUTT)) {
291 osal_printk("%s not found in array!\n", left);
292 return count;
293 }
294 g_log_level[idx] = level;
295
296 out:
297 return len;
298 #undef TMP_BUF_LEN
299 }
300 #endif
301
302 static hi_s32 log_close(void *private_data);
303 /* IOCTL operation for get and config the debug level */
do_ioctl(unsigned int cmd,unsigned long arg,void * private_data)304 static hi_s32 do_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
305 {
306 hi_unused(private_data);
307 switch (cmd) {
308 case LOG_SETLOGLEVEL_CTRL: {
309 hi_log_level_conf *conf = (hi_log_level_conf *)(hi_uintptr_t)arg;
310
311 if (conf->level > HI_DBG_DEBUG) {
312 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "illegal level: %d\n", conf->level);
313 return HI_FAILURE;
314 }
315
316 conf->mod_name[sizeof(conf->mod_name) - 1] = '\0';
317
318 if (!osal_strcmp("all", conf->mod_name)) {
319 int i = 0;
320 for (; i < HI_ID_BUTT; i++) {
321 g_log_level[i] = conf->level;
322 }
323 } else {
324 if (conf->mod_id >= HI_ID_BUTT) {
325 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, modeid: %d\n",
326 __FUNCTION__, __LINE__, conf->mod_id);
327 return HI_FAILURE;
328 }
329
330 g_log_level[conf->mod_id] = conf->level;
331 }
332 break;
333 }
334 case LOG_GETLOGLEVEL_CTRL: {
335 errno_t err_value;
336 hi_log_level_conf *conf = (hi_log_level_conf *)(hi_uintptr_t)arg;
337
338 if (conf->mod_id >= HI_ID_BUTT) {
339 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, modeid: %d\n",
340 __FUNCTION__, __LINE__, conf->mod_id);
341 return HI_FAILURE;
342 }
343
344 conf->level = g_log_level[conf->mod_id];
345
346 if (cmpi_get_module_name(conf->mod_id) == NULL) {
347 return HI_FAILURE;
348 }
349
350 err_value = strncpy_s(conf->mod_name, sizeof(conf->mod_name), cmpi_get_module_name(conf->mod_id),
351 sizeof(conf->mod_name) - 1);
352 if (err_value != EOK) {
353 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "copy err!\n");
354 return HI_FAILURE;
355 }
356
357 break;
358 }
359 case LOG_CLOSE_CTRL: {
360 log_close(HI_NULL);
361 break;
362 }
363 case LOG_SETWAITFLAG_CTRL: {
364 hi_bool wait;
365
366 wait = *((hi_bool *)(hi_uintptr_t)arg);
367
368 if ((wait != HI_FALSE) && (wait != HI_TRUE)) {
369 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, wait: %d\n",
370 __FUNCTION__, __LINE__, wait);
371 return HI_FAILURE;
372 }
373
374 g_wait_data = wait;
375 break;
376 }
377 default:
378 {
379 break;
380 }
381 }
382
383 return HI_SUCCESS;
384 }
385
log_ioctl(unsigned int cmd,unsigned long arg,void * private_data)386 static long log_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
387 {
388 return do_ioctl(cmd, arg, private_data);
389 }
390
391 #ifdef __HuaweiLite__
read_q(hi_void * data)392 hi_void *read_q(hi_void *data)
393 {
394 int c;
395
396 hi_unused(data);
397 prctl(PR_SET_NAME, "hi_log_read_q", 0, 0, 0);
398 while (1) {
399 c = getchar();
400 if ((c == 'q') || (c == 'Q')) {
401 log_close(HI_NULL);
402 return 0;
403 }
404 }
405 }
406 #endif
407
wait_condition_call_back(const void * param)408 int wait_condition_call_back(const void *param)
409 {
410 hi_unused(param);
411 return ((g_log_buf.read_pos != g_log_buf.write_pos) ||
412 (g_state == LOG_STATE_CLOSE) ||
413 (g_wait_data == HI_FALSE));
414 }
415
416 /* read operation for log information */
log_read(char * buf,int count,long * offset,void * private_data)417 static int log_read(char *buf, int count, long *offset, void *private_data)
418 {
419 hi_s32 read_len = 0;
420 hi_s32 error;
421 hi_char c;
422 unsigned long lock_flag;
423
424 hi_unused(private_data);
425 hi_unused(offset);
426 #ifdef __HuaweiLite__
427
428 hi_unused(buf);
429 count = LOG_BUFFER_LEN * 1024; /* 1024, 1 k bit */
430 pthread_t threadid;
431 pthread_attr_t attr;
432 pthread_attr_init(&attr);
433 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
434 if (pthread_create(&threadid, &attr, read_q, NULL) != 0) {
435 HI_PRINT("cmpi_log read pthread_create error!\n");
436 return -1;
437 }
438 #endif
439
440 g_state = LOG_STATE_READ;
441
442 error = osal_wait_event_interruptible(&g_log_buf.block_wait, wait_condition_call_back, NULL);
443 if (error) {
444 return error;
445 }
446
447 osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
448 while ((!error) && (read_len < count) &&
449 (g_log_buf.write_pos != g_log_buf.read_pos)) {
450 if (g_log_buf.read_pos > g_log_buf.butt_pos) {
451 g_log_buf.read_pos = 0;
452 }
453
454 if (g_log_buf.write_pos == g_log_buf.read_pos) {
455 break;
456 }
457
458 c = *(g_log_buf.addr + g_log_buf.read_pos);
459 g_log_buf.read_pos += 1;
460
461 osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
462
463 #ifdef __HuaweiLite__
464 printk("%c", c);
465 #else
466 error = osal_copy_to_user(buf, &c, 1);
467 buf++;
468 #endif
469
470 read_len++;
471 osal_yield();
472 osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
473 }
474 osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
475
476 return read_len;
477 }
478
479 #ifdef __HuaweiLite__
480 /*
481 This function uses Camel_Style ,not Linux_Style.
482 Because it is exported to the sample/app_init.c
483 */
CatLogShell(void)484 void CatLogShell(void)
485 {
486 osCmdReg(CMD_TYPE_EX, "cat_logmpp", 0, (CMD_CBK_FUNC)log_read);
487 }
488 #endif
489
log_open(void * data)490 static hi_s32 log_open(void *data)
491 {
492 hi_unused(data);
493 g_state = LOG_STATE_OPEN;
494 return HI_SUCCESS;
495 }
496
log_close(void * data)497 static hi_s32 log_close(void *data)
498 {
499 hi_unused(data);
500 g_state = LOG_STATE_CLOSE;
501 g_wait_data = HI_TRUE;
502 osal_wakeup(&(g_log_buf.block_wait));
503 return HI_SUCCESS;
504 }
505
506 static struct osal_fileops g_log_file_op = {
507 .open = log_open,
508 .unlocked_ioctl = log_ioctl,
509 .release = log_close,
510 .read = log_read
511 };
512
513 static osal_dev_t *s_log_device;
514
cmpi_log_init(hi_u32 log_buf_len)515 hi_s32 cmpi_log_init(hi_u32 log_buf_len)
516 {
517 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
518 osal_proc_entry_t *item = NULL;
519 #endif
520 s_log_device = osal_createdev(UMAP_DEVNAME_LOG_BASE);
521 if (s_log_device == NULL) {
522 osal_printk("log createdev failed!\n");
523 goto OUT0;
524 }
525 s_log_device->fops = &g_log_file_op;
526 s_log_device->minor = UMAP_LOG_MINOR_BASE;
527
528 if (osal_registerdevice(s_log_device)) {
529 osal_printk("log register device failed!\n");
530 goto OUT1;
531 }
532
533 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
534 item = osal_create_proc_entry(PROC_ENTRY_LOG, NULL);
535 if (item == NULL) {
536 goto OUT2;
537 }
538 item->read = log_proc_read;
539 item->write = log_proc_write;
540 #endif
541 if (osal_spin_lock_init(&(g_log_buf.lock)) < 0) {
542 osal_printk("spinlock init failed!\n");
543 goto OUT3;
544 }
545
546 if (osal_wait_init(&(g_log_buf.block_wait)) < 0) {
547 osal_printk("wait init failed!\n");
548 goto OUT4;
549 }
550
551 if ((log_buf_len >= 2) && (log_buf_len <= 128)) { /* 2,min len. 128 max len */
552 g_log_buf.max_len = log_buf_len * 1024; /* 1024,1kB is 1024 byte */
553 } else {
554 g_log_buf.max_len = LOG_BUFFER_LEN * 1024; /* 1024,1kB is 1024 byte */
555 }
556 g_log_buf.butt_pos = g_log_buf.max_len;
557 g_log_buf.read_pos = g_log_buf.write_pos = 0;
558 g_log_buf.addr = (hi_char *)osal_vmalloc(g_log_buf.max_len);
559 if (g_log_buf.addr == NULL) {
560 osal_printk("log buffer %d_b malloc failed.\n", g_log_buf.max_len);
561 goto OUT5;
562 }
563
564 return HI_SUCCESS;
565
566 OUT5:
567 osal_wait_destroy(&(g_log_buf.block_wait));
568 OUT4:
569 osal_spin_lock_destroy(&(g_log_buf.lock));
570 OUT3:
571 osal_remove_proc_entry(PROC_ENTRY_LOG, NULL);
572 OUT2:
573 osal_deregisterdevice(s_log_device);
574 OUT1:
575 osal_destroydev(s_log_device);
576 s_log_device = HI_NULL;
577 OUT0:
578 return HI_FAILURE;
579 }
580
cmpi_log_exit(hi_void)581 hi_void cmpi_log_exit(hi_void)
582 {
583 if (g_log_buf.addr != NULL) {
584 osal_vfree(g_log_buf.addr);
585 g_log_buf.addr = NULL;
586 }
587 osal_deregisterdevice(s_log_device);
588 osal_destroydev(s_log_device);
589 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
590 osal_remove_proc_entry(PROC_ENTRY_LOG, NULL);
591 #endif
592
593 osal_spin_lock_destroy(&(g_log_buf.lock));
594 osal_wait_destroy(&(g_log_buf.block_wait));
595 }
596