mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 09:31:26 +00:00
Merge branch 'mlxsw-Expose-transceiver-overheat-counter'
Ido Schimmel says: ==================== mlxsw: Expose transceiver overheat counter Amit says: An overheated transceiver can be the root cause of various network problems such as link flapping. Counting the number of times a transceiver's temperature was higher than its configured threshold can therefore help in debugging such issues. This patch set exposes a transceiver overheat counter via ethtool. This is achieved by configuring the Spectrum ASIC to generate events whenever a transceiver is overheated. The temperature thresholds are queried from the transceiver (if available) and set to the default otherwise. Example: ... transceiver_overheat: 2 Patch set overview: Patches #1-#3 add required device registers Patches #4-#5 add required infrastructure in mlxsw to configure and count overheat events Patches #6-#9 gradually add support for the transceiver overheat counter Patch #10 exposes the transceiver overheat counter via ethtool ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7cd427e2f9
@ -26,6 +26,7 @@
|
||||
#include <trace/events/devlink.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "core_env.h"
|
||||
#include "item.h"
|
||||
#include "cmd.h"
|
||||
#include "port.h"
|
||||
@ -87,6 +88,8 @@ struct mlxsw_core {
|
||||
struct {
|
||||
struct devlink_health_reporter *fw_fatal;
|
||||
} health;
|
||||
struct mlxsw_env *env;
|
||||
bool is_initialized; /* Denotes if core was already initialized. */
|
||||
unsigned long driver_priv[];
|
||||
/* driver_priv has to be always the last item */
|
||||
};
|
||||
@ -133,6 +136,11 @@ bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core)
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_core_res_query_enabled);
|
||||
|
||||
bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
return mlxsw_core->driver->temp_warn_enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
|
||||
const struct mlxsw_fw_rev *req_rev)
|
||||
@ -1943,6 +1951,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
if (err)
|
||||
goto err_thermal_init;
|
||||
|
||||
err = mlxsw_env_init(mlxsw_core, &mlxsw_core->env);
|
||||
if (err)
|
||||
goto err_env_init;
|
||||
|
||||
mlxsw_core->is_initialized = true;
|
||||
devlink_params_publish(devlink);
|
||||
|
||||
if (!reload)
|
||||
@ -1950,6 +1963,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
|
||||
|
||||
return 0;
|
||||
|
||||
err_env_init:
|
||||
mlxsw_thermal_fini(mlxsw_core->thermal);
|
||||
err_thermal_init:
|
||||
mlxsw_hwmon_fini(mlxsw_core->hwmon);
|
||||
err_hwmon_init:
|
||||
@ -2026,6 +2041,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
|
||||
}
|
||||
|
||||
devlink_params_unpublish(devlink);
|
||||
mlxsw_core->is_initialized = false;
|
||||
mlxsw_env_fini(mlxsw_core->env);
|
||||
mlxsw_thermal_fini(mlxsw_core->thermal);
|
||||
mlxsw_hwmon_fini(mlxsw_core->hwmon);
|
||||
if (mlxsw_core->driver->fini)
|
||||
@ -2829,6 +2846,16 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
|
||||
|
||||
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
return mlxsw_core->env;
|
||||
}
|
||||
|
||||
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
return mlxsw_core->is_initialized;
|
||||
}
|
||||
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
enum mlxsw_reg_pmtm_module_type module_type;
|
||||
|
@ -32,6 +32,8 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core);
|
||||
|
||||
bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core);
|
||||
|
||||
bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core);
|
||||
|
||||
bool
|
||||
mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
|
||||
const struct mlxsw_fw_rev *req_rev);
|
||||
@ -221,6 +223,8 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
|
||||
struct devlink_port *
|
||||
mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
|
||||
u8 local_port);
|
||||
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core);
|
||||
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core);
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
|
||||
@ -371,6 +375,7 @@ struct mlxsw_driver {
|
||||
const struct mlxsw_config_profile *profile;
|
||||
bool res_query_enabled;
|
||||
bool fw_fatal_enabled;
|
||||
bool temp_warn_enabled;
|
||||
};
|
||||
|
||||
int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
|
||||
|
@ -10,6 +10,18 @@
|
||||
#include "item.h"
|
||||
#include "reg.h"
|
||||
|
||||
struct mlxsw_env_module_info {
|
||||
u64 module_overheat_counter;
|
||||
bool is_overheat;
|
||||
};
|
||||
|
||||
struct mlxsw_env {
|
||||
struct mlxsw_core *core;
|
||||
u8 module_count;
|
||||
spinlock_t module_info_lock; /* Protects 'module_info'. */
|
||||
struct mlxsw_env_module_info module_info[];
|
||||
};
|
||||
|
||||
static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
|
||||
bool *qsfp, bool *cmis)
|
||||
{
|
||||
@ -293,3 +305,359 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
|
||||
|
||||
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
|
||||
u8 module,
|
||||
bool *p_has_temp_sensor)
|
||||
{
|
||||
char mtbr_pl[MLXSW_REG_MTBR_LEN];
|
||||
u16 temp;
|
||||
int err;
|
||||
|
||||
mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
|
||||
1);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
|
||||
|
||||
switch (temp) {
|
||||
case MLXSW_REG_MTBR_BAD_SENS_INFO:
|
||||
case MLXSW_REG_MTBR_NO_CONN:
|
||||
case MLXSW_REG_MTBR_NO_TEMP_SENS:
|
||||
case MLXSW_REG_MTBR_INDEX_NA:
|
||||
*p_has_temp_sensor = false;
|
||||
break;
|
||||
default:
|
||||
*p_has_temp_sensor = temp ? true : false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core,
|
||||
u16 sensor_index, bool enable)
|
||||
{
|
||||
char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
|
||||
enum mlxsw_reg_mtmp_tee tee;
|
||||
int err, threshold_hi;
|
||||
|
||||
mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (enable) {
|
||||
err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
|
||||
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;
|
||||
|
||||
mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
|
||||
mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
|
||||
MLXSW_REG_MTMP_HYSTERESIS_TEMP);
|
||||
}
|
||||
tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
|
||||
mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
|
||||
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
|
||||
u8 module_count)
|
||||
{
|
||||
int i, err, sensor_index;
|
||||
bool has_temp_sensor;
|
||||
|
||||
for (i = 0; i < module_count; i++) {
|
||||
err = mlxsw_env_module_has_temp_sensor(mlxsw_core, 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, sensor_index, true);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
|
||||
char *mtwe_pl, void *priv)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = priv;
|
||||
int i, sensor_warning;
|
||||
bool is_overheat;
|
||||
|
||||
for (i = 0; i < mlxsw_env->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(mtwe_pl,
|
||||
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
|
||||
spin_lock(&mlxsw_env->module_info_lock);
|
||||
is_overheat =
|
||||
mlxsw_env->module_info[i].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.
|
||||
*/
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
continue;
|
||||
} else if (is_overheat && !sensor_warning) {
|
||||
/* MTWE reports "no warning", turn is_overheat off.
|
||||
*/
|
||||
mlxsw_env->module_info[i].is_overheat = false;
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
} else {
|
||||
/* Current state is "no warning" and MTWE reports
|
||||
* "warning", increase the counter and turn is_overheat
|
||||
* on.
|
||||
*/
|
||||
mlxsw_env->module_info[i].is_overheat = true;
|
||||
mlxsw_env->module_info[i].module_overheat_counter++;
|
||||
spin_unlock(&mlxsw_env->module_info_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
|
||||
MLXSW_EVENTL(mlxsw_env_mtwe_event_func, MTWE, MTWE);
|
||||
|
||||
static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
|
||||
return 0;
|
||||
|
||||
return mlxsw_core_trap_register(mlxsw_core,
|
||||
&mlxsw_env_temp_warn_listener,
|
||||
mlxsw_env);
|
||||
}
|
||||
|
||||
static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
|
||||
{
|
||||
if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
|
||||
return;
|
||||
|
||||
mlxsw_core_trap_unregister(mlxsw_env->core,
|
||||
&mlxsw_env_temp_warn_listener, mlxsw_env);
|
||||
}
|
||||
|
||||
struct mlxsw_env_module_plug_unplug_event {
|
||||
struct mlxsw_env *mlxsw_env;
|
||||
u8 module;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
static void mlxsw_env_pmpe_event_work(struct work_struct *work)
|
||||
{
|
||||
struct mlxsw_env_module_plug_unplug_event *event;
|
||||
struct mlxsw_env *mlxsw_env;
|
||||
bool has_temp_sensor;
|
||||
u16 sensor_index;
|
||||
int err;
|
||||
|
||||
event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
|
||||
work);
|
||||
mlxsw_env = event->mlxsw_env;
|
||||
|
||||
spin_lock_bh(&mlxsw_env->module_info_lock);
|
||||
mlxsw_env->module_info[event->module].is_overheat = false;
|
||||
spin_unlock_bh(&mlxsw_env->module_info_lock);
|
||||
|
||||
err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
|
||||
&has_temp_sensor);
|
||||
/* Do not disable events on modules without sensors or faulty sensors
|
||||
* because FW returns errors.
|
||||
*/
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!has_temp_sensor)
|
||||
goto out;
|
||||
|
||||
sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
|
||||
mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true);
|
||||
|
||||
out:
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
|
||||
void *priv)
|
||||
{
|
||||
struct mlxsw_env_module_plug_unplug_event *event;
|
||||
enum mlxsw_reg_pmpe_module_status module_status;
|
||||
u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
|
||||
struct mlxsw_env *mlxsw_env = priv;
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return;
|
||||
|
||||
module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
|
||||
if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
|
||||
return;
|
||||
|
||||
event = kmalloc(sizeof(*event), GFP_ATOMIC);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
event->mlxsw_env = mlxsw_env;
|
||||
event->module = module;
|
||||
INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
|
||||
mlxsw_core_schedule_work(&event->work);
|
||||
}
|
||||
|
||||
static const struct mlxsw_listener mlxsw_env_module_plug_listener =
|
||||
MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE);
|
||||
|
||||
static int
|
||||
mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
|
||||
return 0;
|
||||
|
||||
return mlxsw_core_trap_register(mlxsw_core,
|
||||
&mlxsw_env_module_plug_listener,
|
||||
mlxsw_env);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
|
||||
{
|
||||
if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
|
||||
return;
|
||||
|
||||
mlxsw_core_trap_unregister(mlxsw_env->core,
|
||||
&mlxsw_env_module_plug_listener,
|
||||
mlxsw_env);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
|
||||
u8 module_count)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < module_count; i++) {
|
||||
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
|
||||
|
||||
mlxsw_reg_pmaos_pack(pmaos_pl, i,
|
||||
MLXSW_REG_PMAOS_E_GENERATE_EVENT);
|
||||
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
u64 *p_counter)
|
||||
{
|
||||
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
|
||||
|
||||
/* Prevent switch driver from accessing uninitialized data. */
|
||||
if (!mlxsw_core_is_initialized(mlxsw_core)) {
|
||||
*p_counter = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_bh(&mlxsw_env->module_info_lock);
|
||||
*p_counter = mlxsw_env->module_info[module].module_overheat_counter;
|
||||
spin_unlock_bh(&mlxsw_env->module_info_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
|
||||
|
||||
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
|
||||
{
|
||||
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
|
||||
struct mlxsw_env *env;
|
||||
u8 module_count;
|
||||
int err;
|
||||
|
||||
mlxsw_reg_mgpir_pack(mgpir_pl);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count);
|
||||
|
||||
env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL);
|
||||
if (!env)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&env->module_info_lock);
|
||||
env->core = mlxsw_core;
|
||||
env->module_count = module_count;
|
||||
*p_env = env;
|
||||
|
||||
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;
|
||||
|
||||
err = mlxsw_env_module_oper_state_event_enable(mlxsw_core,
|
||||
env->module_count);
|
||||
if (err)
|
||||
goto err_oper_state_event_enable;
|
||||
|
||||
err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count);
|
||||
if (err)
|
||||
goto err_temp_event_enable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_temp_event_enable:
|
||||
err_oper_state_event_enable:
|
||||
mlxsw_env_module_plug_event_unregister(env);
|
||||
err_module_plug_event_register:
|
||||
mlxsw_env_temp_warn_event_unregister(env);
|
||||
err_temp_warn_event_register:
|
||||
kfree(env);
|
||||
return err;
|
||||
}
|
||||
|
||||
void mlxsw_env_fini(struct mlxsw_env *env)
|
||||
{
|
||||
mlxsw_env_module_plug_event_unregister(env);
|
||||
/* Make sure there is no more event work scheduled. */
|
||||
mlxsw_core_flush_owq();
|
||||
mlxsw_env_temp_warn_event_unregister(env);
|
||||
kfree(env);
|
||||
}
|
||||
|
@ -14,4 +14,10 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
|
||||
struct mlxsw_core *mlxsw_core, int module,
|
||||
struct ethtool_eeprom *ee, u8 *data);
|
||||
|
||||
int
|
||||
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
|
||||
u64 *p_counter);
|
||||
int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env);
|
||||
void mlxsw_env_fini(struct mlxsw_env *env);
|
||||
|
||||
#endif
|
||||
|
@ -106,7 +106,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
|
||||
struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
|
||||
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
|
||||
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
|
||||
char mtmp_pl[MLXSW_REG_MTMP_LEN];
|
||||
char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
|
||||
unsigned long val;
|
||||
int index;
|
||||
int err;
|
||||
@ -119,7 +119,13 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
|
||||
|
||||
index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
|
||||
mlxsw_hwmon->module_sensor_max);
|
||||
mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true);
|
||||
|
||||
mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index);
|
||||
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
|
||||
if (err)
|
||||
return err;
|
||||
mlxsw_reg_mtmp_mte_set(mtmp_pl, true);
|
||||
mlxsw_reg_mtmp_mtr_set(mtmp_pl, true);
|
||||
err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
|
||||
if (err) {
|
||||
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n");
|
||||
@ -570,7 +576,6 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
|
||||
static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
|
||||
{
|
||||
char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
|
||||
char mtmp_pl[MLXSW_REG_MTMP_LEN];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
@ -581,7 +586,15 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
|
||||
}
|
||||
mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
|
||||
for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
|
||||
mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true);
|
||||
char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
|
||||
|
||||
mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i);
|
||||
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp),
|
||||
mtmp_pl);
|
||||
if (err)
|
||||
return err;
|
||||
mlxsw_reg_mtmp_mte_set(mtmp_pl, true);
|
||||
mlxsw_reg_mtmp_mtr_set(mtmp_pl, true);
|
||||
err = mlxsw_reg_write(mlxsw_hwmon->core,
|
||||
MLXSW_REG(mtmp), mtmp_pl);
|
||||
if (err) {
|
||||
|
@ -5405,6 +5405,64 @@ static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port)
|
||||
mlxsw_reg_pspa_sub_port_set(payload, 0);
|
||||
}
|
||||
|
||||
/* PMAOS - Ports Module Administrative and Operational Status
|
||||
* ----------------------------------------------------------
|
||||
* This register configures and retrieves the per module status.
|
||||
*/
|
||||
#define MLXSW_REG_PMAOS_ID 0x5012
|
||||
#define MLXSW_REG_PMAOS_LEN 0x10
|
||||
|
||||
MLXSW_REG_DEFINE(pmaos, MLXSW_REG_PMAOS_ID, MLXSW_REG_PMAOS_LEN);
|
||||
|
||||
/* reg_slot_index
|
||||
* Slot index.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, slot_index, 0x00, 24, 4);
|
||||
|
||||
/* reg_pmaos_module
|
||||
* Module number.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, module, 0x00, 16, 8);
|
||||
|
||||
/* reg_pmaos_ase
|
||||
* Admin state update enable.
|
||||
* If this bit is set, admin state will be updated based on admin_state field.
|
||||
* Only relevant on Set() operations.
|
||||
* Access: WO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, ase, 0x04, 31, 1);
|
||||
|
||||
/* reg_pmaos_ee
|
||||
* Event update enable.
|
||||
* If this bit is set, event generation will be updated based on the e field.
|
||||
* Only relevant on Set operations.
|
||||
* Access: WO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, ee, 0x04, 30, 1);
|
||||
|
||||
enum mlxsw_reg_pmaos_e {
|
||||
MLXSW_REG_PMAOS_E_DO_NOT_GENERATE_EVENT,
|
||||
MLXSW_REG_PMAOS_E_GENERATE_EVENT,
|
||||
MLXSW_REG_PMAOS_E_GENERATE_SINGLE_EVENT,
|
||||
};
|
||||
|
||||
/* reg_pmaos_e
|
||||
* Event Generation on operational state change.
|
||||
* Access: RW
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmaos, e, 0x04, 0, 2);
|
||||
|
||||
static inline void mlxsw_reg_pmaos_pack(char *payload, u8 module,
|
||||
enum mlxsw_reg_pmaos_e e)
|
||||
{
|
||||
MLXSW_REG_ZERO(pmaos, payload);
|
||||
mlxsw_reg_pmaos_module_set(payload, module);
|
||||
mlxsw_reg_pmaos_e_set(payload, e);
|
||||
mlxsw_reg_pmaos_ee_set(payload, true);
|
||||
}
|
||||
|
||||
/* PPLR - Port Physical Loopback Register
|
||||
* --------------------------------------
|
||||
* This register allows configuration of the port's loopback mode.
|
||||
@ -5441,6 +5499,50 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port,
|
||||
MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0);
|
||||
}
|
||||
|
||||
/* PMPE - Port Module Plug/Unplug Event Register
|
||||
* ---------------------------------------------
|
||||
* This register reports any operational status change of a module.
|
||||
* A change in the module’s state will generate an event only if the change
|
||||
* happens after arming the event mechanism. Any changes to the module state
|
||||
* while the event mechanism is not armed will not be reported. Software can
|
||||
* query the PMPE register for module status.
|
||||
*/
|
||||
#define MLXSW_REG_PMPE_ID 0x5024
|
||||
#define MLXSW_REG_PMPE_LEN 0x10
|
||||
|
||||
MLXSW_REG_DEFINE(pmpe, MLXSW_REG_PMPE_ID, MLXSW_REG_PMPE_LEN);
|
||||
|
||||
/* reg_pmpe_slot_index
|
||||
* Slot index.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmpe, slot_index, 0x00, 24, 4);
|
||||
|
||||
/* reg_pmpe_module
|
||||
* Module number.
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmpe, module, 0x00, 16, 8);
|
||||
|
||||
enum mlxsw_reg_pmpe_module_status {
|
||||
MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED = 1,
|
||||
MLXSW_REG_PMPE_MODULE_STATUS_UNPLUGGED,
|
||||
MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ERROR,
|
||||
MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_DISABLED,
|
||||
};
|
||||
|
||||
/* reg_pmpe_module_status
|
||||
* Module status.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmpe, module_status, 0x00, 0, 4);
|
||||
|
||||
/* reg_pmpe_error_type
|
||||
* Module error details.
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pmpe, error_type, 0x04, 8, 4);
|
||||
|
||||
/* PDDR - Port Diagnostics Database Register
|
||||
* -----------------------------------------
|
||||
* The PDDR enables to read the Phy debug database
|
||||
@ -5580,6 +5682,8 @@ MLXSW_ITEM32(reg, htgt, type, 0x00, 8, 4);
|
||||
enum mlxsw_reg_htgt_trap_group {
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_MFDE,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_MTWE,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_PMPE,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,
|
||||
MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,
|
||||
@ -8413,6 +8517,13 @@ MLXSW_ITEM32(reg, mtmp, max_temperature, 0x08, 0, 16);
|
||||
* 2 - Generate single event
|
||||
* Access: RW
|
||||
*/
|
||||
|
||||
enum mlxsw_reg_mtmp_tee {
|
||||
MLXSW_REG_MTMP_TEE_NO_EVENT,
|
||||
MLXSW_REG_MTMP_TEE_GENERATE_EVENT,
|
||||
MLXSW_REG_MTMP_TEE_GENERATE_SINGLE_EVENT,
|
||||
};
|
||||
|
||||
MLXSW_ITEM32(reg, mtmp, tee, 0x0C, 30, 2);
|
||||
|
||||
#define MLXSW_REG_MTMP_THRESH_HI 0x348 /* 105 Celsius */
|
||||
@ -8423,6 +8534,7 @@ MLXSW_ITEM32(reg, mtmp, tee, 0x0C, 30, 2);
|
||||
*/
|
||||
MLXSW_ITEM32(reg, mtmp, temperature_threshold_hi, 0x0C, 0, 16);
|
||||
|
||||
#define MLXSW_REG_MTMP_HYSTERESIS_TEMP 0x28 /* 5 Celsius */
|
||||
/* reg_mtmp_temperature_threshold_lo
|
||||
* Low threshold for Temperature Warning Event. In 0.125 Celsius.
|
||||
* Access: RW
|
||||
@ -8466,6 +8578,23 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp,
|
||||
mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name);
|
||||
}
|
||||
|
||||
/* MTWE - Management Temperature Warning Event
|
||||
* -------------------------------------------
|
||||
* This register is used for over temperature warning.
|
||||
*/
|
||||
#define MLXSW_REG_MTWE_ID 0x900B
|
||||
#define MLXSW_REG_MTWE_LEN 0x10
|
||||
|
||||
MLXSW_REG_DEFINE(mtwe, MLXSW_REG_MTWE_ID, MLXSW_REG_MTWE_LEN);
|
||||
|
||||
/* reg_mtwe_sensor_warning
|
||||
* Bit vector indicating which of the sensor reading is above threshold.
|
||||
* Address 00h bit31 is sensor_warning[127].
|
||||
* Address 0Ch bit0 is sensor_warning[0].
|
||||
* Access: RO
|
||||
*/
|
||||
MLXSW_ITEM_BIT_ARRAY(reg, mtwe, sensor_warning, 0x0, 0x10, 1);
|
||||
|
||||
/* MTBR - Management Temperature Bulk Register
|
||||
* -------------------------------------------
|
||||
* This register is used for bulk temperature reading.
|
||||
@ -11041,7 +11170,9 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
|
||||
MLXSW_REG(pptb),
|
||||
MLXSW_REG(pbmc),
|
||||
MLXSW_REG(pspa),
|
||||
MLXSW_REG(pmaos),
|
||||
MLXSW_REG(pplr),
|
||||
MLXSW_REG(pmpe),
|
||||
MLXSW_REG(pddr),
|
||||
MLXSW_REG(pmtm),
|
||||
MLXSW_REG(htgt),
|
||||
@ -11071,6 +11202,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
|
||||
MLXSW_REG(fore),
|
||||
MLXSW_REG(mtcap),
|
||||
MLXSW_REG(mtmp),
|
||||
MLXSW_REG(mtwe),
|
||||
MLXSW_REG(mtbr),
|
||||
MLXSW_REG(mcia),
|
||||
MLXSW_REG(mpat),
|
||||
|
@ -1365,6 +1365,22 @@ static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
u8 module = mlxsw_sp_port->mapping.module;
|
||||
u64 overheat_counter;
|
||||
int err;
|
||||
|
||||
err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, module,
|
||||
&overheat_counter);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_sp_port->module_overheat_initial_val = overheat_counter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
u8 split_base_local_port,
|
||||
struct mlxsw_sp_port_mapping *port_mapping)
|
||||
@ -1575,6 +1591,14 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
mlxsw_sp->ptp_ops->shaper_work);
|
||||
|
||||
mlxsw_sp->ports[local_port] = mlxsw_sp_port;
|
||||
|
||||
err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n",
|
||||
mlxsw_sp_port->local_port);
|
||||
goto err_port_overheat_init_val_set;
|
||||
}
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n",
|
||||
@ -1588,6 +1612,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
|
||||
return 0;
|
||||
|
||||
err_register_netdev:
|
||||
err_port_overheat_init_val_set:
|
||||
mlxsw_sp->ports[local_port] = NULL;
|
||||
mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
|
||||
err_port_vlan_create:
|
||||
@ -2440,6 +2465,22 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
|
||||
MLXSW_REG_HTGT_INVALID_POLICER,
|
||||
MLXSW_REG_HTGT_DEFAULT_PRIORITY,
|
||||
MLXSW_REG_HTGT_DEFAULT_TC);
|
||||
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_MTWE,
|
||||
MLXSW_REG_HTGT_INVALID_POLICER,
|
||||
MLXSW_REG_HTGT_DEFAULT_PRIORITY,
|
||||
MLXSW_REG_HTGT_DEFAULT_TC);
|
||||
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_PMPE,
|
||||
MLXSW_REG_HTGT_INVALID_POLICER,
|
||||
MLXSW_REG_HTGT_DEFAULT_PRIORITY,
|
||||
MLXSW_REG_HTGT_DEFAULT_TC);
|
||||
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
|
||||
}
|
||||
|
||||
@ -3197,6 +3238,7 @@ static struct mlxsw_driver mlxsw_sp1_driver = {
|
||||
.profile = &mlxsw_sp1_config_profile,
|
||||
.res_query_enabled = true,
|
||||
.fw_fatal_enabled = true,
|
||||
.temp_warn_enabled = true,
|
||||
};
|
||||
|
||||
static struct mlxsw_driver mlxsw_sp2_driver = {
|
||||
@ -3237,6 +3279,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
|
||||
.profile = &mlxsw_sp2_config_profile,
|
||||
.res_query_enabled = true,
|
||||
.fw_fatal_enabled = true,
|
||||
.temp_warn_enabled = true,
|
||||
};
|
||||
|
||||
static struct mlxsw_driver mlxsw_sp3_driver = {
|
||||
@ -3277,6 +3320,7 @@ static struct mlxsw_driver mlxsw_sp3_driver = {
|
||||
.profile = &mlxsw_sp2_config_profile,
|
||||
.res_query_enabled = true,
|
||||
.fw_fatal_enabled = true,
|
||||
.temp_warn_enabled = true,
|
||||
};
|
||||
|
||||
bool mlxsw_sp_port_dev_check(const struct net_device *dev)
|
||||
|
@ -319,6 +319,7 @@ struct mlxsw_sp_port {
|
||||
int max_mtu;
|
||||
u32 max_speed;
|
||||
struct mlxsw_sp_hdroom *hdroom;
|
||||
u64 module_overheat_initial_val;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_port_type_speed_ops {
|
||||
|
@ -2,6 +2,7 @@
|
||||
/* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
|
||||
|
||||
#include "reg.h"
|
||||
#include "core.h"
|
||||
#include "spectrum.h"
|
||||
#include "core_env.h"
|
||||
|
||||
@ -552,6 +553,37 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
|
||||
|
||||
#define MLXSW_SP_PORT_HW_TC_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_hw_tc_stats)
|
||||
|
||||
struct mlxsw_sp_port_stats {
|
||||
char str[ETH_GSTRING_LEN];
|
||||
u64 (*getter)(struct mlxsw_sp_port *mlxsw_sp_port);
|
||||
};
|
||||
|
||||
static u64
|
||||
mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
struct mlxsw_sp_port_mapping port_mapping = mlxsw_sp_port->mapping;
|
||||
struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core;
|
||||
u64 stats;
|
||||
int err;
|
||||
|
||||
err = mlxsw_env_module_overheat_counter_get(mlxsw_core,
|
||||
port_mapping.module,
|
||||
&stats);
|
||||
if (err)
|
||||
return mlxsw_sp_port->module_overheat_initial_val;
|
||||
|
||||
return stats - mlxsw_sp_port->module_overheat_initial_val;
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_port_stats mlxsw_sp_port_transceiver_stats[] = {
|
||||
{
|
||||
.str = "transceiver_overheat",
|
||||
.getter = mlxsw_sp_port_get_transceiver_overheat_stats,
|
||||
},
|
||||
};
|
||||
|
||||
#define MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN ARRAY_SIZE(mlxsw_sp_port_transceiver_stats)
|
||||
|
||||
#define MLXSW_SP_PORT_ETHTOOL_STATS_LEN (MLXSW_SP_PORT_HW_STATS_LEN + \
|
||||
MLXSW_SP_PORT_HW_RFC_2863_STATS_LEN + \
|
||||
MLXSW_SP_PORT_HW_RFC_2819_STATS_LEN + \
|
||||
@ -561,7 +593,8 @@ static struct mlxsw_sp_port_hw_stats mlxsw_sp_port_hw_tc_stats[] = {
|
||||
(MLXSW_SP_PORT_HW_PRIO_STATS_LEN * \
|
||||
IEEE_8021QAZ_MAX_TCS) + \
|
||||
(MLXSW_SP_PORT_HW_TC_STATS_LEN * \
|
||||
TC_MAX_QUEUE))
|
||||
TC_MAX_QUEUE) + \
|
||||
MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN)
|
||||
|
||||
static void mlxsw_sp_port_get_prio_strings(u8 **p, int prio)
|
||||
{
|
||||
@ -637,6 +670,12 @@ static void mlxsw_sp_port_get_strings(struct net_device *dev,
|
||||
mlxsw_sp_port_get_tc_strings(&p, i);
|
||||
|
||||
mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_strings(&p);
|
||||
|
||||
for (i = 0; i < MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN; i++) {
|
||||
memcpy(p, mlxsw_sp_port_transceiver_stats[i].str,
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -732,6 +771,17 @@ static void __mlxsw_sp_port_get_stats(struct net_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void __mlxsw_sp_port_get_env_stats(struct net_device *dev, u64 *data, int data_index,
|
||||
struct mlxsw_sp_port_stats *port_stats,
|
||||
int len)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
data[data_index + i] = port_stats[i].getter(mlxsw_sp_port);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_port_get_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
@ -786,6 +836,11 @@ static void mlxsw_sp_port_get_stats(struct net_device *dev,
|
||||
mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats(mlxsw_sp_port,
|
||||
data, data_index);
|
||||
data_index += mlxsw_sp_port->mlxsw_sp->ptp_ops->get_stats_count();
|
||||
|
||||
/* Transceiver counters */
|
||||
__mlxsw_sp_port_get_env_stats(dev, data, data_index, mlxsw_sp_port_transceiver_stats,
|
||||
MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN);
|
||||
data_index += MLXSW_SP_PORT_HW_TRANSCEIVER_STATS_LEN;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_get_sset_count(struct net_device *dev, int sset)
|
||||
|
@ -124,6 +124,10 @@ enum mlxsw_event_trap_id {
|
||||
MLXSW_TRAP_ID_MFDE = 0x3,
|
||||
/* Port Up/Down event generated by hardware */
|
||||
MLXSW_TRAP_ID_PUDE = 0x8,
|
||||
/* Port Module Plug/Unplug Event generated by hardware */
|
||||
MLXSW_TRAP_ID_PMPE = 0x9,
|
||||
/* Temperature Warning event generated by hardware */
|
||||
MLXSW_TRAP_ID_MTWE = 0xC,
|
||||
/* PTP Ingress FIFO has a new entry */
|
||||
MLXSW_TRAP_ID_PTP_ING_FIFO = 0x2D,
|
||||
/* PTP Egress FIFO has a new entry */
|
||||
|
Loading…
Reference in New Issue
Block a user