xref: /OK3568_Linux_fs/u-boot/common/iotrace.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2014 Google, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:     GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define IOTRACE_IMPL
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <mapmem.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* Support up to the machine word length for now */
16*4882a593Smuzhiyun typedef ulong iovalue_t;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun enum iotrace_flags {
19*4882a593Smuzhiyun 	IOT_8 = 0,
20*4882a593Smuzhiyun 	IOT_16,
21*4882a593Smuzhiyun 	IOT_32,
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	IOT_READ = 0 << 3,
24*4882a593Smuzhiyun 	IOT_WRITE = 1 << 3,
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /**
28*4882a593Smuzhiyun  * struct iotrace_record - Holds a single I/O trace record
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * @flags: I/O access type
31*4882a593Smuzhiyun  * @addr: Address of access
32*4882a593Smuzhiyun  * @value: Value written or read
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun struct iotrace_record {
35*4882a593Smuzhiyun 	enum iotrace_flags flags;
36*4882a593Smuzhiyun 	phys_addr_t addr;
37*4882a593Smuzhiyun 	iovalue_t value;
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /**
41*4882a593Smuzhiyun  * struct iotrace - current trace status and checksum
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * @start:	Start address of iotrace buffer
44*4882a593Smuzhiyun  * @size:	Size of iotrace buffer in bytes
45*4882a593Smuzhiyun  * @offset:	Current write offset into iotrace buffer
46*4882a593Smuzhiyun  * @crc32:	Current value of CRC chceksum of trace records
47*4882a593Smuzhiyun  * @enabled:	true if enabled, false if disabled
48*4882a593Smuzhiyun  */
49*4882a593Smuzhiyun static struct iotrace {
50*4882a593Smuzhiyun 	ulong start;
51*4882a593Smuzhiyun 	ulong size;
52*4882a593Smuzhiyun 	ulong offset;
53*4882a593Smuzhiyun 	u32 crc32;
54*4882a593Smuzhiyun 	bool enabled;
55*4882a593Smuzhiyun } iotrace;
56*4882a593Smuzhiyun 
add_record(int flags,const void * ptr,ulong value)57*4882a593Smuzhiyun static void add_record(int flags, const void *ptr, ulong value)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct iotrace_record srec, *rec = &srec;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/*
62*4882a593Smuzhiyun 	 * We don't support iotrace before relocation. Since the trace buffer
63*4882a593Smuzhiyun 	 * is set up by a command, it can't be enabled at present. To change
64*4882a593Smuzhiyun 	 * this we would need to set the iotrace buffer at build-time. See
65*4882a593Smuzhiyun 	 * lib/trace.c for how this might be done if you are interested.
66*4882a593Smuzhiyun 	 */
67*4882a593Smuzhiyun 	if (!(gd->flags & GD_FLG_RELOC) || !iotrace.enabled)
68*4882a593Smuzhiyun 		return;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/* Store it if there is room */
71*4882a593Smuzhiyun 	if (iotrace.offset + sizeof(*rec) < iotrace.size) {
72*4882a593Smuzhiyun 		rec = (struct iotrace_record *)map_sysmem(
73*4882a593Smuzhiyun 					iotrace.start + iotrace.offset,
74*4882a593Smuzhiyun 					sizeof(value));
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	rec->flags = flags;
78*4882a593Smuzhiyun 	rec->addr = map_to_sysmem(ptr);
79*4882a593Smuzhiyun 	rec->value = value;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	/* Update our checksum */
82*4882a593Smuzhiyun 	iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec,
83*4882a593Smuzhiyun 			      sizeof(*rec));
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	iotrace.offset += sizeof(struct iotrace_record);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
iotrace_readl(const void * ptr)88*4882a593Smuzhiyun u32 iotrace_readl(const void *ptr)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	u32 v;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	printf("[iotrace]: read  addr 0x%08lx... ", (ulong)ptr);
93*4882a593Smuzhiyun 	v = readl(ptr);
94*4882a593Smuzhiyun 	add_record(IOT_32 | IOT_READ, ptr, v);
95*4882a593Smuzhiyun 	printf("OK\n");
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return v;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
iotrace_writel(ulong value,const void * ptr)100*4882a593Smuzhiyun void iotrace_writel(ulong value, const void *ptr)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	printf("[iotrace]: write addr 0x%08lx value 0x%08lx... ", (ulong)ptr, value);
103*4882a593Smuzhiyun 	add_record(IOT_32 | IOT_WRITE, ptr, value);
104*4882a593Smuzhiyun 	writel(value, ptr);
105*4882a593Smuzhiyun 	printf("OK\n");
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
iotrace_readw(const void * ptr)108*4882a593Smuzhiyun u16 iotrace_readw(const void *ptr)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	u32 v;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	v = readw(ptr);
113*4882a593Smuzhiyun 	add_record(IOT_16 | IOT_READ, ptr, v);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return v;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
iotrace_writew(ulong value,const void * ptr)118*4882a593Smuzhiyun void iotrace_writew(ulong value, const void *ptr)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	add_record(IOT_16 | IOT_WRITE, ptr, value);
121*4882a593Smuzhiyun 	writew(value, ptr);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
iotrace_readb(const void * ptr)124*4882a593Smuzhiyun u8 iotrace_readb(const void *ptr)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	u32 v;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	v = readb(ptr);
129*4882a593Smuzhiyun 	add_record(IOT_8 | IOT_READ, ptr, v);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return v;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
iotrace_writeb(ulong value,const void * ptr)134*4882a593Smuzhiyun void iotrace_writeb(ulong value, const void *ptr)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	add_record(IOT_8 | IOT_WRITE, ptr, value);
137*4882a593Smuzhiyun 	writeb(value, ptr);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
iotrace_reset_checksum(void)140*4882a593Smuzhiyun void iotrace_reset_checksum(void)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	iotrace.crc32 = 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
iotrace_get_checksum(void)145*4882a593Smuzhiyun u32 iotrace_get_checksum(void)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	return iotrace.crc32;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
iotrace_set_enabled(int enable)150*4882a593Smuzhiyun void iotrace_set_enabled(int enable)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	iotrace.enabled = enable;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
iotrace_get_enabled(void)155*4882a593Smuzhiyun int iotrace_get_enabled(void)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	return iotrace.enabled;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
iotrace_set_buffer(ulong start,ulong size)160*4882a593Smuzhiyun void iotrace_set_buffer(ulong start, ulong size)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	iotrace.start = start;
163*4882a593Smuzhiyun 	iotrace.size = size;
164*4882a593Smuzhiyun 	iotrace.offset = 0;
165*4882a593Smuzhiyun 	iotrace.crc32 = 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
iotrace_get_buffer(ulong * start,ulong * size,ulong * offset,ulong * count)168*4882a593Smuzhiyun void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	*start = iotrace.start;
171*4882a593Smuzhiyun 	*size = iotrace.size;
172*4882a593Smuzhiyun 	*offset = iotrace.offset;
173*4882a593Smuzhiyun 	*count = iotrace.offset / sizeof(struct iotrace_record);
174*4882a593Smuzhiyun }
175