* [PATCH v0 10/12] mlxsw: core: Extend cooling device with cooling levels
@ 2018-06-21 15:28 Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 11/12] mlxsw: core: Rename cooling device Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 12/12] mlxsw: core: Add ports temperature measurement to thermal algorithm Vadim Pasternak
0 siblings, 2 replies; 3+ messages in thread
From: Vadim Pasternak @ 2018-06-21 15:28 UTC (permalink / raw)
To: davem; +Cc: netdev, jiri, Vadim Pasternak
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>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 59 +++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index 1587820..53e4ef9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -46,6 +46,15 @@
#define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */
#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 percent */
struct mlxsw_thermal_trip {
int type;
@@ -97,6 +106,7 @@ struct mlxsw_thermal {
struct thermal_zone_device *tzdev;
int polling_delay;
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;
};
@@ -361,12 +371,52 @@ 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;
+ int idx, i;
+ 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 < state; i++)
+ thermal->cooling_levels[i] = state;
+ for (i = state; i <= MLXSW_THERMAL_MAX_STATE; i++)
+ thermal->cooling_levels[i] = i;
+
+ mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0);
+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl);
+ if (err) {
+ dev_err(dev, "Failed to query PWM duty\n");
+ return err;
+ }
+
+ duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl);
+ cur_state = mlxsw_duty_to_state(duty);
+
+ 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) {
@@ -445,6 +495,13 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
}
}
+ /* Init cooling levels per PWM state. */
+ for (i = 0; i < MLXSW_THERMAL_SPEED_MIN_LEVEL; i++)
+ thermal->cooling_levels[i] = MLXSW_THERMAL_SPEED_MIN_LEVEL;
+ for (i = MLXSW_THERMAL_SPEED_MIN_LEVEL;
+ i <= MLXSW_THERMAL_MAX_STATE; i++)
+ thermal->cooling_levels[i] = i;
+
if (bus_info->low_frequency)
thermal->polling_delay = MLXSW_THERMAL_SLOW_POLL_INT;
else
--
2.1.4
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH v0 11/12] mlxsw: core: Rename cooling device
2018-06-21 15:28 [PATCH v0 10/12] mlxsw: core: Extend cooling device with cooling levels Vadim Pasternak
@ 2018-06-21 15:28 ` Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 12/12] mlxsw: core: Add ports temperature measurement to thermal algorithm Vadim Pasternak
1 sibling, 0 replies; 3+ messages in thread
From: Vadim Pasternak @ 2018-06-21 15:28 UTC (permalink / raw)
To: davem; +Cc: netdev, jiri, Vadim Pasternak
Name "Fan" is too common name, and such name is misleading, while it's
interpreted by user.
For example name "Fan" could be used by ACPI.
Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index 53e4ef9..65962ed 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -484,7 +484,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
if (pwm_active & BIT(i)) {
struct thermal_cooling_device *cdev;
- cdev = thermal_cooling_device_register("Fan", thermal,
+ cdev = thermal_cooling_device_register("mlxsw_fan",
+ thermal,
&mlxsw_cooling_ops);
if (IS_ERR(cdev)) {
err = PTR_ERR(cdev);
--
2.1.4
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH v0 12/12] mlxsw: core: Add ports temperature measurement to thermal algorithm
2018-06-21 15:28 [PATCH v0 10/12] mlxsw: core: Extend cooling device with cooling levels Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 11/12] mlxsw: core: Rename cooling device Vadim Pasternak
@ 2018-06-21 15:28 ` Vadim Pasternak
1 sibling, 0 replies; 3+ messages in thread
From: Vadim Pasternak @ 2018-06-21 15:28 UTC (permalink / raw)
To: davem; +Cc: netdev, jiri, Vadim Pasternak
Ports temperature has most significant impact on system thermal state
and should be considered by the thermal algorithm. The thermal zone
temperature is extended for reading ports temperatures along with a
chip temperature. The temperature value, provided to the core thermal
algorithm will be accumulated value of a chip and ports temperature
sensing, normalized according to the basic constant thresholds.
Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 66 ++++++++++++++++++++--
1 file changed, 62 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index 65962ed..23d6197 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -109,6 +109,8 @@ struct mlxsw_thermal {
u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
enum thermal_device_mode mode;
+ int count;
+ int *ports_temp_cache;
};
static inline u8 mlxsw_state_to_duty(int state)
@@ -213,10 +215,11 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
return 0;
}
-static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
- int *p_temp)
+static int mlxsw_thermal_init_temp(struct mlxsw_thermal *thermal,
+ struct mlxsw_env_temp_thresh *delta,
+ struct mlxsw_env_temp_multi *multi,
+ int *p_temp, bool *p_crit)
{
- struct mlxsw_thermal *thermal = tzdev->devdata;
struct device *dev = thermal->bus_info->dev;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
unsigned int temp;
@@ -231,10 +234,58 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
}
mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
- *p_temp = (int) temp;
+ if (temp >= MLXSW_ENV_TEMP_CRIT) {
+ *p_crit = true;
+ } else if (temp < MLXSW_ENV_TEMP_NORM) {
+ multi->thresh.normal = temp;
+ delta->normal = MLXSW_ENV_TEMP_NORM - temp;
+ } else if (temp >= MLXSW_ENV_TEMP_HOT) {
+ multi->thresh.crit = temp;
+ delta->crit = temp - MLXSW_ENV_TEMP_HOT;
+ multi->mask |= MLXSW_ENV_CRIT_MASK;
+ } else {
+ multi->thresh.hot = temp;
+ delta->hot = temp - MLXSW_ENV_TEMP_NORM;
+ multi->mask |= MLXSW_ENV_HOT_MASK;
+ }
+ *p_temp = temp;
+
return 0;
}
+static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
+ int *p_temp)
+{
+ struct mlxsw_thermal *thermal = tzdev->devdata;
+ struct device *dev = thermal->bus_info->dev;
+ struct mlxsw_env_temp_multi multi;
+ struct mlxsw_env_temp_thresh delta;
+ bool crit = false;
+ int err;
+
+ memset(&multi, 0, sizeof(struct mlxsw_env_temp_multi));
+ memset(&delta, 0, sizeof(struct mlxsw_env_temp_thresh));
+ /* Read ASIC temperature */
+ err = mlxsw_thermal_init_temp(thermal, &delta, &multi,
+ p_temp, &crit);
+ if (err) {
+ dev_err(dev, "Failed to query ASIC temp sensor\n");
+ return err;
+ }
+
+ /* No need to proceed ports temperature reading, since ASIC temperature
+ * should be resulted in system shutdown.
+ */
+ if (crit)
+ return 0;
+
+ /* Collect ports temperature */
+ return mlxsw_env_collect_port_temp(thermal->core,
+ thermal->ports_temp_cache,
+ thermal->count, &multi, &delta,
+ NULL, p_temp);
+}
+
static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev,
int trip,
enum thermal_trip_type *p_type)
@@ -436,6 +487,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_thermal **p_thermal)
{
+ unsigned int max_ports = mlxsw_core_max_ports(core);
char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
enum mlxsw_reg_mfcr_pwm_frequency freq;
struct device *dev = bus_info->dev;
@@ -452,6 +504,12 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
thermal->core = core;
thermal->bus_info = bus_info;
memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
+ thermal->ports_temp_cache = devm_kmalloc_array(dev, max_ports,
+ sizeof(int),
+ GFP_KERNEL);
+ if (!thermal->ports_temp_cache)
+ return -ENOMEM;
+ thermal->count = max_ports;
err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
if (err) {
--
2.1.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-06-21 13:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-21 15:28 [PATCH v0 10/12] mlxsw: core: Extend cooling device with cooling levels Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 11/12] mlxsw: core: Rename cooling device Vadim Pasternak
2018-06-21 15:28 ` [PATCH v0 12/12] mlxsw: core: Add ports temperature measurement to thermal algorithm Vadim Pasternak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox