Firmware that predates range reporting uses the threshold event to flag that a limit was exceeded, with the attribute hardcoded to 1, rather than reporting which range the sensor entered. The range enum reserves that value as FBNIC_FW_TSENE_ALARM_DEPRECATED. It does not indicate which limit was crossed, so it is not cached and the alarm classifies a fresh reading on every sysfs read. Such firmware re-arms the trip points around the range the reading landed in, so every crossing interrupts, including the one back to normal. The event carries the reading that tripped it, so derive the range from that, against the same capability response thresholds and boundaries firmware uses. The alarm then tracks crossings there too, and wakes anything polling the sysfs attribute. An event can arrive before the capability response that carries those thresholds, since rx messages are parsed while polling for it. There is nothing to classify against yet, so the reading would come back as the normal range and stick there. Leave the range unknown and let the read path derive it once the thresholds are in. Signed-off-by: Zinc Lim --- drivers/net/ethernet/meta/fbnic/fbnic.h | 1 + drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 18 +++++++++--- drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 29 +++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h index 90e54cffe6a9..8180028b20a2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic.h @@ -201,6 +201,7 @@ void fbnic_fw_free_mbx(struct fbnic_dev *fbd); void fbnic_hwmon_register(struct fbnic_dev *fbd); void fbnic_hwmon_unregister(struct fbnic_dev *fbd); void fbnic_hwmon_notify_event(struct fbnic_dev *fbd, int id); +void fbnic_hwmon_old_notify_event(struct fbnic_dev *fbd, int id, s32 value); int fbnic_mac_request_irq(struct fbnic_dev *fbd); void fbnic_mac_free_irq(struct fbnic_dev *fbd); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c index 9485665cba46..cfec30e5cb98 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c @@ -1737,8 +1737,13 @@ static int fbnic_fw_parse_threshold_exceeded_resp(void *opaque, dev_err(fbd->dev, "Thermal alarm %u, temperature is currently %dmC!\n", alarm, value); - /* Old firmware reports no range, leave the cache alone */ - if (alarm != FBNIC_FW_TSENE_ALARM_DEPRECATED) { + if (alarm == FBNIC_FW_TSENE_ALARM_DEPRECATED) { + /* Nothing to derive the range from, so do not guess */ + if (have_temp) + fbnic_hwmon_old_notify_event(fbd, + FBNIC_SENSOR_TEMP, + value); + } else { WRITE_ONCE(fbd->hwmon_cache.temp_alarm, alarm); fbnic_hwmon_notify_event(fbd, FBNIC_SENSOR_TEMP); } @@ -1757,8 +1762,13 @@ static int fbnic_fw_parse_threshold_exceeded_resp(void *opaque, dev_err(fbd->dev, "Voltage alarm %u, voltage is currently %dmV!\n", alarm, value); - /* Old firmware reports no range, leave the cache alone */ - if (alarm != FBNIC_FW_TSENE_ALARM_DEPRECATED) { + if (alarm == FBNIC_FW_TSENE_ALARM_DEPRECATED) { + /* Nothing to derive the range from, so do not guess */ + if (have_volt) + fbnic_hwmon_old_notify_event(fbd, + FBNIC_SENSOR_VOLTAGE, + value); + } else { WRITE_ONCE(fbd->hwmon_cache.volt_alarm, alarm); fbnic_hwmon_notify_event(fbd, FBNIC_SENSOR_VOLTAGE); } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c index 310a2c52bb4d..9fa9eb843c68 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c @@ -302,6 +302,35 @@ void fbnic_hwmon_unregister(struct fbnic_dev *fbd) hwmon_device_unregister(hwmon); } +void fbnic_hwmon_old_notify_event(struct fbnic_dev *fbd, int id, s32 value) +{ + const struct fbnic_threshold *thr; + u8 *cached; + + switch (id) { + case FBNIC_SENSOR_TEMP: + thr = &fbd->fw_cap.temp; + cached = &fbd->hwmon_cache.temp_alarm; + break; + case FBNIC_SENSOR_VOLTAGE: + thr = &fbd->fw_cap.volt; + cached = &fbd->hwmon_cache.volt_alarm; + break; + default: + return; + } + + /* Event arrived before the capability response containing + * the thresholds. + */ + if (thr->min == FBNIC_SENSOR_NO_DATA || + thr->max == FBNIC_SENSOR_NO_DATA) + return; + + WRITE_ONCE(*cached, fbnic_hwmon_classify(thr, value)); + fbnic_hwmon_notify_event(fbd, id); +} + void fbnic_hwmon_notify_event(struct fbnic_dev *fbd, int id) { enum hwmon_sensor_types type; -- 2.53.0-Meta