|
16 | 16 | #define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */
|
17 | 17 | #define MLXSW_THERMAL_MAX_STATE 10
|
18 | 18 | #define MLXSW_THERMAL_MAX_DUTY 255
|
| 19 | +/* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values |
| 20 | + * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for |
| 21 | + * setting fan speed dynamic minimum. For example, if value is set to 14 (40%) |
| 22 | + * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to |
| 23 | + * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100. |
| 24 | + */ |
| 25 | +#define MLXSW_THERMAL_SPEED_MIN (MLXSW_THERMAL_MAX_STATE + 2) |
| 26 | +#define MLXSW_THERMAL_SPEED_MAX (MLXSW_THERMAL_MAX_STATE * 2) |
| 27 | +#define MLXSW_THERMAL_SPEED_MIN_LEVEL 2 /* 20% */ |
19 | 28 |
|
20 | 29 | struct mlxsw_thermal_trip {
|
21 | 30 | int type;
|
@@ -68,6 +77,7 @@ struct mlxsw_thermal {
|
68 | 77 | const struct mlxsw_bus_info *bus_info;
|
69 | 78 | struct thermal_zone_device *tzdev;
|
70 | 79 | struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
|
| 80 | + u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; |
71 | 81 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
|
72 | 82 | enum thermal_device_mode mode;
|
73 | 83 | };
|
@@ -285,12 +295,51 @@ static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev,
|
285 | 295 | struct mlxsw_thermal *thermal = cdev->devdata;
|
286 | 296 | struct device *dev = thermal->bus_info->dev;
|
287 | 297 | char mfsc_pl[MLXSW_REG_MFSC_LEN];
|
288 |
| - int err, idx; |
| 298 | + unsigned long cur_state, i; |
| 299 | + int idx; |
| 300 | + u8 duty; |
| 301 | + int err; |
289 | 302 |
|
290 | 303 | idx = mlxsw_get_cooling_device_idx(thermal, cdev);
|
291 | 304 | if (idx < 0)
|
292 | 305 | return idx;
|
293 | 306 |
|
| 307 | + /* Verify if this request is for changing allowed fan dynamical |
| 308 | + * minimum. If it is - update cooling levels accordingly and update |
| 309 | + * state, if current state is below the newly requested minimum state. |
| 310 | + * For example, if current state is 5, and minimal state is to be |
| 311 | + * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed |
| 312 | + * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be |
| 313 | + * overwritten. |
| 314 | + */ |
| 315 | + if (state >= MLXSW_THERMAL_SPEED_MIN && |
| 316 | + state <= MLXSW_THERMAL_SPEED_MAX) { |
| 317 | + state -= MLXSW_THERMAL_MAX_STATE; |
| 318 | + for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++) |
| 319 | + thermal->cooling_levels[i] = max(state, i); |
| 320 | + |
| 321 | + mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0); |
| 322 | + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl); |
| 323 | + if (err) |
| 324 | + return err; |
| 325 | + |
| 326 | + duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl); |
| 327 | + cur_state = mlxsw_duty_to_state(duty); |
| 328 | + |
| 329 | + /* If current fan state is lower than requested dynamical |
| 330 | + * minimum, increase fan speed up to dynamical minimum. |
| 331 | + */ |
| 332 | + if (state < cur_state) |
| 333 | + return 0; |
| 334 | + |
| 335 | + state = cur_state; |
| 336 | + } |
| 337 | + |
| 338 | + if (state > MLXSW_THERMAL_MAX_STATE) |
| 339 | + return -EINVAL; |
| 340 | + |
| 341 | + /* Normalize the state to the valid speed range. */ |
| 342 | + state = thermal->cooling_levels[state]; |
294 | 343 | mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state));
|
295 | 344 | err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
|
296 | 345 | if (err) {
|
@@ -369,6 +418,11 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
|
369 | 418 | }
|
370 | 419 | }
|
371 | 420 |
|
| 421 | + /* Initialize cooling levels per PWM state. */ |
| 422 | + for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++) |
| 423 | + thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL, |
| 424 | + i); |
| 425 | + |
372 | 426 | thermal->tzdev = thermal_zone_device_register("mlxsw",
|
373 | 427 | MLXSW_THERMAL_NUM_TRIPS,
|
374 | 428 | MLXSW_THERMAL_TRIP_MASK,
|
|
0 commit comments