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