1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/err.h> 6 #include <linux/ethtool.h> 7 #include <linux/sfp.h> 8 #include <linux/mutex.h> 9 10 #include "core.h" 11 #include "core_env.h" 12 #include "item.h" 13 #include "reg.h" 14 15 struct mlxsw_env_module_info { 16 u64 module_overheat_counter; 17 bool is_overheat; 18 int num_ports_mapped; 19 int num_ports_up; 20 enum ethtool_module_power_mode_policy power_mode_policy; 21 enum mlxsw_reg_pmtm_module_type type; 22 }; 23 24 struct mlxsw_env_line_card { 25 u8 module_count; 26 bool active; 27 struct mlxsw_env_module_info module_info[]; 28 }; 29 30 struct mlxsw_env { 31 struct mlxsw_core *core; 32 const struct mlxsw_bus_info *bus_info; 33 u8 max_module_count; /* Maximum number of modules per-slot. */ 34 u8 num_of_slots; /* Including the main board. */ 35 u8 max_eeprom_len; /* Maximum module EEPROM transaction length. */ 36 struct mutex line_cards_lock; /* Protects line cards. */ 37 struct mlxsw_env_line_card *line_cards[] __counted_by(num_of_slots); 38 }; 39 40 static bool __mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env, 41 u8 slot_index) 42 { 43 return mlxsw_env->line_cards[slot_index]->active; 44 } 45 46 static bool mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env, 47 u8 slot_index) 48 { 49 bool active; 50 51 mutex_lock(&mlxsw_env->line_cards_lock); 52 active = __mlxsw_env_linecard_is_active(mlxsw_env, slot_index); 53 mutex_unlock(&mlxsw_env->line_cards_lock); 54 55 return active; 56 } 57 58 static struct 59 mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core, 60 u8 slot_index, u8 module) 61 { 62 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 63 64 return &mlxsw_env->line_cards[slot_index]->module_info[module]; 65 } 66 67 static int __mlxsw_env_validate_module_type(struct mlxsw_core *core, 68 u8 slot_index, u8 module) 69 { 70 struct mlxsw_env *mlxsw_env = mlxsw_core_env(core); 71 struct mlxsw_env_module_info *module_info; 72 int err; 73 74 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) 75 return 0; 76 77 module_info = mlxsw_env_module_info_get(core, slot_index, module); 78 switch (module_info->type) { 79 case MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR: 80 err = -EINVAL; 81 break; 82 default: 83 err = 0; 84 } 85 86 return err; 87 } 88 89 static int mlxsw_env_validate_module_type(struct mlxsw_core *core, 90 u8 slot_index, u8 module) 91 { 92 struct mlxsw_env *mlxsw_env = mlxsw_core_env(core); 93 int err; 94 95 mutex_lock(&mlxsw_env->line_cards_lock); 96 err = __mlxsw_env_validate_module_type(core, slot_index, module); 97 mutex_unlock(&mlxsw_env->line_cards_lock); 98 99 return err; 100 } 101 102 static int 103 mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, 104 bool *qsfp, bool *cmis) 105 { 106 char mcia_pl[MLXSW_REG_MCIA_LEN]; 107 char *eeprom_tmp; 108 u8 ident; 109 int err; 110 111 err = mlxsw_env_validate_module_type(core, slot_index, id); 112 if (err) 113 return err; 114 115 mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 116 MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, 117 MLXSW_REG_MCIA_I2C_ADDR_LOW); 118 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); 119 if (err) 120 return err; 121 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 122 ident = eeprom_tmp[0]; 123 *cmis = false; 124 switch (ident) { 125 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: 126 *qsfp = false; 127 break; 128 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: 129 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: 130 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: 131 *qsfp = true; 132 break; 133 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: 134 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP: 135 *qsfp = true; 136 *cmis = true; 137 break; 138 default: 139 return -EINVAL; 140 } 141 142 return 0; 143 } 144 145 static int 146 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, 147 int module, u16 offset, u16 size, void *data, 148 bool qsfp, unsigned int *p_read_size) 149 { 150 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 151 char mcia_pl[MLXSW_REG_MCIA_LEN]; 152 char *eeprom_tmp; 153 u16 i2c_addr; 154 u8 page = 0; 155 int status; 156 int err; 157 158 size = min_t(u16, size, mlxsw_env->max_eeprom_len); 159 160 if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && 161 offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) 162 /* Cross pages read, read until offset 256 in low page */ 163 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; 164 165 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; 166 if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { 167 if (qsfp) { 168 /* When reading upper pages 1, 2 and 3 the offset 169 * starts at 128. Please refer to "QSFP+ Memory Map" 170 * figure in SFF-8436 specification and to "CMIS Module 171 * Memory Map" figure in CMIS specification for 172 * graphical depiction. 173 */ 174 page = MLXSW_REG_MCIA_PAGE_GET(offset); 175 offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; 176 if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) 177 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; 178 } else { 179 /* When reading upper pages 1, 2 and 3 the offset 180 * starts at 0 and I2C high address is used. Please refer 181 * to "Memory Organization" figure in SFF-8472 182 * specification for graphical depiction. 183 */ 184 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; 185 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; 186 } 187 } 188 189 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, offset, size, 190 i2c_addr); 191 192 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); 193 if (err) 194 return err; 195 196 status = mlxsw_reg_mcia_status_get(mcia_pl); 197 if (status) 198 return -EIO; 199 200 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 201 memcpy(data, eeprom_tmp, size); 202 *p_read_size = size; 203 204 return 0; 205 } 206 207 int 208 mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index, 209 int module, int off, int *temp) 210 { 211 unsigned int module_temp, module_crit, module_emerg; 212 union { 213 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE]; 214 u16 temp; 215 } temp_thresh; 216 char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; 217 char mtmp_pl[MLXSW_REG_MTMP_LEN]; 218 char *eeprom_tmp; 219 bool qsfp, cmis; 220 int page; 221 int err; 222 223 mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, 224 MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, 225 false); 226 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); 227 if (err) 228 return err; 229 mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit, 230 &module_emerg, NULL); 231 if (!module_temp) { 232 *temp = 0; 233 return 0; 234 } 235 236 /* Validate if threshold reading is available through MTMP register, 237 * otherwise fallback to read through MCIA. 238 */ 239 if (module_emerg) { 240 *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg; 241 return 0; 242 } 243 244 /* Read Free Side Device Temperature Thresholds from page 03h 245 * (MSB at lower byte address). 246 * Bytes: 247 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM); 248 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM); 249 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN); 250 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN); 251 */ 252 253 /* Validate module identifier value. */ 254 err = mlxsw_env_validate_cable_ident(core, slot_index, module, &qsfp, 255 &cmis); 256 if (err) 257 return err; 258 259 if (qsfp) { 260 /* For QSFP/CMIS module-defined thresholds are located in page 261 * 02h, otherwise in page 03h. 262 */ 263 if (cmis) 264 page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; 265 else 266 page = MLXSW_REG_MCIA_TH_PAGE_NUM; 267 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, 268 MLXSW_REG_MCIA_TH_PAGE_OFF + off, 269 MLXSW_REG_MCIA_TH_ITEM_SIZE, 270 MLXSW_REG_MCIA_I2C_ADDR_LOW); 271 } else { 272 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 273 MLXSW_REG_MCIA_PAGE0_LO, 274 off, MLXSW_REG_MCIA_TH_ITEM_SIZE, 275 MLXSW_REG_MCIA_I2C_ADDR_HIGH); 276 } 277 278 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); 279 if (err) 280 return err; 281 282 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 283 memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE); 284 *temp = temp_thresh.temp * 1000; 285 286 return 0; 287 } 288 289 int mlxsw_env_get_module_info(struct net_device *netdev, 290 struct mlxsw_core *mlxsw_core, u8 slot_index, 291 int module, struct ethtool_modinfo *modinfo) 292 { 293 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 294 u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; 295 u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; 296 u8 module_rev_id, module_id, diag_mon; 297 unsigned int read_size; 298 int err; 299 300 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) { 301 netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n"); 302 return -EIO; 303 } 304 305 err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); 306 if (err) { 307 netdev_err(netdev, 308 "EEPROM is not equipped on port module type"); 309 return err; 310 } 311 312 err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, module, 0, 313 offset, module_info, false, 314 &read_size); 315 if (err) 316 return err; 317 318 if (read_size < offset) 319 return -EIO; 320 321 module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID]; 322 module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID]; 323 324 switch (module_id) { 325 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: 326 modinfo->type = ETH_MODULE_SFF_8436; 327 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 328 break; 329 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: 330 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: 331 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 || 332 module_rev_id >= 333 MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { 334 modinfo->type = ETH_MODULE_SFF_8636; 335 modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 336 } else { 337 modinfo->type = ETH_MODULE_SFF_8436; 338 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 339 } 340 break; 341 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: 342 /* Verify if transceiver provides diagnostic monitoring page */ 343 err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, 344 module, SFP_DIAGMON, 1, 345 &diag_mon, false, 346 &read_size); 347 if (err) 348 return err; 349 350 if (read_size < 1) 351 return -EIO; 352 353 modinfo->type = ETH_MODULE_SFF_8472; 354 if (diag_mon) 355 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 356 else 357 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; 358 break; 359 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: 360 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP: 361 /* Use SFF_8636 as base type. ethtool should recognize specific 362 * type through the identifier value. 363 */ 364 modinfo->type = ETH_MODULE_SFF_8636; 365 /* Verify if module EEPROM is a flat memory. In case of flat 366 * memory only page 00h (0-255 bytes) can be read. Otherwise 367 * upper pages 01h and 02h can also be read. Upper pages 10h 368 * and 11h are currently not supported by the driver. 369 */ 370 if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] & 371 MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY) 372 modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 373 else 374 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 375 break; 376 default: 377 return -EINVAL; 378 } 379 380 return 0; 381 } 382 EXPORT_SYMBOL(mlxsw_env_get_module_info); 383 384 int mlxsw_env_get_module_eeprom(struct net_device *netdev, 385 struct mlxsw_core *mlxsw_core, u8 slot_index, 386 int module, struct ethtool_eeprom *ee, 387 u8 *data) 388 { 389 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 390 int offset = ee->offset; 391 unsigned int read_size; 392 bool qsfp, cmis; 393 int i = 0; 394 int err; 395 396 if (!ee->len) 397 return -EINVAL; 398 399 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) { 400 netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n"); 401 return -EIO; 402 } 403 404 memset(data, 0, ee->len); 405 /* Validate module identifier value. */ 406 err = mlxsw_env_validate_cable_ident(mlxsw_core, slot_index, module, 407 &qsfp, &cmis); 408 if (err) 409 return err; 410 411 while (i < ee->len) { 412 err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, 413 module, offset, 414 ee->len - i, data + i, 415 qsfp, &read_size); 416 if (err) { 417 netdev_err(netdev, "Eeprom query failed\n"); 418 return err; 419 } 420 421 i += read_size; 422 offset += read_size; 423 } 424 425 return 0; 426 } 427 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom); 428 429 static int mlxsw_env_mcia_status_process(const char *mcia_pl, 430 struct netlink_ext_ack *extack) 431 { 432 u8 status = mlxsw_reg_mcia_status_get(mcia_pl); 433 434 switch (status) { 435 case MLXSW_REG_MCIA_STATUS_GOOD: 436 return 0; 437 case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE: 438 NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM"); 439 return -EIO; 440 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED: 441 NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device"); 442 return -EOPNOTSUPP; 443 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED: 444 NL_SET_ERR_MSG_MOD(extack, "No module present indication"); 445 return -EIO; 446 case MLXSW_REG_MCIA_STATUS_I2C_ERROR: 447 NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C"); 448 return -EIO; 449 case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED: 450 NL_SET_ERR_MSG_MOD(extack, "Module is disabled"); 451 return -EIO; 452 default: 453 NL_SET_ERR_MSG_MOD(extack, "Unknown error"); 454 return -EIO; 455 } 456 } 457 458 int 459 mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, 460 u8 slot_index, u8 module, 461 const struct ethtool_module_eeprom *page, 462 struct netlink_ext_ack *extack) 463 { 464 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 465 u32 bytes_read = 0; 466 u16 device_addr; 467 int err; 468 469 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) { 470 NL_SET_ERR_MSG_MOD(extack, 471 "Cannot read EEPROM of module on an inactive line card"); 472 return -EIO; 473 } 474 475 err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); 476 if (err) { 477 NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type"); 478 return err; 479 } 480 481 /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */ 482 device_addr = page->offset; 483 484 while (bytes_read < page->length) { 485 char mcia_pl[MLXSW_REG_MCIA_LEN]; 486 char *eeprom_tmp; 487 u8 size; 488 489 size = min_t(u8, page->length - bytes_read, 490 mlxsw_env->max_eeprom_len); 491 492 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page, 493 device_addr + bytes_read, size, 494 page->i2c_address); 495 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); 496 497 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); 498 if (err) { 499 NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM"); 500 return err; 501 } 502 503 err = mlxsw_env_mcia_status_process(mcia_pl, extack); 504 if (err) 505 return err; 506 507 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 508 memcpy(page->data + bytes_read, eeprom_tmp, size); 509 bytes_read += size; 510 } 511 512 return bytes_read; 513 } 514 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); 515 516 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index, 517 u8 module) 518 { 519 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 520 521 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); 522 mlxsw_reg_pmaos_rst_set(pmaos_pl, true); 523 524 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 525 } 526 527 int mlxsw_env_reset_module(struct net_device *netdev, 528 struct mlxsw_core *mlxsw_core, u8 slot_index, 529 u8 module, u32 *flags) 530 { 531 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 532 struct mlxsw_env_module_info *module_info; 533 u32 req = *flags; 534 int err; 535 536 if (!(req & ETH_RESET_PHY) && 537 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) 538 return 0; 539 540 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) { 541 netdev_err(netdev, "Cannot reset module on an inactive line card\n"); 542 return -EIO; 543 } 544 545 mutex_lock(&mlxsw_env->line_cards_lock); 546 547 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); 548 if (err) { 549 netdev_err(netdev, "Reset module is not supported on port module type\n"); 550 goto out; 551 } 552 553 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 554 if (module_info->num_ports_up) { 555 netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n"); 556 err = -EINVAL; 557 goto out; 558 } 559 560 if (module_info->num_ports_mapped > 1 && 561 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) { 562 netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n"); 563 err = -EINVAL; 564 goto out; 565 } 566 567 err = mlxsw_env_module_reset(mlxsw_core, slot_index, module); 568 if (err) { 569 netdev_err(netdev, "Failed to reset module\n"); 570 goto out; 571 } 572 573 *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)); 574 575 out: 576 mutex_unlock(&mlxsw_env->line_cards_lock); 577 return err; 578 } 579 EXPORT_SYMBOL(mlxsw_env_reset_module); 580 581 int 582 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, 583 u8 module, 584 struct ethtool_module_power_mode_params *params, 585 struct netlink_ext_ack *extack) 586 { 587 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 588 struct mlxsw_env_module_info *module_info; 589 char mcion_pl[MLXSW_REG_MCION_LEN]; 590 u32 status_bits; 591 int err = 0; 592 593 mutex_lock(&mlxsw_env->line_cards_lock); 594 595 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); 596 if (err) { 597 NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type"); 598 goto out; 599 } 600 601 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 602 params->policy = module_info->power_mode_policy; 603 604 /* Avoid accessing an inactive line card, as it will result in an error. */ 605 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) 606 goto out; 607 608 mlxsw_reg_mcion_pack(mcion_pl, slot_index, module); 609 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); 610 if (err) { 611 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); 612 goto out; 613 } 614 615 status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl); 616 if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK)) 617 goto out; 618 619 if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK) 620 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW; 621 else 622 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH; 623 624 out: 625 mutex_unlock(&mlxsw_env->line_cards_lock); 626 return err; 627 } 628 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); 629 630 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, 631 u8 slot_index, u8 module, bool enable) 632 { 633 enum mlxsw_reg_pmaos_admin_status admin_status; 634 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 635 636 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); 637 admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : 638 MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; 639 mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); 640 mlxsw_reg_pmaos_ase_set(pmaos_pl, true); 641 642 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 643 } 644 645 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, 646 u8 slot_index, u8 module, 647 bool low_power) 648 { 649 u16 eeprom_override_mask, eeprom_override; 650 char pmmp_pl[MLXSW_REG_PMMP_LEN]; 651 652 mlxsw_reg_pmmp_pack(pmmp_pl, slot_index, module); 653 mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); 654 /* Mask all the bits except low power mode. */ 655 eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; 656 mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask); 657 eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK : 658 0; 659 mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override); 660 661 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl); 662 } 663 664 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, 665 u8 slot_index, u8 module, 666 bool low_power, 667 struct netlink_ext_ack *extack) 668 { 669 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 670 int err; 671 672 /* Avoid accessing an inactive line card, as it will result in an error. 673 * Cached configuration will be applied by mlxsw_env_got_active() when 674 * line card becomes active. 675 */ 676 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) 677 return 0; 678 679 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false); 680 if (err) { 681 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module"); 682 return err; 683 } 684 685 err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, 686 low_power); 687 if (err) { 688 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode"); 689 goto err_module_low_power_set; 690 } 691 692 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); 693 if (err) { 694 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module"); 695 goto err_module_enable_set; 696 } 697 698 return 0; 699 700 err_module_enable_set: 701 mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, 702 !low_power); 703 err_module_low_power_set: 704 mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); 705 return err; 706 } 707 708 static int 709 mlxsw_env_set_module_power_mode_apply(struct mlxsw_core *mlxsw_core, 710 u8 slot_index, u8 module, 711 enum ethtool_module_power_mode_policy policy, 712 struct netlink_ext_ack *extack) 713 { 714 struct mlxsw_env_module_info *module_info; 715 bool low_power; 716 int err = 0; 717 718 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); 719 if (err) { 720 NL_SET_ERR_MSG_MOD(extack, 721 "Power mode set is not supported on port module type"); 722 goto out; 723 } 724 725 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 726 if (module_info->power_mode_policy == policy) 727 goto out; 728 729 /* If any ports are up, we are already in high power mode. */ 730 if (module_info->num_ports_up) 731 goto out_set_policy; 732 733 low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; 734 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, 735 low_power, extack); 736 if (err) 737 goto out; 738 739 out_set_policy: 740 module_info->power_mode_policy = policy; 741 out: 742 return err; 743 } 744 745 int 746 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, 747 u8 module, 748 enum ethtool_module_power_mode_policy policy, 749 struct netlink_ext_ack *extack) 750 { 751 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 752 int err; 753 754 if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH && 755 policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) { 756 NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy"); 757 return -EOPNOTSUPP; 758 } 759 760 mutex_lock(&mlxsw_env->line_cards_lock); 761 err = mlxsw_env_set_module_power_mode_apply(mlxsw_core, slot_index, 762 module, policy, extack); 763 mutex_unlock(&mlxsw_env->line_cards_lock); 764 765 return err; 766 } 767 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); 768 769 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, 770 u8 slot_index, u8 module, 771 bool *p_has_temp_sensor) 772 { 773 char mtbr_pl[MLXSW_REG_MTBR_LEN]; 774 u16 temp; 775 int err; 776 777 mlxsw_reg_mtbr_pack(mtbr_pl, slot_index, 778 MLXSW_REG_MTBR_BASE_MODULE_INDEX + module); 779 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); 780 if (err) 781 return err; 782 783 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); 784 785 switch (temp) { 786 case MLXSW_REG_MTBR_BAD_SENS_INFO: 787 case MLXSW_REG_MTBR_NO_CONN: 788 case MLXSW_REG_MTBR_NO_TEMP_SENS: 789 case MLXSW_REG_MTBR_INDEX_NA: 790 *p_has_temp_sensor = false; 791 break; 792 default: 793 *p_has_temp_sensor = temp ? true : false; 794 } 795 return 0; 796 } 797 798 static int 799 mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index, 800 u16 sensor_index, bool enable) 801 { 802 char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; 803 enum mlxsw_reg_mtmp_tee tee; 804 int err, threshold_hi; 805 806 mlxsw_reg_mtmp_slot_index_set(mtmp_pl, slot_index); 807 mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index); 808 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); 809 if (err) 810 return err; 811 812 if (enable) { 813 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core, 814 slot_index, 815 sensor_index - 816 MLXSW_REG_MTMP_MODULE_INDEX_MIN, 817 SFP_TEMP_HIGH_WARN, 818 &threshold_hi); 819 /* In case it is not possible to query the module's threshold, 820 * use the default value. 821 */ 822 if (err) 823 threshold_hi = MLXSW_REG_MTMP_THRESH_HI; 824 else 825 /* mlxsw_env_module_temp_thresholds_get() multiplies 826 * Celsius degrees by 1000 whereas MTMP expects 827 * temperature in 0.125 Celsius degrees units. 828 * Convert threshold_hi to correct units. 829 */ 830 threshold_hi = threshold_hi / 1000 * 8; 831 832 mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi); 833 mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi - 834 MLXSW_REG_MTMP_HYSTERESIS_TEMP); 835 } 836 tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT; 837 mlxsw_reg_mtmp_tee_set(mtmp_pl, tee); 838 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); 839 } 840 841 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, 842 u8 slot_index) 843 { 844 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 845 int i, err, sensor_index; 846 bool has_temp_sensor; 847 848 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) { 849 err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index, 850 i, &has_temp_sensor); 851 if (err) 852 return err; 853 854 if (!has_temp_sensor) 855 continue; 856 857 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN; 858 err = mlxsw_env_temp_event_set(mlxsw_core, slot_index, 859 sensor_index, true); 860 if (err) 861 return err; 862 } 863 864 return 0; 865 } 866 867 struct mlxsw_env_module_temp_warn_event { 868 struct mlxsw_env *mlxsw_env; 869 char mtwe_pl[MLXSW_REG_MTWE_LEN]; 870 struct work_struct work; 871 }; 872 873 static void mlxsw_env_mtwe_event_work(struct work_struct *work) 874 { 875 struct mlxsw_env_module_temp_warn_event *event; 876 struct mlxsw_env_module_info *module_info; 877 struct mlxsw_env *mlxsw_env; 878 int i, sensor_warning; 879 bool is_overheat; 880 881 event = container_of(work, struct mlxsw_env_module_temp_warn_event, 882 work); 883 mlxsw_env = event->mlxsw_env; 884 885 for (i = 0; i < mlxsw_env->max_module_count; i++) { 886 /* 64-127 of sensor_index are mapped to the port modules 887 * sequentially (module 0 is mapped to sensor_index 64, 888 * module 1 to sensor_index 65 and so on) 889 */ 890 sensor_warning = 891 mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl, 892 i + MLXSW_REG_MTMP_MODULE_INDEX_MIN); 893 mutex_lock(&mlxsw_env->line_cards_lock); 894 /* MTWE only supports main board. */ 895 module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i); 896 is_overheat = module_info->is_overheat; 897 898 if ((is_overheat && sensor_warning) || 899 (!is_overheat && !sensor_warning)) { 900 /* Current state is "warning" and MTWE still reports 901 * warning OR current state in "no warning" and MTWE 902 * does not report warning. 903 */ 904 mutex_unlock(&mlxsw_env->line_cards_lock); 905 continue; 906 } else if (is_overheat && !sensor_warning) { 907 /* MTWE reports "no warning", turn is_overheat off. 908 */ 909 module_info->is_overheat = false; 910 mutex_unlock(&mlxsw_env->line_cards_lock); 911 } else { 912 /* Current state is "no warning" and MTWE reports 913 * "warning", increase the counter and turn is_overheat 914 * on. 915 */ 916 module_info->is_overheat = true; 917 module_info->module_overheat_counter++; 918 mutex_unlock(&mlxsw_env->line_cards_lock); 919 } 920 } 921 922 kfree(event); 923 } 924 925 static void 926 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl, 927 void *priv) 928 { 929 struct mlxsw_env_module_temp_warn_event *event; 930 struct mlxsw_env *mlxsw_env = priv; 931 932 event = kmalloc(sizeof(*event), GFP_ATOMIC); 933 if (!event) 934 return; 935 936 event->mlxsw_env = mlxsw_env; 937 memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN); 938 INIT_WORK(&event->work, mlxsw_env_mtwe_event_work); 939 mlxsw_core_schedule_work(&event->work); 940 } 941 942 static const struct mlxsw_listener mlxsw_env_temp_warn_listener = 943 MLXSW_CORE_EVENTL(mlxsw_env_mtwe_listener_func, MTWE); 944 945 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core) 946 { 947 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 948 949 return mlxsw_core_trap_register(mlxsw_core, 950 &mlxsw_env_temp_warn_listener, 951 mlxsw_env); 952 } 953 954 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env) 955 { 956 mlxsw_core_trap_unregister(mlxsw_env->core, 957 &mlxsw_env_temp_warn_listener, mlxsw_env); 958 } 959 960 struct mlxsw_env_module_plug_unplug_event { 961 struct mlxsw_env *mlxsw_env; 962 u8 slot_index; 963 u8 module; 964 struct work_struct work; 965 }; 966 967 static void mlxsw_env_pmpe_event_work(struct work_struct *work) 968 { 969 struct mlxsw_env_module_plug_unplug_event *event; 970 struct mlxsw_env_module_info *module_info; 971 struct mlxsw_env *mlxsw_env; 972 bool has_temp_sensor; 973 u16 sensor_index; 974 int err; 975 976 event = container_of(work, struct mlxsw_env_module_plug_unplug_event, 977 work); 978 mlxsw_env = event->mlxsw_env; 979 980 mutex_lock(&mlxsw_env->line_cards_lock); 981 module_info = mlxsw_env_module_info_get(mlxsw_env->core, 982 event->slot_index, 983 event->module); 984 module_info->is_overheat = false; 985 mutex_unlock(&mlxsw_env->line_cards_lock); 986 987 err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, 988 event->slot_index, 989 event->module, 990 &has_temp_sensor); 991 /* Do not disable events on modules without sensors or faulty sensors 992 * because FW returns errors. 993 */ 994 if (err) 995 goto out; 996 997 if (!has_temp_sensor) 998 goto out; 999 1000 sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN; 1001 mlxsw_env_temp_event_set(mlxsw_env->core, event->slot_index, 1002 sensor_index, true); 1003 1004 out: 1005 kfree(event); 1006 } 1007 1008 static void 1009 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, 1010 void *priv) 1011 { 1012 u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl); 1013 struct mlxsw_env_module_plug_unplug_event *event; 1014 enum mlxsw_reg_pmpe_module_status module_status; 1015 u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); 1016 struct mlxsw_env *mlxsw_env = priv; 1017 1018 if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count || 1019 slot_index >= mlxsw_env->num_of_slots)) 1020 return; 1021 1022 module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); 1023 if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED) 1024 return; 1025 1026 event = kmalloc(sizeof(*event), GFP_ATOMIC); 1027 if (!event) 1028 return; 1029 1030 event->mlxsw_env = mlxsw_env; 1031 event->slot_index = slot_index; 1032 event->module = module; 1033 INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); 1034 mlxsw_core_schedule_work(&event->work); 1035 } 1036 1037 static const struct mlxsw_listener mlxsw_env_module_plug_listener = 1038 MLXSW_CORE_EVENTL(mlxsw_env_pmpe_listener_func, PMPE); 1039 1040 static int 1041 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core) 1042 { 1043 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1044 1045 return mlxsw_core_trap_register(mlxsw_core, 1046 &mlxsw_env_module_plug_listener, 1047 mlxsw_env); 1048 } 1049 1050 static void 1051 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env) 1052 { 1053 mlxsw_core_trap_unregister(mlxsw_env->core, 1054 &mlxsw_env_module_plug_listener, 1055 mlxsw_env); 1056 } 1057 1058 static int 1059 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, 1060 u8 slot_index) 1061 { 1062 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1063 int i, err; 1064 1065 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) { 1066 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 1067 1068 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i); 1069 mlxsw_reg_pmaos_e_set(pmaos_pl, 1070 MLXSW_REG_PMAOS_E_GENERATE_EVENT); 1071 mlxsw_reg_pmaos_ee_set(pmaos_pl, true); 1072 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 1073 if (err) 1074 return err; 1075 } 1076 return 0; 1077 } 1078 1079 int 1080 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index, 1081 u8 module, u64 *p_counter) 1082 { 1083 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1084 struct mlxsw_env_module_info *module_info; 1085 1086 mutex_lock(&mlxsw_env->line_cards_lock); 1087 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 1088 *p_counter = module_info->module_overheat_counter; 1089 mutex_unlock(&mlxsw_env->line_cards_lock); 1090 1091 return 0; 1092 } 1093 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get); 1094 1095 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, 1096 u8 module) 1097 { 1098 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1099 struct mlxsw_env_module_info *module_info; 1100 1101 mutex_lock(&mlxsw_env->line_cards_lock); 1102 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 1103 module_info->num_ports_mapped++; 1104 mutex_unlock(&mlxsw_env->line_cards_lock); 1105 } 1106 EXPORT_SYMBOL(mlxsw_env_module_port_map); 1107 1108 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, 1109 u8 module) 1110 { 1111 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1112 struct mlxsw_env_module_info *module_info; 1113 1114 mutex_lock(&mlxsw_env->line_cards_lock); 1115 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 1116 module_info->num_ports_mapped--; 1117 mutex_unlock(&mlxsw_env->line_cards_lock); 1118 } 1119 EXPORT_SYMBOL(mlxsw_env_module_port_unmap); 1120 1121 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, 1122 u8 module) 1123 { 1124 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1125 struct mlxsw_env_module_info *module_info; 1126 int err = 0; 1127 1128 mutex_lock(&mlxsw_env->line_cards_lock); 1129 1130 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 1131 if (module_info->power_mode_policy != 1132 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) 1133 goto out_inc; 1134 1135 if (module_info->num_ports_up != 0) 1136 goto out_inc; 1137 1138 /* Transition to high power mode following first port using the module 1139 * being put administratively up. 1140 */ 1141 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, 1142 false, NULL); 1143 if (err) 1144 goto out_unlock; 1145 1146 out_inc: 1147 module_info->num_ports_up++; 1148 out_unlock: 1149 mutex_unlock(&mlxsw_env->line_cards_lock); 1150 return err; 1151 } 1152 EXPORT_SYMBOL(mlxsw_env_module_port_up); 1153 1154 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, 1155 u8 module) 1156 { 1157 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1158 struct mlxsw_env_module_info *module_info; 1159 1160 mutex_lock(&mlxsw_env->line_cards_lock); 1161 1162 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); 1163 module_info->num_ports_up--; 1164 1165 if (module_info->power_mode_policy != 1166 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) 1167 goto out_unlock; 1168 1169 if (module_info->num_ports_up != 0) 1170 goto out_unlock; 1171 1172 /* Transition to low power mode following last port using the module 1173 * being put administratively down. 1174 */ 1175 __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true, 1176 NULL); 1177 1178 out_unlock: 1179 mutex_unlock(&mlxsw_env->line_cards_lock); 1180 } 1181 EXPORT_SYMBOL(mlxsw_env_module_port_down); 1182 1183 static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env) 1184 { 1185 struct mlxsw_env_module_info *module_info; 1186 int i, j; 1187 1188 for (i = 0; i < env->num_of_slots; i++) { 1189 env->line_cards[i] = kzalloc(struct_size(env->line_cards[i], 1190 module_info, 1191 env->max_module_count), 1192 GFP_KERNEL); 1193 if (!env->line_cards[i]) 1194 goto kzalloc_err; 1195 1196 /* Firmware defaults to high power mode policy where modules 1197 * are transitioned to high power mode following plug-in. 1198 */ 1199 for (j = 0; j < env->max_module_count; j++) { 1200 module_info = &env->line_cards[i]->module_info[j]; 1201 module_info->power_mode_policy = 1202 ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; 1203 } 1204 } 1205 1206 return 0; 1207 1208 kzalloc_err: 1209 for (i--; i >= 0; i--) 1210 kfree(env->line_cards[i]); 1211 return -ENOMEM; 1212 } 1213 1214 static void mlxsw_env_line_cards_free(struct mlxsw_env *env) 1215 { 1216 int i = env->num_of_slots; 1217 1218 for (i--; i >= 0; i--) 1219 kfree(env->line_cards[i]); 1220 } 1221 1222 static int 1223 mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index) 1224 { 1225 int err; 1226 1227 err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core, 1228 slot_index); 1229 if (err) 1230 return err; 1231 1232 err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index); 1233 if (err) 1234 return err; 1235 1236 return 0; 1237 } 1238 1239 static void 1240 mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index) 1241 { 1242 } 1243 1244 static int 1245 mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index) 1246 { 1247 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 1248 int i; 1249 1250 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) { 1251 struct mlxsw_env_module_info *module_info; 1252 char pmtm_pl[MLXSW_REG_PMTM_LEN]; 1253 int err; 1254 1255 mlxsw_reg_pmtm_pack(pmtm_pl, slot_index, i); 1256 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl); 1257 if (err) 1258 return err; 1259 1260 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, 1261 i); 1262 module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl); 1263 } 1264 1265 return 0; 1266 } 1267 1268 static void 1269 mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core *mlxsw_core, 1270 struct mlxsw_env *env, 1271 u8 slot_index) 1272 { 1273 int i; 1274 1275 for (i = 0; i < env->line_cards[slot_index]->module_count; i++) { 1276 enum ethtool_module_power_mode_policy policy; 1277 struct mlxsw_env_module_info *module_info; 1278 struct netlink_ext_ack extack; 1279 int err; 1280 1281 module_info = &env->line_cards[slot_index]->module_info[i]; 1282 policy = module_info->power_mode_policy; 1283 err = mlxsw_env_set_module_power_mode_apply(mlxsw_core, 1284 slot_index, i, 1285 policy, &extack); 1286 if (err) 1287 dev_err(env->bus_info->dev, "%s\n", extack._msg); 1288 } 1289 } 1290 1291 static void 1292 mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv) 1293 { 1294 struct mlxsw_env *mlxsw_env = priv; 1295 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 1296 int err; 1297 1298 mutex_lock(&mlxsw_env->line_cards_lock); 1299 if (__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) 1300 goto out_unlock; 1301 1302 mlxsw_reg_mgpir_pack(mgpir_pl, slot_index); 1303 err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl); 1304 if (err) 1305 goto out_unlock; 1306 1307 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, 1308 &mlxsw_env->line_cards[slot_index]->module_count, 1309 NULL); 1310 1311 err = mlxsw_env_module_event_enable(mlxsw_env, slot_index); 1312 if (err) { 1313 dev_err(mlxsw_env->bus_info->dev, "Failed to enable port module events for line card in slot %d\n", 1314 slot_index); 1315 goto err_mlxsw_env_module_event_enable; 1316 } 1317 err = mlxsw_env_module_type_set(mlxsw_env->core, slot_index); 1318 if (err) { 1319 dev_err(mlxsw_env->bus_info->dev, "Failed to set modules' type for line card in slot %d\n", 1320 slot_index); 1321 goto err_type_set; 1322 } 1323 1324 mlxsw_env->line_cards[slot_index]->active = true; 1325 /* Apply power mode policy. */ 1326 mlxsw_env_linecard_modules_power_mode_apply(mlxsw_core, mlxsw_env, 1327 slot_index); 1328 mutex_unlock(&mlxsw_env->line_cards_lock); 1329 1330 return; 1331 1332 err_type_set: 1333 mlxsw_env_module_event_disable(mlxsw_env, slot_index); 1334 err_mlxsw_env_module_event_enable: 1335 out_unlock: 1336 mutex_unlock(&mlxsw_env->line_cards_lock); 1337 } 1338 1339 static void 1340 mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, 1341 void *priv) 1342 { 1343 struct mlxsw_env *mlxsw_env = priv; 1344 1345 mutex_lock(&mlxsw_env->line_cards_lock); 1346 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) 1347 goto out_unlock; 1348 mlxsw_env->line_cards[slot_index]->active = false; 1349 mlxsw_env_module_event_disable(mlxsw_env, slot_index); 1350 mlxsw_env->line_cards[slot_index]->module_count = 0; 1351 out_unlock: 1352 mutex_unlock(&mlxsw_env->line_cards_lock); 1353 } 1354 1355 static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = { 1356 .got_active = mlxsw_env_got_active, 1357 .got_inactive = mlxsw_env_got_inactive, 1358 }; 1359 1360 static int mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env) 1361 { 1362 char mcam_pl[MLXSW_REG_MCAM_LEN]; 1363 bool mcia_128b_supported; 1364 int err; 1365 1366 mlxsw_reg_mcam_pack(mcam_pl, 1367 MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES); 1368 err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mcam), mcam_pl); 1369 if (err) 1370 return err; 1371 1372 mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B, 1373 &mcia_128b_supported); 1374 1375 mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48; 1376 1377 return 0; 1378 } 1379 1380 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, 1381 const struct mlxsw_bus_info *bus_info, 1382 struct mlxsw_env **p_env) 1383 { 1384 u8 module_count, num_of_slots, max_module_count; 1385 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 1386 struct mlxsw_env *env; 1387 int err; 1388 1389 mlxsw_reg_mgpir_pack(mgpir_pl, 0); 1390 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); 1391 if (err) 1392 return err; 1393 1394 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, 1395 &num_of_slots); 1396 /* If the system is modular, get the maximum number of modules per-slot. 1397 * Otherwise, get the maximum number of modules on the main board. 1398 */ 1399 max_module_count = num_of_slots ? 1400 mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) : 1401 module_count; 1402 1403 env = kzalloc(struct_size(env, line_cards, num_of_slots + 1), 1404 GFP_KERNEL); 1405 if (!env) 1406 return -ENOMEM; 1407 1408 env->core = mlxsw_core; 1409 env->bus_info = bus_info; 1410 env->num_of_slots = num_of_slots + 1; 1411 env->max_module_count = max_module_count; 1412 err = mlxsw_env_line_cards_alloc(env); 1413 if (err) 1414 goto err_mlxsw_env_line_cards_alloc; 1415 1416 mutex_init(&env->line_cards_lock); 1417 *p_env = env; 1418 1419 err = mlxsw_linecards_event_ops_register(env->core, 1420 &mlxsw_env_event_ops, env); 1421 if (err) 1422 goto err_linecards_event_ops_register; 1423 1424 err = mlxsw_env_temp_warn_event_register(mlxsw_core); 1425 if (err) 1426 goto err_temp_warn_event_register; 1427 1428 err = mlxsw_env_module_plug_event_register(mlxsw_core); 1429 if (err) 1430 goto err_module_plug_event_register; 1431 1432 /* Set 'module_count' only for main board. Actual count for line card 1433 * is to be set after line card is activated. 1434 */ 1435 env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; 1436 /* Enable events only for main board. Line card events are to be 1437 * configured only after line card is activated. Before that, access to 1438 * modules on line cards is not allowed. 1439 */ 1440 err = mlxsw_env_module_event_enable(env, 0); 1441 if (err) 1442 goto err_mlxsw_env_module_event_enable; 1443 1444 err = mlxsw_env_module_type_set(mlxsw_core, 0); 1445 if (err) 1446 goto err_type_set; 1447 1448 err = mlxsw_env_max_module_eeprom_len_query(env); 1449 if (err) 1450 goto err_eeprom_len_query; 1451 1452 env->line_cards[0]->active = true; 1453 1454 return 0; 1455 1456 err_eeprom_len_query: 1457 err_type_set: 1458 mlxsw_env_module_event_disable(env, 0); 1459 err_mlxsw_env_module_event_enable: 1460 mlxsw_env_module_plug_event_unregister(env); 1461 err_module_plug_event_register: 1462 mlxsw_env_temp_warn_event_unregister(env); 1463 err_temp_warn_event_register: 1464 mlxsw_linecards_event_ops_unregister(env->core, 1465 &mlxsw_env_event_ops, env); 1466 err_linecards_event_ops_register: 1467 mutex_destroy(&env->line_cards_lock); 1468 mlxsw_env_line_cards_free(env); 1469 err_mlxsw_env_line_cards_alloc: 1470 kfree(env); 1471 return err; 1472 } 1473 1474 void mlxsw_env_fini(struct mlxsw_env *env) 1475 { 1476 env->line_cards[0]->active = false; 1477 mlxsw_env_module_event_disable(env, 0); 1478 mlxsw_env_module_plug_event_unregister(env); 1479 /* Make sure there is no more event work scheduled. */ 1480 mlxsw_core_flush_owq(); 1481 mlxsw_env_temp_warn_event_unregister(env); 1482 mlxsw_linecards_event_ops_unregister(env->core, 1483 &mlxsw_env_event_ops, env); 1484 mutex_destroy(&env->line_cards_lock); 1485 mlxsw_env_line_cards_free(env); 1486 kfree(env); 1487 } 1488