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