]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mlxsw: core: Extend cooling device with cooling levels
authorVadim Pasternak <vadimp@mellanox.com>
Tue, 20 Nov 2018 06:52:03 +0000 (06:52 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 20 Nov 2018 18:31:15 +0000 (10:31 -0800)
Extend cooling device with cooling levels vector to allow more
flexibility of PWM setting.

Thermal zone algorithm operates with the numerical states for PWM
setting. Each state is the index, defined in range from 0 to 10 and it's
mapped to the relevant duty cycle value, which is written to PWM
controller. With the current definition fan speed is set to 0% for state
0, 10% for state 1, and so on up to 100% for the maximum state 10.

Some systems have limitation for the PWM speed minimum. For such systems
PWM setting speed to 0% will just disable the ability to increase speed
anymore and such device will be stall on zero speed.  Cooling levels
allow to configure state vector according to the particular system
requirements. For example, if PWM speed is not allowed to be below 30%,
cooling levels could be configured as 30%, 30%, 30%, 30%, 40%, 50% and
so on.

Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c

index 6d29dc4286086cbacf50fdf7338eaeab7c460b26..61f897b40f82340a8741b89f9ff424f6e9d0012b 100644 (file)
 #define MLXSW_THERMAL_MAX_TEMP 110000  /* 110C */
 #define MLXSW_THERMAL_MAX_STATE        10
 #define MLXSW_THERMAL_MAX_DUTY 255
+/* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values
+ * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for
+ * setting fan speed dynamic minimum. For example, if value is set to 14 (40%)
+ * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
+ * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
+ */
+#define MLXSW_THERMAL_SPEED_MIN                (MLXSW_THERMAL_MAX_STATE + 2)
+#define MLXSW_THERMAL_SPEED_MAX                (MLXSW_THERMAL_MAX_STATE * 2)
+#define MLXSW_THERMAL_SPEED_MIN_LEVEL  2               /* 20% */
 
 struct mlxsw_thermal_trip {
        int     type;
@@ -68,6 +77,7 @@ struct mlxsw_thermal {
        const struct mlxsw_bus_info *bus_info;
        struct thermal_zone_device *tzdev;
        struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
+       u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
        struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
        enum thermal_device_mode mode;
 };
@@ -285,12 +295,51 @@ static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
        struct mlxsw_thermal *thermal = cdev->devdata;
        struct device *dev = thermal->bus_info->dev;
        char mfsc_pl[MLXSW_REG_MFSC_LEN];
-       int err, idx;
+       unsigned long cur_state, i;
+       int idx;
+       u8 duty;
+       int err;
 
        idx = mlxsw_get_cooling_device_idx(thermal, cdev);
        if (idx < 0)
                return idx;
 
+       /* Verify if this request is for changing allowed fan dynamical
+        * minimum. If it is - update cooling levels accordingly and update
+        * state, if current state is below the newly requested minimum state.
+        * For example, if current state is 5, and minimal state is to be
+        * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed
+        * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be
+        * overwritten.
+        */
+       if (state >= MLXSW_THERMAL_SPEED_MIN &&
+           state <= MLXSW_THERMAL_SPEED_MAX) {
+               state -= MLXSW_THERMAL_MAX_STATE;
+               for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++)
+                       thermal->cooling_levels[i] = max(state, i);
+
+               mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
+               err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
+               if (err)
+                       return err;
+
+               duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
+               cur_state = mlxsw_duty_to_state(duty);
+
+               /* If current fan state is lower than requested dynamical
+                * minimum, increase fan speed up to dynamical minimum.
+                */
+               if (state < cur_state)
+                       return 0;
+
+               state = cur_state;
+       }
+
+       if (state > MLXSW_THERMAL_MAX_STATE)
+               return -EINVAL;
+
+       /* Normalize the state to the valid speed range. */
+       state = thermal->cooling_levels[state];
        mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
        err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
        if (err) {
@@ -369,6 +418,11 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
                }
        }
 
+       /* Initialize cooling levels per PWM state. */
+       for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++)
+               thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL,
+                                                i);
+
        thermal->tzdev = thermal_zone_device_register("mlxsw",
                                                      MLXSW_THERMAL_NUM_TRIPS,
                                                      MLXSW_THERMAL_TRIP_MASK,