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