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