mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-16 01:24:08 +08:00
Merge branch 'mlxsw-Query-number-of-modules-from-firmware'
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>
This commit is contained in:
commit
54e02957f4
@ -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;
|
||||
|
@ -24,6 +24,7 @@ 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);
|
||||
|
||||
@ -31,6 +32,10 @@ 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);
|
||||
|
||||
|
@ -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,
|
||||
@ -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) {
|
||||
@ -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) {
|
||||
@ -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) {
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
@ -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)
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -859,13 +855,12 @@ err_unreg_tz_module_arr:
|
||||
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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
@ -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)
|
||||
@ -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");
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
@ -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
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user