cvmx-coremask.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018-2020 Marvell International Ltd.
  4. */
  5. #include <env.h>
  6. #include <errno.h>
  7. #include <linux/compat.h>
  8. #include <linux/ctype.h>
  9. #include <mach/cvmx-regs.h>
  10. #include <mach/cvmx-coremask.h>
  11. #include <mach/cvmx-fuse.h>
  12. #include <mach/octeon-model.h>
  13. #include <mach/octeon-feature.h>
  14. #include <mach/cvmx-ciu-defs.h>
  15. struct cvmx_coremask *get_coremask_override(struct cvmx_coremask *pcm)
  16. {
  17. struct cvmx_coremask pcm_override = CVMX_COREMASK_MAX;
  18. char *cptr;
  19. /* The old code sets the number of cores to be to 16 in this case. */
  20. cvmx_coremask_set_cores(pcm, 0, 16);
  21. if (OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3())
  22. cvmx_coremask_copy(pcm, &pcm_override);
  23. cptr = env_get("coremask_override");
  24. if (cptr) {
  25. if (cvmx_coremask_str2bmp(pcm, cptr) < 0)
  26. return NULL;
  27. }
  28. return pcm;
  29. }
  30. /* Validate the coremask that is passed to a boot* function. */
  31. int validate_coremask(struct cvmx_coremask *pcm)
  32. {
  33. struct cvmx_coremask coremask_override;
  34. struct cvmx_coremask fuse_coremask;
  35. if (!get_coremask_override(&coremask_override))
  36. return -1;
  37. octeon_get_available_coremask(&fuse_coremask);
  38. if (!cvmx_coremask_is_subset(&fuse_coremask, pcm)) {
  39. puts("ERROR: Can't boot cores that don't exist!\n");
  40. puts("Available coremask:\n");
  41. cvmx_coremask_print(&fuse_coremask);
  42. return -1;
  43. }
  44. if (!cvmx_coremask_is_subset(&coremask_override, pcm)) {
  45. struct cvmx_coremask print_cm;
  46. puts("Notice: coremask changed from:\n");
  47. cvmx_coremask_print(pcm);
  48. puts("based on coremask_override of:\n");
  49. cvmx_coremask_print(&coremask_override);
  50. cvmx_coremask_and(&print_cm, pcm, &coremask_override);
  51. puts("to:\n");
  52. cvmx_coremask_print(&print_cm);
  53. }
  54. return 0;
  55. }
  56. /**
  57. * In CIU_FUSE for the 78XX, odd and even cores are separated out.
  58. * For example, a CIU_FUSE value of 0xfffffefffffe indicates that bits 0 and 1
  59. * are set.
  60. * This function converts the bit number in the CIU_FUSE register to a
  61. * physical core number.
  62. */
  63. static int convert_ciu_fuse_to_physical_core(int core, int max_cores)
  64. {
  65. if (!octeon_has_feature(OCTEON_FEATURE_CIU3))
  66. return core;
  67. else if (!OCTEON_IS_MODEL(OCTEON_CN78XX))
  68. return core;
  69. else if (core < (max_cores / 2))
  70. return core * 2;
  71. else
  72. return ((core - (max_cores / 2)) * 2) + 1;
  73. }
  74. /**
  75. * Get the total number of fuses blown as well as the number blown per tad.
  76. *
  77. * @param coremask fuse coremask
  78. * @param[out] tad_blown_count number of cores blown for each tad
  79. * @param num_tads number of tads
  80. * @param max_cores maximum number of cores
  81. *
  82. * Return: void
  83. */
  84. void fill_tad_corecount(u64 coremask, int tad_blown_count[], int num_tads,
  85. int max_cores)
  86. {
  87. int core, physical_core;
  88. for (core = 0; core < max_cores; core++) {
  89. if (!(coremask & (1ULL << core))) {
  90. int tad;
  91. physical_core =
  92. convert_ciu_fuse_to_physical_core(core,
  93. max_cores);
  94. tad = physical_core % num_tads;
  95. tad_blown_count[tad]++;
  96. }
  97. }
  98. }
  99. u64 get_core_pattern(int num_tads, int max_cores)
  100. {
  101. u64 pattern = 1ULL;
  102. int cnt;
  103. for (cnt = 1; cnt < (max_cores / num_tads); cnt++)
  104. pattern |= pattern << num_tads;
  105. return pattern;
  106. }
  107. /**
  108. * For CN78XX and CN68XX this function returns the logical coremask from the
  109. * CIU_FUSE register value. For other models there is no difference.
  110. *
  111. * @param ciu_fuse_value fuse value from CIU_FUSE register
  112. * Return: logical coremask of CIU_FUSE value.
  113. */
  114. u64 get_logical_coremask(u64 ciu_fuse_value)
  115. {
  116. int tad_blown_count[MAX_CORE_TADS] = {0};
  117. int tad;
  118. u64 logical_coremask = 0;
  119. u64 tad_mask, pattern;
  120. int num_tads, max_cores;
  121. if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
  122. num_tads = 8;
  123. max_cores = 48;
  124. } else if (OCTEON_IS_MODEL(OCTEON_CN73XX) ||
  125. OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
  126. num_tads = 4;
  127. max_cores = 16;
  128. } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
  129. num_tads = 4;
  130. max_cores = 32;
  131. } else {
  132. /* Most Octeon devices don't need any mapping. */
  133. return ciu_fuse_value;
  134. }
  135. pattern = get_core_pattern(num_tads, max_cores);
  136. fill_tad_corecount(ciu_fuse_value, tad_blown_count,
  137. num_tads, max_cores);
  138. for (tad = 0; tad < num_tads; tad++) {
  139. tad_mask = pattern << tad;
  140. logical_coremask |= tad_mask >> (tad_blown_count[tad] * num_tads);
  141. }
  142. return logical_coremask;
  143. }
  144. /**
  145. * Returns the available coremask either from env or fuses.
  146. * If the fuses are blown and locked, they are the definitive coremask.
  147. *
  148. * @param pcm pointer to coremask to fill in
  149. * Return: pointer to coremask
  150. */
  151. struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm)
  152. {
  153. u8 node_mask = 0x01; /* ToDo: Currently only one node is supported */
  154. u64 ciu_fuse;
  155. u64 cores;
  156. cvmx_coremask_clear_all(pcm);
  157. if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
  158. int node;
  159. cvmx_coremask_for_each_node(node, node_mask) {
  160. ciu_fuse = (csr_rd(CVMX_CIU_FUSE) &
  161. 0x0000FFFFFFFFFFFFULL);
  162. ciu_fuse = get_logical_coremask(ciu_fuse);
  163. cvmx_coremask_set64_node(pcm, node, ciu_fuse);
  164. }
  165. return pcm;
  166. }
  167. ciu_fuse = (csr_rd(CVMX_CIU_FUSE) & 0x0000FFFFFFFFFFFFULL);
  168. ciu_fuse = get_logical_coremask(ciu_fuse);
  169. if (OCTEON_IS_MODEL(OCTEON_CN68XX))
  170. cvmx_coremask_set64(pcm, ciu_fuse);
  171. /* Get number of cores from fuse register, convert to coremask */
  172. cores = __builtin_popcountll(ciu_fuse);
  173. cvmx_coremask_set_cores(pcm, 0, cores);
  174. return pcm;
  175. }
  176. int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr)
  177. {
  178. int i, j;
  179. int l; /* length of the hexstr in characters */
  180. int lb; /* number of bits taken by hexstr */
  181. int hldr_offset;/* holder's offset within the coremask */
  182. int hldr_xsz; /* holder's size in the number of hex digits */
  183. u64 h;
  184. char c;
  185. #define MINUS_ONE (hexstr[0] == '-' && hexstr[1] == '1' && hexstr[2] == 0)
  186. if (MINUS_ONE) {
  187. cvmx_coremask_set_all(pcm);
  188. return 0;
  189. }
  190. /* Skip '0x' from hexstr */
  191. if (hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] == 'X'))
  192. hexstr += 2;
  193. if (!strlen(hexstr)) {
  194. printf("%s: Error: hex string is empty\n", __func__);
  195. return -2;
  196. }
  197. /* Trim leading zeros */
  198. while (*hexstr == '0')
  199. hexstr++;
  200. cvmx_coremask_clear_all(pcm);
  201. l = strlen(hexstr);
  202. /* If length is 0 then the hex string must be all zeros */
  203. if (l == 0)
  204. return 0;
  205. for (i = 0; i < l; i++) {
  206. if (isxdigit((int)hexstr[i]) == 0) {
  207. printf("%s: Non-hex digit within hexstr\n", __func__);
  208. return -2;
  209. }
  210. }
  211. lb = (l - 1) * 4;
  212. if (hexstr[0] > '7')
  213. lb += 4;
  214. else if (hexstr[0] > '3')
  215. lb += 3;
  216. else if (hexstr[0] > '1')
  217. lb += 2;
  218. else
  219. lb += 1;
  220. if (lb > CVMX_MIPS_MAX_CORES) {
  221. printf("%s: hexstr (%s) is too long\n", __func__, hexstr);
  222. return -1;
  223. }
  224. hldr_offset = 0;
  225. hldr_xsz = 2 * sizeof(u64);
  226. for (i = l; i > 0; i -= hldr_xsz) {
  227. c = hexstr[i];
  228. hexstr[i] = 0;
  229. j = i - hldr_xsz;
  230. if (j < 0)
  231. j = 0;
  232. h = simple_strtoull(&hexstr[j], NULL, 16);
  233. if (errno == EINVAL) {
  234. printf("%s: strtou returns w/ EINVAL\n", __func__);
  235. return -2;
  236. }
  237. pcm->coremask_bitmap[hldr_offset] = h;
  238. hexstr[i] = c;
  239. hldr_offset++;
  240. }
  241. return 0;
  242. }
  243. void cvmx_coremask_print(const struct cvmx_coremask *pcm)
  244. {
  245. int i, j;
  246. int start;
  247. int found = 0;
  248. /*
  249. * Print one node per line. Since the bitmap is stored LSB to MSB
  250. * we reverse the order when printing.
  251. */
  252. if (!octeon_has_feature(OCTEON_FEATURE_MULTINODE)) {
  253. start = 0;
  254. for (j = CVMX_COREMASK_MAX_CORES_PER_NODE -
  255. CVMX_COREMASK_HLDRSZ;
  256. j >= 0; j -= CVMX_COREMASK_HLDRSZ) {
  257. if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
  258. start = 1;
  259. if (start) {
  260. printf(" 0x%llx",
  261. (u64)pcm->coremask_bitmap[j /
  262. CVMX_COREMASK_HLDRSZ]);
  263. }
  264. }
  265. if (start)
  266. found = 1;
  267. /*
  268. * If the coremask is empty print <EMPTY> so it is not
  269. * confusing
  270. */
  271. if (!found)
  272. printf("<EMPTY>");
  273. printf("\n");
  274. return;
  275. }
  276. for (i = 0; i < CVMX_MAX_USED_CORES_BMP;
  277. i += CVMX_COREMASK_MAX_CORES_PER_NODE) {
  278. printf("%s node %d:", i > 0 ? "\n" : "",
  279. cvmx_coremask_core_to_node(i));
  280. start = 0;
  281. for (j = i + CVMX_COREMASK_MAX_CORES_PER_NODE -
  282. CVMX_COREMASK_HLDRSZ;
  283. j >= i;
  284. j -= CVMX_COREMASK_HLDRSZ) {
  285. /* Don't start printing until we get a non-zero word. */
  286. if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
  287. start = 1;
  288. if (start) {
  289. printf(" 0x%llx", (u64)pcm->coremask_bitmap[j /
  290. CVMX_COREMASK_HLDRSZ]);
  291. }
  292. }
  293. if (start)
  294. found = 1;
  295. }
  296. i /= CVMX_COREMASK_HLDRSZ;
  297. for (; i < CVMX_COREMASK_BMPSZ; i++) {
  298. if (pcm->coremask_bitmap[i]) {
  299. printf(" EXTRA GARBAGE[%i]: %016llx\n", i,
  300. (u64)pcm->coremask_bitmap[i]);
  301. }
  302. }
  303. /* If the coremask is empty print <EMPTY> so it is not confusing */
  304. if (!found)
  305. printf("<EMPTY>");
  306. printf("\n");
  307. }