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 }; 22 23 struct mlxsw_env { 24 struct mlxsw_core *core; 25 u8 module_count; 26 struct mutex module_info_lock; /* Protects 'module_info'. */ 27 struct mlxsw_env_module_info module_info[]; 28 }; 29 30 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, 31 bool *qsfp, bool *cmis) 32 { 33 char mcia_pl[MLXSW_REG_MCIA_LEN]; 34 char *eeprom_tmp; 35 u8 ident; 36 int err; 37 38 mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, 39 MLXSW_REG_MCIA_I2C_ADDR_LOW); 40 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); 41 if (err) 42 return err; 43 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 44 ident = eeprom_tmp[0]; 45 *cmis = false; 46 switch (ident) { 47 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: 48 *qsfp = false; 49 break; 50 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: 51 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: 52 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: 53 *qsfp = true; 54 break; 55 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: 56 *qsfp = true; 57 *cmis = true; 58 break; 59 default: 60 return -EINVAL; 61 } 62 63 return 0; 64 } 65 66 static int 67 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, 68 u16 offset, u16 size, void *data, 69 bool qsfp, unsigned int *p_read_size) 70 { 71 char mcia_pl[MLXSW_REG_MCIA_LEN]; 72 char *eeprom_tmp; 73 u16 i2c_addr; 74 u8 page = 0; 75 int status; 76 int err; 77 78 /* MCIA register accepts buffer size <= 48. Page of size 128 should be 79 * read by chunks of size 48, 48, 32. Align the size of the last chunk 80 * to avoid reading after the end of the page. 81 */ 82 size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE); 83 84 if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && 85 offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) 86 /* Cross pages read, read until offset 256 in low page */ 87 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; 88 89 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; 90 if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { 91 if (qsfp) { 92 /* When reading upper pages 1, 2 and 3 the offset 93 * starts at 128. Please refer to "QSFP+ Memory Map" 94 * figure in SFF-8436 specification and to "CMIS Module 95 * Memory Map" figure in CMIS specification for 96 * graphical depiction. 97 */ 98 page = MLXSW_REG_MCIA_PAGE_GET(offset); 99 offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; 100 if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) 101 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; 102 } else { 103 /* When reading upper pages 1, 2 and 3 the offset 104 * starts at 0 and I2C high address is used. Please refer 105 * refer to "Memory Organization" figure in SFF-8472 106 * specification for graphical depiction. 107 */ 108 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; 109 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; 110 } 111 } 112 113 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); 114 115 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); 116 if (err) 117 return err; 118 119 status = mlxsw_reg_mcia_status_get(mcia_pl); 120 if (status) 121 return -EIO; 122 123 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 124 memcpy(data, eeprom_tmp, size); 125 *p_read_size = size; 126 127 return 0; 128 } 129 130 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, 131 int off, int *temp) 132 { 133 unsigned int module_temp, module_crit, module_emerg; 134 union { 135 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE]; 136 u16 temp; 137 } temp_thresh; 138 char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; 139 char mtmp_pl[MLXSW_REG_MTMP_LEN]; 140 char *eeprom_tmp; 141 bool qsfp, cmis; 142 int page; 143 int err; 144 145 mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, 146 false, false); 147 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); 148 if (err) 149 return err; 150 mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit, 151 &module_emerg, NULL); 152 if (!module_temp) { 153 *temp = 0; 154 return 0; 155 } 156 157 /* Validate if threshold reading is available through MTMP register, 158 * otherwise fallback to read through MCIA. 159 */ 160 if (module_emerg) { 161 *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg; 162 return 0; 163 } 164 165 /* Read Free Side Device Temperature Thresholds from page 03h 166 * (MSB at lower byte address). 167 * Bytes: 168 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM); 169 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM); 170 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN); 171 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN); 172 */ 173 174 /* Validate module identifier value. */ 175 err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis); 176 if (err) 177 return err; 178 179 if (qsfp) { 180 /* For QSFP/CMIS module-defined thresholds are located in page 181 * 02h, otherwise in page 03h. 182 */ 183 if (cmis) 184 page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; 185 else 186 page = MLXSW_REG_MCIA_TH_PAGE_NUM; 187 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, 188 MLXSW_REG_MCIA_TH_PAGE_OFF + off, 189 MLXSW_REG_MCIA_TH_ITEM_SIZE, 190 MLXSW_REG_MCIA_I2C_ADDR_LOW); 191 } else { 192 mlxsw_reg_mcia_pack(mcia_pl, module, 0, 193 MLXSW_REG_MCIA_PAGE0_LO, 194 off, MLXSW_REG_MCIA_TH_ITEM_SIZE, 195 MLXSW_REG_MCIA_I2C_ADDR_HIGH); 196 } 197 198 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); 199 if (err) 200 return err; 201 202 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 203 memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE); 204 *temp = temp_thresh.temp * 1000; 205 206 return 0; 207 } 208 209 int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, 210 struct ethtool_modinfo *modinfo) 211 { 212 u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; 213 u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; 214 u8 module_rev_id, module_id, diag_mon; 215 unsigned int read_size; 216 int err; 217 218 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, 219 module_info, false, &read_size); 220 if (err) 221 return err; 222 223 if (read_size < offset) 224 return -EIO; 225 226 module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID]; 227 module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID]; 228 229 switch (module_id) { 230 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: 231 modinfo->type = ETH_MODULE_SFF_8436; 232 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 233 break; 234 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: 235 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: 236 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 || 237 module_rev_id >= 238 MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { 239 modinfo->type = ETH_MODULE_SFF_8636; 240 modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 241 } else { 242 modinfo->type = ETH_MODULE_SFF_8436; 243 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 244 } 245 break; 246 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: 247 /* Verify if transceiver provides diagnostic monitoring page */ 248 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 249 SFP_DIAGMON, 1, &diag_mon, 250 false, &read_size); 251 if (err) 252 return err; 253 254 if (read_size < 1) 255 return -EIO; 256 257 modinfo->type = ETH_MODULE_SFF_8472; 258 if (diag_mon) 259 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 260 else 261 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; 262 break; 263 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: 264 /* Use SFF_8636 as base type. ethtool should recognize specific 265 * type through the identifier value. 266 */ 267 modinfo->type = ETH_MODULE_SFF_8636; 268 /* Verify if module EEPROM is a flat memory. In case of flat 269 * memory only page 00h (0-255 bytes) can be read. Otherwise 270 * upper pages 01h and 02h can also be read. Upper pages 10h 271 * and 11h are currently not supported by the driver. 272 */ 273 if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] & 274 MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY) 275 modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 276 else 277 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 278 break; 279 default: 280 return -EINVAL; 281 } 282 283 return 0; 284 } 285 EXPORT_SYMBOL(mlxsw_env_get_module_info); 286 287 int mlxsw_env_get_module_eeprom(struct net_device *netdev, 288 struct mlxsw_core *mlxsw_core, int module, 289 struct ethtool_eeprom *ee, u8 *data) 290 { 291 int offset = ee->offset; 292 unsigned int read_size; 293 bool qsfp, cmis; 294 int i = 0; 295 int err; 296 297 if (!ee->len) 298 return -EINVAL; 299 300 memset(data, 0, ee->len); 301 /* Validate module identifier value. */ 302 err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis); 303 if (err) 304 return err; 305 306 while (i < ee->len) { 307 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, 308 ee->len - i, data + i, 309 qsfp, &read_size); 310 if (err) { 311 netdev_err(netdev, "Eeprom query failed\n"); 312 return err; 313 } 314 315 i += read_size; 316 offset += read_size; 317 } 318 319 return 0; 320 } 321 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom); 322 323 static int mlxsw_env_mcia_status_process(const char *mcia_pl, 324 struct netlink_ext_ack *extack) 325 { 326 u8 status = mlxsw_reg_mcia_status_get(mcia_pl); 327 328 switch (status) { 329 case MLXSW_REG_MCIA_STATUS_GOOD: 330 return 0; 331 case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE: 332 NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM"); 333 return -EIO; 334 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED: 335 NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device"); 336 return -EOPNOTSUPP; 337 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED: 338 NL_SET_ERR_MSG_MOD(extack, "No module present indication"); 339 return -EIO; 340 case MLXSW_REG_MCIA_STATUS_I2C_ERROR: 341 NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C"); 342 return -EIO; 343 case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED: 344 NL_SET_ERR_MSG_MOD(extack, "Module is disabled"); 345 return -EIO; 346 default: 347 NL_SET_ERR_MSG_MOD(extack, "Unknown error"); 348 return -EIO; 349 } 350 } 351 352 int 353 mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, 354 const struct ethtool_module_eeprom *page, 355 struct netlink_ext_ack *extack) 356 { 357 u32 bytes_read = 0; 358 u16 device_addr; 359 360 /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */ 361 device_addr = page->offset; 362 363 while (bytes_read < page->length) { 364 char mcia_pl[MLXSW_REG_MCIA_LEN]; 365 char *eeprom_tmp; 366 u8 size; 367 int err; 368 369 size = min_t(u8, page->length - bytes_read, 370 MLXSW_REG_MCIA_EEPROM_SIZE); 371 372 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page, 373 device_addr + bytes_read, size, 374 page->i2c_address); 375 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); 376 377 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); 378 if (err) { 379 NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM"); 380 return err; 381 } 382 383 err = mlxsw_env_mcia_status_process(mcia_pl, extack); 384 if (err) 385 return err; 386 387 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl); 388 memcpy(page->data + bytes_read, eeprom_tmp, size); 389 bytes_read += size; 390 } 391 392 return bytes_read; 393 } 394 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); 395 396 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module) 397 { 398 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 399 400 mlxsw_reg_pmaos_pack(pmaos_pl, module); 401 mlxsw_reg_pmaos_rst_set(pmaos_pl, true); 402 403 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 404 } 405 406 int mlxsw_env_reset_module(struct net_device *netdev, 407 struct mlxsw_core *mlxsw_core, u8 module, u32 *flags) 408 { 409 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 410 u32 req = *flags; 411 int err; 412 413 if (!(req & ETH_RESET_PHY) && 414 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) 415 return 0; 416 417 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 418 return -EINVAL; 419 420 mutex_lock(&mlxsw_env->module_info_lock); 421 422 if (mlxsw_env->module_info[module].num_ports_up) { 423 netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n"); 424 err = -EINVAL; 425 goto out; 426 } 427 428 if (mlxsw_env->module_info[module].num_ports_mapped > 1 && 429 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) { 430 netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n"); 431 err = -EINVAL; 432 goto out; 433 } 434 435 err = mlxsw_env_module_reset(mlxsw_core, module); 436 if (err) { 437 netdev_err(netdev, "Failed to reset module\n"); 438 goto out; 439 } 440 441 *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)); 442 443 out: 444 mutex_unlock(&mlxsw_env->module_info_lock); 445 return err; 446 } 447 EXPORT_SYMBOL(mlxsw_env_reset_module); 448 449 int 450 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, 451 struct ethtool_module_power_mode_params *params, 452 struct netlink_ext_ack *extack) 453 { 454 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 455 char mcion_pl[MLXSW_REG_MCION_LEN]; 456 u32 status_bits; 457 int err; 458 459 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 460 return -EINVAL; 461 462 mutex_lock(&mlxsw_env->module_info_lock); 463 464 params->policy = mlxsw_env->module_info[module].power_mode_policy; 465 466 mlxsw_reg_mcion_pack(mcion_pl, module); 467 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); 468 if (err) { 469 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); 470 goto out; 471 } 472 473 status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl); 474 if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK)) 475 goto out; 476 477 if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK) 478 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW; 479 else 480 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH; 481 482 out: 483 mutex_unlock(&mlxsw_env->module_info_lock); 484 return err; 485 } 486 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); 487 488 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, 489 u8 module, bool enable) 490 { 491 enum mlxsw_reg_pmaos_admin_status admin_status; 492 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 493 494 mlxsw_reg_pmaos_pack(pmaos_pl, module); 495 admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : 496 MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; 497 mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); 498 mlxsw_reg_pmaos_ase_set(pmaos_pl, true); 499 500 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 501 } 502 503 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, 504 u8 module, bool low_power) 505 { 506 u16 eeprom_override_mask, eeprom_override; 507 char pmmp_pl[MLXSW_REG_PMMP_LEN]; 508 509 mlxsw_reg_pmmp_pack(pmmp_pl, module); 510 mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); 511 /* Mask all the bits except low power mode. */ 512 eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; 513 mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask); 514 eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK : 515 0; 516 mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override); 517 518 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl); 519 } 520 521 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, 522 u8 module, bool low_power, 523 struct netlink_ext_ack *extack) 524 { 525 int err; 526 527 err = mlxsw_env_module_enable_set(mlxsw_core, module, false); 528 if (err) { 529 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module"); 530 return err; 531 } 532 533 err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power); 534 if (err) { 535 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode"); 536 goto err_module_low_power_set; 537 } 538 539 err = mlxsw_env_module_enable_set(mlxsw_core, module, true); 540 if (err) { 541 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module"); 542 goto err_module_enable_set; 543 } 544 545 return 0; 546 547 err_module_enable_set: 548 mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power); 549 err_module_low_power_set: 550 mlxsw_env_module_enable_set(mlxsw_core, module, true); 551 return err; 552 } 553 554 int 555 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, 556 enum ethtool_module_power_mode_policy policy, 557 struct netlink_ext_ack *extack) 558 { 559 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 560 bool low_power; 561 int err = 0; 562 563 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 564 return -EINVAL; 565 566 if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH && 567 policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) { 568 NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy"); 569 return -EOPNOTSUPP; 570 } 571 572 mutex_lock(&mlxsw_env->module_info_lock); 573 574 if (mlxsw_env->module_info[module].power_mode_policy == policy) 575 goto out; 576 577 /* If any ports are up, we are already in high power mode. */ 578 if (mlxsw_env->module_info[module].num_ports_up) 579 goto out_set_policy; 580 581 low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; 582 err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power, 583 extack); 584 if (err) 585 goto out; 586 587 out_set_policy: 588 mlxsw_env->module_info[module].power_mode_policy = policy; 589 out: 590 mutex_unlock(&mlxsw_env->module_info_lock); 591 return err; 592 } 593 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); 594 595 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, 596 u8 module, 597 bool *p_has_temp_sensor) 598 { 599 char mtbr_pl[MLXSW_REG_MTBR_LEN]; 600 u16 temp; 601 int err; 602 603 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 604 1); 605 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); 606 if (err) 607 return err; 608 609 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); 610 611 switch (temp) { 612 case MLXSW_REG_MTBR_BAD_SENS_INFO: 613 case MLXSW_REG_MTBR_NO_CONN: 614 case MLXSW_REG_MTBR_NO_TEMP_SENS: 615 case MLXSW_REG_MTBR_INDEX_NA: 616 *p_has_temp_sensor = false; 617 break; 618 default: 619 *p_has_temp_sensor = temp ? true : false; 620 } 621 return 0; 622 } 623 624 static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, 625 u16 sensor_index, bool enable) 626 { 627 char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; 628 enum mlxsw_reg_mtmp_tee tee; 629 int err, threshold_hi; 630 631 mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index); 632 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); 633 if (err) 634 return err; 635 636 if (enable) { 637 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core, 638 sensor_index - 639 MLXSW_REG_MTMP_MODULE_INDEX_MIN, 640 SFP_TEMP_HIGH_WARN, 641 &threshold_hi); 642 /* In case it is not possible to query the module's threshold, 643 * use the default value. 644 */ 645 if (err) 646 threshold_hi = MLXSW_REG_MTMP_THRESH_HI; 647 else 648 /* mlxsw_env_module_temp_thresholds_get() multiplies 649 * Celsius degrees by 1000 whereas MTMP expects 650 * temperature in 0.125 Celsius degrees units. 651 * Convert threshold_hi to correct units. 652 */ 653 threshold_hi = threshold_hi / 1000 * 8; 654 655 mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi); 656 mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi - 657 MLXSW_REG_MTMP_HYSTERESIS_TEMP); 658 } 659 tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT; 660 mlxsw_reg_mtmp_tee_set(mtmp_pl, tee); 661 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); 662 } 663 664 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, 665 u8 module_count) 666 { 667 int i, err, sensor_index; 668 bool has_temp_sensor; 669 670 for (i = 0; i < module_count; i++) { 671 err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i, 672 &has_temp_sensor); 673 if (err) 674 return err; 675 676 if (!has_temp_sensor) 677 continue; 678 679 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN; 680 err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true); 681 if (err) 682 return err; 683 } 684 685 return 0; 686 } 687 688 struct mlxsw_env_module_temp_warn_event { 689 struct mlxsw_env *mlxsw_env; 690 char mtwe_pl[MLXSW_REG_MTWE_LEN]; 691 struct work_struct work; 692 }; 693 694 static void mlxsw_env_mtwe_event_work(struct work_struct *work) 695 { 696 struct mlxsw_env_module_temp_warn_event *event; 697 struct mlxsw_env *mlxsw_env; 698 int i, sensor_warning; 699 bool is_overheat; 700 701 event = container_of(work, struct mlxsw_env_module_temp_warn_event, 702 work); 703 mlxsw_env = event->mlxsw_env; 704 705 for (i = 0; i < mlxsw_env->module_count; i++) { 706 /* 64-127 of sensor_index are mapped to the port modules 707 * sequentially (module 0 is mapped to sensor_index 64, 708 * module 1 to sensor_index 65 and so on) 709 */ 710 sensor_warning = 711 mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl, 712 i + MLXSW_REG_MTMP_MODULE_INDEX_MIN); 713 mutex_lock(&mlxsw_env->module_info_lock); 714 is_overheat = 715 mlxsw_env->module_info[i].is_overheat; 716 717 if ((is_overheat && sensor_warning) || 718 (!is_overheat && !sensor_warning)) { 719 /* Current state is "warning" and MTWE still reports 720 * warning OR current state in "no warning" and MTWE 721 * does not report warning. 722 */ 723 mutex_unlock(&mlxsw_env->module_info_lock); 724 continue; 725 } else if (is_overheat && !sensor_warning) { 726 /* MTWE reports "no warning", turn is_overheat off. 727 */ 728 mlxsw_env->module_info[i].is_overheat = false; 729 mutex_unlock(&mlxsw_env->module_info_lock); 730 } else { 731 /* Current state is "no warning" and MTWE reports 732 * "warning", increase the counter and turn is_overheat 733 * on. 734 */ 735 mlxsw_env->module_info[i].is_overheat = true; 736 mlxsw_env->module_info[i].module_overheat_counter++; 737 mutex_unlock(&mlxsw_env->module_info_lock); 738 } 739 } 740 741 kfree(event); 742 } 743 744 static void 745 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl, 746 void *priv) 747 { 748 struct mlxsw_env_module_temp_warn_event *event; 749 struct mlxsw_env *mlxsw_env = priv; 750 751 event = kmalloc(sizeof(*event), GFP_ATOMIC); 752 if (!event) 753 return; 754 755 event->mlxsw_env = mlxsw_env; 756 memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN); 757 INIT_WORK(&event->work, mlxsw_env_mtwe_event_work); 758 mlxsw_core_schedule_work(&event->work); 759 } 760 761 static const struct mlxsw_listener mlxsw_env_temp_warn_listener = 762 MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE); 763 764 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core) 765 { 766 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 767 768 if (!mlxsw_core_temp_warn_enabled(mlxsw_core)) 769 return 0; 770 771 return mlxsw_core_trap_register(mlxsw_core, 772 &mlxsw_env_temp_warn_listener, 773 mlxsw_env); 774 } 775 776 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env) 777 { 778 if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core)) 779 return; 780 781 mlxsw_core_trap_unregister(mlxsw_env->core, 782 &mlxsw_env_temp_warn_listener, mlxsw_env); 783 } 784 785 struct mlxsw_env_module_plug_unplug_event { 786 struct mlxsw_env *mlxsw_env; 787 u8 module; 788 struct work_struct work; 789 }; 790 791 static void mlxsw_env_pmpe_event_work(struct work_struct *work) 792 { 793 struct mlxsw_env_module_plug_unplug_event *event; 794 struct mlxsw_env *mlxsw_env; 795 bool has_temp_sensor; 796 u16 sensor_index; 797 int err; 798 799 event = container_of(work, struct mlxsw_env_module_plug_unplug_event, 800 work); 801 mlxsw_env = event->mlxsw_env; 802 803 mutex_lock(&mlxsw_env->module_info_lock); 804 mlxsw_env->module_info[event->module].is_overheat = false; 805 mutex_unlock(&mlxsw_env->module_info_lock); 806 807 err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module, 808 &has_temp_sensor); 809 /* Do not disable events on modules without sensors or faulty sensors 810 * because FW returns errors. 811 */ 812 if (err) 813 goto out; 814 815 if (!has_temp_sensor) 816 goto out; 817 818 sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN; 819 mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true); 820 821 out: 822 kfree(event); 823 } 824 825 static void 826 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, 827 void *priv) 828 { 829 struct mlxsw_env_module_plug_unplug_event *event; 830 enum mlxsw_reg_pmpe_module_status module_status; 831 u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); 832 struct mlxsw_env *mlxsw_env = priv; 833 834 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 835 return; 836 837 module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); 838 if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED) 839 return; 840 841 event = kmalloc(sizeof(*event), GFP_ATOMIC); 842 if (!event) 843 return; 844 845 event->mlxsw_env = mlxsw_env; 846 event->module = module; 847 INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); 848 mlxsw_core_schedule_work(&event->work); 849 } 850 851 static const struct mlxsw_listener mlxsw_env_module_plug_listener = 852 MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE); 853 854 static int 855 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core) 856 { 857 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 858 859 if (!mlxsw_core_temp_warn_enabled(mlxsw_core)) 860 return 0; 861 862 return mlxsw_core_trap_register(mlxsw_core, 863 &mlxsw_env_module_plug_listener, 864 mlxsw_env); 865 } 866 867 static void 868 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env) 869 { 870 if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core)) 871 return; 872 873 mlxsw_core_trap_unregister(mlxsw_env->core, 874 &mlxsw_env_module_plug_listener, 875 mlxsw_env); 876 } 877 878 static int 879 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, 880 u8 module_count) 881 { 882 int i, err; 883 884 for (i = 0; i < module_count; i++) { 885 char pmaos_pl[MLXSW_REG_PMAOS_LEN]; 886 887 mlxsw_reg_pmaos_pack(pmaos_pl, i); 888 mlxsw_reg_pmaos_e_set(pmaos_pl, 889 MLXSW_REG_PMAOS_E_GENERATE_EVENT); 890 mlxsw_reg_pmaos_ee_set(pmaos_pl, true); 891 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); 892 if (err) 893 return err; 894 } 895 return 0; 896 } 897 898 int 899 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, 900 u64 *p_counter) 901 { 902 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 903 904 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 905 return -EINVAL; 906 907 mutex_lock(&mlxsw_env->module_info_lock); 908 *p_counter = mlxsw_env->module_info[module].module_overheat_counter; 909 mutex_unlock(&mlxsw_env->module_info_lock); 910 911 return 0; 912 } 913 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get); 914 915 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) 916 { 917 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 918 919 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 920 return; 921 922 mutex_lock(&mlxsw_env->module_info_lock); 923 mlxsw_env->module_info[module].num_ports_mapped++; 924 mutex_unlock(&mlxsw_env->module_info_lock); 925 } 926 EXPORT_SYMBOL(mlxsw_env_module_port_map); 927 928 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) 929 { 930 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 931 932 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 933 return; 934 935 mutex_lock(&mlxsw_env->module_info_lock); 936 mlxsw_env->module_info[module].num_ports_mapped--; 937 mutex_unlock(&mlxsw_env->module_info_lock); 938 } 939 EXPORT_SYMBOL(mlxsw_env_module_port_unmap); 940 941 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) 942 { 943 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 944 int err = 0; 945 946 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 947 return -EINVAL; 948 949 mutex_lock(&mlxsw_env->module_info_lock); 950 951 if (mlxsw_env->module_info[module].power_mode_policy != 952 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) 953 goto out_inc; 954 955 if (mlxsw_env->module_info[module].num_ports_up != 0) 956 goto out_inc; 957 958 /* Transition to high power mode following first port using the module 959 * being put administratively up. 960 */ 961 err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false, 962 NULL); 963 if (err) 964 goto out_unlock; 965 966 out_inc: 967 mlxsw_env->module_info[module].num_ports_up++; 968 out_unlock: 969 mutex_unlock(&mlxsw_env->module_info_lock); 970 return err; 971 } 972 EXPORT_SYMBOL(mlxsw_env_module_port_up); 973 974 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) 975 { 976 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 977 978 if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) 979 return; 980 981 mutex_lock(&mlxsw_env->module_info_lock); 982 983 mlxsw_env->module_info[module].num_ports_up--; 984 985 if (mlxsw_env->module_info[module].power_mode_policy != 986 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) 987 goto out_unlock; 988 989 if (mlxsw_env->module_info[module].num_ports_up != 0) 990 goto out_unlock; 991 992 /* Transition to low power mode following last port using the module 993 * being put administratively down. 994 */ 995 __mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL); 996 997 out_unlock: 998 mutex_unlock(&mlxsw_env->module_info_lock); 999 } 1000 EXPORT_SYMBOL(mlxsw_env_module_port_down); 1001 1002 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) 1003 { 1004 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 1005 struct mlxsw_env *env; 1006 u8 module_count; 1007 int i, err; 1008 1009 mlxsw_reg_mgpir_pack(mgpir_pl); 1010 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); 1011 if (err) 1012 return err; 1013 1014 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count); 1015 1016 env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL); 1017 if (!env) 1018 return -ENOMEM; 1019 1020 /* Firmware defaults to high power mode policy where modules are 1021 * transitioned to high power mode following plug-in. 1022 */ 1023 for (i = 0; i < module_count; i++) 1024 env->module_info[i].power_mode_policy = 1025 ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; 1026 1027 mutex_init(&env->module_info_lock); 1028 env->core = mlxsw_core; 1029 env->module_count = module_count; 1030 *p_env = env; 1031 1032 err = mlxsw_env_temp_warn_event_register(mlxsw_core); 1033 if (err) 1034 goto err_temp_warn_event_register; 1035 1036 err = mlxsw_env_module_plug_event_register(mlxsw_core); 1037 if (err) 1038 goto err_module_plug_event_register; 1039 1040 err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 1041 env->module_count); 1042 if (err) 1043 goto err_oper_state_event_enable; 1044 1045 err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count); 1046 if (err) 1047 goto err_temp_event_enable; 1048 1049 return 0; 1050 1051 err_temp_event_enable: 1052 err_oper_state_event_enable: 1053 mlxsw_env_module_plug_event_unregister(env); 1054 err_module_plug_event_register: 1055 mlxsw_env_temp_warn_event_unregister(env); 1056 err_temp_warn_event_register: 1057 mutex_destroy(&env->module_info_lock); 1058 kfree(env); 1059 return err; 1060 } 1061 1062 void mlxsw_env_fini(struct mlxsw_env *env) 1063 { 1064 mlxsw_env_module_plug_event_unregister(env); 1065 /* Make sure there is no more event work scheduled. */ 1066 mlxsw_core_flush_owq(); 1067 mlxsw_env_temp_warn_event_unregister(env); 1068 mutex_destroy(&env->module_info_lock); 1069 kfree(env); 1070 } 1071