diff mbox series

[net-next,4/9] mlxsw: core_hwmon: Extend internal structures to support multi hwmon objects

Message ID 20220413151733.2738867-5-idosch@nvidia.com (mailing list archive)
State Accepted
Commit b890ad418e1feada06dddc3f00ee2c8cccf77c13
Delegated to: Netdev Maintainers
Headers show
Series mlxsw: Preparations for line cards support | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 3 maintainers not CCed: jdelvare@suse.com linux@roeck-us.net linux-hwmon@vger.kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Ido Schimmel April 13, 2022, 3:17 p.m. UTC
From: Vadim Pasternak <vadimp@nvidia.com>

Currently, mlxsw supports a single hwmon device and registers it with
attributes corresponding to the various objects found on the main
board such as fans and gearboxes.

Line cards can have the same objects, but unlike the main board they
can be added and removed while the system is running. The various
hwmon objects found on these line cards should be created when the
line card becomes available and destroyed when the line card becomes
unavailable.

The above can be achieved by representing each line card as a
different hwmon device and registering / unregistering it when the
line card becomes available / unavailable.

Prepare for multi hwmon device support by splitting
'struct mlxsw_hwmon' into 'struct mlxsw_hwmon' and
'struct mlxsw_hwmon_dev'. The first will hold information relevant to
all hwmon devices, whereas the second will hold per-hwmon device
information.

Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 .../net/ethernet/mellanox/mlxsw/core_hwmon.c  | 187 +++++++++++-------
 1 file changed, 111 insertions(+), 76 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index 5df54a5bf292..d35aa135beed 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -27,7 +27,7 @@ 
 
 struct mlxsw_hwmon_attr {
 	struct device_attribute dev_attr;
-	struct mlxsw_hwmon *hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev;
 	unsigned int type_index;
 	char name[32];
 };
@@ -40,9 +40,8 @@  static int mlxsw_hwmon_get_attr_index(int index, int count)
 	return index;
 }
 
-struct mlxsw_hwmon {
-	struct mlxsw_core *core;
-	const struct mlxsw_bus_info *bus_info;
+struct mlxsw_hwmon_dev {
+	struct mlxsw_hwmon *hwmon;
 	struct device *hwmon_dev;
 	struct attribute_group group;
 	const struct attribute_group *groups[2];
@@ -53,19 +52,26 @@  struct mlxsw_hwmon {
 	u8 module_sensor_max;
 };
 
+struct mlxsw_hwmon {
+	struct mlxsw_core *core;
+	const struct mlxsw_bus_info *bus_info;
+	struct mlxsw_hwmon_dev line_cards[];
+};
+
 static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
 				     struct device_attribute *attr,
 				     char *buf)
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mtmp_pl[MLXSW_REG_MTMP_LEN];
 	int temp, index;
 	int err;
 
 	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
-					   mlxsw_hwmon->module_sensor_max);
+					   mlxsw_hwmon_dev->module_sensor_max);
 	mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false);
 	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
 	if (err) {
@@ -82,13 +88,14 @@  static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mtmp_pl[MLXSW_REG_MTMP_LEN];
 	int temp_max, index;
 	int err;
 
 	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
-					   mlxsw_hwmon->module_sensor_max);
+					   mlxsw_hwmon_dev->module_sensor_max);
 	mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false);
 	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
 	if (err) {
@@ -105,8 +112,9 @@  static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
-	char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
+	char mtmp_pl[MLXSW_REG_MTMP_LEN];
 	unsigned long val;
 	int index;
 	int err;
@@ -118,7 +126,7 @@  static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
 		return -EINVAL;
 
 	index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index,
-					   mlxsw_hwmon->module_sensor_max);
+					   mlxsw_hwmon_dev->module_sensor_max);
 
 	mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index);
 	err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
@@ -140,7 +148,8 @@  static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mfsm_pl[MLXSW_REG_MFSM_LEN];
 	int err;
 
@@ -159,7 +168,8 @@  static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char fore_pl[MLXSW_REG_FORE_LEN];
 	bool fault;
 	int err;
@@ -180,7 +190,8 @@  static ssize_t mlxsw_hwmon_pwm_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mfsc_pl[MLXSW_REG_MFSC_LEN];
 	int err;
 
@@ -200,7 +211,8 @@  static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mfsc_pl[MLXSW_REG_MFSC_LEN];
 	unsigned long val;
 	int err;
@@ -226,12 +238,13 @@  static int mlxsw_hwmon_module_temp_get(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mtmp_pl[MLXSW_REG_MTMP_LEN];
 	u8 module;
 	int err;
 
-	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
+	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
 	mlxsw_reg_mtmp_pack(mtmp_pl, 0,
 			    MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false,
 			    false);
@@ -264,15 +277,16 @@  static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
 	u8 module, fault;
 	u16 temp;
 	int err;
 
-	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
-	mlxsw_reg_mtbr_pack(mtbr_pl, 0,
-			    MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1);
+	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
+	mlxsw_reg_mtbr_pack(mtbr_pl, 0, 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");
@@ -306,11 +320,12 @@  static int mlxsw_hwmon_module_temp_critical_get(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	u8 module;
 	int err;
 
-	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
+	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
 	err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0,
 						   module, SFP_TEMP_HIGH_WARN,
 						   p_temp);
@@ -341,11 +356,12 @@  static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	u8 module;
 	int err;
 
-	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
+	module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count;
 	err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0,
 						   module, SFP_TEMP_HIGH_ALARM,
 						   p_temp);
@@ -390,9 +406,9 @@  mlxsw_hwmon_gbox_temp_label_show(struct device *dev,
 {
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr =
 			container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
-	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon;
+	struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev;
 	int index = mlxsw_hwmon_attr->type_index -
-		    mlxsw_hwmon->module_sensor_max + 1;
+		    mlxsw_hwmon_dev->module_sensor_max + 1;
 
 	return sprintf(buf, "gearbox %03u\n", index);
 }
@@ -461,14 +477,15 @@  enum mlxsw_hwmon_attr_type {
 	MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM,
 };
 
-static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
+static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev,
 				 enum mlxsw_hwmon_attr_type attr_type,
-				 unsigned int type_index, unsigned int num) {
+				 unsigned int type_index, unsigned int num)
+{
 	struct mlxsw_hwmon_attr *mlxsw_hwmon_attr;
 	unsigned int attr_index;
 
-	attr_index = mlxsw_hwmon->attrs_count;
-	mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index];
+	attr_index = mlxsw_hwmon_dev->attrs_count;
+	mlxsw_hwmon_attr = &mlxsw_hwmon_dev->hwmon_attrs[attr_index];
 
 	switch (attr_type) {
 	case MLXSW_HWMON_ATTR_TYPE_TEMP:
@@ -568,16 +585,17 @@  static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
 	}
 
 	mlxsw_hwmon_attr->type_index = type_index;
-	mlxsw_hwmon_attr->hwmon = mlxsw_hwmon;
+	mlxsw_hwmon_attr->mlxsw_hwmon_dev = mlxsw_hwmon_dev;
 	mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name;
 	sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr);
 
-	mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr;
-	mlxsw_hwmon->attrs_count++;
+	mlxsw_hwmon_dev->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr;
+	mlxsw_hwmon_dev->attrs_count++;
 }
 
-static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
+static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
 {
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
 	int i;
 	int err;
@@ -587,8 +605,8 @@  static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
 		dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
 		return err;
 	}
-	mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
-	for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
+	mlxsw_hwmon_dev->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
+	for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) {
 		char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
 
 		mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i);
@@ -605,18 +623,19 @@  static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
 				i);
 			return err;
 		}
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP, i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i);
 	}
 	return 0;
 }
 
-static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
+static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
 {
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0};
 	enum mlxsw_reg_mfcr_pwm_frequency freq;
 	unsigned int type_index;
@@ -634,10 +653,10 @@  static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
 	num = 0;
 	for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) {
 		if (tacho_active & BIT(type_index)) {
-			mlxsw_hwmon_attr_add(mlxsw_hwmon,
+			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 					     MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
 					     type_index, num);
-			mlxsw_hwmon_attr_add(mlxsw_hwmon,
+			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 					     MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
 					     type_index, num++);
 		}
@@ -645,15 +664,16 @@  static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
 	num = 0;
 	for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) {
 		if (pwm_active & BIT(type_index))
-			mlxsw_hwmon_attr_add(mlxsw_hwmon,
+			mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 					     MLXSW_HWMON_ATTR_TYPE_PWM,
 					     type_index, num++);
 	}
 	return 0;
 }
 
-static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
+static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
 {
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
 	u8 module_sensor_max;
 	int i, err;
@@ -671,28 +691,28 @@  static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
 	 * sensor_count are already utilized by the sensors connected through
 	 * mtmp register by mlxsw_hwmon_temp_init().
 	 */
-	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_dev->module_sensor_max = mlxsw_hwmon_dev->sensor_count +
+					     module_sensor_max;
+	for (i = mlxsw_hwmon_dev->sensor_count;
+	     i < mlxsw_hwmon_dev->module_sensor_max; i++) {
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
 				     i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i,
 				     i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
 				     i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
 				     i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM,
 				     i, i);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM,
 				     i, i);
 	}
@@ -700,8 +720,9 @@  static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
 	return 0;
 }
 
-static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
+static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev)
 {
+	struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon;
 	enum mlxsw_reg_mgpir_device_type device_type;
 	int index, max_index, sensor_index;
 	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
@@ -720,10 +741,10 @@  static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
 	    !gbox_num)
 		return 0;
 
-	index = mlxsw_hwmon->module_sensor_max;
-	max_index = mlxsw_hwmon->module_sensor_max + gbox_num;
+	index = mlxsw_hwmon_dev->module_sensor_max;
+	max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num;
 	while (index < max_index) {
-		sensor_index = index % mlxsw_hwmon->module_sensor_max +
+		sensor_index = index % mlxsw_hwmon_dev->module_sensor_max +
 			       MLXSW_REG_MTMP_GBOX_INDEX_MIN;
 		mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true);
 		err = mlxsw_reg_write(mlxsw_hwmon->core,
@@ -733,15 +754,15 @@  static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
 				sensor_index);
 			return err;
 		}
-		mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP,
-				     index, index);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
+				     MLXSW_HWMON_ATTR_TYPE_TEMP, index, index);
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index,
 				     index);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index,
 				     index);
-		mlxsw_hwmon_attr_add(mlxsw_hwmon,
+		mlxsw_hwmon_attr_add(mlxsw_hwmon_dev,
 				     MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
 				     index, index);
 		index++;
@@ -754,44 +775,58 @@  int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
 		     const struct mlxsw_bus_info *mlxsw_bus_info,
 		     struct mlxsw_hwmon **p_hwmon)
 {
+	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
 	struct mlxsw_hwmon *mlxsw_hwmon;
 	struct device *hwmon_dev;
+	u8 num_of_slots;
 	int err;
 
-	mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL);
+	mlxsw_reg_mgpir_pack(mgpir_pl, 0);
+	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
+	if (err)
+		return err;
+
+	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, NULL,
+			       &num_of_slots);
+
+	mlxsw_hwmon = kzalloc(struct_size(mlxsw_hwmon, line_cards,
+					  num_of_slots + 1), GFP_KERNEL);
 	if (!mlxsw_hwmon)
 		return -ENOMEM;
+
 	mlxsw_hwmon->core = mlxsw_core;
 	mlxsw_hwmon->bus_info = mlxsw_bus_info;
+	mlxsw_hwmon->line_cards[0].hwmon = mlxsw_hwmon;
 
-	err = mlxsw_hwmon_temp_init(mlxsw_hwmon);
+	err = mlxsw_hwmon_temp_init(&mlxsw_hwmon->line_cards[0]);
 	if (err)
 		goto err_temp_init;
 
-	err = mlxsw_hwmon_fans_init(mlxsw_hwmon);
+	err = mlxsw_hwmon_fans_init(&mlxsw_hwmon->line_cards[0]);
 	if (err)
 		goto err_fans_init;
 
-	err = mlxsw_hwmon_module_init(mlxsw_hwmon);
+	err = mlxsw_hwmon_module_init(&mlxsw_hwmon->line_cards[0]);
 	if (err)
 		goto err_temp_module_init;
 
-	err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon);
+	err = mlxsw_hwmon_gearbox_init(&mlxsw_hwmon->line_cards[0]);
 	if (err)
 		goto err_temp_gearbox_init;
 
-	mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
-	mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
+	mlxsw_hwmon->line_cards[0].groups[0] = &mlxsw_hwmon->line_cards[0].group;
+	mlxsw_hwmon->line_cards[0].group.attrs = mlxsw_hwmon->line_cards[0].attrs;
 
 	hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev,
-						      "mlxsw", mlxsw_hwmon,
-						      mlxsw_hwmon->groups);
+						      "mlxsw",
+						      &mlxsw_hwmon->line_cards[0],
+						      mlxsw_hwmon->line_cards[0].groups);
 	if (IS_ERR(hwmon_dev)) {
 		err = PTR_ERR(hwmon_dev);
 		goto err_hwmon_register;
 	}
 
-	mlxsw_hwmon->hwmon_dev = hwmon_dev;
+	mlxsw_hwmon->line_cards[0].hwmon_dev = hwmon_dev;
 	*p_hwmon = mlxsw_hwmon;
 	return 0;
 
@@ -806,6 +841,6 @@  int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
 
 void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
 {
-	hwmon_device_unregister(mlxsw_hwmon->hwmon_dev);
+	hwmon_device_unregister(mlxsw_hwmon->line_cards[0].hwmon_dev);
 	kfree(mlxsw_hwmon);
 }