xref: /dpdk/drivers/common/cnxk/roc_model.c (revision 966f57a6232ea2efd83cb3d12053390384f645b9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include <dirent.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 
9 #include "roc_api.h"
10 #include "roc_priv.h"
11 
12 struct roc_model *roc_model;
13 
14 /* RoC and CPU IDs and revisions */
15 #define VENDOR_ARM    0x41 /* 'A' */
16 #define VENDOR_CAVIUM 0x43 /* 'C' */
17 
18 #define SOC_PART_CN10K 0xD49
19 #define SOC_PART_CN20K 0xD8E
20 
21 #define PART_206xx  0xA0
22 #define PART_106xx  0xB9
23 #define PART_105xx  0xBA
24 #define PART_105xxN 0xBC
25 #define PART_103xx  0xBD
26 #define PART_98xx   0xB1
27 #define PART_96xx   0xB2
28 #define PART_95xx   0xB3
29 #define PART_95xxN  0xB4
30 #define PART_95xxMM 0xB5
31 #define PART_95O    0xB6
32 
33 #define MODEL_IMPL_BITS	  8
34 #define MODEL_IMPL_SHIFT  24
35 #define MODEL_IMPL_MASK	  ((1 << MODEL_IMPL_BITS) - 1)
36 #define MODEL_PART_BITS	  12
37 #define MODEL_PART_SHIFT  4
38 #define MODEL_PART_MASK	  ((1 << MODEL_PART_BITS) - 1)
39 #define MODEL_MAJOR_BITS  4
40 #define MODEL_MAJOR_SHIFT 20
41 #define MODEL_MAJOR_MASK  ((1 << MODEL_MAJOR_BITS) - 1)
42 #define MODEL_MINOR_BITS  4
43 #define MODEL_MINOR_SHIFT 0
44 #define MODEL_MINOR_MASK  ((1 << MODEL_MINOR_BITS) - 1)
45 
46 #define MODEL_CN10K_PART_SHIFT	8
47 #define MODEL_CN10K_PASS_BITS	4
48 #define MODEL_CN10K_PASS_MASK	((1 << MODEL_CN10K_PASS_BITS) - 1)
49 #define MODEL_CN10K_MAJOR_BITS	2
50 #define MODEL_CN10K_MAJOR_SHIFT 2
51 #define MODEL_CN10K_MAJOR_MASK	((1 << MODEL_CN10K_MAJOR_BITS) - 1)
52 #define MODEL_CN10K_MINOR_BITS	2
53 #define MODEL_CN10K_MINOR_SHIFT 0
54 #define MODEL_CN10K_MINOR_MASK	((1 << MODEL_CN10K_MINOR_BITS) - 1)
55 
56 static const struct model_db {
57 	uint32_t impl;
58 	uint32_t part;
59 	uint32_t major;
60 	uint32_t minor;
61 	uint64_t flag;
62 	char name[ROC_MODEL_STR_LEN_MAX];
63 } model_db[] = {
64 	{VENDOR_ARM, PART_206xx, 0, 0, ROC_MODEL_CN206xx_A0, "cn20ka_a0"},
65 	{VENDOR_ARM, PART_106xx, 0, 0, ROC_MODEL_CN106xx_A0, "cn10ka_a0"},
66 	{VENDOR_ARM, PART_106xx, 0, 1, ROC_MODEL_CN106xx_A1, "cn10ka_a1"},
67 	{VENDOR_ARM, PART_106xx, 1, 0, ROC_MODEL_CN106xx_B0, "cn10ka_b0"},
68 	{VENDOR_ARM, PART_105xx, 0, 0, ROC_MODEL_CNF105xx_A0, "cnf10ka_a0"},
69 	{VENDOR_ARM, PART_105xx, 0, 1, ROC_MODEL_CNF105xx_A1, "cnf10ka_a1"},
70 	{VENDOR_ARM, PART_103xx, 0, 0, ROC_MODEL_CN103xx_A0, "cn10kb_a0"},
71 	{VENDOR_ARM, PART_105xxN, 0, 0, ROC_MODEL_CNF105xxN_A0, "cnf10kb_a0"},
72 	{VENDOR_ARM, PART_105xxN, 1, 0, ROC_MODEL_CNF105xxN_B0, "cnf10kb_b0"},
73 	{VENDOR_CAVIUM, PART_98xx, 0, 0, ROC_MODEL_CN98xx_A0, "cn98xx_a0"},
74 	{VENDOR_CAVIUM, PART_98xx, 0, 1, ROC_MODEL_CN98xx_A1, "cn98xx_a1"},
75 	{VENDOR_CAVIUM, PART_96xx, 0, 0, ROC_MODEL_CN96xx_A0, "cn96xx_a0"},
76 	{VENDOR_CAVIUM, PART_96xx, 0, 1, ROC_MODEL_CN96xx_B0, "cn96xx_b0"},
77 	{VENDOR_CAVIUM, PART_96xx, 2, 0, ROC_MODEL_CN96xx_C0, "cn96xx_c0"},
78 	{VENDOR_CAVIUM, PART_96xx, 2, 1, ROC_MODEL_CN96xx_C0, "cn96xx_c1"},
79 	{VENDOR_CAVIUM, PART_95xx, 0, 0, ROC_MODEL_CNF95xx_A0, "cnf95xx_a0"},
80 	{VENDOR_CAVIUM, PART_95xx, 1, 0, ROC_MODEL_CNF95xx_B0, "cnf95xx_b0"},
81 	{VENDOR_CAVIUM, PART_95xxN, 0, 0, ROC_MODEL_CNF95xxN_A0, "cnf95xxn_a0"},
82 	{VENDOR_CAVIUM, PART_95xxN, 0, 1, ROC_MODEL_CNF95xxN_A0, "cnf95xxn_a1"},
83 	{VENDOR_CAVIUM, PART_95xxN, 1, 0, ROC_MODEL_CNF95xxN_B0, "cnf95xxn_b0"},
84 	{VENDOR_CAVIUM, PART_95O, 0, 0, ROC_MODEL_CNF95xxO_A0, "cnf95O_a0"},
85 	{VENDOR_CAVIUM, PART_95xxMM, 0, 0, ROC_MODEL_CNF95xxMM_A0,
86 	 "cnf95xxmm_a0"}};
87 
88 /* Detect if RVU device */
89 static bool
90 is_rvu_device(unsigned long val)
91 {
92 	return (val == PCI_DEVID_CNXK_RVU_PF || val == PCI_DEVID_CNXK_RVU_VF ||
93 		val == PCI_DEVID_CNXK_RVU_AF ||
94 		val == PCI_DEVID_CNXK_RVU_AF_VF ||
95 		val == PCI_DEVID_CNXK_RVU_NPA_PF ||
96 		val == PCI_DEVID_CNXK_RVU_NPA_VF ||
97 		val == PCI_DEVID_CNXK_RVU_SSO_TIM_PF ||
98 		val == PCI_DEVID_CNXK_RVU_SSO_TIM_VF ||
99 		val == PCI_DEVID_CN10K_RVU_CPT_PF ||
100 		val == PCI_DEVID_CN10K_RVU_CPT_VF);
101 }
102 
103 static int
104 rvu_device_lookup(const char *dirname, uint32_t *part, uint32_t *pass)
105 {
106 	char filename[PATH_MAX];
107 	unsigned long val;
108 
109 	/* Check if vendor id is cavium */
110 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
111 	if (plt_sysfs_value_parse(filename, &val) < 0)
112 		goto error;
113 
114 	if (val != PCI_VENDOR_ID_CAVIUM)
115 		goto error;
116 
117 	/* Get device id  */
118 	snprintf(filename, sizeof(filename), "%s/device", dirname);
119 	if (plt_sysfs_value_parse(filename, &val) < 0)
120 		goto error;
121 
122 	/* Check if device ID belongs to any RVU device */
123 	if (!is_rvu_device(val))
124 		goto error;
125 
126 	/* Get subsystem_device id */
127 	snprintf(filename, sizeof(filename), "%s/subsystem_device", dirname);
128 	if (plt_sysfs_value_parse(filename, &val) < 0)
129 		goto error;
130 
131 	*part = val >> MODEL_CN10K_PART_SHIFT;
132 
133 	/* Get revision for pass value*/
134 	snprintf(filename, sizeof(filename), "%s/revision", dirname);
135 	if (plt_sysfs_value_parse(filename, &val) < 0)
136 		goto error;
137 
138 	*pass = val & MODEL_CN10K_PASS_MASK;
139 
140 	return 0;
141 error:
142 	return -EINVAL;
143 }
144 
145 /* Scans through all PCI devices, detects RVU device and returns
146  * subsystem_device
147  */
148 static int
149 cn10k_part_pass_get(uint32_t *part, uint32_t *pass)
150 {
151 #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
152 	char dirname[PATH_MAX];
153 	struct dirent *e;
154 	int ret = -1;
155 	DIR *dir;
156 
157 	dir = opendir(SYSFS_PCI_DEVICES);
158 	if (dir == NULL) {
159 		plt_err("%s(): opendir failed: %s", __func__,
160 			strerror(errno));
161 		return -errno;
162 	}
163 
164 	while ((e = readdir(dir)) != NULL) {
165 		if (e->d_name[0] == '.')
166 			continue;
167 
168 		snprintf(dirname, sizeof(dirname), "%s/%s", SYSFS_PCI_DEVICES,
169 			 e->d_name);
170 
171 		/* Lookup for rvu device and get part pass information */
172 		ret = rvu_device_lookup(dirname, part, pass);
173 		if (!ret)
174 			break;
175 	}
176 
177 	closedir(dir);
178 	return ret;
179 }
180 
181 static bool
182 populate_model(struct roc_model *model, uint32_t midr)
183 {
184 	uint32_t impl, major, part, minor, pass = 0;
185 	bool found = false;
186 	size_t i;
187 
188 	impl = (midr >> MODEL_IMPL_SHIFT) & MODEL_IMPL_MASK;
189 	part = (midr >> MODEL_PART_SHIFT) & MODEL_PART_MASK;
190 	major = (midr >> MODEL_MAJOR_SHIFT) & MODEL_MAJOR_MASK;
191 	minor = (midr >> MODEL_MINOR_SHIFT) & MODEL_MINOR_MASK;
192 
193 	/* Update part number from device-tree */
194 	if (part == SOC_PART_CN10K || part == SOC_PART_CN20K) {
195 		if (cn10k_part_pass_get(&part, &pass))
196 			goto not_found;
197 		/*
198 		 * Pass value format:
199 		 * Bits 0..1: minor pass
200 		 * Bits 3..2: major pass
201 		 */
202 		minor = (pass >> MODEL_CN10K_MINOR_SHIFT) &
203 			MODEL_CN10K_MINOR_MASK;
204 		major = (pass >> MODEL_CN10K_MAJOR_SHIFT) &
205 			MODEL_CN10K_MAJOR_MASK;
206 	}
207 
208 	for (i = 0; i < PLT_DIM(model_db); i++)
209 		if (model_db[i].impl == impl && model_db[i].part == part &&
210 		    model_db[i].major == major && model_db[i].minor == minor) {
211 			model->flag = model_db[i].flag;
212 			strncpy(model->name, model_db[i].name,
213 				ROC_MODEL_STR_LEN_MAX - 1);
214 			found = true;
215 			break;
216 		}
217 not_found:
218 	if (!found) {
219 		model->flag = 0;
220 		strncpy(model->name, "unknown", ROC_MODEL_STR_LEN_MAX - 1);
221 		plt_err("Invalid RoC model (impl=0x%x, part=0x%x, major=0x%x, minor=0x%x)",
222 			impl, part, major, minor);
223 	}
224 
225 	return found;
226 }
227 
228 static int
229 midr_get(unsigned long *val)
230 {
231 	const char *file =
232 		"/sys/devices/system/cpu/cpu0/regs/identification/midr_el1";
233 	int rc = UTIL_ERR_FS;
234 	char buf[BUFSIZ];
235 	char *end = NULL;
236 	FILE *f;
237 
238 	if (val == NULL)
239 		goto err;
240 	f = fopen(file, "r");
241 	if (f == NULL)
242 		goto err;
243 
244 	if (fgets(buf, sizeof(buf), f) == NULL)
245 		goto fclose;
246 
247 	*val = strtoul(buf, &end, 0);
248 	if ((buf[0] == '\0') || (end == NULL) || (*end != '\n'))
249 		goto fclose;
250 
251 	rc = 0;
252 fclose:
253 	fclose(f);
254 err:
255 	return rc;
256 }
257 
258 static void
259 detect_invalid_config(void)
260 {
261 #ifdef ROC_PLATFORM_CN9K
262 #ifdef ROC_PLATFORM_CN10K
263 #ifdef ROC_PLATFORM_CN20K
264 	PLT_STATIC_ASSERT(0);
265 #endif
266 #endif
267 #endif
268 }
269 
270 static uint64_t
271 env_lookup_flag(const char *name)
272 {
273 	unsigned int i;
274 	struct {
275 		const char *name;
276 		uint64_t flag;
277 	} envs[] = {
278 		{"HW_PLATFORM", ROC_ENV_HW},
279 		{"EMUL_PLATFORM", ROC_ENV_EMUL},
280 		{"ASIM_PLATFORM", ROC_ENV_ASIM},
281 	};
282 
283 	for (i = 0; i < PLT_DIM(envs); i++)
284 		if (!strncmp(envs[i].name, name, strlen(envs[i].name)))
285 			return envs[i].flag;
286 
287 	return 0;
288 }
289 
290 static void
291 of_env_get(struct roc_model *model)
292 {
293 	const char *const path = "/proc/device-tree/soc@0/runplatform";
294 	uint64_t flag;
295 	FILE *fp;
296 
297 	if (access(path, F_OK) != 0) {
298 		strncpy(model->env, "HW_PLATFORM", ROC_MODEL_STR_LEN_MAX - 1);
299 		model->flag |= ROC_ENV_HW;
300 		return;
301 	}
302 
303 	fp = fopen(path, "r");
304 	if (!fp) {
305 		plt_err("Failed to open %s", path);
306 		return;
307 	}
308 
309 	if (!fgets(model->env, sizeof(model->env), fp)) {
310 		plt_err("Failed to read %s", path);
311 		goto err;
312 	}
313 
314 	flag = env_lookup_flag(model->env);
315 	if (flag == 0) {
316 		plt_err("Unknown platform: %s", model->env);
317 		goto err;
318 	}
319 
320 	model->flag |= flag;
321 err:
322 	fclose(fp);
323 }
324 
325 int
326 roc_model_init(struct roc_model *model)
327 {
328 	int rc = UTIL_ERR_PARAM;
329 	unsigned long midr;
330 
331 	detect_invalid_config();
332 
333 	if (!model)
334 		goto err;
335 
336 	rc = midr_get(&midr);
337 	if (rc)
338 		goto err;
339 
340 	rc = UTIL_ERR_INVALID_MODEL;
341 	if (!populate_model(model, midr))
342 		goto err;
343 
344 	of_env_get(model);
345 
346 	rc = 0;
347 	plt_info("RoC Model: %s (%s)", model->name, model->env);
348 	roc_model = model;
349 err:
350 	return rc;
351 }
352