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