* [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support
@ 2026-07-21 22:15 Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 1/6] eth: fbnic: move sensor read logic out of fbnic_mac Zinc Lim
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
fbnic currently exposes only the raw temperature and voltage readings
(temp1_input, in0_input) via hwmon. This series builds that out into a
complete sensor interface and hardens the read path.
The firmware capability response already carries per-board sensor
thresholds, and the firmware can asynchronously report when a sensor
crosses one of them. This series surfaces both to userspace and cleans
up the supporting plumbing:
- Move the sensor read logic out of fbnic_mac, closer to its only
caller in the hwmon code, and drop the now-unused get_sensor op.
- Expose all hwmon attributes unconditionally as read-only (0444).
- Cache the temperature and voltage readings for the current jiffy so
a burst of attribute reads issues a single firmware round-trip.
- Parse and expose the temperature (min/max/crit) and voltage
(min/max) thresholds. Thresholds the firmware did not populate read
back as -ENODATA.
- Add the corresponding alarm attributes, computed by comparing a live
reading against the stored thresholds.
- Translate the firmware's sensor-threshold-exceeded message into an
hwmon event so userspace is notified on the relevant attribute.
Zinc Lim (6):
eth: fbnic: move sensor read logic out of fbnic_mac
eth: fbnic: expose all hwmon attributes unconditionally as read-only
eth: fbnic: cache hwmon sensor readings
eth: fbnic: report temperature and voltage thresholds via hwmon
eth: fbnic: report temperature and voltage alarms via hwmon
eth: fbnic: firmware notifies hwmon on sensor threshold events
drivers/net/ethernet/meta/fbnic/fbnic.h | 8 +
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 75 +++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 30 ++
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 260 ++++++++++++++++--
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 55 ----
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 2 -
6 files changed, 346 insertions(+), 84 deletions(-)
--
2.53.0-Meta
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next 1/6] eth: fbnic: move sensor read logic out of fbnic_mac
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 2/6] eth: fbnic: expose all hwmon attributes unconditionally as read-only Zinc Lim
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
The sensor read lived behind the fbnic_mac get_sensor op, but it is only
ever used by the hwmon subsystem. Move the read into fbnic_hwmon.c and
call it directly there, closer to where it is used, and drop the
now-unused get_sensor op from struct fbnic_mac. No functional change.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 56 ++++++++++++++++++-
drivers/net/ethernet/meta/fbnic/fbnic_mac.c | 55 ------------------
drivers/net/ethernet/meta/fbnic/fbnic_mac.h | 2 -
3 files changed, 54 insertions(+), 59 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index def8598aceec..6c8c66ab86c1 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -28,15 +28,67 @@ static umode_t fbnic_hwmon_is_visible(const void *drvdata,
return 0;
}
+static int fbnic_hwmon_sensor_read(struct fbnic_dev *fbd, int id, long *val)
+{
+ struct fbnic_fw_completion *fw_cmpl;
+ int err = 0;
+ s32 *sensor;
+
+ fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_TSENE_READ_RESP);
+ if (!fw_cmpl)
+ return -ENOMEM;
+
+ switch (id) {
+ case FBNIC_SENSOR_TEMP:
+ sensor = &fw_cmpl->u.tsene.millidegrees;
+ break;
+ case FBNIC_SENSOR_VOLTAGE:
+ sensor = &fw_cmpl->u.tsene.millivolts;
+ break;
+ default:
+ err = -EINVAL;
+ goto exit_free;
+ }
+
+ err = fbnic_fw_xmit_tsene_read_msg(fbd, fw_cmpl);
+ if (err) {
+ dev_err(fbd->dev,
+ "Failed to transmit TSENE read msg, err %d\n",
+ err);
+ goto exit_free;
+ }
+
+ if (!wait_for_completion_timeout(&fw_cmpl->done, 10 * HZ)) {
+ dev_err(fbd->dev, "Timed out waiting for TSENE read\n");
+ err = -ETIMEDOUT;
+ goto exit_cleanup;
+ }
+
+ /* Handle error returned by firmware */
+ if (fw_cmpl->result) {
+ err = fw_cmpl->result;
+ dev_err(fbd->dev, "%s: Firmware returned error %d\n",
+ __func__, err);
+ goto exit_cleanup;
+ }
+
+ *val = *sensor;
+exit_cleanup:
+ fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
+exit_free:
+ fbnic_fw_put_cmpl(fw_cmpl);
+
+ return err;
+}
+
static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct fbnic_dev *fbd = dev_get_drvdata(dev);
- const struct fbnic_mac *mac = fbd->mac;
int id;
id = fbnic_hwmon_sensor_id(type);
- return id < 0 ? id : mac->get_sensor(fbd, id, val);
+ return id < 0 ? id : fbnic_hwmon_sensor_read(fbd, id, val);
}
static const struct hwmon_ops fbnic_hwmon_ops = {
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
index 53b7a938b4c2..fba2e2efaeb8 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c
@@ -899,60 +899,6 @@ fbnic_mac_get_rmon_stats(struct fbnic_dev *fbd, bool reset,
TMI_STAT_TX_PACKET_9217_MAX_BYTES);
}
-static int fbnic_mac_get_sensor_asic(struct fbnic_dev *fbd, int id,
- long *val)
-{
- struct fbnic_fw_completion *fw_cmpl;
- int err = 0;
- s32 *sensor;
-
- fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_TSENE_READ_RESP);
- if (!fw_cmpl)
- return -ENOMEM;
-
- switch (id) {
- case FBNIC_SENSOR_TEMP:
- sensor = &fw_cmpl->u.tsene.millidegrees;
- break;
- case FBNIC_SENSOR_VOLTAGE:
- sensor = &fw_cmpl->u.tsene.millivolts;
- break;
- default:
- err = -EINVAL;
- goto exit_free;
- }
-
- err = fbnic_fw_xmit_tsene_read_msg(fbd, fw_cmpl);
- if (err) {
- dev_err(fbd->dev,
- "Failed to transmit TSENE read msg, err %d\n",
- err);
- goto exit_free;
- }
-
- if (!wait_for_completion_timeout(&fw_cmpl->done, 10 * HZ)) {
- dev_err(fbd->dev, "Timed out waiting for TSENE read\n");
- err = -ETIMEDOUT;
- goto exit_cleanup;
- }
-
- /* Handle error returned by firmware */
- if (fw_cmpl->result) {
- err = fw_cmpl->result;
- dev_err(fbd->dev, "%s: Firmware returned error %d\n",
- __func__, err);
- goto exit_cleanup;
- }
-
- *val = *sensor;
-exit_cleanup:
- fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
-exit_free:
- fbnic_fw_put_cmpl(fw_cmpl);
-
- return err;
-}
-
static const struct fbnic_mac fbnic_mac_asic = {
.init_regs = fbnic_mac_init_regs,
.get_link = fbnic_mac_get_link,
@@ -966,7 +912,6 @@ static const struct fbnic_mac fbnic_mac_asic = {
.get_rmon_stats = fbnic_mac_get_rmon_stats,
.link_down = fbnic_mac_link_down_asic,
.link_up = fbnic_mac_link_up_asic,
- .get_sensor = fbnic_mac_get_sensor_asic,
};
/**
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
index 10f30e0e8f69..bde2daa65645 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h
@@ -137,8 +137,6 @@ struct fbnic_mac {
void (*link_down)(struct fbnic_dev *fbd);
void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause);
-
- int (*get_sensor)(struct fbnic_dev *fbd, int id, long *val);
};
int fbnic_mac_init(struct fbnic_dev *fbd);
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 2/6] eth: fbnic: expose all hwmon attributes unconditionally as read-only
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 1/6] eth: fbnic: move sensor read logic out of fbnic_mac Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 3/6] eth: fbnic: cache hwmon sensor readings Zinc Lim
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
All fbnic hwmon attributes are read-only and always present, so
fbnic_hwmon_is_visible() can simply return 0444 for everything
instead of matching on the sensor type and attribute. This also
prepares for the threshold and alarm attributes added in the
following patches: they are exposed unconditionally and reads
return attribute values.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index 6c8c66ab86c1..38bb26cb8e6c 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -20,12 +20,7 @@ static umode_t fbnic_hwmon_is_visible(const void *drvdata,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
- if (type == hwmon_temp && attr == hwmon_temp_input)
- return 0444;
- if (type == hwmon_in && attr == hwmon_in_input)
- return 0444;
-
- return 0;
+ return 0444;
}
static int fbnic_hwmon_sensor_read(struct fbnic_dev *fbd, int id, long *val)
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 3/6] eth: fbnic: cache hwmon sensor readings
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 1/6] eth: fbnic: move sensor read logic out of fbnic_mac Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 2/6] eth: fbnic: expose all hwmon attributes unconditionally as read-only Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 4/6] eth: fbnic: report temperature and voltage thresholds via hwmon Zinc Lim
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
Each hwmon attribute access triggers its own TSENE firmware mailbox
round-trip, so reading the full set of attributes or polling them at a
high rate floods the firmware mailbox with quick, successive IPC messages
for data that barely changes between ticks.
Cache the last temperature and voltage reading and serve reads from it
for the remainder of the current jiffy. A single TSENE response carries
both readings, so one transaction on a miss refreshes both and satisfies
a whole batch of reads. The cache is seeded with the FBNIC_SENSOR_NO_DATA
sentinel at registration so the first read always refreshes, and
concurrent reads are serialized by the hwmon core so no additional
locking is required.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic.h | 7 ++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 7 ++++
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 36 +++++++++++++------
3 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index d0715695c43e..f647ef07704b 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -22,11 +22,18 @@ struct fbnic_napi_vector;
#define FBNIC_MAX_NAPI_VECTORS 128u
#define FBNIC_MBX_CMPL_SLOTS 4
+struct fbnic_hwmon_cache {
+ unsigned long last_read;
+ s32 temp_mdeg;
+ s32 volt_mv;
+};
+
struct fbnic_dev {
struct device *dev;
struct net_device *netdev;
struct dentry *dbg_fbd;
struct device *hwmon;
+ struct fbnic_hwmon_cache hwmon_cache;
struct devlink_health_reporter *fw_reporter;
struct devlink_health_reporter *otp_reporter;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
index d84723e4cfa3..42a5f83ddb45 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -6,6 +6,7 @@
#include <linux/completion.h>
#include <linux/if_ether.h>
+#include <linux/limits.h>
#include <linux/types.h>
struct fbnic_dev;
@@ -44,6 +45,12 @@ struct fbnic_fw_ver {
char commit[FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE];
};
+/* Sentinel for a sensor value the driver does not have: a threshold the
+ * firmware never populated (older firmware) or a cache entry not yet
+ * refreshed.
+ */
+#define FBNIC_SENSOR_NO_DATA S32_MIN
+
struct fbnic_fw_cap {
struct {
struct fbnic_fw_ver mgmt, bootloader;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index 38bb26cb8e6c..f35cb0065093 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -2,6 +2,7 @@
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
#include <linux/hwmon.h>
+#include <linux/jiffies.h>
#include "fbnic.h"
#include "fbnic_mac.h"
@@ -25,26 +26,32 @@ static umode_t fbnic_hwmon_is_visible(const void *drvdata,
static int fbnic_hwmon_sensor_read(struct fbnic_dev *fbd, int id, long *val)
{
+ struct fbnic_hwmon_cache *cache = &fbd->hwmon_cache;
struct fbnic_fw_completion *fw_cmpl;
int err = 0;
- s32 *sensor;
-
- fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_TSENE_READ_RESP);
- if (!fw_cmpl)
- return -ENOMEM;
+ s32 *cached;
switch (id) {
case FBNIC_SENSOR_TEMP:
- sensor = &fw_cmpl->u.tsene.millidegrees;
+ cached = &cache->temp_mdeg;
break;
case FBNIC_SENSOR_VOLTAGE:
- sensor = &fw_cmpl->u.tsene.millivolts;
+ cached = &cache->volt_mv;
break;
default:
- err = -EINVAL;
- goto exit_free;
+ return -EINVAL;
+ }
+
+ if (*cached != FBNIC_SENSOR_NO_DATA &&
+ time_is_after_eq_jiffies(cache->last_read)) {
+ *val = *cached;
+ return 0;
}
+ fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_TSENE_READ_RESP);
+ if (!fw_cmpl)
+ return -ENOMEM;
+
err = fbnic_fw_xmit_tsene_read_msg(fbd, fw_cmpl);
if (err) {
dev_err(fbd->dev,
@@ -67,7 +74,12 @@ static int fbnic_hwmon_sensor_read(struct fbnic_dev *fbd, int id, long *val)
goto exit_cleanup;
}
- *val = *sensor;
+ /* FW returns both readings in one response, cache both. */
+ cache->temp_mdeg = fw_cmpl->u.tsene.millidegrees;
+ cache->volt_mv = fw_cmpl->u.tsene.millivolts;
+ cache->last_read = jiffies;
+
+ *val = *cached;
exit_cleanup:
fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
exit_free:
@@ -107,6 +119,10 @@ void fbnic_hwmon_register(struct fbnic_dev *fbd)
if (!IS_REACHABLE(CONFIG_HWMON))
return;
+ /* Seed cache with sentinel so the first read always refreshes. */
+ fbd->hwmon_cache.temp_mdeg = FBNIC_SENSOR_NO_DATA;
+ fbd->hwmon_cache.volt_mv = FBNIC_SENSOR_NO_DATA;
+
fbd->hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic",
fbd, &fbnic_chip_info,
NULL);
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 4/6] eth: fbnic: report temperature and voltage thresholds via hwmon
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
` (2 preceding siblings ...)
2026-07-21 22:15 ` [PATCH net-next 3/6] eth: fbnic: cache hwmon sensor readings Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 5/6] eth: fbnic: report temperature and voltage alarms " Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 6/6] eth: fbnic: firmware notifies hwmon on sensor threshold events Zinc Lim
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
The firmware capability response carries per-board temperature
(min/max/crit) and voltage (min/max) thresholds. Parse and store them in
fbnic_fw_cap, and expose them through the hwmon interface as
temp1_{min,max,crit} and in0_{min,max}.
The thresholds are always exposed. Values the firmware did not report are
stored as the FBNIC_SENSOR_NO_DATA sentinel in the capability response
parser, and a read of such an attribute returns -ENODATA.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 21 ++++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 14 ++++
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 67 ++++++++++++++-----
3 files changed, 87 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
index 283d25fae79e..d814bd4041a0 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
@@ -575,6 +575,11 @@ static const struct fbnic_tlv_index fbnic_fw_cap_resp_index[] = {
FBNIC_TLV_ATTR_STRING(FBNIC_FW_CAP_RESP_UEFI_COMMIT_STR,
FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE),
FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_CAP_RESP_TEMP_MIN),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_CAP_RESP_TEMP_MAX),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_CAP_RESP_TEMP_CRIT),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_CAP_RESP_VOLT_MIN),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_CAP_RESP_VOLT_MAX),
FBNIC_TLV_ATTR_LAST
};
@@ -702,6 +707,22 @@ static int fbnic_fw_parse_cap_resp(void *opaque, struct fbnic_tlv_msg **results)
/* Always assume we need a BMC reinit */
fbd->fw_cap.need_bmc_tcam_reinit = true;
+ fbd->fw_cap.temp.min =
+ fbnic_tlv_attr_get_signed(results[FBNIC_FW_CAP_RESP_TEMP_MIN],
+ FBNIC_SENSOR_NO_DATA);
+ fbd->fw_cap.temp.max =
+ fbnic_tlv_attr_get_signed(results[FBNIC_FW_CAP_RESP_TEMP_MAX],
+ FBNIC_SENSOR_NO_DATA);
+ fbd->fw_cap.temp.crit =
+ fbnic_tlv_attr_get_signed(results[FBNIC_FW_CAP_RESP_TEMP_CRIT],
+ FBNIC_SENSOR_NO_DATA);
+ fbd->fw_cap.volt.min =
+ fbnic_tlv_attr_get_signed(results[FBNIC_FW_CAP_RESP_VOLT_MIN],
+ FBNIC_SENSOR_NO_DATA);
+ fbd->fw_cap.volt.max =
+ fbnic_tlv_attr_get_signed(results[FBNIC_FW_CAP_RESP_VOLT_MAX],
+ FBNIC_SENSOR_NO_DATA);
+
return 0;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
index 42a5f83ddb45..68ffd49e0cdd 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -51,6 +51,12 @@ struct fbnic_fw_ver {
*/
#define FBNIC_SENSOR_NO_DATA S32_MIN
+struct fbnic_threshold {
+ s32 min;
+ s32 max;
+ s32 crit;
+};
+
struct fbnic_fw_cap {
struct {
struct fbnic_fw_ver mgmt, bootloader;
@@ -67,6 +73,8 @@ struct fbnic_fw_cap {
u8 link_speed;
u8 link_fec;
u32 anti_rollback_version;
+ struct fbnic_threshold temp;
+ struct fbnic_threshold volt;
};
struct fbnic_fw_completion {
@@ -249,6 +257,12 @@ enum {
FBNIC_FW_CAP_RESP_UEFI_VERSION = 0x11,
FBNIC_FW_CAP_RESP_UEFI_COMMIT_STR = 0x12,
FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION = 0x15,
+ /* 0x16 and 0x17 are reserved for future use */
+ FBNIC_FW_CAP_RESP_TEMP_MIN = 0x18,
+ FBNIC_FW_CAP_RESP_TEMP_MAX = 0x19,
+ FBNIC_FW_CAP_RESP_TEMP_CRIT = 0x1a,
+ FBNIC_FW_CAP_RESP_VOLT_MIN = 0x1b,
+ FBNIC_FW_CAP_RESP_VOLT_MAX = 0x1c,
FBNIC_FW_CAP_RESP_MSG_MAX
};
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index f35cb0065093..4938f7b39140 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -7,16 +7,6 @@
#include "fbnic.h"
#include "fbnic_mac.h"
-static int fbnic_hwmon_sensor_id(enum hwmon_sensor_types type)
-{
- if (type == hwmon_temp)
- return FBNIC_SENSOR_TEMP;
- if (type == hwmon_in)
- return FBNIC_SENSOR_VOLTAGE;
-
- return -EOPNOTSUPP;
-}
-
static umode_t fbnic_hwmon_is_visible(const void *drvdata,
enum hwmon_sensor_types type,
u32 attr, int channel)
@@ -88,14 +78,58 @@ static int fbnic_hwmon_sensor_read(struct fbnic_dev *fbd, int id, long *val)
return err;
}
+static int fbnic_hwmon_read_threshold(long thr, long *val)
+{
+ if (thr == FBNIC_SENSOR_NO_DATA)
+ return -ENODATA;
+
+ *val = thr;
+ return 0;
+}
+
+static int fbnic_hwmon_temp_read(struct fbnic_dev *fbd, u32 attr, long *val)
+{
+ switch (attr) {
+ case hwmon_temp_input:
+ return fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_TEMP, val);
+ case hwmon_temp_min:
+ return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.min, val);
+ case hwmon_temp_max:
+ return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.max, val);
+ case hwmon_temp_crit:
+ return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.crit, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int fbnic_hwmon_in_read(struct fbnic_dev *fbd, u32 attr, long *val)
+{
+ switch (attr) {
+ case hwmon_in_input:
+ return fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_VOLTAGE, val);
+ case hwmon_in_min:
+ return fbnic_hwmon_read_threshold(fbd->fw_cap.volt.min, val);
+ case hwmon_in_max:
+ return fbnic_hwmon_read_threshold(fbd->fw_cap.volt.max, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct fbnic_dev *fbd = dev_get_drvdata(dev);
- int id;
- id = fbnic_hwmon_sensor_id(type);
- return id < 0 ? id : fbnic_hwmon_sensor_read(fbd, id, val);
+ switch (type) {
+ case hwmon_temp:
+ return fbnic_hwmon_temp_read(fbd, attr, val);
+ case hwmon_in:
+ return fbnic_hwmon_in_read(fbd, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static const struct hwmon_ops fbnic_hwmon_ops = {
@@ -104,8 +138,11 @@ static const struct hwmon_ops fbnic_hwmon_ops = {
};
static const struct hwmon_channel_info *fbnic_hwmon_info[] = {
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
- HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
+ HWMON_T_CRIT),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX),
NULL
};
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 5/6] eth: fbnic: report temperature and voltage alarms via hwmon
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
` (3 preceding siblings ...)
2026-07-21 22:15 ` [PATCH net-next 4/6] eth: fbnic: report temperature and voltage thresholds via hwmon Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 6/6] eth: fbnic: firmware notifies hwmon on sensor threshold events Zinc Lim
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
Building on the temperature and voltage thresholds stored in
fbnic_fw_cap, expose alarm attributes through the hwmon interface:
temp1_{min,max,crit}_alarm and in0_{min,max}_alarm.
Each alarm is computed by taking a live sensor reading and comparing it
against the corresponding stored threshold. The static thresholds
(min/max/crit) are returned first straight from fbnic_fw_cap without a
firmware round-trip, and unsupported attributes are rejected up front, so
only attributes that actually need a live value fall through to a single
sensor read that then feeds input and every alarm.
A threshold the firmware did not populate reports -ENODATA for both the
threshold attribute and its alarm.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 68 +++++++++++++++++--
1 file changed, 61 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index 4938f7b39140..c5cddd9cef12 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -87,34 +87,84 @@ static int fbnic_hwmon_read_threshold(long thr, long *val)
return 0;
}
+static int fbnic_hwmon_read_alarm(long a, long b, long *val)
+{
+ if (a == FBNIC_SENSOR_NO_DATA || b == FBNIC_SENSOR_NO_DATA)
+ return -ENODATA;
+
+ *val = a >= b;
+ return 0;
+}
+
static int fbnic_hwmon_temp_read(struct fbnic_dev *fbd, u32 attr, long *val)
{
+ int err;
+
switch (attr) {
- case hwmon_temp_input:
- return fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_TEMP, val);
case hwmon_temp_min:
return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.min, val);
case hwmon_temp_max:
return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.max, val);
case hwmon_temp_crit:
return fbnic_hwmon_read_threshold(fbd->fw_cap.temp.crit, val);
+ case hwmon_temp_input:
+ case hwmon_temp_min_alarm:
+ case hwmon_temp_max_alarm:
+ case hwmon_temp_crit_alarm:
+ break;
default:
return -EOPNOTSUPP;
}
+
+ err = fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_TEMP, val);
+ if (err)
+ return err;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ return 0;
+ case hwmon_temp_min_alarm:
+ return fbnic_hwmon_read_alarm(fbd->fw_cap.temp.min, *val, val);
+ case hwmon_temp_max_alarm:
+ return fbnic_hwmon_read_alarm(*val, fbd->fw_cap.temp.max, val);
+ case hwmon_temp_crit_alarm:
+ return fbnic_hwmon_read_alarm(*val, fbd->fw_cap.temp.crit, val);
+ }
+
+ return -EOPNOTSUPP;
}
static int fbnic_hwmon_in_read(struct fbnic_dev *fbd, u32 attr, long *val)
{
+ int err;
+
switch (attr) {
- case hwmon_in_input:
- return fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_VOLTAGE, val);
case hwmon_in_min:
return fbnic_hwmon_read_threshold(fbd->fw_cap.volt.min, val);
case hwmon_in_max:
return fbnic_hwmon_read_threshold(fbd->fw_cap.volt.max, val);
+ case hwmon_in_input:
+ case hwmon_in_min_alarm:
+ case hwmon_in_max_alarm:
+ break;
default:
return -EOPNOTSUPP;
}
+
+ err = fbnic_hwmon_sensor_read(fbd, FBNIC_SENSOR_VOLTAGE, val);
+ if (err)
+ return err;
+
+ switch (attr) {
+ case hwmon_in_input:
+ return 0;
+ case hwmon_in_min_alarm:
+ return fbnic_hwmon_read_alarm(fbd->fw_cap.volt.min, *val, val);
+ case hwmon_in_max_alarm:
+ return fbnic_hwmon_read_alarm(*val, fbd->fw_cap.volt.max, val);
+ }
+
+ return -EOPNOTSUPP;
}
static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
@@ -139,10 +189,14 @@ static const struct hwmon_ops fbnic_hwmon_ops = {
static const struct hwmon_channel_info *fbnic_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
- HWMON_T_CRIT),
+ HWMON_T_INPUT |
+ HWMON_T_MIN | HWMON_T_MIN_ALARM |
+ HWMON_T_MAX | HWMON_T_MAX_ALARM |
+ HWMON_T_CRIT | HWMON_T_CRIT_ALARM),
HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX),
+ HWMON_I_INPUT |
+ HWMON_I_MIN | HWMON_I_MIN_ALARM |
+ HWMON_I_MAX | HWMON_I_MAX_ALARM),
NULL
};
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 6/6] eth: fbnic: firmware notifies hwmon on sensor threshold events
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
` (4 preceding siblings ...)
2026-07-21 22:15 ` [PATCH net-next 5/6] eth: fbnic: report temperature and voltage alarms " Zinc Lim
@ 2026-07-21 22:15 ` Zinc Lim
5 siblings, 0 replies; 7+ messages in thread
From: Zinc Lim @ 2026-07-21 22:15 UTC (permalink / raw)
To: Alexander Duyck, Jakub Kicinski, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Guenter Roeck, Simon Horman,
Mohsin Bashir
Cc: kernel-team, netdev, linux-kernel, linux-hwmon, zinclim, Zinc Lim
The firmware sends an unsolicited message via the new
FBNIC_TLV_MSG_ID_SENSOR_THRESHOLD_EXCEEDED_RESP IPC message when a
temperature or voltage sensor crosses one of its thresholds. Parse this
message and translate it into the corresponding hwmon alarm
(temp1_{min,max,crit}_alarm or in0_{min,max}_alarm) via
hwmon_notify_event(), so userspace listeners are woken on the relevant
sysfs attribute.
fbnic_hwmon_notify_event() is driven from the FW mailbox IRQ path, so it
can run concurrently with hwmon registration and teardown. Guard the
publish/teardown of fbd->hwmon: register publishes it with WRITE_ONCE()
only after a successful registration (and leaves it NULL on failure),
unregister clears it with WRITE_ONCE(NULL) and then
synchronize_irq(fbd->fw_msix_vector) to drain any in-flight mailbox IRQ
before unregistering, and notify_event reads it once with READ_ONCE() and
skips the notification when it is NULL.
Signed-off-by: Zinc Lim <limzhineng2@gmail.com>
---
drivers/net/ethernet/meta/fbnic/fbnic.h | 1 +
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 54 +++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 9 +++
drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 68 ++++++++++++++++---
4 files changed, 124 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index f647ef07704b..4a49c20e4a01 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -192,6 +192,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, long val);
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 d814bd4041a0..6dca38076d7b 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
@@ -1639,6 +1639,57 @@ 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_S32(FBNIC_FW_TSENE_THERM_EXCEEDED_FLAG),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_TSENE_VOLT_EXCEEDED_FLAG),
+ 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)
+{
+ bool therm_exceeded, volt_exceeded;
+ struct fbnic_dev *fbd = opaque;
+ s32 value;
+
+ therm_exceeded =
+ fta_get_sint(results, FBNIC_FW_TSENE_THERM_EXCEEDED_FLAG);
+ volt_exceeded =
+ fta_get_sint(results, FBNIC_FW_TSENE_VOLT_EXCEEDED_FLAG);
+
+ if (!therm_exceeded && !volt_exceeded) {
+ dev_err(fbd->dev,
+ "Threshold exceeded message with no flag set\n");
+ return -EINVAL;
+ }
+
+ if (therm_exceeded) {
+ if (!results[FBNIC_FW_TSENE_THERMAL]) {
+ dev_err(fbd->dev,
+ "Thermal threshold exceeded but no value received\n");
+ return -EINVAL;
+ }
+ value = fta_get_sint(results, FBNIC_FW_TSENE_THERMAL);
+ dev_err(fbd->dev, "Thermal threshold exceeded: %d mC\n", value);
+ fbnic_hwmon_notify_event(fbd, FBNIC_SENSOR_TEMP, value);
+ }
+
+ if (volt_exceeded) {
+ if (!results[FBNIC_FW_TSENE_VOLTAGE]) {
+ dev_err(fbd->dev,
+ "Voltage threshold exceeded but no value received\n");
+ return -EINVAL;
+ }
+ value = fta_get_sint(results, FBNIC_FW_TSENE_VOLTAGE);
+ dev_err(fbd->dev, "Voltage threshold exceeded: %d mV\n", value);
+ fbnic_hwmon_notify_event(fbd, FBNIC_SENSOR_VOLTAGE, value);
+ }
+
+ 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,
@@ -1667,6 +1718,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 68ffd49e0cdd..87301e608255 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -227,6 +227,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,
@@ -296,6 +297,14 @@ enum {
FBNIC_FW_TSENE_MSG_MAX
};
+enum {
+ FBNIC_FW_TSENE_THERM_EXCEEDED_FLAG = 0x0,
+ FBNIC_FW_TSENE_VOLT_EXCEEDED_FLAG = 0x1,
+ FBNIC_FW_TSENE_THERMAL = 0x2,
+ FBNIC_FW_TSENE_VOLTAGE = 0x3,
+ FBNIC_FW_TSENE_EXCEEDED_MSG_MAX,
+};
+
enum {
FBNIC_FW_OWNERSHIP_FLAG = 0x0,
FBNIC_FW_OWNERSHIP_TIME = 0x1,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
index c5cddd9cef12..eb910ba47f37 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c
@@ -207,6 +207,8 @@ static const struct hwmon_chip_info fbnic_chip_info = {
void fbnic_hwmon_register(struct fbnic_dev *fbd)
{
+ struct device *hwmon;
+
if (!IS_REACHABLE(CONFIG_HWMON))
return;
@@ -214,22 +216,72 @@ void fbnic_hwmon_register(struct fbnic_dev *fbd)
fbd->hwmon_cache.temp_mdeg = FBNIC_SENSOR_NO_DATA;
fbd->hwmon_cache.volt_mv = FBNIC_SENSOR_NO_DATA;
- fbd->hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic",
- fbd, &fbnic_chip_info,
- NULL);
- if (IS_ERR(fbd->hwmon)) {
+ hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic", fbd,
+ &fbnic_chip_info, NULL);
+ if (IS_ERR(hwmon)) {
dev_notice(fbd->dev,
"Failed to register hwmon device %pe\n",
- fbd->hwmon);
- fbd->hwmon = NULL;
+ hwmon);
+ return;
}
+
+ WRITE_ONCE(fbd->hwmon, hwmon);
}
void fbnic_hwmon_unregister(struct fbnic_dev *fbd)
{
+ struct device *hwmon;
+
if (!IS_REACHABLE(CONFIG_HWMON) || !fbd->hwmon)
return;
- hwmon_device_unregister(fbd->hwmon);
- fbd->hwmon = NULL;
+ hwmon = fbd->hwmon;
+ /* Pair with READ_ONCE() in fbnic_hwmon_notify_event(). Publish NULL
+ * and wait for any in-flight FW mailbox IRQ handler to finish so it
+ * cannot dereference the hwmon device after we unregister it.
+ */
+ WRITE_ONCE(fbd->hwmon, NULL);
+ synchronize_irq(fbd->fw_msix_vector);
+
+ hwmon_device_unregister(hwmon);
+}
+
+void fbnic_hwmon_notify_event(struct fbnic_dev *fbd, int id, long val)
+{
+ enum hwmon_sensor_types type;
+ struct device *hwmon;
+ s32 attr = -1;
+
+ switch (id) {
+ case FBNIC_SENSOR_TEMP:
+ type = hwmon_temp;
+
+ if (val <= fbd->fw_cap.temp.min)
+ attr = hwmon_temp_min_alarm;
+ else if (val >= fbd->fw_cap.temp.crit)
+ attr = hwmon_temp_crit_alarm;
+ else if (val >= fbd->fw_cap.temp.max)
+ attr = hwmon_temp_max_alarm;
+
+ break;
+ case FBNIC_SENSOR_VOLTAGE:
+ type = hwmon_in;
+
+ if (val <= fbd->fw_cap.volt.min)
+ attr = hwmon_in_min_alarm;
+ else if (val >= fbd->fw_cap.volt.max)
+ attr = hwmon_in_max_alarm;
+
+ break;
+ default:
+ return;
+ }
+
+ /* Pair with WRITE_ONCE() in fbnic_hwmon_unregister(). Skip the
+ * notification if hwmon failed to register or has already been torn
+ * down.
+ */
+ hwmon = READ_ONCE(fbd->hwmon);
+ if (attr >= 0 && hwmon)
+ hwmon_notify_event(hwmon, type, attr, 0);
}
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-21 22:15 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 22:15 [PATCH net-next 0/6] eth: fbnic: expand hwmon sensor support Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 1/6] eth: fbnic: move sensor read logic out of fbnic_mac Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 2/6] eth: fbnic: expose all hwmon attributes unconditionally as read-only Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 3/6] eth: fbnic: cache hwmon sensor readings Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 4/6] eth: fbnic: report temperature and voltage thresholds via hwmon Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 5/6] eth: fbnic: report temperature and voltage alarms " Zinc Lim
2026-07-21 22:15 ` [PATCH net-next 6/6] eth: fbnic: firmware notifies hwmon on sensor threshold events Zinc Lim
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox