Skip to content

Commit 2974e66

Browse files
committed
Merge branch 'eth-fbnic-add-hardware-monitoring-support'
Sanman Pradhan says: ==================== eth: fbnic: Add hardware monitoring support This patch series adds hardware monitoring support to the fbnic driver. It implements support for reading temperature and voltage sensors via firmware requests, and exposes this data through the HWMON interface. The series is structured as follows: Patch 1: Adds completion infrastructure for firmware requests Patch 2: Implements TSENE sensor message handling Patch 3: Adds HWMON interface support Output: $ ls -l /sys/class/hwmon/hwmon1/ total 0 lrwxrwxrwx 1 root root 0 Sep 10 00:00 device -> ../../../0000:01:00.0 -r--r--r-- 1 root root 4096 Sep 10 00:00 in0_input -r--r--r-- 1 root root 4096 Sep 10 00:00 name lrwxrwxrwx 1 root root 0 Sep 10 00:00 subsystem -> ../../../../../../class/hwmon -r--r--r-- 1 root root 4096 Sep 10 00:00 temp1_input -rw-r--r-- 1 root root 4096 Sep 10 00:00 uevent $ cat /sys/class/hwmon/hwmon1/temp1_input 40480 $ cat /sys/class/hwmon/hwmon1/in0_input 750 ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 586b298 + 8806307 commit 2974e66

File tree

8 files changed

+357
-0
lines changed

8 files changed

+357
-0
lines changed

drivers/net/ethernet/meta/fbnic/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fbnic-y := fbnic_csr.o \
1313
fbnic_ethtool.o \
1414
fbnic_fw.o \
1515
fbnic_hw_stats.o \
16+
fbnic_hwmon.o \
1617
fbnic_irq.o \
1718
fbnic_mac.o \
1819
fbnic_netdev.o \

drivers/net/ethernet/meta/fbnic/fbnic.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct fbnic_dev {
2424
struct device *dev;
2525
struct net_device *netdev;
2626
struct dentry *dbg_fbd;
27+
struct device *hwmon;
2728

2829
u32 __iomem *uc_addr0;
2930
u32 __iomem *uc_addr4;
@@ -41,6 +42,7 @@ struct fbnic_dev {
4142

4243
struct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES];
4344
struct fbnic_fw_cap fw_cap;
45+
struct fbnic_fw_completion *cmpl_data;
4446
/* Lock protecting Tx Mailbox queue to prevent possible races */
4547
spinlock_t fw_tx_lock;
4648

@@ -149,6 +151,9 @@ void fbnic_devlink_unregister(struct fbnic_dev *fbd);
149151
int fbnic_fw_enable_mbx(struct fbnic_dev *fbd);
150152
void fbnic_fw_disable_mbx(struct fbnic_dev *fbd);
151153

154+
void fbnic_hwmon_register(struct fbnic_dev *fbd);
155+
void fbnic_hwmon_unregister(struct fbnic_dev *fbd);
156+
152157
int fbnic_pcs_irq_enable(struct fbnic_dev *fbd);
153158
void fbnic_pcs_irq_disable(struct fbnic_dev *fbd);
154159

drivers/net/ethernet/meta/fbnic/fbnic_fw.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,63 @@ static void fbnic_mbx_process_tx_msgs(struct fbnic_dev *fbd)
228228
tx_mbx->head = head;
229229
}
230230

231+
static int fbnic_mbx_map_req_w_cmpl(struct fbnic_dev *fbd,
232+
struct fbnic_tlv_msg *msg,
233+
struct fbnic_fw_completion *cmpl_data)
234+
{
235+
unsigned long flags;
236+
int err;
237+
238+
spin_lock_irqsave(&fbd->fw_tx_lock, flags);
239+
240+
/* If we are already waiting on a completion then abort */
241+
if (cmpl_data && fbd->cmpl_data) {
242+
err = -EBUSY;
243+
goto unlock_mbx;
244+
}
245+
246+
/* Record completion location and submit request */
247+
if (cmpl_data)
248+
fbd->cmpl_data = cmpl_data;
249+
250+
err = fbnic_mbx_map_msg(fbd, FBNIC_IPC_MBX_TX_IDX, msg,
251+
le16_to_cpu(msg->hdr.len) * sizeof(u32), 1);
252+
253+
/* If msg failed then clear completion data for next caller */
254+
if (err && cmpl_data)
255+
fbd->cmpl_data = NULL;
256+
257+
unlock_mbx:
258+
spin_unlock_irqrestore(&fbd->fw_tx_lock, flags);
259+
260+
return err;
261+
}
262+
263+
static void fbnic_fw_release_cmpl_data(struct kref *kref)
264+
{
265+
struct fbnic_fw_completion *cmpl_data;
266+
267+
cmpl_data = container_of(kref, struct fbnic_fw_completion,
268+
ref_count);
269+
kfree(cmpl_data);
270+
}
271+
272+
static struct fbnic_fw_completion *
273+
fbnic_fw_get_cmpl_by_type(struct fbnic_dev *fbd, u32 msg_type)
274+
{
275+
struct fbnic_fw_completion *cmpl_data = NULL;
276+
unsigned long flags;
277+
278+
spin_lock_irqsave(&fbd->fw_tx_lock, flags);
279+
if (fbd->cmpl_data && fbd->cmpl_data->msg_type == msg_type) {
280+
cmpl_data = fbd->cmpl_data;
281+
kref_get(&fbd->cmpl_data->ref_count);
282+
}
283+
spin_unlock_irqrestore(&fbd->fw_tx_lock, flags);
284+
285+
return cmpl_data;
286+
}
287+
231288
/**
232289
* fbnic_fw_xmit_simple_msg - Transmit a simple single TLV message w/o data
233290
* @fbd: FBNIC device structure
@@ -651,13 +708,94 @@ void fbnic_fw_check_heartbeat(struct fbnic_dev *fbd)
651708
dev_warn(fbd->dev, "Failed to send heartbeat message\n");
652709
}
653710

711+
/**
712+
* fbnic_fw_xmit_tsene_read_msg - Create and transmit a sensor read request
713+
* @fbd: FBNIC device structure
714+
* @cmpl_data: Completion data structure to store sensor response
715+
*
716+
* Asks the firmware to provide an update with the latest sensor data.
717+
* The response will contain temperature and voltage readings.
718+
*
719+
* Return: 0 on success, negative error value on failure
720+
*/
721+
int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
722+
struct fbnic_fw_completion *cmpl_data)
723+
{
724+
struct fbnic_tlv_msg *msg;
725+
int err;
726+
727+
if (!fbnic_fw_present(fbd))
728+
return -ENODEV;
729+
730+
msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_TSENE_READ_REQ);
731+
if (!msg)
732+
return -ENOMEM;
733+
734+
err = fbnic_mbx_map_req_w_cmpl(fbd, msg, cmpl_data);
735+
if (err)
736+
goto free_message;
737+
738+
return 0;
739+
740+
free_message:
741+
free_page((unsigned long)msg);
742+
return err;
743+
}
744+
745+
static const struct fbnic_tlv_index fbnic_tsene_read_resp_index[] = {
746+
FBNIC_TLV_ATTR_S32(FBNIC_TSENE_THERM),
747+
FBNIC_TLV_ATTR_S32(FBNIC_TSENE_VOLT),
748+
FBNIC_TLV_ATTR_S32(FBNIC_TSENE_ERROR),
749+
FBNIC_TLV_ATTR_LAST
750+
};
751+
752+
static int fbnic_fw_parse_tsene_read_resp(void *opaque,
753+
struct fbnic_tlv_msg **results)
754+
{
755+
struct fbnic_fw_completion *cmpl_data;
756+
struct fbnic_dev *fbd = opaque;
757+
int err = 0;
758+
759+
/* Verify we have a completion pointer to provide with data */
760+
cmpl_data = fbnic_fw_get_cmpl_by_type(fbd,
761+
FBNIC_TLV_MSG_ID_TSENE_READ_RESP);
762+
if (!cmpl_data)
763+
return -EINVAL;
764+
765+
if (results[FBNIC_TSENE_ERROR]) {
766+
err = fbnic_tlv_attr_get_unsigned(results[FBNIC_TSENE_ERROR]);
767+
if (err)
768+
goto exit_complete;
769+
}
770+
771+
if (!results[FBNIC_TSENE_THERM] || !results[FBNIC_TSENE_VOLT]) {
772+
err = -EINVAL;
773+
goto exit_complete;
774+
}
775+
776+
cmpl_data->u.tsene.millidegrees =
777+
fbnic_tlv_attr_get_signed(results[FBNIC_TSENE_THERM]);
778+
cmpl_data->u.tsene.millivolts =
779+
fbnic_tlv_attr_get_signed(results[FBNIC_TSENE_VOLT]);
780+
781+
exit_complete:
782+
cmpl_data->result = err;
783+
complete(&cmpl_data->done);
784+
fbnic_fw_put_cmpl(cmpl_data);
785+
786+
return err;
787+
}
788+
654789
static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
655790
FBNIC_TLV_PARSER(FW_CAP_RESP, fbnic_fw_cap_resp_index,
656791
fbnic_fw_parse_cap_resp),
657792
FBNIC_TLV_PARSER(OWNERSHIP_RESP, fbnic_ownership_resp_index,
658793
fbnic_fw_parse_ownership_resp),
659794
FBNIC_TLV_PARSER(HEARTBEAT_RESP, fbnic_heartbeat_resp_index,
660795
fbnic_fw_parse_heartbeat_resp),
796+
FBNIC_TLV_PARSER(TSENE_READ_RESP,
797+
fbnic_tsene_read_resp_index,
798+
fbnic_fw_parse_tsene_read_resp),
661799
FBNIC_TLV_MSG_ERROR
662800
};
663801

@@ -802,3 +940,25 @@ void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,
802940
fbnic_mk_full_fw_ver_str(mgmt->version, delim, mgmt->commit,
803941
fw_version, str_sz);
804942
}
943+
944+
void fbnic_fw_init_cmpl(struct fbnic_fw_completion *fw_cmpl,
945+
u32 msg_type)
946+
{
947+
fw_cmpl->msg_type = msg_type;
948+
init_completion(&fw_cmpl->done);
949+
kref_init(&fw_cmpl->ref_count);
950+
}
951+
952+
void fbnic_fw_clear_compl(struct fbnic_dev *fbd)
953+
{
954+
unsigned long flags;
955+
956+
spin_lock_irqsave(&fbd->fw_tx_lock, flags);
957+
fbd->cmpl_data = NULL;
958+
spin_unlock_irqrestore(&fbd->fw_tx_lock, flags);
959+
}
960+
961+
void fbnic_fw_put_cmpl(struct fbnic_fw_completion *fw_cmpl)
962+
{
963+
kref_put(&fw_cmpl->ref_count, fbnic_fw_release_cmpl_data);
964+
}

drivers/net/ethernet/meta/fbnic/fbnic_fw.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ struct fbnic_fw_cap {
4444
u8 link_fec;
4545
};
4646

47+
struct fbnic_fw_completion {
48+
u32 msg_type;
49+
struct completion done;
50+
struct kref ref_count;
51+
int result;
52+
union {
53+
struct {
54+
s32 millivolts;
55+
s32 millidegrees;
56+
} tsene;
57+
} u;
58+
};
59+
4760
void fbnic_mbx_init(struct fbnic_dev *fbd);
4861
void fbnic_mbx_clean(struct fbnic_dev *fbd);
4962
void fbnic_mbx_poll(struct fbnic_dev *fbd);
@@ -52,6 +65,12 @@ void fbnic_mbx_flush_tx(struct fbnic_dev *fbd);
5265
int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership);
5366
int fbnic_fw_init_heartbeat(struct fbnic_dev *fbd, bool poll);
5467
void fbnic_fw_check_heartbeat(struct fbnic_dev *fbd);
68+
int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
69+
struct fbnic_fw_completion *cmpl_data);
70+
void fbnic_fw_init_cmpl(struct fbnic_fw_completion *cmpl_data,
71+
u32 msg_type);
72+
void fbnic_fw_clear_compl(struct fbnic_dev *fbd);
73+
void fbnic_fw_put_cmpl(struct fbnic_fw_completion *cmpl_data);
5574

5675
#define fbnic_mk_full_fw_ver_str(_rev_id, _delim, _commit, _str, _str_sz) \
5776
do { \
@@ -76,6 +95,8 @@ enum {
7695
FBNIC_TLV_MSG_ID_OWNERSHIP_RESP = 0x13,
7796
FBNIC_TLV_MSG_ID_HEARTBEAT_REQ = 0x14,
7897
FBNIC_TLV_MSG_ID_HEARTBEAT_RESP = 0x15,
98+
FBNIC_TLV_MSG_ID_TSENE_READ_REQ = 0x3C,
99+
FBNIC_TLV_MSG_ID_TSENE_READ_RESP = 0x3D,
79100
};
80101

81102
#define FBNIC_FW_CAP_RESP_VERSION_MAJOR CSR_GENMASK(31, 24)
@@ -117,6 +138,13 @@ enum {
117138
FBNIC_FW_LINK_FEC_BASER = 3,
118139
};
119140

141+
enum {
142+
FBNIC_TSENE_THERM = 0x0,
143+
FBNIC_TSENE_VOLT = 0x1,
144+
FBNIC_TSENE_ERROR = 0x2,
145+
FBNIC_TSENE_MSG_MAX
146+
};
147+
120148
enum {
121149
FBNIC_FW_OWNERSHIP_FLAG = 0x0,
122150
FBNIC_FW_OWNERSHIP_MSG_MAX
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3+
4+
#include <linux/hwmon.h>
5+
6+
#include "fbnic.h"
7+
#include "fbnic_mac.h"
8+
9+
static int fbnic_hwmon_sensor_id(enum hwmon_sensor_types type)
10+
{
11+
if (type == hwmon_temp)
12+
return FBNIC_SENSOR_TEMP;
13+
if (type == hwmon_in)
14+
return FBNIC_SENSOR_VOLTAGE;
15+
16+
return -EOPNOTSUPP;
17+
}
18+
19+
static umode_t fbnic_hwmon_is_visible(const void *drvdata,
20+
enum hwmon_sensor_types type,
21+
u32 attr, int channel)
22+
{
23+
if (type == hwmon_temp && attr == hwmon_temp_input)
24+
return 0444;
25+
if (type == hwmon_in && attr == hwmon_in_input)
26+
return 0444;
27+
28+
return 0;
29+
}
30+
31+
static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
32+
u32 attr, int channel, long *val)
33+
{
34+
struct fbnic_dev *fbd = dev_get_drvdata(dev);
35+
const struct fbnic_mac *mac = fbd->mac;
36+
int id;
37+
38+
id = fbnic_hwmon_sensor_id(type);
39+
return id < 0 ? id : mac->get_sensor(fbd, id, val);
40+
}
41+
42+
static const struct hwmon_ops fbnic_hwmon_ops = {
43+
.is_visible = fbnic_hwmon_is_visible,
44+
.read = fbnic_hwmon_read,
45+
};
46+
47+
static const struct hwmon_channel_info *fbnic_hwmon_info[] = {
48+
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
49+
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
50+
NULL
51+
};
52+
53+
static const struct hwmon_chip_info fbnic_chip_info = {
54+
.ops = &fbnic_hwmon_ops,
55+
.info = fbnic_hwmon_info,
56+
};
57+
58+
void fbnic_hwmon_register(struct fbnic_dev *fbd)
59+
{
60+
if (!IS_REACHABLE(CONFIG_HWMON))
61+
return;
62+
63+
fbd->hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic",
64+
fbd, &fbnic_chip_info,
65+
NULL);
66+
if (IS_ERR(fbd->hwmon)) {
67+
dev_notice(fbd->dev,
68+
"Failed to register hwmon device %pe\n",
69+
fbd->hwmon);
70+
fbd->hwmon = NULL;
71+
}
72+
}
73+
74+
void fbnic_hwmon_unregister(struct fbnic_dev *fbd)
75+
{
76+
if (!IS_REACHABLE(CONFIG_HWMON) || !fbd->hwmon)
77+
return;
78+
79+
hwmon_device_unregister(fbd->hwmon);
80+
fbd->hwmon = NULL;
81+
}

0 commit comments

Comments
 (0)