2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
10 #include <linux/debugfs.h>
11 #include <linux/mutex.h>
12 #include <linux/vmalloc.h>
14 #include <linux/device.h>
15 #include <linux/module.h>
16 #include <linux/iommu.h>
17 #include <linux/poll.h>
18 #include <linux/uaccess.h>
19 #include <linux/delay.h>
25 #ifdef CONFIG_CONTEXTHUB_DEBUG
26 #define SIZE_OF_BUFFER (SZ_512K + SZ_128K)
28 #define SIZE_OF_BUFFER (SZ_128K)
31 #define S_IRWUG (0660)
32 #define DEFAULT_FLUSH_MS (1000)
34 static u32 log_auto_save
;
35 static struct dentry
*dbg_root_dir __read_mostly
;
36 static LIST_HEAD(log_list_head
);
37 static struct log_buffer_info
*print_info
;
38 u32 auto_log_flush_ms
;
40 static void log_memcpy(struct log_buffer_info
*info
,
41 struct log_kernel_buffer
*kernel_buffer
,
42 const char *src
, size_t size
)
46 size_t left_size
= SIZE_OF_BUFFER
- kernel_buffer
->index
;
48 dev_dbg(info
->dev
, "%s(%zu)\n", __func__
, size
);
49 if (size
> SIZE_OF_BUFFER
) {
51 "flush size (%zu, %zu) is bigger than kernel buffer size (%d)",
52 size
, left_size
, SIZE_OF_BUFFER
);
53 size
= SIZE_OF_BUFFER
;
60 if (likely(info
->file_created
)) {
61 info
->filp
= filp_open(info
->save_file_name
, O_RDWR
| O_APPEND
| O_CREAT
, S_IRWUG
);
62 dev_info(info
->dev
, "appended to %s\n", info
->save_file_name
);
64 info
->filp
= filp_open(info
->save_file_name
, O_RDWR
| O_TRUNC
| O_CREAT
, S_IRWUG
);
65 info
->file_created
= true;
66 dev_info(info
->dev
, "created %s\n", info
->save_file_name
);
69 if (IS_ERR(info
->filp
)) {
70 dev_warn(info
->dev
, "%s: saving log fail\n", __func__
);
75 if (left_size
< size
) {
76 if (info
->sram_log_buffer
)
77 memcpy_fromio(kernel_buffer
->buffer
+ kernel_buffer
->index
, src
, left_size
);
79 memcpy(kernel_buffer
->buffer
+ kernel_buffer
->index
, src
, left_size
);
82 vfs_write(info
->filp
, kernel_buffer
->buffer
+ kernel_buffer
->index
, left_size
, &info
->filp
->f_pos
);
83 vfs_fsync(info
->filp
, 0);
88 kernel_buffer
->index
= 0;
89 kernel_buffer
->wrap
= true;
92 if (info
->sram_log_buffer
)
93 memcpy_fromio(kernel_buffer
->buffer
+ kernel_buffer
->index
, src
, size
);
95 memcpy(kernel_buffer
->buffer
+ kernel_buffer
->index
, src
, size
);
99 kernel_buffer
->buffer
+ kernel_buffer
->index
, size
, &info
->filp
->f_pos
);
100 vfs_fsync(info
->filp
, 0);
101 filp_close(info
->filp
, NULL
);
104 kernel_buffer
->index
+= size
;
110 void log_flush(struct log_buffer_info
*info
)
112 struct LOG_BUFFER
*buffer
= info
->log_buffer
;
113 struct log_kernel_buffer
*kernel_buffer
= &info
->kernel_buffer
;
114 unsigned int index_writer
= buffer
->index_writer
;
116 /* check logbuf index dueto sram corruption */
117 if ((buffer
->index_reader
>= ipc_get_offset(IPC_REG_LOG
))
118 || (buffer
->index_writer
>= ipc_get_offset(IPC_REG_LOG
))) {
119 dev_err(info
->dev
, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u-%u\n",
120 __func__
, info
->id
, buffer
->index_writer
, buffer
->index_reader
, buffer
->size
,
121 ipc_get_offset(IPC_REG_LOG
));
126 if (buffer
->index_reader
== index_writer
)
130 "%s(%d): index_writer=%u, index_reader=%u, size=%u\n", __func__
,
131 info
->id
, index_writer
, buffer
->index_reader
, buffer
->size
);
133 mutex_lock(&info
->lock
);
135 if (buffer
->index_reader
> index_writer
) {
136 log_memcpy(info
, kernel_buffer
,
137 buffer
->buffer
+ buffer
->index_reader
,
138 buffer
->size
- buffer
->index_reader
);
139 buffer
->index_reader
= 0;
141 log_memcpy(info
, kernel_buffer
,
142 buffer
->buffer
+ buffer
->index_reader
,
143 index_writer
- buffer
->index_reader
);
144 buffer
->index_reader
= index_writer
;
147 mutex_unlock(&info
->lock
);
149 kernel_buffer
->updated
= true;
150 wake_up_interruptible(&kernel_buffer
->wq
);
153 static void log_flush_all_work_func(struct work_struct
*work
);
154 static DECLARE_DEFERRABLE_WORK(log_flush_all_work
, log_flush_all_work_func
);
156 static void log_flush_all(void)
158 struct log_buffer_info
*info
;
160 list_for_each_entry(info
, &log_list_head
, list
) {
162 pr_warn("%s: fails get info\n", __func__
);
169 static void log_flush_all_work_func(struct work_struct
*work
)
173 if (auto_log_flush_ms
)
174 schedule_delayed_work(&log_flush_all_work
,
175 msecs_to_jiffies(auto_log_flush_ms
));
178 void log_schedule_flush_all(void)
180 schedule_delayed_work(&log_flush_all_work
, msecs_to_jiffies(3000));
183 static int log_file_open(struct inode
*inode
, struct file
*file
)
185 struct log_buffer_info
*info
= inode
->i_private
;
187 dev_dbg(info
->dev
, "%s\n", __func__
);
189 file
->private_data
= inode
->i_private
;
190 info
->log_file_index
= -1;
195 static ssize_t
log_file_read(struct file
*file
, char __user
*buf
, size_t count
,
198 struct log_buffer_info
*info
= file
->private_data
;
199 struct log_kernel_buffer
*kernel_buffer
= &info
->kernel_buffer
;
201 bool first
= (info
->log_file_index
< 0);
204 dev_dbg(info
->dev
, "%s(%zu, %lld)\n", __func__
, count
, *ppos
);
206 mutex_lock(&info
->lock
);
208 if (info
->log_file_index
< 0) {
209 info
->log_file_index
=
210 likely(kernel_buffer
->wrap
) ? kernel_buffer
->index
: 0;
214 end
= ((info
->log_file_index
< kernel_buffer
->index
) ||
215 ((info
->log_file_index
== kernel_buffer
->index
) &&
216 !first
)) ? kernel_buffer
->index
: SIZE_OF_BUFFER
;
217 size
= min(end
- info
->log_file_index
, count
);
219 mutex_unlock(&info
->lock
);
220 if (file
->f_flags
& O_NONBLOCK
) {
221 dev_dbg(info
->dev
, "non block\n");
224 kernel_buffer
->updated
= false;
226 result
= wait_event_interruptible(kernel_buffer
->wq
,
227 kernel_buffer
->updated
);
229 dev_dbg(info
->dev
, "interrupted\n");
232 mutex_lock(&info
->lock
);
236 dev_dbg(info
->dev
, "start=%zd, end=%zd size=%zd\n",
237 info
->log_file_index
, end
, size
);
239 (buf
, kernel_buffer
->buffer
+ info
->log_file_index
, size
)) {
240 mutex_unlock(&info
->lock
);
244 info
->log_file_index
+= size
;
245 if (info
->log_file_index
>= SIZE_OF_BUFFER
)
246 info
->log_file_index
= 0;
248 mutex_unlock(&info
->lock
);
250 dev_dbg(info
->dev
, "%s: size = %zd\n", __func__
, size
);
255 static unsigned int log_file_poll(struct file
*file
, poll_table
*wait
)
257 struct log_buffer_info
*info
= file
->private_data
;
258 struct log_kernel_buffer
*kernel_buffer
= &info
->kernel_buffer
;
260 dev_dbg(info
->dev
, "%s\n", __func__
);
262 poll_wait(file
, &kernel_buffer
->wq
, wait
);
263 return POLLIN
| POLLRDNORM
;
266 static const struct file_operations log_fops
= {
267 .open
= log_file_open
,
268 .read
= log_file_read
,
269 .poll
= log_file_poll
,
270 .llseek
= generic_file_llseek
,
271 .owner
= THIS_MODULE
,
274 static struct dentry
*chub_dbg_get_root_dir(void)
277 dbg_root_dir
= debugfs_create_dir("nanohub", NULL
);
282 static void chub_log_auto_save_open(struct log_buffer_info
*info
)
284 mm_segment_t old_fs
= get_fs();
289 if (info
->filp
&& !IS_ERR(info
->filp
)) {
290 dev_info(info
->dev
, "%s closing previous file %p\n", __func__
, info
->filp
);
291 filp_close(info
->filp
, current
->files
);
295 filp_open(info
->save_file_name
, O_RDWR
| O_TRUNC
| O_CREAT
,
298 dev_info(info
->dev
, "%s created\n", info
->save_file_name
);
300 if (IS_ERR(info
->filp
))
301 dev_warn(info
->dev
, "%s: saving log fail\n", __func__
);
306 static void chub_log_auto_save_ctrl(struct log_buffer_info
*info
, u32 event
)
310 snprintf(info
->save_file_name
, sizeof(info
->save_file_name
),
311 "%s/nano-%02d-00-%06u.log", CHUB_DBG_DIR
, info
->id
,
312 (u32
)(sched_clock() / NSEC_PER_SEC
));
313 chub_log_auto_save_open(info
);
320 pr_info("%s: %s, %d, %p\n", __func__
, info
->save_file_name
,
321 log_auto_save
, info
->filp
);
324 static ssize_t
chub_log_save_show(struct device
*kobj
,
325 struct device_attribute
*attr
, char *buf
)
327 return sprintf(buf
, "%d\n", log_auto_save
);
330 static ssize_t
chub_log_save_save(struct device
*dev
,
331 struct device_attribute
*attr
,
332 const char *buf
, size_t count
)
338 err
= kstrtol(&buf
[0], 10, &event
);
341 struct log_buffer_info
*info
;
343 list_for_each_entry(info
, &log_list_head
, list
)
344 if (info
->support_log_save
) /* sram can support it */
345 chub_log_auto_save_ctrl(info
, event
);
347 /* set log_flush to save log */
348 if (!auto_log_flush_ms
) {
349 log_schedule_flush_all();
350 auto_log_flush_ms
= DEFAULT_FLUSH_MS
;
351 dev_dbg(dev
, "%s: set log_flush time(% dms) for log_save\n",
360 #define TMP_BUFFER_SIZE (1000)
362 #if defined(CONFIG_CONTEXTHUB_DEBUG)
363 static void log_dump(struct log_buffer_info
*info
, int err
)
367 char save_file_name
[64];
368 struct LOG_BUFFER
*buffer
= info
->log_buffer
;
369 u32 wrap_index
= buffer
->index_writer
;
371 /* check logbuf index dueto sram corruption */
372 if ((buffer
->index_reader
>= ipc_get_offset(IPC_REG_LOG
))
373 || (buffer
->index_writer
>= ipc_get_offset(IPC_REG_LOG
))) {
374 dev_err(info
->dev
, "%s(%d): offset is corrupted. index_writer=%u, index_reader=%u, size=%u-%u\n",
375 __func__
, info
->id
, buffer
->index_writer
, buffer
->index_reader
, buffer
->size
,
376 ipc_get_offset(IPC_REG_LOG
));
380 snprintf(save_file_name
, sizeof(save_file_name
),
381 "%s/nano-%02d-%02d-%06u.log", CHUB_DBG_DIR
,
382 info
->id
, err
, (u32
)(sched_clock() / NSEC_PER_SEC
));
387 filp
= filp_open(save_file_name
, O_RDWR
| O_TRUNC
| O_CREAT
, S_IRWUG
);
389 dev_warn(info
->dev
, "%s: fails filp:%p\n", __func__
, filp
);
393 if (info
->sram_log_buffer
) {
397 char tmp_buffer
[TMP_BUFFER_SIZE
];
398 u32 start_index
= wrap_index
;
401 /* dump sram-log buffer to fs (eq ~ eq + logbuf_size) */
402 dev_dbg(info
->dev
, "%s: logbuf:%p, eq:%d, dq:%d, size:%d, loop:%d\n", __func__
,
403 (void *)buffer
, wrap_index
, buffer
->index_reader
, buffer
->size
,
404 (buffer
->size
/ TMP_BUFFER_SIZE
) + 1);
405 for (i
= 0; i
< (buffer
->size
/ TMP_BUFFER_SIZE
) + 1;
406 i
++, start_index
+= TMP_BUFFER_SIZE
) {
407 if (start_index
+ TMP_BUFFER_SIZE
> buffer
->size
) {
408 size
= buffer
->size
- start_index
;
411 } else if (bottom
&& (wrap_index
- start_index
< TMP_BUFFER_SIZE
)) {
412 size
= wrap_index
- start_index
;
414 size
= TMP_BUFFER_SIZE
;
416 memcpy_fromio(tmp_buffer
, buffer
->buffer
+ start_index
, size
);
417 vfs_write(filp
, tmp_buffer
, size
, &filp
->f_pos
);
424 vfs_write(filp
, buffer
->buffer
+ wrap_index
, buffer
->size
- wrap_index
,
426 vfs_write(filp
, buffer
->buffer
, wrap_index
, &filp
->f_pos
);
428 dev_dbg(info
->dev
, "%s is created\n", save_file_name
);
431 filp_close(filp
, NULL
);
437 void log_dump_all(int err
)
439 struct log_buffer_info
*info
;
441 list_for_each_entry(info
, &log_list_head
, list
)
446 static ssize_t
chub_log_flush_show(struct device
*kobj
,
447 struct device_attribute
*attr
, char *buf
)
449 return sprintf(buf
, "%d\n", auto_log_flush_ms
);
452 static ssize_t
chub_log_flush_save(struct device
*dev
,
453 struct device_attribute
*attr
,
454 const char *buf
, size_t count
)
459 err
= kstrtol(&buf
[0], 10, &event
);
461 if (!auto_log_flush_ms
) {
465 pr_err("%s: fails to flush log\n", __func__
);
468 /* update log_flush time */
469 auto_log_flush_ms
= event
* 1000;
479 static ssize_t
chub_dump_log_save(struct device
*dev
,
480 struct device_attribute
*attr
,
481 const char *buf
, size_t count
)
487 static struct device_attribute attributes
[] = {
488 /* enable auto-save with flush_log */
489 __ATTR(save_log
, 0664, chub_log_save_show
, chub_log_save_save
),
490 /* flush sram-logbuf to dram */
491 __ATTR(flush_log
, 0664, chub_log_flush_show
, chub_log_flush_save
),
492 /* dump sram-logbuf to file */
493 __ATTR(dump_log
, 0220, NULL
, chub_dump_log_save
)
496 struct log_buffer_info
*log_register_buffer(struct device
*dev
, int id
,
497 struct LOG_BUFFER
*buffer
,
498 char *name
, bool sram
)
500 struct log_buffer_info
*info
= vmalloc(sizeof(*info
));
507 mutex_init(&info
->lock
);
509 info
->file_created
= false;
510 info
->kernel_buffer
.buffer
= vzalloc(SIZE_OF_BUFFER
);
511 info
->kernel_buffer
.index
= 0;
512 info
->kernel_buffer
.index_reader
= 0;
513 info
->kernel_buffer
.index_writer
= 0;
514 info
->kernel_buffer
.wrap
= false;
515 init_waitqueue_head(&info
->kernel_buffer
.wq
);
517 info
->log_buffer
= buffer
;
519 /* HACK: clang make error
520 buffer->index_reader = 0;
521 buffer->index_writer = 0;
523 info
->save_file_name
[0] = '\0';
526 dev_info(dev
, "%s with %p buffer size %d. %p kernel buffer size %d\n",
527 __func__
, buffer
->buffer
, buffer
->size
,
528 info
->kernel_buffer
.buffer
, SIZE_OF_BUFFER
);
530 debugfs_create_file(name
, S_IRWUG
, chub_dbg_get_root_dir(), info
,
533 list_add_tail(&info
->list
, &log_list_head
);
536 info
->sram_log_buffer
= true;
537 info
->support_log_save
= true;
539 /* add device files */
540 for (i
= 0, ret
= 0; i
< ARRAY_SIZE(attributes
); i
++) {
541 ret
= device_create_file(dev
, &attributes
[i
]);
543 dev_warn(dev
, "Failed to create file: %s\n",
544 attributes
[i
].attr
.name
);
548 info
->sram_log_buffer
= false;
549 info
->support_log_save
= false;
555 void log_printf(const char *format
, ...)
557 struct LOG_BUFFER
*buffer
;
563 char *buffer_index
= tmp_buf
;
565 buffer
= print_info
->log_buffer
;
567 va_start(args
, format
);
568 size
= vsprintf(tmp_buf
, format
, args
);
572 if (buffer
->index_writer
+ size
> buffer
->size
) {
573 int left_size
= buffer
->size
- buffer
->index_writer
;
575 memcpy(&buffer
->buffer
[buffer
->index_writer
],
576 buffer_index
, left_size
);
577 buffer
->index_writer
= 0;
578 buffer_index
+= left_size
;
580 memcpy(&buffer
->buffer
[buffer
->index_writer
], buffer_index
,
581 size
- (buffer_index
- tmp_buf
));
582 buffer
->index_writer
+= size
- (buffer_index
- tmp_buf
);
587 static int __init
log_late_initcall(void)
589 debugfs_create_u32("log_auto_save", S_IRWUG
, chub_dbg_get_root_dir(),
594 late_initcall(log_late_initcall
);