Skip to content

Commit

Permalink
Merge branch 'mlxsw-Query-number-of-modules-from-firmware'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
mlxsw: Query number of modules from firmware

Vadim says:

The patchset adds support for a new field "num_of_modules" of Management
General Peripheral Information Register (MGPIR), providing the maximum
number of QSFP modules, which can be supported by the system.

It allows to obtain the number of QSFP modules directly from this field,
as a static data, instead of old method of getting this info through
"network port to QSFP module" mapping. With the old method, in case of
port dynamic re-configuration some modules can logically "disappear" as
a result of port split operations, which can cause some modules to
appear missing.

Such scenario can happen on a system equipped with a BMC card, while PCI
chip driver at host CPU side can perform some ports "split" or "unsplit"
operations, while BMC side I2C chip driver reads the "port-to-module"
mapping.

Add common API for FW "minor" and "subminor" versions validation and
share it between PCI and I2C based drivers.

Add FW version validation for "minimal" driver, because use of new field
"num_of_modules" in MGPIR register is not backward compatible.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Oct 6, 2019
2 parents 0eb8516 + 6935af8 commit 54e0295
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 62 deletions.
10 changes: 10 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core)
}
EXPORT_SYMBOL(mlxsw_core_res_query_enabled);

bool
mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
const struct mlxsw_fw_rev *req_rev)
{
return rev->minor > req_rev->minor ||
(rev->minor == req_rev->minor &&
rev->subminor >= req_rev->subminor);
}
EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate);

struct mlxsw_rx_listener_item {
struct list_head list;
struct mlxsw_rx_listener rxl;
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ struct mlxsw_core_port;
struct mlxsw_driver;
struct mlxsw_bus;
struct mlxsw_bus_info;
struct mlxsw_fw_rev;

unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core);

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_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
const struct mlxsw_fw_rev *req_rev);

int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver);
void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver);

Expand Down
66 changes: 30 additions & 36 deletions drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct mlxsw_hwmon {
struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
unsigned int attrs_count;
u8 sensor_count;
u8 module_sensor_count;
u8 module_sensor_max;
};

static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
Expand All @@ -56,7 +56,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
int err;

index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
mlxsw_hwmon->module_sensor_count);
mlxsw_hwmon->module_sensor_max);
mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
Expand All @@ -79,7 +79,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
int err;

index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
mlxsw_hwmon->module_sensor_count);
mlxsw_hwmon->module_sensor_max);
mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
Expand Down Expand Up @@ -109,7 +109,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
return -EINVAL;

index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
mlxsw_hwmon->module_sensor_count);
mlxsw_hwmon->module_sensor_max);
mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true);
err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
if (err) {
Expand Down Expand Up @@ -336,7 +336,7 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
int index = mlwsw_hwmon_attr->type_index -
mlxsw_hwmon->module_sensor_count + 1;
mlxsw_hwmon->module_sensor_max + 1;

return sprintf(buf, "gearbox %03u\n", index);
}
Expand Down Expand Up @@ -528,51 +528,45 @@ 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);
char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0};
int i, index;
u8 width;
int err;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
u8 module_sensor_max;
int i, 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,
&module_sensor_max);

/* 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;
mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count +
module_sensor_max;
for (i = mlxsw_hwmon->sensor_count;
i < mlxsw_hwmon->module_sensor_max; 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;
}
Expand All @@ -590,14 +584,14 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
if (err)
return err;

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;

index = mlxsw_hwmon->module_sensor_count;
max_index = mlxsw_hwmon->module_sensor_count + gbox_num;
index = mlxsw_hwmon->module_sensor_max;
max_index = mlxsw_hwmon->module_sensor_max + gbox_num;
while (index < max_index) {
sensor_index = index % mlxsw_hwmon->module_sensor_count +
sensor_index = index % mlxsw_hwmon->module_sensor_max +
MLXSW_REG_MTMP_GBOX_INDEX_MIN;
mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true);
err = mlxsw_reg_write(mlxsw_hwmon->core,
Expand Down
40 changes: 18 additions & 22 deletions drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,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;
Expand Down Expand Up @@ -775,23 +776,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)
Expand Down Expand Up @@ -819,26 +807,34 @@ 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);
struct mlxsw_thermal_module *module_tz;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
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);

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;
Expand All @@ -850,7 +846,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;
Expand All @@ -859,13 +855,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);
}
Expand Down Expand Up @@ -913,7 +908,8 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
if (err)
return err;

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;

Expand Down
30 changes: 30 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/minimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@

static const char mlxsw_m_driver_name[] = "mlxsw_minimal";

#define MLXSW_M_FWREV_MINOR 2000
#define MLXSW_M_FWREV_SUBMINOR 1886

static const struct mlxsw_fw_rev mlxsw_m_fw_rev = {
.minor = MLXSW_M_FWREV_MINOR,
.subminor = MLXSW_M_FWREV_SUBMINOR,
};

struct mlxsw_m_port;

struct mlxsw_m {
Expand Down Expand Up @@ -326,6 +334,24 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
kfree(mlxsw_m->ports);
}

static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
{
const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;

/* Validate driver and FW are compatible.
* Do not check major version, since it defines chip type, while
* driver is supposed to support any type.
*/
if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev))
return 0;

dev_err(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_fw_rev.minor, mlxsw_m_fw_rev.subminor);

return -EINVAL;
}

static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct netlink_ext_ack *extack)
Expand All @@ -336,6 +362,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_base_mac_get(mlxsw_m);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
Expand Down
10 changes: 9 additions & 1 deletion drivers/net/ethernet/mellanox/mlxsw/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -9531,6 +9531,12 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8);
*/
MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8);

/* 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);
Expand All @@ -9539,7 +9545,7 @@ static inline void mlxsw_reg_mgpir_pack(char *payload)
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 *devices_per_flash, u8 *num_of_modules)
{
if (num_of_devices)
*num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload);
Expand All @@ -9548,6 +9554,8 @@ 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
Expand Down
4 changes: 1 addition & 3 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)
}
if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) ==
MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) &&
(rev->minor > req_rev->minor ||
(rev->minor == req_rev->minor &&
rev->subminor >= req_rev->subminor)))
mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev))
return 0;

dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n",
Expand Down

0 comments on commit 54e0295

Please sign in to comment.