From: Zinc Lim <limzhineng2@gmail.com>
To: alexanderduyck@fb.com, kuba@kernel.org, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@kernel.org, pabeni@redhat.com,
linux@roeck-us.net, horms@kernel.org, hmohsin@meta.com,
mike.marciniszyn@gmail.com
Cc: kernel-team@meta.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org,
zinclim@meta.com, limzhineng2@gmail.com
Subject: [PATCH net-next v4 4/6] eth: fbnic: parse the alarm range reported by firmware
Date: Wed, 14 Oct 2026 15:22:22 -0700 [thread overview]
Message-ID: <20261014222225.2803660-5-limzhineng2@gmail.com> (raw)
In-Reply-To: <20261014222225.2803660-1-limzhineng2@gmail.com>
Firmware reports which range a sensor is in: normal, below min, above
max, above crit. It sends the range in an unsolicited event on every
trip point crossing, including the crossing back into the normal range,
and in the response to a sensor read. Parse both and keep the last
reported range per sensor, so the driver holds a condition the hardware
reported.
The range is cached from the mailbox thread in both cases, so an event
and a read response cannot be applied out of the order firmware sent
them. It is seeded alongside the rest of the sensor cache in
fbnic_mbx_init(), before the mailbox interrupt is enabled, since an
event can arrive as soon as it is.
Firmware predating range reporting sends ALARM_DEPRECATED for every
threshold event and omits the range from the read response entirely.
Neither is cached, as neither says which limit was crossed.
Subsequent patches in this series will consume the cached range.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic.h | 2 +
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 84 ++++++++++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 23 ++++++
3 files changed, 109 insertions(+)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index 857a64b518f3..93bf7004b67d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -26,6 +26,8 @@ struct fbnic_hwmon_cache {
unsigned long last_read;
s32 temp_mdeg;
s32 volt_mv;
+ u8 temp_alarm;
+ u8 volt_alarm;
};
struct fbnic_dev {
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
index d9a00a2ef34d..7863f6ba1e7d 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
@@ -121,6 +121,8 @@ void fbnic_mbx_init(struct fbnic_dev *fbd)
*/
fbd->hwmon_cache.temp_mdeg = FBNIC_SENSOR_NO_DATA;
fbd->hwmon_cache.volt_mv = FBNIC_SENSOR_NO_DATA;
+ fbd->hwmon_cache.temp_alarm = FBNIC_FW_TSENE_ALARM_UNKNOWN;
+ fbd->hwmon_cache.volt_alarm = FBNIC_FW_TSENE_ALARM_UNKNOWN;
/* Reinitialize mailbox memory */
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
@@ -1466,6 +1468,8 @@ static const struct fbnic_tlv_index fbnic_tsene_read_resp_index[] = {
FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_THERM),
FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_VOLT),
FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_ERROR),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_TSENE_THERM_ALARM_STATE),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_TSENE_VOLT_ALARM_STATE),
FBNIC_TLV_ATTR_LAST
};
@@ -1476,6 +1480,7 @@ static int fbnic_fw_parse_tsene_read_resp(void *opaque,
struct fbnic_dev *fbd = opaque;
s32 err_resp;
int err = 0;
+ u32 alarm;
/* Verify we have a completion pointer to provide with data */
cmpl_data = fbnic_fw_get_cmpl_by_type(fbd,
@@ -1497,6 +1502,20 @@ static int fbnic_fw_parse_tsene_read_resp(void *opaque,
cmpl_data->u.tsene.millivolts =
fta_get_sint(results, FBNIC_FW_TSENE_VOLT);
+ /* Cache here so that it and the threshold event land in the order firmware
+ * sent them. Firmware predating alarm state reporting sends neither
+ * attribute.
+ */
+ alarm = fbnic_tlv_attr_get_unsigned(results[FBNIC_FW_TSENE_THERM_ALARM_STATE],
+ FBNIC_FW_TSENE_ALARM_UNKNOWN);
+ if (alarm != FBNIC_FW_TSENE_ALARM_UNKNOWN)
+ WRITE_ONCE(fbd->hwmon_cache.temp_alarm, alarm);
+
+ alarm = fbnic_tlv_attr_get_unsigned(results[FBNIC_FW_TSENE_VOLT_ALARM_STATE],
+ FBNIC_FW_TSENE_ALARM_UNKNOWN);
+ if (alarm != FBNIC_FW_TSENE_ALARM_UNKNOWN)
+ WRITE_ONCE(fbd->hwmon_cache.volt_alarm, alarm);
+
msg_err:
cmpl_data->result = err_resp ? : err;
complete(&cmpl_data->done);
@@ -1689,6 +1708,68 @@ fbnic_fw_parser_test(void *opaque, struct fbnic_tlv_msg **results)
return err;
}
+static const struct fbnic_tlv_index fbnic_threshold_exceeded_resp_index[] = {
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_TSENE_THERM_ALARM),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_TSENE_VOLT_ALARM),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_THERMAL),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_VOLTAGE),
+ FBNIC_TLV_ATTR_LAST
+};
+
+static int fbnic_fw_parse_threshold_exceeded_resp(void *opaque,
+ struct fbnic_tlv_msg
+ **results)
+{
+ struct fbnic_dev *fbd = opaque;
+ bool rec_flag = false;
+ u32 alarm;
+ s32 value;
+
+ if (results[FBNIC_FW_TSENE_THERM_ALARM]) {
+ bool have_temp = !!results[FBNIC_FW_TSENE_THERMAL];
+
+ alarm = fta_get_uint(results, FBNIC_FW_TSENE_THERM_ALARM);
+ value = fta_get_sint(results, FBNIC_FW_TSENE_THERMAL);
+ if (!have_temp)
+ dev_err(fbd->dev, "Thermal alarm %u received with no temperature!\n",
+ alarm);
+ else if (alarm != FBNIC_FW_TSENE_ALARM_NORMAL)
+ 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)
+ WRITE_ONCE(fbd->hwmon_cache.temp_alarm, alarm);
+ rec_flag = true;
+ }
+
+ if (results[FBNIC_FW_TSENE_VOLT_ALARM]) {
+ bool have_volt = !!results[FBNIC_FW_TSENE_VOLTAGE];
+
+ alarm = fta_get_uint(results, FBNIC_FW_TSENE_VOLT_ALARM);
+ value = fta_get_sint(results, FBNIC_FW_TSENE_VOLTAGE);
+ if (!have_volt)
+ dev_err(fbd->dev, "Voltage alarm %u received with no voltage!\n",
+ alarm);
+ else if (alarm != FBNIC_FW_TSENE_ALARM_NORMAL)
+ 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)
+ WRITE_ONCE(fbd->hwmon_cache.volt_alarm, alarm);
+ rec_flag = true;
+ }
+
+ if (!rec_flag) {
+ dev_warn(fbd->dev,
+ "Threshold exceeded message received but no alarm found!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
FBNIC_TLV_PARSER(TEST, fbnic_tlv_test_index, fbnic_fw_parser_test),
FBNIC_TLV_PARSER(FW_CAP_RESP, fbnic_fw_cap_resp_index,
@@ -1717,6 +1798,9 @@ static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
FBNIC_TLV_PARSER(TSENE_READ_RESP,
fbnic_tsene_read_resp_index,
fbnic_fw_parse_tsene_read_resp),
+ FBNIC_TLV_PARSER(SENSOR_THRESHOLD_EXCEEDED_RESP,
+ fbnic_threshold_exceeded_resp_index,
+ fbnic_fw_parse_threshold_exceeded_resp),
FBNIC_TLV_PARSER(LOG_MSG_REQ,
fbnic_fw_log_req_index,
fbnic_fw_parse_log_req),
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
index dde2929f8660..3b4787277408 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -239,6 +239,7 @@ enum {
FBNIC_TLV_MSG_ID_QSFP_READ_RESP = 0x39,
FBNIC_TLV_MSG_ID_TSENE_READ_REQ = 0x3C,
FBNIC_TLV_MSG_ID_TSENE_READ_RESP = 0x3D,
+ FBNIC_TLV_MSG_ID_SENSOR_THRESHOLD_EXCEEDED_RESP = 0x40,
FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ = 0x43,
FBNIC_TLV_MSG_ID_LOG_MSG_REQ = 0x44,
FBNIC_TLV_MSG_ID_LOG_MSG_RESP = 0x45,
@@ -305,9 +306,31 @@ enum {
FBNIC_FW_TSENE_THERM = 0x0,
FBNIC_FW_TSENE_VOLT = 0x1,
FBNIC_FW_TSENE_ERROR = 0x2,
+ FBNIC_FW_TSENE_THERM_ALARM_STATE = 0x3,
+ FBNIC_FW_TSENE_VOLT_ALARM_STATE = 0x4,
FBNIC_FW_TSENE_MSG_MAX
};
+enum {
+ FBNIC_FW_TSENE_THERM_ALARM = 0x0,
+ FBNIC_FW_TSENE_VOLT_ALARM = 0x1,
+ FBNIC_FW_TSENE_THERMAL = 0x2,
+ FBNIC_FW_TSENE_VOLTAGE = 0x3,
+ FBNIC_FW_TSENE_EXCEEDED_MSG_MAX,
+};
+
+enum {
+ FBNIC_FW_TSENE_ALARM_NORMAL = 0x0,
+ FBNIC_FW_TSENE_ALARM_DEPRECATED = 0x1,
+ FBNIC_FW_TSENE_ALARM_BELOW_MIN = 0x2,
+ FBNIC_FW_TSENE_ALARM_ABOVE_MAX = 0x3,
+ FBNIC_FW_TSENE_ALARM_CRIT = 0x4,
+ /* Driver internal, never sent by firmware. 0xff so its out of
+ * range wherever the range is held in a u8.
+ */
+ FBNIC_FW_TSENE_ALARM_UNKNOWN = 0xff,
+};
+
enum {
FBNIC_FW_OWNERSHIP_FLAG = 0x0,
FBNIC_FW_OWNERSHIP_TIME = 0x1,
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-14 22:22 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 22:22 [PATCH net-next v4 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
2026-10-14 22:22 ` [PATCH net-next v4 1/6] eth: fbnic: move sensor read logic out of fbnic_mac Zinc Lim
2026-10-14 22:22 ` [PATCH net-next v4 2/6] eth: fbnic: cache hwmon sensor readings Zinc Lim
2026-10-14 22:22 ` [PATCH net-next v4 3/6] eth: fbnic: report temperature and voltage thresholds via hwmon Zinc Lim
2026-10-14 22:22 ` Zinc Lim [this message]
2026-10-14 22:22 ` [PATCH net-next v4 5/6] eth: fbnic: report temperature and voltage alarms " Zinc Lim
2026-10-14 22:22 ` [PATCH net-next v4 6/6] eth: fbnic: derive the alarm range on older firmware Zinc Lim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261014222225.2803660-5-limzhineng2@gmail.com \
--to=limzhineng2@gmail.com \
--cc=alexanderduyck@fb.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=hmohsin@meta.com \
--cc=horms@kernel.org \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=mike.marciniszyn@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=zinclim@meta.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox