cvmx-range.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018-2022 Marvell International Ltd.
  4. */
  5. #include <log.h>
  6. #include <time.h>
  7. #include <linux/delay.h>
  8. #include <mach/cvmx-regs.h>
  9. #include <mach/cvmx-csr.h>
  10. #include <mach/cvmx-bootmem.h>
  11. #include <mach/octeon-model.h>
  12. #include <mach/cvmx-fuse.h>
  13. #include <mach/octeon-feature.h>
  14. #include <mach/cvmx-qlm.h>
  15. #include <mach/octeon_qlm.h>
  16. #include <mach/cvmx-pcie.h>
  17. #include <mach/cvmx-coremask.h>
  18. #include <mach/cvmx-global-resources.h>
  19. #include <mach/cvmx-pki.h>
  20. #include <mach/cvmx-helper.h>
  21. #include <mach/cvmx-helper-board.h>
  22. #include <mach/cvmx-helper-cfg.h>
  23. #include <mach/cvmx-range.h>
  24. #define CVMX_RANGE_AVAILABLE ((u64)-88)
  25. #define addr_of_element(base, index) \
  26. (1ull << 63 | ((base) + sizeof(u64) + (index) * sizeof(u64)))
  27. #define addr_of_size(base) (1ull << 63 | (base))
  28. static const int debug;
  29. int cvmx_range_memory_size(int nelements)
  30. {
  31. return sizeof(u64) * (nelements + 1);
  32. }
  33. int cvmx_range_init(u64 range_addr, int size)
  34. {
  35. u64 lsize = size;
  36. u64 i;
  37. cvmx_write64_uint64(addr_of_size(range_addr), lsize);
  38. for (i = 0; i < lsize; i++) {
  39. cvmx_write64_uint64(addr_of_element(range_addr, i),
  40. CVMX_RANGE_AVAILABLE);
  41. }
  42. return 0;
  43. }
  44. static int64_t cvmx_range_find_next_available(u64 range_addr, u64 index,
  45. int align)
  46. {
  47. u64 size = cvmx_read64_uint64(addr_of_size(range_addr));
  48. u64 i;
  49. while ((index % align) != 0)
  50. index++;
  51. for (i = index; i < size; i += align) {
  52. u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i));
  53. if (debug)
  54. debug("%s: index=%d owner=%llx\n", __func__, (int)i,
  55. (unsigned long long)r_owner);
  56. if (r_owner == CVMX_RANGE_AVAILABLE)
  57. return i;
  58. }
  59. return -1;
  60. }
  61. static int64_t cvmx_range_find_last_available(u64 range_addr, u64 index,
  62. u64 align)
  63. {
  64. u64 size = cvmx_read64_uint64(addr_of_size(range_addr));
  65. u64 i;
  66. if (index == 0)
  67. index = size - 1;
  68. while ((index % align) != 0)
  69. index++;
  70. for (i = index; i > align; i -= align) {
  71. u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i));
  72. if (debug)
  73. debug("%s: index=%d owner=%llx\n", __func__, (int)i,
  74. (unsigned long long)r_owner);
  75. if (r_owner == CVMX_RANGE_AVAILABLE)
  76. return i;
  77. }
  78. return -1;
  79. }
  80. int cvmx_range_alloc_ordered(u64 range_addr, u64 owner, u64 cnt,
  81. int align, int reverse)
  82. {
  83. u64 i = 0, size;
  84. s64 first_available;
  85. if (debug)
  86. debug("%s: range_addr=%llx owner=%llx cnt=%d\n", __func__,
  87. (unsigned long long)range_addr,
  88. (unsigned long long)owner, (int)cnt);
  89. size = cvmx_read64_uint64(addr_of_size(range_addr));
  90. while (i < size) {
  91. u64 available_cnt = 0;
  92. if (reverse)
  93. first_available = cvmx_range_find_last_available(range_addr, i, align);
  94. else
  95. first_available = cvmx_range_find_next_available(range_addr, i, align);
  96. if (first_available == -1)
  97. return -1;
  98. i = first_available;
  99. if (debug)
  100. debug("%s: first_available=%d\n", __func__, (int)first_available);
  101. while ((available_cnt != cnt) && (i < size)) {
  102. u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i));
  103. if (r_owner == CVMX_RANGE_AVAILABLE)
  104. available_cnt++;
  105. i++;
  106. }
  107. if (available_cnt == cnt) {
  108. u64 j;
  109. if (debug)
  110. debug("%s: first_available=%d available=%d\n",
  111. __func__,
  112. (int)first_available, (int)available_cnt);
  113. for (j = first_available; j < first_available + cnt;
  114. j++) {
  115. u64 a = addr_of_element(range_addr, j);
  116. cvmx_write64_uint64(a, owner);
  117. }
  118. return first_available;
  119. }
  120. }
  121. if (debug) {
  122. debug("ERROR: %s: failed to allocate range cnt=%d\n",
  123. __func__, (int)cnt);
  124. cvmx_range_show(range_addr);
  125. }
  126. return -1;
  127. }
  128. int cvmx_range_alloc(u64 range_addr, u64 owner, u64 cnt, int align)
  129. {
  130. return cvmx_range_alloc_ordered(range_addr, owner, cnt, align, 0);
  131. }
  132. int cvmx_range_reserve(u64 range_addr, u64 owner, u64 base,
  133. u64 cnt)
  134. {
  135. u64 i, size, r_owner;
  136. u64 up = base + cnt;
  137. size = cvmx_read64_uint64(addr_of_size(range_addr));
  138. if (up > size) {
  139. debug("ERROR: %s: invalid base or cnt. range_addr=0x%llx, owner=0x%llx, size=%d base+cnt=%d\n",
  140. __func__, (unsigned long long)range_addr,
  141. (unsigned long long)owner,
  142. (int)size, (int)up);
  143. return -1;
  144. }
  145. for (i = base; i < up; i++) {
  146. r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i));
  147. if (debug)
  148. debug("%s: %d: %llx\n",
  149. __func__, (int)i, (unsigned long long)r_owner);
  150. if (r_owner != CVMX_RANGE_AVAILABLE) {
  151. if (debug) {
  152. debug("%s: resource already reserved base+cnt=%d %llu %llu %llx %llx %llx\n",
  153. __func__, (int)i, (unsigned long long)cnt,
  154. (unsigned long long)base,
  155. (unsigned long long)r_owner,
  156. (unsigned long long)range_addr,
  157. (unsigned long long)owner);
  158. }
  159. return -1;
  160. }
  161. }
  162. for (i = base; i < up; i++)
  163. cvmx_write64_uint64(addr_of_element(range_addr, i), owner);
  164. return base;
  165. }
  166. int __cvmx_range_is_allocated(u64 range_addr, int bases[], int count)
  167. {
  168. u64 i, cnt, size;
  169. u64 r_owner;
  170. cnt = count;
  171. size = cvmx_read64_uint64(addr_of_size(range_addr));
  172. for (i = 0; i < cnt; i++) {
  173. u64 base = bases[i];
  174. if (base >= size) {
  175. debug("ERROR: %s: invalid base or cnt size=%d base=%d\n",
  176. __func__, (int)size, (int)base);
  177. return 0;
  178. }
  179. r_owner = cvmx_read64_uint64(addr_of_element(range_addr, base));
  180. if (r_owner == CVMX_RANGE_AVAILABLE) {
  181. if (debug) {
  182. debug("%s: i=%d:base=%d is available\n",
  183. __func__, (int)i, (int)base);
  184. }
  185. return 0;
  186. }
  187. }
  188. return 1;
  189. }
  190. int cvmx_range_free_mutiple(u64 range_addr, int bases[], int count)
  191. {
  192. u64 i, cnt;
  193. cnt = count;
  194. if (__cvmx_range_is_allocated(range_addr, bases, count) != 1)
  195. return -1;
  196. for (i = 0; i < cnt; i++) {
  197. u64 base = bases[i];
  198. cvmx_write64_uint64(addr_of_element(range_addr, base),
  199. CVMX_RANGE_AVAILABLE);
  200. }
  201. return 0;
  202. }
  203. int cvmx_range_free_with_base(u64 range_addr, int base, int cnt)
  204. {
  205. u64 i, size;
  206. u64 up = base + cnt;
  207. size = cvmx_read64_uint64(addr_of_size(range_addr));
  208. if (up > size) {
  209. debug("ERROR: %s: invalid base or cnt size=%d base+cnt=%d\n",
  210. __func__, (int)size, (int)up);
  211. return -1;
  212. }
  213. for (i = base; i < up; i++) {
  214. cvmx_write64_uint64(addr_of_element(range_addr, i),
  215. CVMX_RANGE_AVAILABLE);
  216. }
  217. return 0;
  218. }