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