/* Validate if threshold reading is available through MTMP register, * otherwise fallback to read through MCIA.
*/ if (module_emerg) {
*temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg; return 0;
}
/* Read Free Side Device Temperature Thresholds from page 03h * (MSB at lower byte address). * Bytes: * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM); * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM); * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN); * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
*/
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n"); return -EIO;
}
err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
netdev_err(netdev, "EEPROM is not equipped on port module type"); return err;
}
switch (module_id) { case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
module_rev_id >=
MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
} else {
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
} break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: /* Verify if transceiver provides diagnostic monitoring page */
err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index,
module, SFP_DIAGMON, 1,
&diag_mon, false,
&read_size); if (err) return err;
if (read_size < 1) return -EIO;
modinfo->type = ETH_MODULE_SFF_8472; if (diag_mon)
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; else
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP: /* Use SFF_8636 as base type. ethtool should recognize specific * type through the identifier value.
*/
modinfo->type = ETH_MODULE_SFF_8636; /* Verify if module EEPROM is a flat memory. In case of flat * memory only page 00h (0-255 bytes) can be read. Otherwise * upper pages 01h and 02h can also be read. Upper pages 10h * and 11h are currently not supported by the driver.
*/ if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] &
MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY)
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; else
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; break; default: return -EINVAL;
}
int mlxsw_env_get_module_eeprom(struct net_device *netdev, struct mlxsw_core *mlxsw_core, u8 slot_index, int module, struct ethtool_eeprom *ee,
u8 *data)
{ struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); int offset = ee->offset; unsignedint read_size; bool qsfp, cmis; int i = 0; int err;
if (!ee->len) return -EINVAL;
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n"); return -EIO;
}
while (i < ee->len) {
err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index,
module, offset,
ee->len - i, data + i,
qsfp, &read_size); if (err) {
netdev_err(netdev, "Eeprom query failed\n"); return err;
}
switch (status) { case MLXSW_REG_MCIA_STATUS_GOOD: return 0; case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM"); return -EIO; case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device"); return -EOPNOTSUPP; case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
NL_SET_ERR_MSG_MOD(extack, "No module present indication"); return -EIO; case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C"); return -EIO; case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
NL_SET_ERR_MSG_MOD(extack, "Module is disabled"); return -EIO; default:
NL_SET_ERR_MSG_MOD(extack, "Unknown error"); return -EIO;
}
}
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
NL_SET_ERR_MSG_MOD(extack, "Cannot read EEPROM of module on an inactive line card"); return -EIO;
}
err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type"); return err;
}
/* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
device_addr = page->offset;
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
NL_SET_ERR_MSG_MOD(extack, "Cannot write to EEPROM of a module on an inactive line card"); return -EIO;
}
err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type"); return err;
}
if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
netdev_err(netdev, "Cannot reset module on an inactive line card\n"); return -EIO;
}
mutex_lock(&mlxsw_env->line_cards_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
netdev_err(netdev, "Reset module is not supported on port module type\n"); goto out;
}
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); if (module_info->num_ports_up) {
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
err = -EINVAL; goto out;
}
if (module_info->num_ports_mapped > 1 &&
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
err = -EINVAL; goto out;
}
err = mlxsw_env_module_reset(mlxsw_core, slot_index, module); if (err) {
netdev_err(netdev, "Failed to reset module\n"); goto out;
}
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type"); goto out;
}
/* Avoid accessing an inactive line card, as it will result in an error. * Cached configuration will be applied by mlxsw_env_got_active() when * line card becomes active.
*/ if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) return 0;
err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to disable module"); return err;
}
err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
low_power); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode"); goto err_module_low_power_set;
}
err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to enable module"); goto err_module_enable_set;
}
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Power mode set is not supported on port module type"); goto out;
}
if (enable) {
err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
slot_index,
sensor_index -
MLXSW_REG_MTMP_MODULE_INDEX_MIN,
SFP_TEMP_HIGH_WARN,
&threshold_hi); /* In case it is not possible to query the module's threshold, * use the default value.
*/ if (err)
threshold_hi = MLXSW_REG_MTMP_THRESH_HI; else /* mlxsw_env_module_temp_thresholds_get() multiplies * Celsius degrees by 1000 whereas MTMP expects * temperature in 0.125 Celsius degrees units. * Convert threshold_hi to correct units.
*/
threshold_hi = threshold_hi / 1000 * 8;
staticint mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
u8 slot_index)
{ struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); int i, err, sensor_index; bool has_temp_sensor;
for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index,
i, &has_temp_sensor); if (err) return err;
if (!has_temp_sensor) continue;
sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
err = mlxsw_env_temp_event_set(mlxsw_core, slot_index,
sensor_index, true); if (err) return err;
}
for (i = 0; i < mlxsw_env->max_module_count; i++) { /* 64-127 of sensor_index are mapped to the port modules * sequentially (module 0 is mapped to sensor_index 64, * module 1 to sensor_index 65 and so on)
*/
sensor_warning =
mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
mutex_lock(&mlxsw_env->line_cards_lock); /* MTWE only supports main board. */
module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i);
is_overheat = module_info->is_overheat;
if ((is_overheat && sensor_warning) ||
(!is_overheat && !sensor_warning)) { /* Current state is "warning" and MTWE still reports * warning OR current state in "no warning" and MTWE * does not report warning.
*/
mutex_unlock(&mlxsw_env->line_cards_lock); continue;
} elseif (is_overheat && !sensor_warning) { /* MTWE reports "no warning", turn is_overheat off.
*/
module_info->is_overheat = false;
mutex_unlock(&mlxsw_env->line_cards_lock);
} else { /* Current state is "no warning" and MTWE reports * "warning", increase the counter and turn is_overheat * on.
*/
module_info->is_overheat = true;
module_info->module_overheat_counter++;
mutex_unlock(&mlxsw_env->line_cards_lock);
}
}
err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
event->slot_index,
event->module,
&has_temp_sensor); /* Do not disable events on modules without sensors or faulty sensors * because FW returns errors.
*/ if (err) goto out;
/* Transition to high power mode following first port using the module * being put administratively up.
*/
err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, false, NULL); if (err) goto out_unlock;
if (module_info->power_mode_policy !=
ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) goto out_unlock;
if (module_info->num_ports_up != 0) goto out_unlock;
/* Transition to low power mode following last port using the module * being put administratively down.
*/
__mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true,
NULL);
staticint mlxsw_env_line_cards_alloc(struct mlxsw_env *env)
{ struct mlxsw_env_module_info *module_info; int i, j;
for (i = 0; i < env->num_of_slots; i++) {
env->line_cards[i] = kzalloc(struct_size(env->line_cards[i],
module_info,
env->max_module_count),
GFP_KERNEL); if (!env->line_cards[i]) goto kzalloc_err;
/* Firmware defaults to high power mode policy where modules * are transitioned to high power mode following plug-in.
*/ for (j = 0; j < env->max_module_count; j++) {
module_info = &env->line_cards[i]->module_info[j];
module_info->power_mode_policy =
ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
}
}
return 0;
kzalloc_err: for (i--; i >= 0; i--)
kfree(env->line_cards[i]); return -ENOMEM;
}
staticvoid mlxsw_env_line_cards_free(struct mlxsw_env *env)
{ int i = env->num_of_slots;
for (i--; i >= 0; i--)
kfree(env->line_cards[i]);
}
staticint
mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index)
{ int err;
err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core,
slot_index); if (err) return err;
err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index); if (err) return err;
for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) { struct mlxsw_env_module_info *module_info; char pmtm_pl[MLXSW_REG_PMTM_LEN]; int err;
for (i = 0; i < env->line_cards[slot_index]->module_count; i++) { enum ethtool_module_power_mode_policy policy; struct mlxsw_env_module_info *module_info; struct netlink_ext_ack extack; int err;
module_info = &env->line_cards[slot_index]->module_info[i];
policy = module_info->power_mode_policy;
err = mlxsw_env_set_module_power_mode_apply(mlxsw_core,
slot_index, i,
policy, &extack); if (err)
dev_err(env->bus_info->dev, "%s\n", extack._msg);
}
}
err = mlxsw_env_module_event_enable(mlxsw_env, slot_index); if (err) {
dev_err(mlxsw_env->bus_info->dev, "Failed to enable port module events for line card in slot %d\n",
slot_index); goto err_mlxsw_env_module_event_enable;
}
err = mlxsw_env_module_type_set(mlxsw_env->core, slot_index); if (err) {
dev_err(mlxsw_env->bus_info->dev, "Failed to set modules' type for line card in slot %d\n",
slot_index); goto err_type_set;
}
mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
&num_of_slots); /* If the system is modular, get the maximum number of modules per-slot. * Otherwise, get the maximum number of modules on the main board.
*/
max_module_count = num_of_slots ?
mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
module_count;
err = mlxsw_linecards_event_ops_register(env->core,
&mlxsw_env_event_ops, env); if (err) goto err_linecards_event_ops_register;
err = mlxsw_env_temp_warn_event_register(mlxsw_core); if (err) goto err_temp_warn_event_register;
err = mlxsw_env_module_plug_event_register(mlxsw_core); if (err) goto err_module_plug_event_register;
/* Set 'module_count' only for main board. Actual count for line card * is to be set after line card is activated.
*/
env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; /* Enable events only for main board. Line card events are to be * configured only after line card is activated. Before that, access to * modules on line cards is not allowed.
*/
err = mlxsw_env_module_event_enable(env, 0); if (err) goto err_mlxsw_env_module_event_enable;
err = mlxsw_env_module_type_set(mlxsw_core, 0); if (err) goto err_type_set;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.