* [PATCH net-next] eth: fbnic: Read module EEPROM
@ 2025-09-19 19:16 Mohsin Bashir
2025-09-19 19:25 ` Andrew Lunn
2025-09-21 7:48 ` Ido Schimmel
0 siblings, 2 replies; 6+ messages in thread
From: Mohsin Bashir @ 2025-09-19 19:16 UTC (permalink / raw)
To: netdev
Cc: alexanderduyck, kuba, andrew+netdev, davem, edumazet, gustavoars,
horms, jacob.e.keller, kees, kernel-team, lee, linux,
mohsin.bashr, pabeni, sanman.p211993, suhui, vadim.fedorenko
Add support to read module EEPROM for fbnic. Towards this, add required
support to issue a new command to the firmware and to receive the response
to the corresponding command.
Create a local copy of the data in the completion struct before writing to
ethtool_module_eeprom to avoid writing to data in case it is freed. Given
that EEPROM pages are small, the overhead of additional copy is
negligible.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
---
.../net/ethernet/meta/fbnic/fbnic_ethtool.c | 66 +++++++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 135 ++++++++++++++++++
drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 22 +++
3 files changed, 223 insertions(+)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index b4ff98ee2051..f6069cddffa5 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -1635,6 +1635,71 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
}
}
+static int
+fbnic_get_module_eeprom_by_page(struct net_device *netdev,
+ const struct ethtool_module_eeprom *page_data,
+ struct netlink_ext_ack *extack)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct fbnic_fw_completion *fw_cmpl;
+ struct fbnic_dev *fbd = fbn->fbd;
+ int err;
+
+ if (page_data->i2c_address != 0x50) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Invalid i2c address. Only 0x50 is supported");
+ return -EINVAL;
+ }
+
+ if (page_data->bank != 0) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Invalid bank. Only 0 is supported");
+ return -EINVAL;
+ }
+
+ fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
+ page_data->length);
+ if (!fw_cmpl)
+ return -ENOMEM;
+
+ /* Initialize completion and queue it for FW to process */
+ fw_cmpl->u.qsfp.length = page_data->length;
+ fw_cmpl->u.qsfp.offset = page_data->offset;
+ fw_cmpl->u.qsfp.page = page_data->page;
+ fw_cmpl->u.qsfp.bank = page_data->bank;
+
+ err = fbnic_fw_xmit_qsfp_read_msg(fbd, fw_cmpl, page_data->page,
+ page_data->bank, page_data->offset,
+ page_data->length);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed to transmit EEPROM read request");
+ goto exit_free;
+ }
+
+ if (!wait_for_completion_timeout(&fw_cmpl->done, 2 * HZ)) {
+ err = -ETIMEDOUT;
+ NL_SET_ERR_MSG_MOD(extack,
+ "Timed out waiting for firmware response");
+ goto exit_cleanup;
+ }
+
+ if (fw_cmpl->result) {
+ err = fw_cmpl->result;
+ NL_SET_ERR_MSG_MOD(extack, "Failed to read EEPROM");
+ goto exit_cleanup;
+ }
+
+ memcpy(page_data->data, fw_cmpl->u.qsfp.data, page_data->length);
+
+exit_cleanup:
+ fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
+exit_free:
+ fbnic_fw_put_cmpl(fw_cmpl);
+
+ return err ? : page_data->length;
+}
+
static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
{
if (counter->reported)
@@ -1841,6 +1906,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
.get_link_ksettings = fbnic_phylink_ethtool_ksettings_get,
.get_fec_stats = fbnic_get_fec_stats,
.get_fecparam = fbnic_phylink_get_fecparam,
+ .get_module_eeprom_by_page = fbnic_get_module_eeprom_by_page,
.get_eth_phy_stats = fbnic_get_eth_phy_stats,
.get_eth_mac_stats = fbnic_get_eth_mac_stats,
.get_eth_ctrl_stats = fbnic_get_eth_ctrl_stats,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
index 6c3e7f81a2ed..c87cb9ed09e7 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
@@ -1184,6 +1184,138 @@ static int fbnic_fw_parse_fw_finish_upgrade_req(void *opaque,
return 0;
}
+/**
+ * fbnic_fw_xmit_qsfp_read_msg - Transmit a QSFP read request
+ * @fbd: FBNIC device structure
+ * @cmpl_data: Structure to store EEPROM response in
+ * @page: Refers to page number on page enabled QSFP modules
+ * @bank: Refers to a collection of pages
+ * @offset: Offset into QSFP EEPROM requested
+ * @length: Length of section of QSFP EEPROM to fetch
+ *
+ * Return: zero on success, negative value on failure
+ *
+ * Asks the firmware to provide a section of the QSFP EEPROM back in a
+ * message. The response will have an offset and size matching the values
+ * provided.
+ */
+int fbnic_fw_xmit_qsfp_read_msg(struct fbnic_dev *fbd,
+ struct fbnic_fw_completion *cmpl_data,
+ u32 page, u32 bank, u32 offset, u32 length)
+{
+ struct fbnic_tlv_msg *msg;
+ int err = 0;
+
+ if (!length || length > TLV_MAX_DATA)
+ return -EINVAL;
+
+ msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_QSFP_READ_REQ);
+ if (!msg)
+ return -ENOMEM;
+
+ err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_QSFP_BANK, bank);
+ if (err)
+ goto free_message;
+
+ err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_QSFP_PAGE, page);
+ if (err)
+ goto free_message;
+
+ err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_QSFP_OFFSET, offset);
+ if (err)
+ goto free_message;
+
+ err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_QSFP_LENGTH, length);
+ if (err)
+ goto free_message;
+
+ err = fbnic_mbx_map_req_w_cmpl(fbd, msg, cmpl_data);
+ if (err)
+ goto free_message;
+
+ return 0;
+
+free_message:
+ free_page((unsigned long)msg);
+ return err;
+}
+
+static const struct fbnic_tlv_index fbnic_qsfp_read_resp_index[] = {
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_QSFP_BANK),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_QSFP_PAGE),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_QSFP_OFFSET),
+ FBNIC_TLV_ATTR_U32(FBNIC_FW_QSFP_LENGTH),
+ FBNIC_TLV_ATTR_RAW_DATA(FBNIC_FW_QSFP_DATA),
+ FBNIC_TLV_ATTR_S32(FBNIC_FW_QSFP_ERROR),
+ FBNIC_TLV_ATTR_LAST
+};
+
+static int fbnic_fw_parse_qsfp_read_resp(void *opaque,
+ struct fbnic_tlv_msg **results)
+{
+ struct fbnic_fw_completion *cmpl_data;
+ struct fbnic_dev *fbd = opaque;
+ struct fbnic_tlv_msg *data_hdr;
+ u32 length, offset, page, bank;
+ u8 *data;
+ s32 err;
+
+ /* Verify we have a completion pointer to provide with data */
+ cmpl_data = fbnic_fw_get_cmpl_by_type(fbd,
+ FBNIC_TLV_MSG_ID_QSFP_READ_RESP);
+ if (!cmpl_data)
+ return -ENOSPC;
+
+ bank = fta_get_uint(results, FBNIC_FW_QSFP_BANK);
+ if (bank != cmpl_data->u.qsfp.bank) {
+ dev_warn(fbd->dev, "bank not equal to bank requested: %d vs %d\n",
+ bank, cmpl_data->u.qsfp.bank);
+ err = -EINVAL;
+ goto msg_err;
+ }
+
+ page = fta_get_uint(results, FBNIC_FW_QSFP_PAGE);
+ if (page != cmpl_data->u.qsfp.page) {
+ dev_warn(fbd->dev, "page not equal to page requested: %d vs %d\n",
+ page, cmpl_data->u.qsfp.page);
+ err = -EINVAL;
+ goto msg_err;
+ }
+
+ offset = fta_get_uint(results, FBNIC_FW_QSFP_OFFSET);
+ length = fta_get_uint(results, FBNIC_FW_QSFP_LENGTH);
+
+ if (length != cmpl_data->u.qsfp.length ||
+ offset != cmpl_data->u.qsfp.offset) {
+ dev_warn(fbd->dev,
+ "offset/length not equal to size requested: %d/%d vs %d/%d\n",
+ offset, length,
+ cmpl_data->u.qsfp.offset, cmpl_data->u.qsfp.length);
+ err = -EINVAL;
+ goto msg_err;
+ }
+
+ err = fta_get_sint(results, FBNIC_FW_QSFP_ERROR);
+ if (err)
+ goto msg_err;
+
+ data_hdr = results[FBNIC_FW_QSFP_DATA];
+ if (!data_hdr) {
+ err = -ENODATA;
+ goto msg_err;
+ }
+
+ /* Copy data */
+ data = fbnic_tlv_attr_get_value_ptr(data_hdr);
+ memcpy(cmpl_data->u.qsfp.data, data, length);
+msg_err:
+ cmpl_data->result = err;
+ complete(&cmpl_data->done);
+ fbnic_fw_put_cmpl(cmpl_data);
+
+ return err;
+}
+
/**
* fbnic_fw_xmit_tsene_read_msg - Create and transmit a sensor read request
* @fbd: FBNIC device structure
@@ -1445,6 +1577,9 @@ static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
FBNIC_TLV_PARSER(FW_FINISH_UPGRADE_REQ,
fbnic_fw_finish_upgrade_req_index,
fbnic_fw_parse_fw_finish_upgrade_req),
+ FBNIC_TLV_PARSER(QSFP_READ_RESP,
+ fbnic_qsfp_read_resp_index,
+ fbnic_fw_parse_qsfp_read_resp),
FBNIC_TLV_PARSER(TSENE_READ_RESP,
fbnic_tsene_read_resp_index,
fbnic_fw_parse_tsene_read_resp),
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
index d776be9fc7f7..1ecd777aaada 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h
@@ -78,6 +78,13 @@ struct fbnic_fw_completion {
u32 offset;
u32 length;
} fw_update;
+ struct {
+ u16 length;
+ u8 offset;
+ u8 page;
+ u8 bank;
+ u8 data[] __aligned(sizeof(u32)) __counted_by(length);
+ } qsfp;
struct {
s32 millivolts;
s32 millidegrees;
@@ -109,6 +116,9 @@ int fbnic_fw_xmit_fw_start_upgrade(struct fbnic_dev *fbd,
int fbnic_fw_xmit_fw_write_chunk(struct fbnic_dev *fbd,
const u8 *data, u32 offset, u16 length,
int cancel_error);
+int fbnic_fw_xmit_qsfp_read_msg(struct fbnic_dev *fbd,
+ struct fbnic_fw_completion *cmpl_data,
+ u32 page, u32 bank, u32 offset, u32 length);
int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
struct fbnic_fw_completion *cmpl_data);
int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable,
@@ -161,6 +171,8 @@ enum {
FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_RESP = 0x25,
FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_REQ = 0x28,
FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_RESP = 0x29,
+ FBNIC_TLV_MSG_ID_QSFP_READ_REQ = 0x38,
+ 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_LOG_SEND_LOGS_REQ = 0x43,
@@ -209,6 +221,16 @@ enum {
FBNIC_FW_LINK_FEC_BASER = 3,
};
+enum {
+ FBNIC_FW_QSFP_BANK = 0x0,
+ FBNIC_FW_QSFP_PAGE = 0x1,
+ FBNIC_FW_QSFP_OFFSET = 0x2,
+ FBNIC_FW_QSFP_LENGTH = 0x3,
+ FBNIC_FW_QSFP_ERROR = 0x4,
+ FBNIC_FW_QSFP_DATA = 0x5,
+ FBNIC_FW_QSFP_MSG_MAX
+};
+
enum {
FBNIC_FW_TSENE_THERM = 0x0,
FBNIC_FW_TSENE_VOLT = 0x1,
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net-next] eth: fbnic: Read module EEPROM
2025-09-19 19:16 [PATCH net-next] eth: fbnic: Read module EEPROM Mohsin Bashir
@ 2025-09-19 19:25 ` Andrew Lunn
2025-09-21 23:36 ` Alexander H Duyck
2025-09-21 7:48 ` Ido Schimmel
1 sibling, 1 reply; 6+ messages in thread
From: Andrew Lunn @ 2025-09-19 19:25 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, alexanderduyck, kuba, andrew+netdev, davem, edumazet,
gustavoars, horms, jacob.e.keller, kees, kernel-team, lee, linux,
pabeni, sanman.p211993, suhui, vadim.fedorenko
On Fri, Sep 19, 2025 at 12:16:24PM -0700, Mohsin Bashir wrote:
> Add support to read module EEPROM for fbnic. Towards this, add required
> support to issue a new command to the firmware and to receive the response
> to the corresponding command.
>
> Create a local copy of the data in the completion struct before writing to
> ethtool_module_eeprom to avoid writing to data in case it is freed. Given
> that EEPROM pages are small, the overhead of additional copy is
> negligible.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
> ---
> .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 66 +++++++++
> drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 135 ++++++++++++++++++
> drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 22 +++
> 3 files changed, 223 insertions(+)
>
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> index b4ff98ee2051..f6069cddffa5 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> @@ -1635,6 +1635,71 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
> }
> }
>
> +static int
> +fbnic_get_module_eeprom_by_page(struct net_device *netdev,
> + const struct ethtool_module_eeprom *page_data,
> + struct netlink_ext_ack *extack)
> +{
> + struct fbnic_net *fbn = netdev_priv(netdev);
> + struct fbnic_fw_completion *fw_cmpl;
> + struct fbnic_dev *fbd = fbn->fbd;
> + int err;
> +
> + if (page_data->i2c_address != 0x50) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Invalid i2c address. Only 0x50 is supported");
> + return -EINVAL;
> + }
> +
> + if (page_data->bank != 0) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Invalid bank. Only 0 is supported");
> + return -EINVAL;
> + }
> +
> + fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
> + page_data->length);
> + if (!fw_cmpl)
> + return -ENOMEM;
> +
> + /* Initialize completion and queue it for FW to process */
> + fw_cmpl->u.qsfp.length = page_data->length;
> + fw_cmpl->u.qsfp.offset = page_data->offset;
> + fw_cmpl->u.qsfp.page = page_data->page;
> + fw_cmpl->u.qsfp.bank = page_data->bank;
> +
> + err = fbnic_fw_xmit_qsfp_read_msg(fbd, fw_cmpl, page_data->page,
> + page_data->bank, page_data->offset,
> + page_data->length);
> + if (err) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Failed to transmit EEPROM read request");
> + goto exit_free;
> + }
At some point, you are going to hand off control of the I2C bus to
phylink, so it can drive the SFP. I know Alex at least had a plan how
that will work. At that point, will you just throw this away, and let
sfp_get_module_eeprom_by_page() implement this?
Andrew
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next] eth: fbnic: Read module EEPROM
2025-09-19 19:16 [PATCH net-next] eth: fbnic: Read module EEPROM Mohsin Bashir
2025-09-19 19:25 ` Andrew Lunn
@ 2025-09-21 7:48 ` Ido Schimmel
2025-09-21 23:45 ` Alexander H Duyck
2025-09-22 16:56 ` Mohsin Bashir
1 sibling, 2 replies; 6+ messages in thread
From: Ido Schimmel @ 2025-09-21 7:48 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, alexanderduyck, kuba, andrew+netdev, davem, edumazet,
gustavoars, horms, jacob.e.keller, kees, kernel-team, lee, linux,
pabeni, sanman.p211993, suhui, vadim.fedorenko
On Fri, Sep 19, 2025 at 12:16:24PM -0700, Mohsin Bashir wrote:
> Add support to read module EEPROM for fbnic. Towards this, add required
> support to issue a new command to the firmware and to receive the response
> to the corresponding command.
>
> Create a local copy of the data in the completion struct before writing to
> ethtool_module_eeprom to avoid writing to data in case it is freed. Given
> that EEPROM pages are small, the overhead of additional copy is
> negligible.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
See a few questions below
> ---
> .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 66 +++++++++
> drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 135 ++++++++++++++++++
> drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 22 +++
> 3 files changed, 223 insertions(+)
>
> diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> index b4ff98ee2051..f6069cddffa5 100644
> --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> @@ -1635,6 +1635,71 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
> }
> }
>
> +static int
> +fbnic_get_module_eeprom_by_page(struct net_device *netdev,
> + const struct ethtool_module_eeprom *page_data,
> + struct netlink_ext_ack *extack)
> +{
> + struct fbnic_net *fbn = netdev_priv(netdev);
> + struct fbnic_fw_completion *fw_cmpl;
> + struct fbnic_dev *fbd = fbn->fbd;
> + int err;
> +
> + if (page_data->i2c_address != 0x50) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Invalid i2c address. Only 0x50 is supported");
> + return -EINVAL;
> + }
> +
> + if (page_data->bank != 0) {
What is the reason for this check?
I understand that it's very unlikely to have a transceiver with banked
pages connected to this NIC (requires more than 8 lanes), but it's
generally better to not restrict this ethtool operation unless you have
a good reason to, especially when the firmware seems to support banked
pages.
> + NL_SET_ERR_MSG_MOD(extack,
> + "Invalid bank. Only 0 is supported");
> + return -EINVAL;
> + }
> +
> + fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
QSFP is not the most accurate term, but I assume it's named that way to
be consistent with the HW/FW data sheet.
> + page_data->length);
> + if (!fw_cmpl)
> + return -ENOMEM;
> +
> + /* Initialize completion and queue it for FW to process */
> + fw_cmpl->u.qsfp.length = page_data->length;
> + fw_cmpl->u.qsfp.offset = page_data->offset;
> + fw_cmpl->u.qsfp.page = page_data->page;
> + fw_cmpl->u.qsfp.bank = page_data->bank;
> +
> + err = fbnic_fw_xmit_qsfp_read_msg(fbd, fw_cmpl, page_data->page,
> + page_data->bank, page_data->offset,
> + page_data->length);
> + if (err) {
> + NL_SET_ERR_MSG_MOD(extack,
> + "Failed to transmit EEPROM read request");
> + goto exit_free;
> + }
> +
> + if (!wait_for_completion_timeout(&fw_cmpl->done, 2 * HZ)) {
> + err = -ETIMEDOUT;
> + NL_SET_ERR_MSG_MOD(extack,
> + "Timed out waiting for firmware response");
> + goto exit_cleanup;
> + }
> +
> + if (fw_cmpl->result) {
> + err = fw_cmpl->result;
> + NL_SET_ERR_MSG_MOD(extack, "Failed to read EEPROM");
> + goto exit_cleanup;
> + }
> +
> + memcpy(page_data->data, fw_cmpl->u.qsfp.data, page_data->length);
> +
> +exit_cleanup:
> + fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
> +exit_free:
> + fbnic_fw_put_cmpl(fw_cmpl);
> +
> + return err ? : page_data->length;
> +}
[...]
> +static int fbnic_fw_parse_qsfp_read_resp(void *opaque,
> + struct fbnic_tlv_msg **results)
> +{
> + struct fbnic_fw_completion *cmpl_data;
> + struct fbnic_dev *fbd = opaque;
> + struct fbnic_tlv_msg *data_hdr;
> + u32 length, offset, page, bank;
> + u8 *data;
> + s32 err;
> +
> + /* Verify we have a completion pointer to provide with data */
> + cmpl_data = fbnic_fw_get_cmpl_by_type(fbd,
> + FBNIC_TLV_MSG_ID_QSFP_READ_RESP);
> + if (!cmpl_data)
> + return -ENOSPC;
> +
> + bank = fta_get_uint(results, FBNIC_FW_QSFP_BANK);
> + if (bank != cmpl_data->u.qsfp.bank) {
> + dev_warn(fbd->dev, "bank not equal to bank requested: %d vs %d\n",
> + bank, cmpl_data->u.qsfp.bank);
> + err = -EINVAL;
> + goto msg_err;
> + }
> +
> + page = fta_get_uint(results, FBNIC_FW_QSFP_PAGE);
> + if (page != cmpl_data->u.qsfp.page) {
Out of curiosity, can this happen if user space tries to access a page
that is not supported by the transceiver? I believe most implementations
do not return an error in this case.
> + dev_warn(fbd->dev, "page not equal to page requested: %d vs %d\n",
> + page, cmpl_data->u.qsfp.page);
> + err = -EINVAL;
> + goto msg_err;
> + }
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next] eth: fbnic: Read module EEPROM
2025-09-19 19:25 ` Andrew Lunn
@ 2025-09-21 23:36 ` Alexander H Duyck
0 siblings, 0 replies; 6+ messages in thread
From: Alexander H Duyck @ 2025-09-21 23:36 UTC (permalink / raw)
To: Andrew Lunn, Mohsin Bashir
Cc: netdev, alexanderduyck, kuba, andrew+netdev, davem, edumazet,
gustavoars, horms, jacob.e.keller, kees, kernel-team, lee, linux,
pabeni, sanman.p211993, suhui, vadim.fedorenko
On Fri, 2025-09-19 at 21:25 +0200, Andrew Lunn wrote:
> On Fri, Sep 19, 2025 at 12:16:24PM -0700, Mohsin Bashir wrote:
> > Add support to read module EEPROM for fbnic. Towards this, add required
> > support to issue a new command to the firmware and to receive the response
> > to the corresponding command.
> >
> > Create a local copy of the data in the completion struct before writing to
> > ethtool_module_eeprom to avoid writing to data in case it is freed. Given
> > that EEPROM pages are small, the overhead of additional copy is
> > negligible.
> >
> > Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> > Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
> > ---
> > .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 66 +++++++++
> > drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 135 ++++++++++++++++++
> > drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 22 +++
> > 3 files changed, 223 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > index b4ff98ee2051..f6069cddffa5 100644
> > --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > @@ -1635,6 +1635,71 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
> > }
> > }
> >
> > +static int
> > +fbnic_get_module_eeprom_by_page(struct net_device *netdev,
> > + const struct ethtool_module_eeprom *page_data,
> > + struct netlink_ext_ack *extack)
> > +{
> > + struct fbnic_net *fbn = netdev_priv(netdev);
> > + struct fbnic_fw_completion *fw_cmpl;
> > + struct fbnic_dev *fbd = fbn->fbd;
> > + int err;
> > +
> > + if (page_data->i2c_address != 0x50) {
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Invalid i2c address. Only 0x50 is supported");
> > + return -EINVAL;
> > + }
> > +
> > + if (page_data->bank != 0) {
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Invalid bank. Only 0 is supported");
> > + return -EINVAL;
> > + }
> > +
> > + fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
> > + page_data->length);
> > + if (!fw_cmpl)
> > + return -ENOMEM;
> > +
> > + /* Initialize completion and queue it for FW to process */
> > + fw_cmpl->u.qsfp.length = page_data->length;
> > + fw_cmpl->u.qsfp.offset = page_data->offset;
> > + fw_cmpl->u.qsfp.page = page_data->page;
> > + fw_cmpl->u.qsfp.bank = page_data->bank;
> > +
> > + err = fbnic_fw_xmit_qsfp_read_msg(fbd, fw_cmpl, page_data->page,
> > + page_data->bank, page_data->offset,
> > + page_data->length);
> > + if (err) {
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Failed to transmit EEPROM read request");
> > + goto exit_free;
> > + }
>
> At some point, you are going to hand off control of the I2C bus to
> phylink, so it can drive the SFP. I know Alex at least had a plan how
> that will work. At that point, will you just throw this away, and let
> sfp_get_module_eeprom_by_page() implement this?
>
> Andrew
That would be the general idea. The fbnic_fw_xmit_qsfp_read_msg will
still have to exist as it is essentially the firmware provided front
end to issue a I2C read request to the QSFP module.
I have code that essentially does that somewhere in one of my patch
sets as I had coded it up as proof-of-concept. I am hoping to wrap up
the phydev/phylink code this half. Unfortunately I haven't had a ton of
time as I have been getting pulled in several different directions
lately.
The larger hurdles I am still trying to sort out are adding support for
25/50/100G to a generic clause 45 phydev support in order to support
the fact that we need to deal with a 4s delay due to the PMD needing
time for link training, and then I have to go through and sort out the
PCS/PMA code which may be a bit messy as it looks like XPCS was already
added, but it only seems to support 40G so I will have to sort that
out.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next] eth: fbnic: Read module EEPROM
2025-09-21 7:48 ` Ido Schimmel
@ 2025-09-21 23:45 ` Alexander H Duyck
2025-09-22 16:56 ` Mohsin Bashir
1 sibling, 0 replies; 6+ messages in thread
From: Alexander H Duyck @ 2025-09-21 23:45 UTC (permalink / raw)
To: Ido Schimmel, Mohsin Bashir
Cc: netdev, alexanderduyck, kuba, andrew+netdev, davem, edumazet,
gustavoars, horms, jacob.e.keller, kees, kernel-team, lee, linux,
pabeni, sanman.p211993, suhui, vadim.fedorenko
On Sun, 2025-09-21 at 10:48 +0300, Ido Schimmel wrote:
> On Fri, Sep 19, 2025 at 12:16:24PM -0700, Mohsin Bashir wrote:
> > Add support to read module EEPROM for fbnic. Towards this, add required
> > support to issue a new command to the firmware and to receive the response
> > to the corresponding command.
> >
> > Create a local copy of the data in the completion struct before writing to
> > ethtool_module_eeprom to avoid writing to data in case it is freed. Given
> > that EEPROM pages are small, the overhead of additional copy is
> > negligible.
> >
> > Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> > Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com>
>
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
>
> See a few questions below
>
> > ---
> > .../net/ethernet/meta/fbnic/fbnic_ethtool.c | 66 +++++++++
> > drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 135 ++++++++++++++++++
> > drivers/net/ethernet/meta/fbnic/fbnic_fw.h | 22 +++
> > 3 files changed, 223 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > index b4ff98ee2051..f6069cddffa5 100644
> > --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
> > @@ -1635,6 +1635,71 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
> > }
> > }
> >
> > +static int
> > +fbnic_get_module_eeprom_by_page(struct net_device *netdev,
> > + const struct ethtool_module_eeprom *page_data,
> > + struct netlink_ext_ack *extack)
> > +{
> > + struct fbnic_net *fbn = netdev_priv(netdev);
> > + struct fbnic_fw_completion *fw_cmpl;
> > + struct fbnic_dev *fbd = fbn->fbd;
> > + int err;
> > +
> > + if (page_data->i2c_address != 0x50) {
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Invalid i2c address. Only 0x50 is supported");
> > + return -EINVAL;
> > + }
> > +
> > + if (page_data->bank != 0) {
>
> What is the reason for this check?
>
> I understand that it's very unlikely to have a transceiver with banked
> pages connected to this NIC (requires more than 8 lanes), but it's
> generally better to not restrict this ethtool operation unless you have
> a good reason to, especially when the firmware seems to support banked
> pages.
>
I believe the origin of this is that for now we don't have any parts
that are making use of that field. If I recall the test systems are
running with QSFP-28.
That said I do agree we would probably change this out. I believe in
the original code we had as set of checks to enforce limitations on the
size and offset like below. Perhaps we would be better off with those:
/* Nothing to do if read size is 0 */
if (size == 0)
return 0;
/* Limit reads to current page only, truncate the size to fit
* current page only
*/
if (offset < 128 && (offset + size) > 128)
size = 128 - offset;
/* If page or bank are set we are in paged mode, only support
* offsets greater than 128
*/
if ((page || bank) && offset < 128)
return -EINVAL;
if (offset + size > 256)
return -EINVAL;
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Invalid bank. Only 0 is supported");
> > + return -EINVAL;
> > + }
> > +
> > + fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
>
> QSFP is not the most accurate term, but I assume it's named that way to
> be consistent with the HW/FW data sheet.
>
Yeah, it is the way the FW identifies the I2C bus in question. It is
referred to as the "QSFP" bus.
> > + page_data->length);
> > + if (!fw_cmpl)
> > + return -ENOMEM;
> > +
> > + /* Initialize completion and queue it for FW to process */
> > + fw_cmpl->u.qsfp.length = page_data->length;
> > + fw_cmpl->u.qsfp.offset = page_data->offset;
> > + fw_cmpl->u.qsfp.page = page_data->page;
> > + fw_cmpl->u.qsfp.bank = page_data->bank;
> > +
> > + err = fbnic_fw_xmit_qsfp_read_msg(fbd, fw_cmpl, page_data->page,
> > + page_data->bank, page_data->offset,
> > + page_data->length);
> > + if (err) {
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Failed to transmit EEPROM read request");
> > + goto exit_free;
> > + }
> > +
> > + if (!wait_for_completion_timeout(&fw_cmpl->done, 2 * HZ)) {
> > + err = -ETIMEDOUT;
> > + NL_SET_ERR_MSG_MOD(extack,
> > + "Timed out waiting for firmware response");
> > + goto exit_cleanup;
> > + }
> > +
> > + if (fw_cmpl->result) {
> > + err = fw_cmpl->result;
> > + NL_SET_ERR_MSG_MOD(extack, "Failed to read EEPROM");
> > + goto exit_cleanup;
> > + }
> > +
> > + memcpy(page_data->data, fw_cmpl->u.qsfp.data, page_data->length);
> > +
> > +exit_cleanup:
> > + fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
> > +exit_free:
> > + fbnic_fw_put_cmpl(fw_cmpl);
> > +
> > + return err ? : page_data->length;
> > +}
>
> [...]
>
> > +static int fbnic_fw_parse_qsfp_read_resp(void *opaque,
> > + struct fbnic_tlv_msg **results)
> > +{
> > + struct fbnic_fw_completion *cmpl_data;
> > + struct fbnic_dev *fbd = opaque;
> > + struct fbnic_tlv_msg *data_hdr;
> > + u32 length, offset, page, bank;
> > + u8 *data;
> > + s32 err;
> > +
> > + /* Verify we have a completion pointer to provide with data */
> > + cmpl_data = fbnic_fw_get_cmpl_by_type(fbd,
> > + FBNIC_TLV_MSG_ID_QSFP_READ_RESP);
> > + if (!cmpl_data)
> > + return -ENOSPC;
> > +
> > + bank = fta_get_uint(results, FBNIC_FW_QSFP_BANK);
> > + if (bank != cmpl_data->u.qsfp.bank) {
> > + dev_warn(fbd->dev, "bank not equal to bank requested: %d vs %d\n",
> > + bank, cmpl_data->u.qsfp.bank);
> > + err = -EINVAL;
> > + goto msg_err;
> > + }
> > +
> > + page = fta_get_uint(results, FBNIC_FW_QSFP_PAGE);
> > + if (page != cmpl_data->u.qsfp.page) {
>
> Out of curiosity, can this happen if user space tries to access a page
> that is not supported by the transceiver? I believe most implementations
> do not return an error in this case.
I believe this is meant to handle a possible race or out-of-order
condition on the FW mailbox in which we time-out one request, and then
immediately issue another. Essentially if we end up getting a
completion for a similar message, but it is for a different page/bank
or offset then we return an error instead of reporting it on the
completion.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next] eth: fbnic: Read module EEPROM
2025-09-21 7:48 ` Ido Schimmel
2025-09-21 23:45 ` Alexander H Duyck
@ 2025-09-22 16:56 ` Mohsin Bashir
1 sibling, 0 replies; 6+ messages in thread
From: Mohsin Bashir @ 2025-09-22 16:56 UTC (permalink / raw)
To: Ido Schimmel
Cc: netdev, alexanderduyck, kuba, andrew+netdev, davem, edumazet,
gustavoars, horms, jacob.e.keller, kees, kernel-team, lee, linux,
pabeni, sanman.p211993, suhui, vadim.fedorenko
>> + if (page_data->bank != 0) {
>
> What is the reason for this check?
>
> I understand that it's very unlikely to have a transceiver with banked
> pages connected to this NIC (requires more than 8 lanes), but it's
> generally better to not restrict this ethtool operation unless you have
> a good reason to, especially when the firmware seems to support banked
> pages.
>
Hi Ido,
Thanks for the review.
The bank field is essentially unused in our common case. We were just
sending bank 0 to the FW so I believe, we should be okay removing this.
I'll update this part in V2.
>> + NL_SET_ERR_MSG_MOD(extack,
>> + "Invalid bank. Only 0 is supported");
>> + return -EINVAL;
>> + }
>> +
>> + fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_QSFP_READ_RESP,
>
> QSFP is not the most accurate term, but I assume it's named that way to
> be consistent with the HW/FW data sheet.
>
Yes, as Alex pointed out it is to be consistent with FW.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-09-22 16:56 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-19 19:16 [PATCH net-next] eth: fbnic: Read module EEPROM Mohsin Bashir
2025-09-19 19:25 ` Andrew Lunn
2025-09-21 23:36 ` Alexander H Duyck
2025-09-21 7:48 ` Ido Schimmel
2025-09-21 23:45 ` Alexander H Duyck
2025-09-22 16:56 ` Mohsin Bashir
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).