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;
25 struct mlxsw_core *core;
27 struct mutex module_info_lock; /* Protects 'module_info'. */
28 struct mlxsw_env_module_info module_info[];
31 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
32 bool *qsfp, bool *cmis)
34 char mcia_pl[MLXSW_REG_MCIA_LEN];
39 mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
40 MLXSW_REG_MCIA_I2C_ADDR_LOW);
41 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
44 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
45 ident = eeprom_tmp[0];
48 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
51 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
52 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
53 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
56 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
68 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
69 u16 offset, u16 size, void *data,
70 bool qsfp, unsigned int *p_read_size)
72 char mcia_pl[MLXSW_REG_MCIA_LEN];
79 /* MCIA register accepts buffer size <= 48. Page of size 128 should be
80 * read by chunks of size 48, 48, 32. Align the size of the last chunk
81 * to avoid reading after the end of the page.
83 size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
85 if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
86 offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
87 /* Cross pages read, read until offset 256 in low page */
88 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
90 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
91 if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
93 /* When reading upper pages 1, 2 and 3 the offset
94 * starts at 128. Please refer to "QSFP+ Memory Map"
95 * figure in SFF-8436 specification and to "CMIS Module
96 * Memory Map" figure in CMIS specification for
97 * graphical depiction.
99 page = MLXSW_REG_MCIA_PAGE_GET(offset);
100 offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
101 if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
102 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
104 /* When reading upper pages 1, 2 and 3 the offset
105 * starts at 0 and I2C high address is used. Please refer
106 * refer to "Memory Organization" figure in SFF-8472
107 * specification for graphical depiction.
109 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
110 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
114 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr);
116 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
120 status = mlxsw_reg_mcia_status_get(mcia_pl);
124 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
125 memcpy(data, eeprom_tmp, size);
131 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
134 unsigned int module_temp, module_crit, module_emerg;
136 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
139 char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
140 char mtmp_pl[MLXSW_REG_MTMP_LEN];
146 mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
148 err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
151 mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
152 &module_emerg, NULL);
158 /* Validate if threshold reading is available through MTMP register,
159 * otherwise fallback to read through MCIA.
162 *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
166 /* Read Free Side Device Temperature Thresholds from page 03h
167 * (MSB at lower byte address).
169 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
170 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
171 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
172 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
175 /* Validate module identifier value. */
176 err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis);
181 /* For QSFP/CMIS module-defined thresholds are located in page
182 * 02h, otherwise in page 03h.
185 page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
187 page = MLXSW_REG_MCIA_TH_PAGE_NUM;
188 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page,
189 MLXSW_REG_MCIA_TH_PAGE_OFF + off,
190 MLXSW_REG_MCIA_TH_ITEM_SIZE,
191 MLXSW_REG_MCIA_I2C_ADDR_LOW);
193 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
194 MLXSW_REG_MCIA_PAGE0_LO,
195 off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
196 MLXSW_REG_MCIA_I2C_ADDR_HIGH);
199 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
203 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
204 memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
205 *temp = temp_thresh.temp * 1000;
210 int mlxsw_env_get_module_info(struct net_device *netdev,
211 struct mlxsw_core *mlxsw_core, int module,
212 struct ethtool_modinfo *modinfo)
214 u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
215 u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
216 u8 module_rev_id, module_id, diag_mon;
217 unsigned int read_size;
220 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
221 module_info, false, &read_size);
225 if (read_size < offset)
228 module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
229 module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
232 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
233 modinfo->type = ETH_MODULE_SFF_8436;
234 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
236 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
237 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
238 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
240 MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
241 modinfo->type = ETH_MODULE_SFF_8636;
242 modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
244 modinfo->type = ETH_MODULE_SFF_8436;
245 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
248 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
249 /* Verify if transceiver provides diagnostic monitoring page */
250 err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
251 SFP_DIAGMON, 1, &diag_mon,
259 modinfo->type = ETH_MODULE_SFF_8472;
261 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
263 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
265 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
266 /* Use SFF_8636 as base type. ethtool should recognize specific
267 * type through the identifier value.
269 modinfo->type = ETH_MODULE_SFF_8636;
270 /* Verify if module EEPROM is a flat memory. In case of flat
271 * memory only page 00h (0-255 bytes) can be read. Otherwise
272 * upper pages 01h and 02h can also be read. Upper pages 10h
273 * and 11h are currently not supported by the driver.
275 if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] &
276 MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY)
277 modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
279 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
287 EXPORT_SYMBOL(mlxsw_env_get_module_info);
289 int mlxsw_env_get_module_eeprom(struct net_device *netdev,
290 struct mlxsw_core *mlxsw_core, int module,
291 struct ethtool_eeprom *ee, u8 *data)
293 int offset = ee->offset;
294 unsigned int read_size;
302 memset(data, 0, ee->len);
303 /* Validate module identifier value. */
304 err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis);
308 while (i < ee->len) {
309 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
310 ee->len - i, data + i,
313 netdev_err(netdev, "Eeprom query failed\n");
323 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
325 static int mlxsw_env_mcia_status_process(const char *mcia_pl,
326 struct netlink_ext_ack *extack)
328 u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
331 case MLXSW_REG_MCIA_STATUS_GOOD:
333 case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
334 NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
336 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
337 NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
339 case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
340 NL_SET_ERR_MSG_MOD(extack, "No module present indication");
342 case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
343 NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
345 case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
346 NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
349 NL_SET_ERR_MSG_MOD(extack, "Unknown error");
355 mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
356 const struct ethtool_module_eeprom *page,
357 struct netlink_ext_ack *extack)
362 /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
363 device_addr = page->offset;
365 while (bytes_read < page->length) {
366 char mcia_pl[MLXSW_REG_MCIA_LEN];
371 size = min_t(u8, page->length - bytes_read,
372 MLXSW_REG_MCIA_EEPROM_SIZE);
374 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page,
375 device_addr + bytes_read, size,
377 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
379 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
381 NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
385 err = mlxsw_env_mcia_status_process(mcia_pl, extack);
389 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
390 memcpy(page->data + bytes_read, eeprom_tmp, size);
396 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
398 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
400 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
402 mlxsw_reg_pmaos_pack(pmaos_pl, module);
403 mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
405 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
408 int mlxsw_env_reset_module(struct net_device *netdev,
409 struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
411 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
415 if (!(req & ETH_RESET_PHY) &&
416 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
419 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
422 mutex_lock(&mlxsw_env->module_info_lock);
424 if (mlxsw_env->module_info[module].num_ports_up) {
425 netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
430 if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
431 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
432 netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
437 err = mlxsw_env_module_reset(mlxsw_core, module);
439 netdev_err(netdev, "Failed to reset module\n");
443 *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
446 mutex_unlock(&mlxsw_env->module_info_lock);
449 EXPORT_SYMBOL(mlxsw_env_reset_module);
452 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
453 struct ethtool_module_power_mode_params *params,
454 struct netlink_ext_ack *extack)
456 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
457 char mcion_pl[MLXSW_REG_MCION_LEN];
461 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
464 mutex_lock(&mlxsw_env->module_info_lock);
466 params->policy = mlxsw_env->module_info[module].power_mode_policy;
468 mlxsw_reg_mcion_pack(mcion_pl, module);
469 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
471 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
475 status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
476 if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
479 if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
480 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
482 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
485 mutex_unlock(&mlxsw_env->module_info_lock);
488 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
490 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
491 u8 module, bool enable)
493 enum mlxsw_reg_pmaos_admin_status admin_status;
494 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
496 mlxsw_reg_pmaos_pack(pmaos_pl, module);
497 admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED :
498 MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED;
499 mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status);
500 mlxsw_reg_pmaos_ase_set(pmaos_pl, true);
502 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
505 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
506 u8 module, bool low_power)
508 u16 eeprom_override_mask, eeprom_override;
509 char pmmp_pl[MLXSW_REG_PMMP_LEN];
511 mlxsw_reg_pmmp_pack(pmmp_pl, module);
512 mlxsw_reg_pmmp_sticky_set(pmmp_pl, true);
513 /* Mask all the bits except low power mode. */
514 eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK;
515 mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask);
516 eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK :
518 mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
520 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
523 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
524 u8 module, bool low_power,
525 struct netlink_ext_ack *extack)
529 err = mlxsw_env_module_enable_set(mlxsw_core, module, false);
531 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
535 err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power);
537 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
538 goto err_module_low_power_set;
541 err = mlxsw_env_module_enable_set(mlxsw_core, module, true);
543 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
544 goto err_module_enable_set;
549 err_module_enable_set:
550 mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power);
551 err_module_low_power_set:
552 mlxsw_env_module_enable_set(mlxsw_core, module, true);
557 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
558 enum ethtool_module_power_mode_policy policy,
559 struct netlink_ext_ack *extack)
561 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
565 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
568 if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH &&
569 policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) {
570 NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy");
574 mutex_lock(&mlxsw_env->module_info_lock);
576 if (mlxsw_env->module_info[module].power_mode_policy == policy)
579 /* If any ports are up, we are already in high power mode. */
580 if (mlxsw_env->module_info[module].num_ports_up)
583 low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
584 err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power,
590 mlxsw_env->module_info[module].power_mode_policy = policy;
592 mutex_unlock(&mlxsw_env->module_info_lock);
595 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
597 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
599 bool *p_has_temp_sensor)
601 char mtbr_pl[MLXSW_REG_MTBR_LEN];
605 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
607 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
611 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
614 case MLXSW_REG_MTBR_BAD_SENS_INFO:
615 case MLXSW_REG_MTBR_NO_CONN:
616 case MLXSW_REG_MTBR_NO_TEMP_SENS:
617 case MLXSW_REG_MTBR_INDEX_NA:
618 *p_has_temp_sensor = false;
621 *p_has_temp_sensor = temp ? true : false;
626 static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core,
627 u16 sensor_index, bool enable)
629 char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
630 enum mlxsw_reg_mtmp_tee tee;
631 int err, threshold_hi;
633 mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
634 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
639 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
641 MLXSW_REG_MTMP_MODULE_INDEX_MIN,
644 /* In case it is not possible to query the module's threshold,
645 * use the default value.
648 threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
650 /* mlxsw_env_module_temp_thresholds_get() multiplies
651 * Celsius degrees by 1000 whereas MTMP expects
652 * temperature in 0.125 Celsius degrees units.
653 * Convert threshold_hi to correct units.
655 threshold_hi = threshold_hi / 1000 * 8;
657 mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
658 mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
659 MLXSW_REG_MTMP_HYSTERESIS_TEMP);
661 tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
662 mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
663 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
666 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core)
668 int i, err, sensor_index;
669 bool has_temp_sensor;
671 for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
672 err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i,
677 if (!has_temp_sensor)
680 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
681 err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true);
689 struct mlxsw_env_module_temp_warn_event {
690 struct mlxsw_env *mlxsw_env;
691 char mtwe_pl[MLXSW_REG_MTWE_LEN];
692 struct work_struct work;
695 static void mlxsw_env_mtwe_event_work(struct work_struct *work)
697 struct mlxsw_env_module_temp_warn_event *event;
698 struct mlxsw_env *mlxsw_env;
699 int i, sensor_warning;
702 event = container_of(work, struct mlxsw_env_module_temp_warn_event,
704 mlxsw_env = event->mlxsw_env;
706 for (i = 0; i < mlxsw_env->module_count; i++) {
707 /* 64-127 of sensor_index are mapped to the port modules
708 * sequentially (module 0 is mapped to sensor_index 64,
709 * module 1 to sensor_index 65 and so on)
712 mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
713 i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
714 mutex_lock(&mlxsw_env->module_info_lock);
716 mlxsw_env->module_info[i].is_overheat;
718 if ((is_overheat && sensor_warning) ||
719 (!is_overheat && !sensor_warning)) {
720 /* Current state is "warning" and MTWE still reports
721 * warning OR current state in "no warning" and MTWE
722 * does not report warning.
724 mutex_unlock(&mlxsw_env->module_info_lock);
726 } else if (is_overheat && !sensor_warning) {
727 /* MTWE reports "no warning", turn is_overheat off.
729 mlxsw_env->module_info[i].is_overheat = false;
730 mutex_unlock(&mlxsw_env->module_info_lock);
732 /* Current state is "no warning" and MTWE reports
733 * "warning", increase the counter and turn is_overheat
736 mlxsw_env->module_info[i].is_overheat = true;
737 mlxsw_env->module_info[i].module_overheat_counter++;
738 mutex_unlock(&mlxsw_env->module_info_lock);
746 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
749 struct mlxsw_env_module_temp_warn_event *event;
750 struct mlxsw_env *mlxsw_env = priv;
752 event = kmalloc(sizeof(*event), GFP_ATOMIC);
756 event->mlxsw_env = mlxsw_env;
757 memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
758 INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
759 mlxsw_core_schedule_work(&event->work);
762 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
763 MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
765 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
767 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
769 if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
772 return mlxsw_core_trap_register(mlxsw_core,
773 &mlxsw_env_temp_warn_listener,
777 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
779 if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
782 mlxsw_core_trap_unregister(mlxsw_env->core,
783 &mlxsw_env_temp_warn_listener, mlxsw_env);
786 struct mlxsw_env_module_plug_unplug_event {
787 struct mlxsw_env *mlxsw_env;
789 struct work_struct work;
792 static void mlxsw_env_pmpe_event_work(struct work_struct *work)
794 struct mlxsw_env_module_plug_unplug_event *event;
795 struct mlxsw_env *mlxsw_env;
796 bool has_temp_sensor;
800 event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
802 mlxsw_env = event->mlxsw_env;
804 mutex_lock(&mlxsw_env->module_info_lock);
805 mlxsw_env->module_info[event->module].is_overheat = false;
806 mutex_unlock(&mlxsw_env->module_info_lock);
808 err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
810 /* Do not disable events on modules without sensors or faulty sensors
811 * because FW returns errors.
816 if (!has_temp_sensor)
819 sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
820 mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true);
827 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
830 struct mlxsw_env_module_plug_unplug_event *event;
831 enum mlxsw_reg_pmpe_module_status module_status;
832 u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
833 struct mlxsw_env *mlxsw_env = priv;
835 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
838 module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
839 if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
842 event = kmalloc(sizeof(*event), GFP_ATOMIC);
846 event->mlxsw_env = mlxsw_env;
847 event->module = module;
848 INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
849 mlxsw_core_schedule_work(&event->work);
852 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
853 MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE);
856 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
858 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
860 if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
863 return mlxsw_core_trap_register(mlxsw_core,
864 &mlxsw_env_module_plug_listener,
869 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
871 if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
874 mlxsw_core_trap_unregister(mlxsw_env->core,
875 &mlxsw_env_module_plug_listener,
880 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core)
884 for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
885 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
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);
899 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
902 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
904 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
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);
913 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
915 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
917 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
919 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
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);
926 EXPORT_SYMBOL(mlxsw_env_module_port_map);
928 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
930 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
932 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
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);
939 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
941 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
943 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
946 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
949 mutex_lock(&mlxsw_env->module_info_lock);
951 if (mlxsw_env->module_info[module].power_mode_policy !=
952 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
955 if (mlxsw_env->module_info[module].num_ports_up != 0)
958 /* Transition to high power mode following first port using the module
959 * being put administratively up.
961 err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false,
967 mlxsw_env->module_info[module].num_ports_up++;
969 mutex_unlock(&mlxsw_env->module_info_lock);
972 EXPORT_SYMBOL(mlxsw_env_module_port_up);
974 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
976 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
978 if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
981 mutex_lock(&mlxsw_env->module_info_lock);
983 mlxsw_env->module_info[module].num_ports_up--;
985 if (mlxsw_env->module_info[module].power_mode_policy !=
986 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
989 if (mlxsw_env->module_info[module].num_ports_up != 0)
992 /* Transition to low power mode following last port using the module
993 * being put administratively down.
995 __mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL);
998 mutex_unlock(&mlxsw_env->module_info_lock);
1000 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1003 mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core)
1005 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1008 for (i = 0; i < mlxsw_env->module_count; i++) {
1009 char pmtm_pl[MLXSW_REG_PMTM_LEN];
1012 mlxsw_reg_pmtm_pack(pmtm_pl, 0, i);
1013 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
1017 mlxsw_env->module_info[i].type =
1018 mlxsw_reg_pmtm_module_type_get(pmtm_pl);
1024 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
1026 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1027 struct mlxsw_env *env;
1031 mlxsw_reg_mgpir_pack(mgpir_pl);
1032 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
1036 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count);
1038 env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL);
1042 /* Firmware defaults to high power mode policy where modules are
1043 * transitioned to high power mode following plug-in.
1045 for (i = 0; i < module_count; i++)
1046 env->module_info[i].power_mode_policy =
1047 ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
1049 mutex_init(&env->module_info_lock);
1050 env->core = mlxsw_core;
1051 env->module_count = module_count;
1054 err = mlxsw_env_temp_warn_event_register(mlxsw_core);
1056 goto err_temp_warn_event_register;
1058 err = mlxsw_env_module_plug_event_register(mlxsw_core);
1060 goto err_module_plug_event_register;
1062 err = mlxsw_env_module_oper_state_event_enable(mlxsw_core);
1064 goto err_oper_state_event_enable;
1066 err = mlxsw_env_module_temp_event_enable(mlxsw_core);
1068 goto err_temp_event_enable;
1070 err = mlxsw_env_module_type_set(mlxsw_core);
1077 err_temp_event_enable:
1078 err_oper_state_event_enable:
1079 mlxsw_env_module_plug_event_unregister(env);
1080 err_module_plug_event_register:
1081 mlxsw_env_temp_warn_event_unregister(env);
1082 err_temp_warn_event_register:
1083 mutex_destroy(&env->module_info_lock);
1088 void mlxsw_env_fini(struct mlxsw_env *env)
1090 mlxsw_env_module_plug_event_unregister(env);
1091 /* Make sure there is no more event work scheduled. */
1092 mlxsw_core_flush_owq();
1093 mlxsw_env_temp_warn_event_unregister(env);
1094 mutex_destroy(&env->module_info_lock);