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