1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
6 #include <linux/ethtool.h>
8 #include <linux/mutex.h>
15 struct mlxsw_env_module_info {
16 u64 module_overheat_counter;
20 enum ethtool_module_power_mode_policy power_mode_policy;
21 enum mlxsw_reg_pmtm_module_type type;
24 struct mlxsw_env_line_card {
27 struct mlxsw_env_module_info module_info[];
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);
40 static bool __mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env,
43 return mlxsw_env->line_cards[slot_index]->active;
46 static bool mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env,
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);
59 mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core,
60 u8 slot_index, u8 module)
62 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
64 return &mlxsw_env->line_cards[slot_index]->module_info[module];
67 static int __mlxsw_env_validate_module_type(struct mlxsw_core *core,
68 u8 slot_index, u8 module)
70 struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
71 struct mlxsw_env_module_info *module_info;
74 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
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:
89 static int mlxsw_env_validate_module_type(struct mlxsw_core *core,
90 u8 slot_index, u8 module)
92 struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
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);
103 mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id,
104 bool *qsfp, bool *cmis)
106 char mcia_pl[MLXSW_REG_MCIA_LEN];
111 err = mlxsw_env_validate_module_type(core, slot_index, id);
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);
121 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
122 ident = eeprom_tmp[0];
125 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
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:
133 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
134 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP:
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)
150 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
151 char mcia_pl[MLXSW_REG_MCIA_LEN];
158 size = min_t(u16, size, mlxsw_env->max_eeprom_len);
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;
165 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
166 if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
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.
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;
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.
184 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
185 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
189 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, offset, size,
192 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
196 status = mlxsw_reg_mcia_status_get(mcia_pl);
200 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
201 memcpy(data, eeprom_tmp, size);
208 mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index,
209 int module, int off, int *temp)
211 unsigned int module_temp, module_crit, module_emerg;
213 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
216 char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
217 char mtmp_pl[MLXSW_REG_MTMP_LEN];
223 mlxsw_reg_mtmp_pack(mtmp_pl, slot_index,
224 MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false,
226 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
229 mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
230 &module_emerg, NULL);
236 /* Validate if threshold reading is available through MTMP register,
237 * otherwise fallback to read through MCIA.
240 *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
244 /* Read Free Side Device Temperature Thresholds from page 03h
245 * (MSB at lower byte address).
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);
253 /* Validate module identifier value. */
254 err = mlxsw_env_validate_cable_ident(core, slot_index, module, &qsfp,
260 /* For QSFP/CMIS module-defined thresholds are located in page
261 * 02h, otherwise in page 03h.
264 page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
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);
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);
278 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
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;
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)
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;
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");
305 err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
308 "EEPROM is not equipped on port module type");
312 err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, module, 0,
313 offset, module_info, false,
318 if (read_size < offset)
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];
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;
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 ||
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;
337 modinfo->type = ETH_MODULE_SFF_8436;
338 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
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,
353 modinfo->type = ETH_MODULE_SFF_8472;
355 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
357 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
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.
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.
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;
374 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
382 EXPORT_SYMBOL(mlxsw_env_get_module_info);
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,
389 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
390 int offset = ee->offset;
391 unsigned int read_size;
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");
404 memset(data, 0, ee->len);
405 /* Validate module identifier value. */
406 err = mlxsw_env_validate_cable_ident(mlxsw_core, slot_index, module,
411 while (i < ee->len) {
412 err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index,
414 ee->len - i, data + i,
417 netdev_err(netdev, "Eeprom query failed\n");
427 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
429 static int mlxsw_env_mcia_status_process(const char *mcia_pl,
430 struct netlink_ext_ack *extack)
432 u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
435 case MLXSW_REG_MCIA_STATUS_GOOD:
437 case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
438 NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
440 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
441 NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
443 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
444 NL_SET_ERR_MSG_MOD(extack, "No module present indication");
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");
449 case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
450 NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
453 NL_SET_ERR_MSG_MOD(extack, "Unknown error");
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)
464 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
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");
475 err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
477 NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type");
481 /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
482 device_addr = page->offset;
484 while (bytes_read < page->length) {
485 char mcia_pl[MLXSW_REG_MCIA_LEN];
489 size = min_t(u8, page->length - bytes_read,
490 mlxsw_env->max_eeprom_len);
492 mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page,
493 device_addr + bytes_read, size,
495 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
497 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
499 NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
503 err = mlxsw_env_mcia_status_process(mcia_pl, extack);
507 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
508 memcpy(page->data + bytes_read, eeprom_tmp, size);
514 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
516 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index,
519 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
521 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module);
522 mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
524 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
527 int mlxsw_env_reset_module(struct net_device *netdev,
528 struct mlxsw_core *mlxsw_core, u8 slot_index,
529 u8 module, u32 *flags)
531 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
532 struct mlxsw_env_module_info *module_info;
536 if (!(req & ETH_RESET_PHY) &&
537 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
540 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
541 netdev_err(netdev, "Cannot reset module on an inactive line card\n");
545 mutex_lock(&mlxsw_env->line_cards_lock);
547 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
549 netdev_err(netdev, "Reset module is not supported on port module type\n");
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");
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");
567 err = mlxsw_env_module_reset(mlxsw_core, slot_index, module);
569 netdev_err(netdev, "Failed to reset module\n");
573 *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
576 mutex_unlock(&mlxsw_env->line_cards_lock);
579 EXPORT_SYMBOL(mlxsw_env_reset_module);
582 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
584 struct ethtool_module_power_mode_params *params,
585 struct netlink_ext_ack *extack)
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];
593 mutex_lock(&mlxsw_env->line_cards_lock);
595 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
597 NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type");
601 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
602 params->policy = module_info->power_mode_policy;
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))
608 mlxsw_reg_mcion_pack(mcion_pl, slot_index, module);
609 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
611 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
615 status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
616 if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
619 if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
620 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
622 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
625 mutex_unlock(&mlxsw_env->line_cards_lock);
628 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
630 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
631 u8 slot_index, u8 module, bool enable)
633 enum mlxsw_reg_pmaos_admin_status admin_status;
634 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
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);
642 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
645 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
646 u8 slot_index, u8 module,
649 u16 eeprom_override_mask, eeprom_override;
650 char pmmp_pl[MLXSW_REG_PMMP_LEN];
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 :
659 mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
661 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
664 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
665 u8 slot_index, u8 module,
667 struct netlink_ext_ack *extack)
669 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
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.
676 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
679 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false);
681 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
685 err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
688 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
689 goto err_module_low_power_set;
692 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
694 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
695 goto err_module_enable_set;
700 err_module_enable_set:
701 mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
703 err_module_low_power_set:
704 mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
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)
714 struct mlxsw_env_module_info *module_info;
718 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
720 NL_SET_ERR_MSG_MOD(extack,
721 "Power mode set is not supported on port module type");
725 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
726 if (module_info->power_mode_policy == policy)
729 /* If any ports are up, we are already in high power mode. */
730 if (module_info->num_ports_up)
733 low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
734 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
740 module_info->power_mode_policy = policy;
746 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
748 enum ethtool_module_power_mode_policy policy,
749 struct netlink_ext_ack *extack)
751 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
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");
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);
767 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
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)
773 char mtbr_pl[MLXSW_REG_MTBR_LEN];
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);
783 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
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;
793 *p_has_temp_sensor = temp ? true : false;
799 mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index,
800 u16 sensor_index, bool enable)
802 char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
803 enum mlxsw_reg_mtmp_tee tee;
804 int err, threshold_hi;
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);
813 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
816 MLXSW_REG_MTMP_MODULE_INDEX_MIN,
819 /* In case it is not possible to query the module's threshold,
820 * use the default value.
823 threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
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.
830 threshold_hi = threshold_hi / 1000 * 8;
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);
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);
841 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
844 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
845 int i, err, sensor_index;
846 bool has_temp_sensor;
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);
854 if (!has_temp_sensor)
857 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
858 err = mlxsw_env_temp_event_set(mlxsw_core, slot_index,
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;
873 static void mlxsw_env_mtwe_event_work(struct work_struct *work)
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;
881 event = container_of(work, struct mlxsw_env_module_temp_warn_event,
883 mlxsw_env = event->mlxsw_env;
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)
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;
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.
904 mutex_unlock(&mlxsw_env->line_cards_lock);
906 } else if (is_overheat && !sensor_warning) {
907 /* MTWE reports "no warning", turn is_overheat off.
909 module_info->is_overheat = false;
910 mutex_unlock(&mlxsw_env->line_cards_lock);
912 /* Current state is "no warning" and MTWE reports
913 * "warning", increase the counter and turn is_overheat
916 module_info->is_overheat = true;
917 module_info->module_overheat_counter++;
918 mutex_unlock(&mlxsw_env->line_cards_lock);
926 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
929 struct mlxsw_env_module_temp_warn_event *event;
930 struct mlxsw_env *mlxsw_env = priv;
932 event = kmalloc(sizeof(*event), GFP_ATOMIC);
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);
942 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
943 MLXSW_CORE_EVENTL(mlxsw_env_mtwe_listener_func, MTWE);
945 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
947 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
949 return mlxsw_core_trap_register(mlxsw_core,
950 &mlxsw_env_temp_warn_listener,
954 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
956 mlxsw_core_trap_unregister(mlxsw_env->core,
957 &mlxsw_env_temp_warn_listener, mlxsw_env);
960 struct mlxsw_env_module_plug_unplug_event {
961 struct mlxsw_env *mlxsw_env;
964 struct work_struct work;
967 static void mlxsw_env_pmpe_event_work(struct work_struct *work)
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;
976 event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
978 mlxsw_env = event->mlxsw_env;
980 mutex_lock(&mlxsw_env->line_cards_lock);
981 module_info = mlxsw_env_module_info_get(mlxsw_env->core,
984 module_info->is_overheat = false;
985 mutex_unlock(&mlxsw_env->line_cards_lock);
987 err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
991 /* Do not disable events on modules without sensors or faulty sensors
992 * because FW returns errors.
997 if (!has_temp_sensor)
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);
1009 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
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;
1018 if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count ||
1019 slot_index >= mlxsw_env->num_of_slots))
1022 module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
1023 if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
1026 event = kmalloc(sizeof(*event), GFP_ATOMIC);
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);
1037 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
1038 MLXSW_CORE_EVENTL(mlxsw_env_pmpe_listener_func, PMPE);
1041 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
1043 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1045 return mlxsw_core_trap_register(mlxsw_core,
1046 &mlxsw_env_module_plug_listener,
1051 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
1053 mlxsw_core_trap_unregister(mlxsw_env->core,
1054 &mlxsw_env_module_plug_listener,
1059 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
1062 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1065 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
1066 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
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);
1080 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index,
1081 u8 module, u64 *p_counter)
1083 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1084 struct mlxsw_env_module_info *module_info;
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);
1093 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
1095 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index,
1098 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1099 struct mlxsw_env_module_info *module_info;
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);
1106 EXPORT_SYMBOL(mlxsw_env_module_port_map);
1108 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index,
1111 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1112 struct mlxsw_env_module_info *module_info;
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);
1119 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
1121 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
1124 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1125 struct mlxsw_env_module_info *module_info;
1128 mutex_lock(&mlxsw_env->line_cards_lock);
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)
1135 if (module_info->num_ports_up != 0)
1138 /* Transition to high power mode following first port using the module
1139 * being put administratively up.
1141 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
1147 module_info->num_ports_up++;
1149 mutex_unlock(&mlxsw_env->line_cards_lock);
1152 EXPORT_SYMBOL(mlxsw_env_module_port_up);
1154 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
1157 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1158 struct mlxsw_env_module_info *module_info;
1160 mutex_lock(&mlxsw_env->line_cards_lock);
1162 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1163 module_info->num_ports_up--;
1165 if (module_info->power_mode_policy !=
1166 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
1169 if (module_info->num_ports_up != 0)
1172 /* Transition to low power mode following last port using the module
1173 * being put administratively down.
1175 __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true,
1179 mutex_unlock(&mlxsw_env->line_cards_lock);
1181 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1183 static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env)
1185 struct mlxsw_env_module_info *module_info;
1188 for (i = 0; i < env->num_of_slots; i++) {
1189 env->line_cards[i] = kzalloc(struct_size(env->line_cards[i],
1191 env->max_module_count),
1193 if (!env->line_cards[i])
1196 /* Firmware defaults to high power mode policy where modules
1197 * are transitioned to high power mode following plug-in.
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;
1209 for (i--; i >= 0; i--)
1210 kfree(env->line_cards[i]);
1214 static void mlxsw_env_line_cards_free(struct mlxsw_env *env)
1216 int i = env->num_of_slots;
1218 for (i--; i >= 0; i--)
1219 kfree(env->line_cards[i]);
1223 mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index)
1227 err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core,
1232 err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index);
1240 mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index)
1245 mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
1247 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
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];
1255 mlxsw_reg_pmtm_pack(pmtm_pl, slot_index, i);
1256 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
1260 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index,
1262 module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl);
1269 mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core *mlxsw_core,
1270 struct mlxsw_env *env,
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;
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,
1287 dev_err(env->bus_info->dev, "%s\n", extack._msg);
1292 mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
1294 struct mlxsw_env *mlxsw_env = priv;
1295 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1298 mutex_lock(&mlxsw_env->line_cards_lock);
1299 if (__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
1302 mlxsw_reg_mgpir_pack(mgpir_pl, slot_index);
1303 err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl);
1307 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
1308 &mlxsw_env->line_cards[slot_index]->module_count,
1311 err = mlxsw_env_module_event_enable(mlxsw_env, slot_index);
1313 dev_err(mlxsw_env->bus_info->dev, "Failed to enable port module events for line card in slot %d\n",
1315 goto err_mlxsw_env_module_event_enable;
1317 err = mlxsw_env_module_type_set(mlxsw_env->core, slot_index);
1319 dev_err(mlxsw_env->bus_info->dev, "Failed to set modules' type for line card in slot %d\n",
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,
1328 mutex_unlock(&mlxsw_env->line_cards_lock);
1333 mlxsw_env_module_event_disable(mlxsw_env, slot_index);
1334 err_mlxsw_env_module_event_enable:
1336 mutex_unlock(&mlxsw_env->line_cards_lock);
1340 mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
1343 struct mlxsw_env *mlxsw_env = priv;
1345 mutex_lock(&mlxsw_env->line_cards_lock);
1346 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
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;
1352 mutex_unlock(&mlxsw_env->line_cards_lock);
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,
1360 static void mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env)
1362 char mcam_pl[MLXSW_REG_MCAM_LEN];
1363 bool mcia_128b_supported = false;
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);
1370 mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B,
1371 &mcia_128b_supported);
1373 mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48;
1376 int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
1377 const struct mlxsw_bus_info *bus_info,
1378 struct mlxsw_env **p_env)
1380 u8 module_count, num_of_slots, max_module_count;
1381 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1382 struct mlxsw_env *env;
1385 mlxsw_reg_mgpir_pack(mgpir_pl, 0);
1386 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
1390 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
1392 /* If the system is modular, get the maximum number of modules per-slot.
1393 * Otherwise, get the maximum number of modules on the main board.
1395 max_module_count = num_of_slots ?
1396 mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
1399 env = kzalloc(struct_size(env, line_cards, num_of_slots + 1),
1404 env->core = mlxsw_core;
1405 env->bus_info = bus_info;
1406 env->num_of_slots = num_of_slots + 1;
1407 env->max_module_count = max_module_count;
1408 err = mlxsw_env_line_cards_alloc(env);
1410 goto err_mlxsw_env_line_cards_alloc;
1412 mutex_init(&env->line_cards_lock);
1415 err = mlxsw_linecards_event_ops_register(env->core,
1416 &mlxsw_env_event_ops, env);
1418 goto err_linecards_event_ops_register;
1420 err = mlxsw_env_temp_warn_event_register(mlxsw_core);
1422 goto err_temp_warn_event_register;
1424 err = mlxsw_env_module_plug_event_register(mlxsw_core);
1426 goto err_module_plug_event_register;
1428 /* Set 'module_count' only for main board. Actual count for line card
1429 * is to be set after line card is activated.
1431 env->line_cards[0]->module_count = num_of_slots ? 0 : module_count;
1432 /* Enable events only for main board. Line card events are to be
1433 * configured only after line card is activated. Before that, access to
1434 * modules on line cards is not allowed.
1436 err = mlxsw_env_module_event_enable(env, 0);
1438 goto err_mlxsw_env_module_event_enable;
1440 err = mlxsw_env_module_type_set(mlxsw_core, 0);
1444 mlxsw_env_max_module_eeprom_len_query(env);
1445 env->line_cards[0]->active = true;
1450 mlxsw_env_module_event_disable(env, 0);
1451 err_mlxsw_env_module_event_enable:
1452 mlxsw_env_module_plug_event_unregister(env);
1453 err_module_plug_event_register:
1454 mlxsw_env_temp_warn_event_unregister(env);
1455 err_temp_warn_event_register:
1456 mlxsw_linecards_event_ops_unregister(env->core,
1457 &mlxsw_env_event_ops, env);
1458 err_linecards_event_ops_register:
1459 mutex_destroy(&env->line_cards_lock);
1460 mlxsw_env_line_cards_free(env);
1461 err_mlxsw_env_line_cards_alloc:
1466 void mlxsw_env_fini(struct mlxsw_env *env)
1468 env->line_cards[0]->active = false;
1469 mlxsw_env_module_event_disable(env, 0);
1470 mlxsw_env_module_plug_event_unregister(env);
1471 /* Make sure there is no more event work scheduled. */
1472 mlxsw_core_flush_owq();
1473 mlxsw_env_temp_warn_event_unregister(env);
1474 mlxsw_linecards_event_ops_unregister(env->core,
1475 &mlxsw_env_event_ops, env);
1476 mutex_destroy(&env->line_cards_lock);
1477 mlxsw_env_line_cards_free(env);