aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/aee/ipanic/ipanic_log.c
blob: 36585ace0e6054f5a7f6601b214fd4e9ed2a9600 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <linux/version.h>
#include <linux/module.h>
#include "ipanic.h"
#include "ipanic_version.h"

u8 *log_temp;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
/*
 * The function is used to dump kernel log after *Linux 3.5*
 */
size_t log_rest;
u8 *log_idx;
int ipanic_kmsg_dump3(struct kmsg_dumper *dumper, char *buf, size_t len)
{
	size_t rc = 0;
	size_t sum = 0;
	/* if log_rest is no 0, it means that there some bytes left by previous log entry need to write to buf */
	if (log_rest != 0) {
		memcpy(buf, log_idx, log_rest);
		sum += log_rest;
		log_rest = 0;
	}
	while (kmsg_dump_get_line_nolock(dumper, false, log_temp, len, &rc)
	       && dumper->cur_seq <= dumper->next_seq) {
		if (sum + rc >= len) {
			memcpy(buf + sum, log_temp, len - sum);
			log_rest = rc - (len - sum);
			log_idx = log_temp + (len - sum);
			sum += (len - sum);
			return len;
		}
		memcpy(buf + sum, log_temp, rc);
		sum += rc;
	}
	return sum;
}
EXPORT_SYMBOL(ipanic_kmsg_dump3);
#else
extern int log_buf_copy2(char *dest, int dest_len, int log_copy_start, int log_copy_end);
#endif

void ipanic_klog_region(struct kmsg_dumper *dumper)
{
	static struct ipanic_log_index next = { 0 };
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
	/* tricky usage of dump->list for log_start/log_end index */
	dumper->list.prev =
	    next.value ? (struct list_head *)next.value : (struct list_head *)(log_end -
									       __LOG_BUF_LEN);
	dumper->list.next = (struct list_head *)log_end;
	next.value = log_end;
	LOGD("kernel log region: [%x,%x]", (int)dumper->list.prev, (int)dumper->list.next);
#else
	dumper->cur_idx = next.seq ? next.idx : log_first_idx;
	dumper->cur_seq = next.seq ? next.seq : log_first_seq;
	dumper->next_idx = log_next_idx;
	dumper->next_seq = log_next_seq;
	next.idx = log_next_idx;
	next.seq = log_next_seq;
	LOGD("kernel log region: [%x:%llx,%x:%llx]", dumper->cur_idx, dumper->cur_seq,
	     dumper->next_idx, dumper->next_seq);
#endif
}

int ipanic_klog_buffer(void *data, unsigned char *buffer, size_t sz_buf)
{
	int rc = 0;
	struct kmsg_dumper *dumper = (struct kmsg_dumper *)data;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
	rc = log_buf_copy2(buffer, sz_buf, (int)dumper->list.prev, (int)dumper->list.next);
	if (rc < 0)
		rc = -1;
	else
		dumper->list.prev = (struct list_head *)(rc + (int)dumper->list.prev);
#else
	dumper->active = true;
	rc = ipanic_kmsg_dump3(dumper, buffer, sz_buf);
	if (rc < 0)
		rc = -1;
#endif
	return rc;
}

void ipanic_log_temp_init(void)
{
	log_temp = (u8 *) __get_free_page(GFP_KERNEL);
}