aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/aee/ipanic/ipanic_pstore.c
blob: 8cad0256843afe41f48d426d737cbd2bb125fef4 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/pstore_ram.h>
#include <linux/pstore.h>
#include "ipanic.h"

static struct ipanic_header *aee_poweroff_logs;
static unsigned int aee_active_index;
#define AEE_POWEROFF_NR	4
#define AEE_POWEROFF_OFFSET 0x00700000
#define AEE_POWEROFF_MAGIC 0x43474244  /* DBGC */

struct ipanic_data_zone {
	struct ipanic_data_header *header;
	
};
	
void ipanic_kmsg_hdr(struct ipanic_data_header *hdr, unsigned int id, unsigned int offset)
{
	struct timespec timestamp;
	hdr->id = id;
	hdr->valid = 1;
	hdr->offset = offset;
	hdr->total = __LOG_BUF_LEN;
	hdr->encrypt = 0;
	if (__getnstimeofday(&timestamp)) {
		timestamp.tv_sec = 0;
		timestamp.tv_nsec = 0;
	}
	snprintf(hdr->name, 32, "kmsg_%lu", (long)timestamp.tv_sec);
}

void ipanic_kmsg_init(void)
{
	aee_poweroff_logs = ipanic_header_from_sd(AEE_POWEROFF_OFFSET, AEE_POWEROFF_MAGIC);
	if (!aee_poweroff_logs) {
		aee_poweroff_logs = kzalloc(sizeof(struct ipanic_header), GFP_KERNEL);
		if (ipanic_msdc_info(aee_poweroff_logs)) {
			LOGE("aee poweroff logs init msdc fail");
			kfree(aee_poweroff_logs);
			aee_poweroff_logs = NULL;
			return;
		}
		aee_poweroff_logs->magic = AEE_POWEROFF_MAGIC;
		aee_poweroff_logs->size = sizeof(struct ipanic_header);
	}
}

void ipanic_kmsg_hdr_write(void)
{
	ipanic_mem_write(aee_poweroff_logs, AEE_POWEROFF_OFFSET, sizeof(struct ipanic_header), 0);
}

void ipanic_kmsg_next(void)
{
	int i;
	struct ipanic_data_header *hdr;
	int last_id = 0;
	if (!aee_poweroff_logs)
		return;
	aee_active_index = 0;
	
	for (i = 0; i < AEE_POWEROFF_NR; i++) {
		if (aee_poweroff_logs->data_hdr[i].id < aee_poweroff_logs->data_hdr[aee_active_index].id)
			aee_active_index = i;
		if (aee_poweroff_logs->data_hdr[i].id > aee_poweroff_logs->data_hdr[last_id].id)
			last_id = i;
	}
	hdr = &aee_poweroff_logs->data_hdr[aee_active_index];
	ipanic_kmsg_hdr(hdr, aee_poweroff_logs->data_hdr[last_id].id + 1, AEE_POWEROFF_OFFSET + ALIGN(sizeof(struct ipanic_header), aee_poweroff_logs->blksize) + aee_active_index * __LOG_BUF_LEN);
	hdr->used = hdr->total;
	ipanic_kmsg_hdr_write();
	hdr->used = 0;
}

int ipanic_kmsg_write(unsigned int part, char *buf, size_t size)
{
	if (part == 1)
		ipanic_kmsg_next();
	struct ipanic_data_header *hdr = &aee_poweroff_logs->data_hdr[aee_active_index];
	int offset = hdr->offset + hdr->total - hdr->used - ALIGN(size, aee_poweroff_logs->blksize);
	if (offset < hdr->offset)
		return -EINVAL;
	hdr->used += ALIGN(size, aee_poweroff_logs->blksize);
	ipanic_mem_write(buf, offset, size, hdr->encrypt);
	return 0;
}

int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time,
				  char **buf, struct pstore_info *psi)
{
	char *data;
	int i, size = 0;
	struct ipanic_data_header *hdr;
	if (*count == 0)
		ipanic_kmsg_init();
	for (i = *count; i < AEE_POWEROFF_NR; i++) {
		hdr = &aee_poweroff_logs->data_hdr[i];
		if (!hdr->valid)
			continue;
		data = ipanic_data_from_sd(hdr, 0);
		if (data) {
			*buf = data;
			size = hdr->used;
			*type = PSTORE_TYPE_DMESG;
			*id = hdr->id;
			i++;
			break;
		}
	}
	LOGD("ipanic_kmsg_get_next: count %d, buf %p, size %x\n", *count, *buf, size);
	*count = i;
	return size;
}