Commit 8e521819 authored by Mike Marciniszyn (Meta)'s avatar Mike Marciniszyn (Meta) Committed by Paolo Abeni
Browse files

eth fbnic: Add mailbox self test

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 [1]
Link: https://patch.msgid.link/20260115003353.4150771-6-mohsin.bashr@gmail.com

 [2]

Signed-off-by: default avatarMike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
Link: https://patch.msgid.link/20260307105847.1438-6-mike.marciniszyn@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent d522b1b0
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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;
+100 −0
Original line number Diff line number Diff line
@@ -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 @@ int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable,
	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;
+27 −0
Original line number Diff line number Diff line
@@ -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);