diff --git a/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch b/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch new file mode 100644 index 000000000000..f980053dde5d --- /dev/null +++ b/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch @@ -0,0 +1,86 @@ +From 3d4e440640d63c5bc599a4ad6802ad84dcd0c329 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 10 Jul 2019 17:47:56 +0000 +Subject: [PATCH v1 backport] mlxsw: core: Skip port split entries in hwmon + subsystem + +Skip split entries in hwmon. +Run loop for port creation over maximum port counter, otherwise +in some split configuration with holes, some last modules can be +missed. + +Signed-of-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 7 ++++++- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 5 +++-- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index a414a09efb5d..95b890298952 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -512,9 +512,9 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + { + unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); ++ u8 width, module, last_module = module_count; + char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; + int i, index; +- u8 width; + int err; + + if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) +@@ -538,6 +538,11 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + width = mlxsw_reg_pmlp_width_get(pmlp_pl); + if (!width) + continue; ++ module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); ++ /* Skip, if port belongs to the cluster */ ++ if (module == last_module) ++ continue; ++ last_module = module; + mlxsw_hwmon_attr_add(mlxsw_hwmon, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, + index); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 499c82cea1cb..e9451e447bf0 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -906,7 +906,7 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) + int i; + + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); /*Remove*/ ++ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 5290993ff93f..0aa3abc974ff 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -264,7 +264,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + } + + /* Create port objects for each valid entry */ +- for (i = 0; i < mlxsw_m->max_ports; i++) { ++ for (i = 0; i < max_ports; i++) { + if (mlxsw_m->module_to_port[i] > 0) { + err = mlxsw_m_port_create(mlxsw_m, + mlxsw_m->module_to_port[i], +@@ -294,9 +294,10 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + + static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) + { ++ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); + int i; + +- for (i = 0; i < mlxsw_m->max_ports; i++) { ++ for (i = 0; i < max_ports; i++) { + if (mlxsw_m->module_to_port[i] > 0) { + mlxsw_m_port_remove(mlxsw_m, + mlxsw_m->module_to_port[i]); +-- +2.11.0 + diff --git a/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch b/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch new file mode 100644 index 000000000000..60b9fc4cde8b --- /dev/null +++ b/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch @@ -0,0 +1,1181 @@ +From e68ab2e54837ba9a84e439c933b1e909270fa739 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 7 Aug 2019 04:50:34 +0000 +Subject: [PATCH 5.3 backport 1/3] mellanox: platform: Backporting Melanox + drivers from v5.3 + +This patch is required for new Mellanox systems and also contains +bugfixes. + +Patch contains backporting for the next drivers: +drivers/net/ethernet/mellanox/mlxsw/mlxsw_minimal; +drivers/platform/x86/mlx-platform; +drivers/platform/mellanox/mlxreg-hotplug; +drivers/hwmon/mlxreg-fan; + +Signed-off-by: Vadim Pasternak +--- + drivers/hwmon/mlxreg-fan.c | 52 ++- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 45 ++- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 71 ++--- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 20 +- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 14 +- + drivers/platform/mellanox/mlxreg-hotplug.c | 1 + + drivers/platform/x86/mlx-platform.c | 352 ++++++++++++++++----- + 7 files changed, 389 insertions(+), 166 deletions(-) + +diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c +index 30d2c467b274..7028a4f497b0 100644 +--- a/drivers/hwmon/mlxreg-fan.c ++++ b/drivers/hwmon/mlxreg-fan.c +@@ -27,10 +27,9 @@ + #define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) + #define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ + #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 +-#define MLXREG_FAN_TACHO_DIVIDER_MIN 283 +-#define MLXREG_FAN_TACHO_DIVIDER_DEF (MLXREG_FAN_TACHO_DIVIDER_MIN \ +- * 4) +-#define MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX 32 ++#define MLXREG_FAN_TACHO_DIV_MIN 283 ++#define MLXREG_FAN_TACHO_DIV_DEF (MLXREG_FAN_TACHO_DIV_MIN * 4) ++#define MLXREG_FAN_TACHO_DIV_SCALE_MAX 64 + /* + * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. + * The logic in a programmable device measures the time t-high by sampling the +@@ -364,8 +363,7 @@ static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { + }; + + static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, +- struct mlxreg_core_data *data, +- bool *connected) ++ struct mlxreg_core_data *data) + { + u32 regval; + int err; +@@ -377,9 +375,7 @@ static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, + return err; + } + +- *connected = (regval & data->bit) ? true : false; +- +- return 0; ++ return !!(regval & data->bit); + } + + static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, +@@ -399,10 +395,10 @@ static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, + * Set divider value according to the capability register, in case it + * contains valid value. Otherwise use default value. The purpose of + * this validation is to protect against the old hardware, in which +- * this register can be un-initialized. ++ * this register can return zero. + */ +- if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX) +- fan->divider = regval * MLXREG_FAN_TACHO_DIVIDER_MIN; ++ if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX) ++ fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN; + + return 0; + } +@@ -411,12 +407,12 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + struct mlxreg_core_platform_data *pdata) + { + struct mlxreg_core_data *data = pdata->data; +- bool configured = false, connected = false; ++ bool configured = false; + int tacho_num = 0, i; + int err; + + fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; +- fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; ++ fan->divider = MLXREG_FAN_TACHO_DIV_DEF; + for (i = 0; i < pdata->counter; i++, data++) { + if (strnstr(data->label, "tacho", sizeof(data->label))) { + if (tacho_num == MLXREG_FAN_MAX_TACHO) { +@@ -426,11 +422,10 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + } + + if (data->capability) { +- err = mlxreg_fan_connect_verify(fan, data, +- &connected); +- if (err) ++ err = mlxreg_fan_connect_verify(fan, data); ++ if (err < 0) + return err; +- if (!connected) { ++ else if (!err) { + tacho_num++; + continue; + } +@@ -464,8 +459,10 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + if (err) + return err; + } else { +- fan->samples = data->mask; +- fan->divider = data->bit; ++ if (data->mask) ++ fan->samples = data->mask; ++ if (data->bit) ++ fan->divider = data->bit; + } + configured = true; + } else { +@@ -486,21 +483,22 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + static int mlxreg_fan_probe(struct platform_device *pdev) + { + struct mlxreg_core_platform_data *pdata; ++ struct device *dev = &pdev->dev; + struct mlxreg_fan *fan; + struct device *hwm; + int err; + +- pdata = dev_get_platdata(&pdev->dev); ++ pdata = dev_get_platdata(dev); + if (!pdata) { +- dev_err(&pdev->dev, "Failed to get platform data.\n"); ++ dev_err(dev, "Failed to get platform data.\n"); + return -EINVAL; + } + +- fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); ++ fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL); + if (!fan) + return -ENOMEM; + +- fan->dev = &pdev->dev; ++ fan->dev = dev; + fan->regmap = pdata->regmap; + platform_set_drvdata(pdev, fan); + +@@ -508,12 +506,12 @@ static int mlxreg_fan_probe(struct platform_device *pdev) + if (err) + return err; + +- hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", ++ hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan", + fan, + &mlxreg_fan_hwmon_chip_info, + NULL); + if (IS_ERR(hwm)) { +- dev_err(&pdev->dev, "Failed to register hwmon device\n"); ++ dev_err(dev, "Failed to register hwmon device\n"); + return PTR_ERR(hwm); + } + +@@ -521,7 +519,7 @@ static int mlxreg_fan_probe(struct platform_device *pdev) + fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, + &mlxreg_fan_cooling_ops); + if (IS_ERR(fan->cdev)) { +- dev_err(&pdev->dev, "Failed to register cooling device\n"); ++ dev_err(dev, "Failed to register cooling device\n"); + return PTR_ERR(fan->cdev); + } + } +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 95b890298952..5bd08650e0fc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -52,8 +52,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + 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]; +- unsigned int temp; +- int index; ++ int temp, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, +@@ -65,7 +64,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + return err; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); +- return sprintf(buf, "%u\n", temp); ++ return sprintf(buf, "%d\n", temp); + } + + static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, +@@ -76,8 +75,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + 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]; +- unsigned int temp_max; +- int index; ++ int temp_max, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, +@@ -89,7 +87,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + return err; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL); +- return sprintf(buf, "%u\n", temp_max); ++ return sprintf(buf, "%d\n", temp_max); + } + + static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, +@@ -215,8 +213,8 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, + 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]; +- unsigned int temp; + u8 module; ++ int temp; + int err; + + module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +@@ -227,7 +225,7 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, + return err; + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + +- return sprintf(buf, "%u\n", temp); ++ return sprintf(buf, "%d\n", temp); + } + + static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, +@@ -237,18 +235,37 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(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 mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; + u8 module, fault; ++ u16 temp; + int err; + + module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- false, false); +- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +- if (err) ++ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, ++ 1); ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); ++ if (err) { ++ dev_err(dev, "Failed to query module temperature sensor\n"); ++ return err; ++ } ++ ++ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); ++ ++ /* Update status and temperature cache. */ ++ switch (temp) { ++ case MLXSW_REG_MTBR_BAD_SENS_INFO: ++ /* Untrusted cable is connected. Reading temperature from its ++ * sensor is faulty. ++ */ + fault = 1; +- else ++ break; ++ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ ++ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ ++ case MLXSW_REG_MTBR_INDEX_NA: ++ default: + fault = 0; ++ break; ++ } + + return sprintf(buf, "%u\n", fault); + } +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index e9451e447bf0..8051b62af38a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -98,7 +98,7 @@ struct mlxsw_thermal_module { + struct thermal_zone_device *tzdev; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + enum thermal_device_mode mode; +- int module; ++ int module; /* Module or gearbox number */ + }; + + struct mlxsw_thermal { +@@ -111,9 +111,10 @@ struct mlxsw_thermal { + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + enum thermal_device_mode mode; + struct mlxsw_thermal_module *tz_module_arr; +- unsigned int tz_module_num; + struct mlxsw_thermal_module *tz_gearbox_arr; + u8 tz_gearbox_num; ++ unsigned int tz_highest_score; ++ struct thermal_zone_device *tz_highest_dev; + }; + + static inline u8 mlxsw_state_to_duty(int state) +@@ -282,7 +283,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + struct mlxsw_thermal *thermal = tzdev->devdata; + struct device *dev = thermal->bus_info->dev; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp; ++ int temp; + int err; + + mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); +@@ -294,7 +295,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + +- *p_temp = (int) temp; ++ *p_temp = temp; + return 0; + } + +@@ -453,7 +454,7 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + struct mlxsw_thermal *thermal = tz->parent; + struct device *dev = thermal->bus_info->dev; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp; ++ int temp; + int err; + + /* Read module temperature. */ +@@ -461,21 +462,22 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + tz->module, false, false); + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +- dev_err(dev, "Failed to query temp sensor\n"); ++ /* Do not return error - in case of broken module's sensor ++ * it will cause error message flooding. ++ */ + temp = 0; + *p_temp = (int) temp; + return 0; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ *p_temp = temp; + +- if (temp) { +- err = mlxsw_thermal_module_trips_update(dev, thermal->core, +- tz); +- if (err) +- return err; +- } ++ if (!temp) ++ return 0; ++ ++ /* Update trip points. */ ++ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz); + +- *p_temp = (int) temp; + return 0; + } + +@@ -539,10 +541,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, + return 0; + } + +-static struct thermal_zone_params mlxsw_thermal_module_params = { +- .governor_name = "user_space", +-}; +- + static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { + .bind = mlxsw_thermal_module_bind, + .unbind = mlxsw_thermal_module_unbind, +@@ -562,8 +560,8 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + struct mlxsw_thermal_module *tz = tzdev->devdata; + struct mlxsw_thermal *thermal = tz->parent; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp; + u16 index; ++ int temp; + int err; + + index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; +@@ -575,7 +573,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + +- *p_temp = (int) temp; ++ *p_temp = temp; + return 0; + } + +@@ -592,10 +590,6 @@ static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { + .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, + }; + +-static struct thermal_zone_params mlxsw_thermal_gearbox_params = { +- .governor_name = "user_space", +-}; +- + static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *p_state) + { +@@ -709,13 +703,13 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + MLXSW_THERMAL_TRIP_MASK, + module_tz, + &mlxsw_thermal_module_ops, +- &mlxsw_thermal_module_params, +- 0, 0); ++ NULL, 0, 0); + if (IS_ERR(module_tz->tzdev)) { + err = PTR_ERR(module_tz->tzdev); + return err; + } + ++ module_tz->mode = THERMAL_DEVICE_DISABLED; + return 0; + } + +@@ -754,13 +748,7 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, + /* Initialize all trip point. */ + mlxsw_thermal_module_trips_reset(module_tz); + /* Update trip point according to the module data. */ +- err = mlxsw_thermal_module_trips_update(dev, core, module_tz); +- if (err) +- return err; +- +- thermal->tz_module_num++; +- +- return 0; ++ return mlxsw_thermal_module_trips_update(dev, core, module_tz); + } + + static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) +@@ -831,7 +819,6 @@ static int + mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + { + char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; +- int err; + + snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", + gearbox_tz->module + 1); +@@ -840,13 +827,11 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + MLXSW_THERMAL_TRIP_MASK, + gearbox_tz, + &mlxsw_thermal_gearbox_ops, +- &mlxsw_thermal_gearbox_params, +- 0, 0); +- if (IS_ERR(gearbox_tz->tzdev)) { +- err = PTR_ERR(gearbox_tz->tzdev); +- return err; +- } ++ NULL, 0, 0); ++ if (IS_ERR(gearbox_tz->tzdev)) ++ return PTR_ERR(gearbox_tz->tzdev); + ++ gearbox_tz->mode = THERMAL_DEVICE_DISABLED; + return 0; + } + +@@ -865,6 +850,9 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + int i; + int err; + ++ if (!mlxsw_core_res_query_enabled(core)) ++ return 0; ++ + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +@@ -905,6 +893,9 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) + { + int i; + ++ if (!mlxsw_core_res_query_enabled(thermal->core)) ++ return; ++ + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +@@ -1000,7 +991,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_unreg_tzdev; + +- mlxsw_thermal_gearboxes_init(dev, core, thermal); ++ err = mlxsw_thermal_gearboxes_init(dev, core, thermal); + if (err) + goto err_unreg_modules_tzdev; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index 08c774875d1e..e04d521d9376 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -383,7 +383,6 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, + + mlxsw_i2c_write_exit: + kfree(tran_buf); +- + return err; + } + +@@ -567,12 +566,21 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + if (!mlxsw_i2c) + return -ENOMEM; + +- if (quirks) +- mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, +- min_t(u16, quirks->max_read_len, +- quirks->max_write_len)); +- else ++ if (quirks) { ++ if ((quirks->max_read_len && ++ quirks->max_read_len < MLXSW_I2C_BLK_DEF) || ++ (quirks->max_write_len && ++ quirks->max_write_len < MLXSW_I2C_BLK_DEF)) { ++ dev_err(&client->dev, "Insufficient transaction buffer length\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, ++ min_t(u16, quirks->max_read_len, ++ quirks->max_write_len)); ++ } else { + mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF; ++ } + + i2c_set_clientdata(client, mlxsw_i2c); + mutex_init(&mlxsw_i2c->cmd.lock); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index eb58940d2e9c..31296d888fb8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -7603,7 +7603,10 @@ MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); + MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12); + + /* Convert to milli degrees Celsius */ +-#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) ++#define MLXSW_REG_MTMP_TEMP_TO_MC(val) ({ typeof(val) v_ = (val); \ ++ ((v_) >= 0) ? ((v_) * 125) : \ ++ ((s16)((GENMASK(15, 0) + (v_) + 1) \ ++ * 125)); }) + + /* reg_mtmp_temperature + * Temperature reading from the sensor. Reading is in 0.125 Celsius +@@ -7674,11 +7677,10 @@ static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, + MLXSW_REG_MTMP_THRESH_HI); + } + +-static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, +- unsigned int *p_max_temp, +- char *sensor_name) ++static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp, ++ int *p_max_temp, char *sensor_name) + { +- u16 temp; ++ s16 temp; + + if (p_temp) { + temp = mlxsw_reg_mtmp_temperature_get(payload); +@@ -7738,7 +7740,7 @@ MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, + MLXSW_ITEM32_INDEXED(reg, mtbr, rec_temp, MLXSW_REG_MTBR_BASE_LEN, 0, 16, + MLXSW_REG_MTBR_REC_LEN, 0x00, false); + +-static inline void mlxsw_reg_mtbr_pack(char *payload, u8 base_sensor_index, ++static inline void mlxsw_reg_mtbr_pack(char *payload, u16 base_sensor_index, + u8 num_rec) + { + MLXSW_REG_ZERO(mtbr, payload); +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index 687ce6817d0d..f85a1b9d129b 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -694,6 +694,7 @@ static int mlxreg_hotplug_remove(struct platform_device *pdev) + + /* Clean interrupts setup. */ + mlxreg_hotplug_unset_irq(priv); ++ devm_free_irq(&pdev->dev, priv->irq, priv); + + return 0; + } +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index d5d2448dc7e4..c3e75b26fe0b 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -44,6 +44,10 @@ + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 ++#define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 ++#define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 ++#define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 ++#define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 + #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 + #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 + #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 +@@ -105,7 +109,9 @@ + MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) + #define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 + #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 +-#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 ++#define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) ++#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xe1 ++#define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) + #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) +@@ -114,6 +120,12 @@ + #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) + ++/* Masks for aggregation for comex carriers */ ++#define MLXPLAT_CPLD_AGGR_MASK_CARRIER BIT(1) ++#define MLXPLAT_CPLD_AGGR_MASK_CARR_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ ++ MLXPLAT_CPLD_AGGR_MASK_CARRIER) ++#define MLXPLAT_CPLD_LOW_AGGRCX_MASK 0xc1 ++ + /* Default I2C parent bus number */ + #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 + +@@ -159,6 +171,7 @@ + * @pdev_io_regs - register access platform devices + * @pdev_fan - FAN platform devices + * @pdev_wd - array of watchdog platform devices ++ * @regmap: device register map + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -168,6 +181,7 @@ struct mlxplat_priv { + struct platform_device *pdev_io_regs; + struct platform_device *pdev_fan; + struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; ++ void *regmap; + }; + + /* Regions for LPC I2C controller and LPC base register space */ +@@ -181,6 +195,14 @@ static const struct resource mlxplat_lpc_resources[] = { + IORESOURCE_IO), + }; + ++/* Platform next generation systems i2c data */ ++static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, ++}; ++ + /* Platform default channels */ + static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { + { +@@ -262,6 +284,22 @@ static struct i2c_board_info mlxplat_mlxcpld_fan[] = { + }, + }; + ++/* Platform hotplug comex carrier system family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_comex_psu_items_data[] = { ++ { ++ .label = "psu1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "psu2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ + /* Platform hotplug default data */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { + { +@@ -376,6 +414,45 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { + }, + }; + ++static struct mlxreg_core_item mlxplat_mlxcpld_comex_items[] = { ++ { ++ .data = mlxplat_mlxcpld_comex_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, ++}; ++ + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .items = mlxplat_mlxcpld_default_items, +@@ -386,6 +463,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { ++ .items = mlxplat_mlxcpld_comex_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_CARR_DEF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGRCX_MASK, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { + { + .label = "pwr1", +@@ -704,7 +791,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .items = mlxplat_mlxcpld_default_ng_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, +- .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; +@@ -1113,6 +1200,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { + .mode = 0444, + }, + { ++ .label = "reset_sff_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), +@@ -1201,6 +1294,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mode = 0444, + }, + { ++ .label = "reset_from_asic", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_swb_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { + .label = "reset_asic_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), +@@ -1213,6 +1318,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mode = 0444, + }, + { ++ .label = "reset_comex_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { + .label = "reset_voltmon_upgrade_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), +@@ -1225,6 +1336,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mode = 0444, + }, + { ++ .label = "reset_comex_thermal", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_reload_bios", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), +@@ -1531,6 +1654,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: +@@ -1578,6 +1702,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: +@@ -1645,6 +1771,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: +@@ -1691,6 +1819,17 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { + { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, + }; + ++static const struct reg_default mlxplat_mlxcpld_regmap_ng[] = { ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, ++}; ++ ++static const struct reg_default mlxplat_mlxcpld_regmap_comex_default[] = { ++ { MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET, ++ MLXPLAT_CPLD_LOW_AGGRCX_MASK }, ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++}; ++ + struct mlxplat_mlxcpld_regmap_context { + void __iomem *base; + }; +@@ -1729,17 +1868,47 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = { + .reg_write = mlxplat_mlxcpld_reg_write, + }; + ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 255, ++ .cache_type = REGCACHE_FLAT, ++ .writeable_reg = mlxplat_mlxcpld_writeable_reg, ++ .readable_reg = mlxplat_mlxcpld_readable_reg, ++ .volatile_reg = mlxplat_mlxcpld_volatile_reg, ++ .reg_defaults = mlxplat_mlxcpld_regmap_ng, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_comex = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 255, ++ .cache_type = REGCACHE_FLAT, ++ .writeable_reg = mlxplat_mlxcpld_writeable_reg, ++ .readable_reg = mlxplat_mlxcpld_readable_reg, ++ .volatile_reg = mlxplat_mlxcpld_volatile_reg, ++ .reg_defaults = mlxplat_mlxcpld_regmap_comex_default, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_comex_default), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ + static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), + }; + + static struct platform_device *mlxplat_dev; ++static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c; + static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; + static struct mlxreg_core_platform_data *mlxplat_led; + static struct mlxreg_core_platform_data *mlxplat_regs_io; + static struct mlxreg_core_platform_data *mlxplat_fan; + static struct mlxreg_core_platform_data + *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; ++static const struct regmap_config *mlxplat_regmap_config; + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { +@@ -1834,12 +2003,76 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; ++ ++ return 1; ++}; ++ ++static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { ++ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; ++ mlxplat_mux_data[i].n_values = ++ ARRAY_SIZE(mlxplat_msn21xx_channels); ++ } ++ mlxplat_hotplug = &mlxplat_mlxcpld_comex_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ mlxplat_led = &mlxplat_default_led_data; ++ mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_fan = &mlxplat_default_fan_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; + + return 1; + }; + + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { ++ .callback = mlxplat_dmi_default_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn21xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn274x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn201x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_qmb7xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_qmb7xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_comex_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), ++ }, ++ }, ++ { + .callback = mlxplat_dmi_msn274x_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), +@@ -1916,42 +2149,6 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), + }, + }, +- { +- .callback = mlxplat_dmi_default_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn21xx_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn274x_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn201x_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), +- }, +- }, +- { +- .callback = mlxplat_dmi_qmb7xx_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), +- }, +- }, +- { +- .callback = mlxplat_dmi_qmb7xx_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), +- }, +- }, + { } + }; + +@@ -2018,13 +2215,36 @@ static int __init mlxplat_init(void) + } + platform_set_drvdata(mlxplat_dev, priv); + ++ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, ++ mlxplat_lpc_resources[1].start, 1); ++ if (!mlxplat_mlxcpld_regmap_ctx.base) { ++ err = -ENOMEM; ++ goto fail_alloc; ++ } ++ ++ if (!mlxplat_regmap_config) ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; ++ ++ priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, ++ &mlxplat_mlxcpld_regmap_ctx, ++ mlxplat_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ err = PTR_ERR(priv->regmap); ++ goto fail_alloc; ++ } ++ + err = mlxplat_mlxcpld_verify_bus_topology(&nr); + if (nr < 0) + goto fail_alloc; + + nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; +- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, +- NULL, 0); ++ if (mlxplat_i2c) ++ mlxplat_i2c->regmap = priv->regmap; ++ priv->pdev_i2c = platform_device_register_resndata( ++ &mlxplat_dev->dev, "i2c_mlxcpld", ++ nr, mlxplat_mlxcpld_resources, ++ ARRAY_SIZE(mlxplat_mlxcpld_resources), ++ mlxplat_i2c, sizeof(*mlxplat_i2c)); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); + goto fail_alloc; +@@ -2032,7 +2252,7 @@ static int __init mlxplat_init(void) + + for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { + priv->pdev_mux[i] = platform_device_register_resndata( +- &mlxplat_dev->dev, ++ &priv->pdev_i2c->dev, + "i2c-mux-reg", i, NULL, + 0, &mlxplat_mux_data[i], + sizeof(mlxplat_mux_data[i])); +@@ -2042,21 +2262,8 @@ static int __init mlxplat_init(void) + } + } + +- mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, +- mlxplat_lpc_resources[1].start, 1); +- if (!mlxplat_mlxcpld_regmap_ctx.base) { +- err = -ENOMEM; +- goto fail_platform_mux_register; +- } +- +- mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, +- &mlxplat_mlxcpld_regmap_ctx, +- &mlxplat_mlxcpld_regmap_config); +- if (IS_ERR(mlxplat_hotplug->regmap)) { +- err = PTR_ERR(mlxplat_hotplug->regmap); +- goto fail_platform_mux_register; +- } +- ++ /* Add hotplug driver */ ++ mlxplat_hotplug->regmap = priv->regmap; + priv->pdev_hotplug = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-hotplug", + PLATFORM_DEVID_NONE, +@@ -2069,16 +2276,16 @@ static int __init mlxplat_init(void) + } + + /* Set default registers. */ +- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { +- err = regmap_write(mlxplat_hotplug->regmap, +- mlxplat_mlxcpld_regmap_default[j].reg, +- mlxplat_mlxcpld_regmap_default[j].def); ++ for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) { ++ err = regmap_write(priv->regmap, ++ mlxplat_regmap_config->reg_defaults[j].reg, ++ mlxplat_regmap_config->reg_defaults[j].def); + if (err) + goto fail_platform_mux_register; + } + + /* Add LED driver. */ +- mlxplat_led->regmap = mlxplat_hotplug->regmap; ++ mlxplat_led->regmap = priv->regmap; + priv->pdev_led = platform_device_register_resndata( + &mlxplat_dev->dev, "leds-mlxreg", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -2090,7 +2297,7 @@ static int __init mlxplat_init(void) + + /* Add registers io access driver. */ + if (mlxplat_regs_io) { +- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; ++ mlxplat_regs_io->regmap = priv->regmap; + priv->pdev_io_regs = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -2104,7 +2311,7 @@ static int __init mlxplat_init(void) + + /* Add FAN driver. */ + if (mlxplat_fan) { +- mlxplat_fan->regmap = mlxplat_hotplug->regmap; ++ mlxplat_fan->regmap = priv->regmap; + priv->pdev_fan = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -2119,10 +2326,10 @@ static int __init mlxplat_init(void) + /* Add WD drivers. */ + for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { + if (mlxplat_wd_data[j]) { +- mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; +- priv->pdev_wd[j] = platform_device_register_resndata +- (&mlxplat_dev->dev, +- "mlx-wdt", j, NULL, 0, ++ mlxplat_wd_data[j]->regmap = priv->regmap; ++ priv->pdev_wd[j] = platform_device_register_resndata( ++ &mlxplat_dev->dev, "mlx-wdt", ++ j, NULL, 0, + mlxplat_wd_data[j], + sizeof(*mlxplat_wd_data[j])); + if (IS_ERR(priv->pdev_wd[j])) { +@@ -2133,18 +2340,16 @@ static int __init mlxplat_init(void) + } + + /* Sync registers with hardware. */ +- regcache_mark_dirty(mlxplat_hotplug->regmap); +- err = regcache_sync(mlxplat_hotplug->regmap); ++ regcache_mark_dirty(priv->regmap); ++ err = regcache_sync(priv->regmap); + if (err) + goto fail_platform_wd_register; + + return 0; + + fail_platform_wd_register: +- while (--j >= 0) { +- if (priv->pdev_wd[j]) +- platform_device_unregister(priv->pdev_wd[j]); +- } ++ while (--j >= 0) ++ platform_device_unregister(priv->pdev_wd[j]); + if (mlxplat_fan) + platform_device_unregister(priv->pdev_fan); + fail_platform_io_regs_register: +@@ -2180,6 +2385,7 @@ static void __exit mlxplat_exit(void) + platform_device_unregister(priv->pdev_io_regs); + platform_device_unregister(priv->pdev_led); + platform_device_unregister(priv->pdev_hotplug); ++ + for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_mux[i]); + +-- +2.11.0 + diff --git a/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch b/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch new file mode 100644 index 000000000000..2c02518f3e73 --- /dev/null +++ b/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch @@ -0,0 +1,530 @@ +From 1a2d774224abf9536be53031f476a1d0411b7f63 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 7 Aug 2019 09:57:18 +0000 +Subject: [PATCH 5.3 backport 2/3] mlxsw: minimal: Provide optimization for + module number detection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use new filed ‘num_of_modules’ in MGPIR register in order to get +the number of modules supported by system directly from system +configuration, instead of getting it from port to module mapping info. + +Taking this info through MGPIR register is faster and also does not +depend on possible dynamic re-configuration of ports. +In case of port dynamic re-configuration some modules can logically +“disappeared” or “appeared” as a result of port split and un-spilt +operations, which can cause missing of some modules, in case this info +is taken from port to module mapping info. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 55 +++++------ + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 44 +++++---- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 104 +++++---------------- + drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 41 ++++++-- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 23 +++-- + 5 files changed, 112 insertions(+), 155 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 5bd08650e0fc..9cb19ec47e4d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -528,56 +528,47 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + + static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + { +- unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); +- u8 width, module, last_module = module_count; +- char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; +- int i, index; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ int index, i; + int err; + + if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) + return 0; + ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_hwmon->module_sensor_count); ++ if (!mlxsw_hwmon->module_sensor_count) ++ return 0; ++ + /* Add extra attributes for module temperature. Sensor index is + * assigned to sensor_count value, while all indexed before + * sensor_count are already utilized by the sensors connected through + * mtmp register by mlxsw_hwmon_temp_init(). + */ +- index = mlxsw_hwmon->sensor_count; +- for (i = 1; i < module_count; i++) { +- mlxsw_reg_pmlp_pack(pmlp_pl, i); +- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp), +- pmlp_pl); +- if (err) { +- dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n", +- i); +- return err; +- } +- width = mlxsw_reg_pmlp_width_get(pmlp_pl); +- if (!width) +- continue; +- module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); +- /* Skip, if port belongs to the cluster */ +- if (module == last_module) +- continue; +- last_module = module; ++ index = mlxsw_hwmon->sensor_count + mlxsw_hwmon->module_sensor_count; ++ mlxsw_hwmon->module_sensor_count += mlxsw_hwmon->sensor_count; ++ for (i = mlxsw_hwmon->sensor_count; ++ i < mlxsw_hwmon->module_sensor_count; i++) { + mlxsw_hwmon_attr_add(mlxsw_hwmon, +- MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, +- index); ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); + mlxsw_hwmon_attr_add(mlxsw_hwmon, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, +- index, index); ++ i, i); + mlxsw_hwmon_attr_add(mlxsw_hwmon, +- MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, +- index, index); ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, ++ i); + mlxsw_hwmon_attr_add(mlxsw_hwmon, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, +- index, index); ++ i, i); + mlxsw_hwmon_attr_add(mlxsw_hwmon, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, +- index, index); +- index++; ++ i, i); + } +- mlxsw_hwmon->module_sensor_count = index; + + return 0; + } +@@ -595,7 +586,7 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + if (err) + return 0; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); + if (!gbox_num) + return 0; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 8051b62af38a..17a340aa9f75 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -111,6 +111,7 @@ struct mlxsw_thermal { + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + enum thermal_device_mode mode; + struct mlxsw_thermal_module *tz_module_arr; ++ u8 tz_module_num; + struct mlxsw_thermal_module *tz_gearbox_arr; + u8 tz_gearbox_num; + unsigned int tz_highest_score; +@@ -720,23 +721,10 @@ static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) + + static int + mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal, u8 local_port) ++ struct mlxsw_thermal *thermal, u8 module) + { + struct mlxsw_thermal_module *module_tz; +- char pmlp_pl[MLXSW_REG_PMLP_LEN]; +- u8 width, module; +- int err; +- +- mlxsw_reg_pmlp_pack(pmlp_pl, local_port); +- err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl); +- if (err) +- return err; + +- width = mlxsw_reg_pmlp_width_get(pmlp_pl); +- if (!width) +- return 0; +- +- module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); + module_tz = &thermal->tz_module_arr[module]; + /* Skip if parent is already set (case of port split). */ + if (module_tz->parent) +@@ -764,26 +752,36 @@ static int + mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + struct mlxsw_thermal *thermal) + { +- unsigned int module_count = mlxsw_core_max_ports(core); ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + struct mlxsw_thermal_module *module_tz; + int i, err; + + if (!mlxsw_core_res_query_enabled(core)) + return 0; + +- thermal->tz_module_arr = kcalloc(module_count, ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &thermal->tz_module_num); ++ if (!thermal->tz_module_num) ++ return 0; ++ ++ thermal->tz_module_arr = kcalloc(thermal->tz_module_num, + sizeof(*thermal->tz_module_arr), + GFP_KERNEL); + if (!thermal->tz_module_arr) + return -ENOMEM; + +- for (i = 1; i < module_count; i++) { ++ for (i = 0; i < thermal->tz_module_num; i++) { + err = mlxsw_thermal_module_init(dev, core, thermal, i); + if (err) + goto err_unreg_tz_module_arr; + } + +- for (i = 0; i < module_count - 1; i++) { ++ for (i = 0; i < thermal->tz_module_num; i++) { + module_tz = &thermal->tz_module_arr[i]; + if (!module_tz->parent) + continue; +@@ -795,7 +793,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + return 0; + + err_unreg_tz_module_arr: +- for (i = module_count - 1; i >= 0; i--) ++ for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); + return err; +@@ -804,13 +802,12 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + static void + mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) + { +- unsigned int module_count = mlxsw_core_max_ports(thermal->core); + int i; + + if (!mlxsw_core_res_query_enabled(thermal->core)) + return; + +- for (i = module_count - 1; i >= 0; i--) ++ for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); + } +@@ -858,7 +855,8 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + if (err) + return 0; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, ++ NULL); + if (!thermal->tz_gearbox_num) + return 0; + +@@ -995,7 +993,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_unreg_modules_tzdev; + +- thermal->mode = THERMAL_DEVICE_ENABLED; ++ thermal->mode = THERMAL_DEVICE_DISABLED; + *p_thermal = thermal; + return 0; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 0aa3abc974ff..564b85c06a9a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -89,23 +89,6 @@ static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { + }; + + static int +-mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u8 local_port, +- u8 *p_module, u8 *p_width) +-{ +- char pmlp_pl[MLXSW_REG_PMLP_LEN]; +- int err; +- +- mlxsw_reg_pmlp_pack(pmlp_pl, local_port); +- err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl); +- if (err) +- return err; +- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); +- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); +- +- return 0; +-} +- +-static int + mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) + { + struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; +@@ -158,7 +141,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + mlxsw_m_port = netdev_priv(dev); + mlxsw_m_port->dev = dev; + mlxsw_m_port->mlxsw_m = mlxsw_m; +- mlxsw_m_port->local_port = local_port; ++ mlxsw_m_port->local_port = module; + mlxsw_m_port->module = module; + + dev->netdev_ops = &mlxsw_m_port_netdev_ops; +@@ -205,87 +188,48 @@ static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) + mlxsw_core_port_fini(mlxsw_m->core, local_port); + } + +-static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, +- u8 *last_module) ++static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + { +- u8 module, width; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ int i; + int err; + +- /* Fill out to local port mapping array */ +- err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, +- &width); ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- if (!width) ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_m->max_ports); ++ if (!mlxsw_m->max_ports) + return 0; +- /* Skip, if port belongs to the cluster */ +- if (module == *last_module) +- return 0; +- *last_module = module; +- mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports; +- +- return 0; +-} + +-static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) +-{ +- mlxsw_m->module_to_port[module] = -1; +-} +- +-static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) +-{ +- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); +- u8 last_module = max_ports; +- int i; +- int err; +- +- mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports), ++ mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports), + GFP_KERNEL); + if (!mlxsw_m->ports) + return -ENOMEM; + +- mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int), ++ mlxsw_m->module_to_port = kmalloc_array(mlxsw_m->max_ports, sizeof(int), + GFP_KERNEL); + if (!mlxsw_m->module_to_port) { + err = -ENOMEM; + goto err_module_to_port_alloc; + } + +- /* Invalidate the entries of module to local port mapping array */ +- for (i = 0; i < max_ports; i++) +- mlxsw_m->module_to_port[i] = -1; +- +- /* Fill out module to local port mapping array */ +- for (i = 1; i < max_ports; i++) { +- err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); +- if (err) +- goto err_module_to_port_map; +- } +- + /* Create port objects for each valid entry */ +- for (i = 0; i < max_ports; i++) { +- if (mlxsw_m->module_to_port[i] > 0) { +- err = mlxsw_m_port_create(mlxsw_m, +- mlxsw_m->module_to_port[i], +- i); +- if (err) +- goto err_module_to_port_create; +- } ++ for (i = 0; i < mlxsw_m->max_ports; i++) { ++ mlxsw_m->module_to_port[i] = i; ++ err = mlxsw_m_port_create(mlxsw_m, mlxsw_m->module_to_port[i], ++ i); ++ if (err) ++ goto err_module_to_port_create; + } + + return 0; + + err_module_to_port_create: +- for (i--; i >= 0; i--) { +- if (mlxsw_m->module_to_port[i] > 0) +- mlxsw_m_port_remove(mlxsw_m, +- mlxsw_m->module_to_port[i]); +- } +- i = max_ports; +-err_module_to_port_map: +- for (i--; i > 0; i--) +- mlxsw_m_port_module_unmap(mlxsw_m, i); ++ for (i--; i >= 0; i--) ++ mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); + kfree(mlxsw_m->module_to_port); + err_module_to_port_alloc: + kfree(mlxsw_m->ports); +@@ -294,16 +238,10 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + + static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) + { +- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); + int i; + +- for (i = 0; i < max_ports; i++) { +- if (mlxsw_m->module_to_port[i] > 0) { +- mlxsw_m_port_remove(mlxsw_m, +- mlxsw_m->module_to_port[i]); +- mlxsw_m_port_module_unmap(mlxsw_m, i); +- } +- } ++ for (i = 0; i < mlxsw_m->max_ports; i++) ++ mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); + + kfree(mlxsw_m->module_to_port); + kfree(mlxsw_m->ports); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +index fdf2b796e724..49563a703d75 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +@@ -279,16 +279,36 @@ static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { + }; + MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); + ++static int mlxsw_qsfp_set_module_num(struct mlxsw_qsfp *mlxsw_qsfp) ++{ ++ char pmlp_pl[MLXSW_REG_PMLP_LEN]; ++ u8 width; ++ int i, err; ++ ++ for (i = 1; i <= mlxsw_qsfp_num; i++) { ++ mlxsw_reg_pmlp_pack(pmlp_pl, i); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), ++ pmlp_pl); ++ if (err) ++ return err; ++ width = mlxsw_reg_pmlp_width_get(pmlp_pl); ++ if (!width) ++ continue; ++ mlxsw_qsfp->module_count++; ++ } ++ ++ return 0; ++} ++ + int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct mlxsw_qsfp **p_qsfp) + { + struct device_attribute *dev_attr, *cpld_dev_attr; +- char pmlp_pl[MLXSW_REG_PMLP_LEN]; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + struct mlxsw_qsfp *mlxsw_qsfp; + struct bin_attribute *eeprom; + int i, count; +- u8 width; + int err; + + if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) +@@ -305,16 +325,17 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + mlxsw_qsfp->bus_info = mlxsw_bus_info; + mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; + +- for (i = 1; i <= mlxsw_qsfp_num; i++) { +- mlxsw_reg_pmlp_pack(pmlp_pl, i); +- err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), +- pmlp_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) { ++ err = mlxsw_qsfp_set_module_num(mlxsw_qsfp); + if (err) + return err; +- width = mlxsw_reg_pmlp_width_get(pmlp_pl); +- if (!width) +- continue; +- mlxsw_qsfp->module_count++; ++ } else { ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_qsfp->module_count); ++ if (!mlxsw_qsfp->module_count) ++ return 0; + } + + count = mlxsw_qsfp->module_count + 1; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 31296d888fb8..a8cd53f068ce 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8593,6 +8593,11 @@ static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, + + MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN); + ++enum mlxsw_reg_mgpir_device_type { ++ MLXSW_REG_MGPIR_DEVICE_TYPE_NONE, ++ MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, ++}; ++ + /* device_type + * Access: RO + */ +@@ -8610,19 +8615,21 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + +-enum mlxsw_reg_mgpir_device_type { +- MLXSW_REG_MGPIR_TYPE_NONE, +- MLXSW_REG_MGPIR_TYPE_GEARBOX_DIE, +-}; ++/* num_of_modules ++ * Number of modules. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, num_of_modules, 0x04, 0, 8); + + static inline void mlxsw_reg_mgpir_pack(char *payload) + { + MLXSW_REG_ZERO(mgpir, payload); + } + +-static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, +- u8 *device_type, +- u8 *devices_per_flash) ++static inline void ++mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, ++ enum mlxsw_reg_mgpir_device_type *device_type, ++ u8 *devices_per_flash, u8 *num_of_modules) + { + if (num_of_devices) + *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); +@@ -8631,6 +8638,8 @@ static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + if (devices_per_flash) + *devices_per_flash = + mlxsw_reg_mgpir_devices_per_flash_get(payload); ++ if (num_of_modules) ++ *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); + } + + /* TNGCR - Tunneling NVE General Configuration Register +-- +2.11.0 + diff --git a/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch b/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch new file mode 100644 index 000000000000..0b6a7fd6cc49 --- /dev/null +++ b/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch @@ -0,0 +1,109 @@ +From 3b3986744bb9fb8635adf13575534f271fa58676 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 11 Aug 2019 07:00:03 +0000 +Subject: [PATCH v1 1/1] mlxsw: minimal: Add validation for FW version + +Add validation for FW version in order to prevent driver initialization +in case FW version is older than expected. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 17 +++++++++-------- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 25 +++++++++++++++++++++++++ + 2 files changed, 34 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 9a74ae8beb43..a127e0b01e4e 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -987,6 +987,12 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + goto err_devlink_register; + } + ++ if (mlxsw_driver->init) { ++ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); ++ if (err) ++ goto err_driver_init; ++ } ++ + err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); + if (err) + goto err_hwmon_init; +@@ -1001,21 +1007,16 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (err) + goto err_qsfp_init; + +- if (mlxsw_driver->init) { +- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); +- if (err) +- goto err_driver_init; +- } +- + return 0; + +-err_driver_init: +- mlxsw_qsfp_fini(mlxsw_core->qsfp); + err_qsfp_init: + mlxsw_thermal_fini(mlxsw_core->thermal); + err_thermal_init: + mlxsw_hwmon_fini(mlxsw_core->hwmon); + err_hwmon_init: ++ if (mlxsw_core->driver->fini) ++ mlxsw_core->driver->fini(mlxsw_core); ++err_driver_init: + if (!reload) + devlink_unregister(devlink); + err_devlink_register: +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 564b85c06a9a..504db124ee2f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -17,6 +17,9 @@ + + static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; + ++#define MLXSW_M_FWREV_MINOR 2000 ++#define MLXSW_M_FWREV_SUBMINOR 1886 ++ + struct mlxsw_m_port; + + struct mlxsw_m { +@@ -117,6 +120,24 @@ static void mlxsw_m_port_switchdev_fini(struct mlxsw_m_port *mlxsw_m_port) + { + } + ++static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) ++{ ++ const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; ++ ++ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d\n", ++ rev->major, rev->minor, rev->subminor); ++ /* Validate driver & FW are compatible */ ++ if (rev->minor >= MLXSW_M_FWREV_MINOR && ++ rev->subminor >= MLXSW_M_FWREV_SUBMINOR) ++ return 0; ++ ++ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", ++ rev->major, rev->minor, rev->subminor, rev->major, ++ MLXSW_M_FWREV_MINOR, MLXSW_M_FWREV_SUBMINOR); ++ ++ return -EINVAL; ++} ++ + static int + mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + { +@@ -256,6 +277,10 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + mlxsw_m->core = mlxsw_core; + mlxsw_m->bus_info = mlxsw_bus_info; + ++ err = mlxsw_m_fw_rev_validate(mlxsw_m); ++ if (err) ++ return err; ++ + err = mlxsw_m_ports_create(mlxsw_m); + if (err) { + dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); +-- +2.11.0 + diff --git a/patch/series b/patch/series index 5be0eb129e49..9adc27bd1286 100755 --- a/patch/series +++ b/patch/series @@ -77,6 +77,10 @@ linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch 0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch 0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch 0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch +0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch +0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch +0044-mlxsw-minimal-Provide-optimization-for-module-number.patch +0045-mlxsw-minimal-Add-validation-for-FW-version.patch linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch mellanox-backport-introduce-psample-a-new-genetlink-channel.patch mellanox-backport-introduce-tc-sample-action.patch