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