iotrace.c 3.8 KB

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