]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
eth fbnic: Add mailbox self test
authorMike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
Sat, 7 Mar 2026 10:58:47 +0000 (05:58 -0500)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 10 Mar 2026 12:53:53 +0000 (13:53 +0100)
The mailbox self test ensures the interface to and from
the firmware is healthy by sending a test message and
fielding the response from the firmware.

This patch uses the new completion API [1][2] that allocates a
completion structure, binds the completion to the TEST
message, and uses a new FW parsing routine that wraps the
completion processing around the TLV parser.

Link: https://patch.msgid.link/20250516164804.741348-1-lee@trager.us
Link: https://patch.msgid.link/20260115003353.4150771-6-mohsin.bashr@gmail.com
Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
Link: https://patch.msgid.link/20260307105847.1438-6-mike.marciniszyn@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
drivers/net/ethernet/meta/fbnic/fbnic_fw.c
drivers/net/ethernet/meta/fbnic/fbnic_fw.h

index b5012601b10235d90050b5f9fa56f011acf362da..f14de23668544d8f17a5557433e74f6c2b3040bd 100644 (file)
@@ -129,11 +129,13 @@ static const struct fbnic_stat fbnic_gstrings_xdp_stats[] = {
 enum fbnic_self_test_results {
        TEST_REG = 0,
        TEST_MSIX,
+       TEST_MBX,
 };
 
 static const char fbnic_gstrings_self_test[][ETH_GSTRING_LEN] = {
        [TEST_REG]      = "Register test (offline)",
        [TEST_MSIX]     = "MSI-X Interrupt test (offline)",
+       [TEST_MBX]      = "FW mailbox test (on/offline)",
 };
 
 #define FBNIC_TEST_LEN ARRAY_SIZE(fbnic_gstrings_self_test)
@@ -1528,11 +1530,24 @@ static int fbnic_ethtool_msix_test(struct net_device *netdev, u64 *data)
        return !!*data;
 }
 
+static int fbnic_ethtool_mbx_self_test(struct net_device *netdev, u64 *data)
+{
+       struct fbnic_net *fbn = netdev_priv(netdev);
+       struct fbnic_dev *fbd = fbn->fbd;
+
+       *data = fbnic_fw_mbx_self_test(fbd);
+
+       return !!*data;
+}
+
 static void fbnic_self_test(struct net_device *netdev,
                            struct ethtool_test *eth_test, u64 *data)
 {
        bool if_running = netif_running(netdev);
 
+       if (fbnic_ethtool_mbx_self_test(netdev, &data[TEST_MBX]))
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+
        if (!(eth_test->flags & ETH_TEST_FL_OFFLINE)) {
                data[TEST_REG] = 0;
                data[TEST_MSIX] = 0;
index 1f0b6350bef4493d81744ca5d67de4c88adc4c1c..c2bad51bdde60b32308dfbf64ec32c6f35869767 100644 (file)
@@ -378,6 +378,37 @@ fbnic_fw_get_cmpl_by_type(struct fbnic_dev *fbd, u32 msg_type)
        return cmpl_data;
 }
 
+/**
+ * fbnic_fw_xmit_test_msg - Create and transmit a test message to FW mailbox
+ * @fbd: FBNIC device structure
+ * @cmpl: fw completion struct
+ *
+ * Return: zero on success, negative value on failure
+ *
+ * Generates a single page mailbox test message and places it in the Tx
+ * mailbox queue. Expectation is that the FW will validate that the nested
+ * value matches the external values, and then will echo them back to us.
+ *
+ * Also sets a completion slot for use in the completion wait calls when
+ * the cmpl arg is non-NULL.
+ */
+int fbnic_fw_xmit_test_msg(struct fbnic_dev *fbd,
+                          struct fbnic_fw_completion *cmpl)
+{
+       struct fbnic_tlv_msg *test_msg;
+       int err;
+
+       test_msg = fbnic_tlv_test_create(fbd);
+       if (!test_msg)
+               return -ENOMEM;
+
+       err = fbnic_mbx_map_req_w_cmpl(fbd, test_msg, cmpl);
+       if (err)
+               free_page((unsigned long)test_msg);
+
+       return err;
+}
+
 /**
  * fbnic_fw_xmit_simple_msg - Transmit a simple single TLV message w/o data
  * @fbd: FBNIC device structure
@@ -1556,7 +1587,29 @@ free_message:
        return err;
 }
 
+static int
+fbnic_fw_parser_test(void *opaque, struct fbnic_tlv_msg **results)
+{
+       struct fbnic_fw_completion *cmpl;
+       struct fbnic_dev *fbd = opaque;
+       int err;
+
+       /* find cmpl */
+       cmpl = fbnic_fw_get_cmpl_by_type(fbd, FBNIC_TLV_MSG_ID_TEST);
+       if (!cmpl)
+               return -ENOSPC;
+
+       err = fbnic_tlv_parser_test(opaque, results);
+
+       cmpl->result = err;
+       complete(&cmpl->done);
+       fbnic_fw_put_cmpl(cmpl);
+
+       return err;
+}
+
 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,
                         fbnic_fw_parse_cap_resp),
        FBNIC_TLV_PARSER(OWNERSHIP_RESP, fbnic_ownership_resp_index,
@@ -1787,6 +1840,53 @@ void fbnic_mbx_flush_tx(struct fbnic_dev *fbd)
        } while (time_is_after_jiffies(timeout));
 }
 
+/**
+ * fbnic_fw_mbx_self_test() - verify firmware interface
+ * @fbd: device to test
+ *
+ * This function tests the interfaces to/from the firmware.
+ *
+ * Return: See enum fbnic_fw_self_test_codes
+ **/
+enum fbnic_fw_self_test_codes fbnic_fw_mbx_self_test(struct fbnic_dev *fbd)
+{
+       enum fbnic_fw_self_test_codes err;
+       struct fbnic_fw_completion *cmpl;
+
+       /* Skip test if FW interface is not present */
+       if (!fbnic_fw_present(fbd))
+               return FBNIC_TEST_FW_NO_FIRMWARE;
+
+       cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_TEST);
+       if (!cmpl)
+               return FBNIC_TEST_FW_NO_CMPL;
+
+       /* Load a test message onto the FW mailbox interface
+        * and arm the completion.
+        */
+       err = fbnic_fw_xmit_test_msg(fbd, cmpl);
+       if (err) {
+               err = FBNIC_TEST_FW_NO_XMIT;
+               goto exit_free;
+       }
+
+       /* Verify we received a message back */
+       if (!fbnic_mbx_wait_for_cmpl(cmpl)) {
+               err = FBNIC_TEST_FW_NO_MSG;
+               goto exit_cleanup;
+       }
+
+       /* Verify there were no parsing errors */
+       if (cmpl->result)
+               err = FBNIC_TEST_FW_PARSE;
+exit_cleanup:
+       fbnic_mbx_clear_cmpl(fbd, cmpl);
+exit_free:
+       fbnic_fw_put_cmpl(cmpl);
+
+       return err;
+}
+
 int fbnic_fw_xmit_rpc_macda_sync(struct fbnic_dev *fbd)
 {
        struct fbnic_tlv_msg *mac_array;
index 8f7218900562ebbf50eb26e667fdb6d3be40850b..d84723e4cfa362a51a1b945eb2e9bb7f229613f1 100644 (file)
@@ -104,6 +104,33 @@ void fbnic_mbx_clear_cmpl(struct fbnic_dev *fbd,
 void fbnic_mbx_poll(struct fbnic_dev *fbd);
 int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd);
 void fbnic_mbx_flush_tx(struct fbnic_dev *fbd);
+
+/**
+ * enum fbnic_fw_self_test_codes - return codes from self test routines
+ *
+ * These are the codes returned from the self test routines and
+ * stored in the test result array indexed by the specific
+ * test name.
+ *
+ * @FBNIC_TEST_FW_SUCCESS: test success
+ * @FBNIC_TEST_FW_NO_FIRMWARE: FW interface not present
+ * @FBNIC_TEST_FW_NO_CMPL: No completion available
+ * @FBNIC_TEST_FW_NO_XMIT: Could not xmit message
+ * @FBNIC_TEST_FW_NO_MSG: no message returned
+ * @FBNIC_TEST_FW_PARSE: returned message had parsing error
+ */
+enum fbnic_fw_self_test_codes {
+       FBNIC_TEST_FW_SUCCESS = 0,
+       FBNIC_TEST_FW_NO_FIRMWARE = 10,
+       FBNIC_TEST_FW_NO_CMPL = 20,
+       FBNIC_TEST_FW_NO_XMIT = 30,
+       FBNIC_TEST_FW_NO_MSG = 40,
+       FBNIC_TEST_FW_PARSE = 50,
+};
+
+enum fbnic_fw_self_test_codes fbnic_fw_mbx_self_test(struct fbnic_dev *fbd);
+int fbnic_fw_xmit_test_msg(struct fbnic_dev *fbd,
+                          struct fbnic_fw_completion *c);
 int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership);
 int fbnic_fw_init_heartbeat(struct fbnic_dev *fbd, bool poll);
 void fbnic_fw_check_heartbeat(struct fbnic_dev *fbd);