iotrace.c 3.7 KB

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