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