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