iotrace.c 3.8 KB

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