blob: f39885663a3c7aed93259428fe3b4afdf04f8a88 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassaa532332014-06-11 23:29:41 -06002/*
3 * Copyright (c) 2014 Google, Inc.
Simon Glassaa532332014-06-11 23:29:41 -06004 */
5
6#define IOTRACE_IMPL
7
8#include <common.h>
Joe Hershberger0eb25b62015-03-22 17:08:59 -05009#include <mapmem.h>
Simon Glassaa532332014-06-11 23:29:41 -060010#include <asm/io.h>
11
12DECLARE_GLOBAL_DATA_PTR;
13
14/* Support up to the machine word length for now */
15typedef ulong iovalue_t;
16
17enum iotrace_flags {
18 IOT_8 = 0,
19 IOT_16,
20 IOT_32,
21
22 IOT_READ = 0 << 3,
23 IOT_WRITE = 1 << 3,
24};
25
26/**
27 * struct iotrace_record - Holds a single I/O trace record
28 *
29 * @flags: I/O access type
30 * @addr: Address of access
31 * @value: Value written or read
32 */
33struct iotrace_record {
34 enum iotrace_flags flags;
35 phys_addr_t addr;
36 iovalue_t value;
37};
38
39/**
40 * struct iotrace - current trace status and checksum
41 *
42 * @start: Start address of iotrace buffer
43 * @size: Size of iotrace buffer in bytes
44 * @offset: Current write offset into iotrace buffer
Ramon Frieda74440b2018-05-30 23:09:58 +030045 * @region_start: Address of IO region to trace
46 * @region_size: Size of region to trace. if 0 will trace all address space
Simon Glassaa532332014-06-11 23:29:41 -060047 * @crc32: Current value of CRC chceksum of trace records
48 * @enabled: true if enabled, false if disabled
49 */
50static struct iotrace {
51 ulong start;
52 ulong size;
53 ulong offset;
Ramon Frieda74440b2018-05-30 23:09:58 +030054 ulong region_start;
55 ulong region_size;
Simon Glassaa532332014-06-11 23:29:41 -060056 u32 crc32;
57 bool enabled;
58} iotrace;
59
60static void add_record(int flags, const void *ptr, ulong value)
61{
62 struct iotrace_record srec, *rec = &srec;
63
64 /*
65 * We don't support iotrace before relocation. Since the trace buffer
66 * is set up by a command, it can't be enabled at present. To change
67 * this we would need to set the iotrace buffer at build-time. See
68 * lib/trace.c for how this might be done if you are interested.
69 */
70 if (!(gd->flags & GD_FLG_RELOC) || !iotrace.enabled)
71 return;
72
Ramon Frieda74440b2018-05-30 23:09:58 +030073 if (iotrace.region_size)
74 if ((ulong)ptr < iotrace.region_start ||
75 (ulong)ptr > iotrace.region_start + iotrace.region_size)
76 return;
77
Simon Glassaa532332014-06-11 23:29:41 -060078 /* Store it if there is room */
79 if (iotrace.offset + sizeof(*rec) < iotrace.size) {
80 rec = (struct iotrace_record *)map_sysmem(
81 iotrace.start + iotrace.offset,
82 sizeof(value));
83 }
84
85 rec->flags = flags;
86 rec->addr = map_to_sysmem(ptr);
87 rec->value = value;
88
89 /* Update our checksum */
90 iotrace.crc32 = crc32(iotrace.crc32, (unsigned char *)rec,
91 sizeof(*rec));
92
93 iotrace.offset += sizeof(struct iotrace_record);
94}
95
96u32 iotrace_readl(const void *ptr)
97{
98 u32 v;
99
100 v = readl(ptr);
101 add_record(IOT_32 | IOT_READ, ptr, v);
102
103 return v;
104}
105
106void iotrace_writel(ulong value, const void *ptr)
107{
108 add_record(IOT_32 | IOT_WRITE, ptr, value);
109 writel(value, ptr);
110}
111
112u16 iotrace_readw(const void *ptr)
113{
114 u32 v;
115
116 v = readw(ptr);
117 add_record(IOT_16 | IOT_READ, ptr, v);
118
119 return v;
120}
121
122void iotrace_writew(ulong value, const void *ptr)
123{
124 add_record(IOT_16 | IOT_WRITE, ptr, value);
125 writew(value, ptr);
126}
127
128u8 iotrace_readb(const void *ptr)
129{
130 u32 v;
131
132 v = readb(ptr);
133 add_record(IOT_8 | IOT_READ, ptr, v);
134
135 return v;
136}
137
138void iotrace_writeb(ulong value, const void *ptr)
139{
140 add_record(IOT_8 | IOT_WRITE, ptr, value);
141 writeb(value, ptr);
142}
143
144void iotrace_reset_checksum(void)
145{
146 iotrace.crc32 = 0;
147}
148
149u32 iotrace_get_checksum(void)
150{
151 return iotrace.crc32;
152}
153
Ramon Frieda74440b2018-05-30 23:09:58 +0300154void iotrace_set_region(ulong start, ulong size)
155{
156 iotrace.region_start = start;
157 iotrace.region_size = size;
158}
159
160void iotrace_reset_region(void)
161{
162 iotrace.region_start = 0;
163 iotrace.region_size = 0;
164}
165
166void iotrace_get_region(ulong *start, ulong *size)
167{
168 *start = iotrace.region_start;
169 *size = iotrace.region_size;
170}
171
Simon Glassaa532332014-06-11 23:29:41 -0600172void iotrace_set_enabled(int enable)
173{
174 iotrace.enabled = enable;
175}
176
177int iotrace_get_enabled(void)
178{
179 return iotrace.enabled;
180}
181
182void iotrace_set_buffer(ulong start, ulong size)
183{
184 iotrace.start = start;
185 iotrace.size = size;
186 iotrace.offset = 0;
187 iotrace.crc32 = 0;
188}
189
190void iotrace_get_buffer(ulong *start, ulong *size, ulong *offset, ulong *count)
191{
192 *start = iotrace.start;
193 *size = iotrace.size;
194 *offset = iotrace.offset;
195 *count = iotrace.offset / sizeof(struct iotrace_record);
196}