mirror of
https://github.com/torvalds/linux.git
synced 2026-10-09 03:56:03 +02:00
eth: fbnic: Handle FW mailbox completions flagged with an error
The firmware can complete a mailbox descriptor while also setting FW_ERR
to indicate it could not process the request, for example on a mailbox
DMA error. The completion carries no valid data.
The driver did not check FW_ERR. On the Rx mailbox it would sync and
parse the stale page as a normal message, and on the Tx mailbox it
silently freed the request. If the initial capabilities exchange in
fbnic_mbx_poll_tx_ready() hit FW_ERR -- on the Tx request or on the Rx
response descriptor -- no response was parsed and the poll spun until it
timed out even though the ring was healthy.
Check FW_ERR on both mailboxes. Count it per-mailbox in
fbnic_fw_mbx.resp_error, which is also shown in debugfs, warn (rate
limited, since the bit is firmware controlled), and drop the Rx page
instead of parsing it.
In fbnic_mbx_poll_tx_ready() re-issue the capabilities request when
either the Tx or the Rx resp_error counter advances, so a FW_ERR on the
request or on its response triggers a retry rather than a timeout. A
valid capabilities response is honored before the retry check, so a
response parsed in the same poll as an unrelated FW_ERR is not discarded.
The counters are mailbox-wide rather than keyed to the capabilities
request; that is sufficient here because the exchange runs during
bring-up before any other mailbox traffic, and any spurious retry is
bounded by the existing 10s timeout.
Fixes: da3cde0820 ("eth: fbnic: Add FW communication mechanism")
Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/178942023343.7700.9423398932961964439.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
8947f13e43
commit
1b97a269a5
|
|
@ -1216,6 +1216,10 @@ enum {
|
|||
#define FBNIC_IPC_MBX_DESC_LEN_MASK DESC_GENMASK(63, 48)
|
||||
#define FBNIC_IPC_MBX_DESC_EOM DESC_BIT(46)
|
||||
#define FBNIC_IPC_MBX_DESC_ADDR_MASK DESC_GENMASK(45, 3)
|
||||
/* Set with FW_CMPL when the FW completed a descriptor without successfully
|
||||
* processing it (e.g. a mailbox DMA error); the completion has no valid data.
|
||||
*/
|
||||
#define FBNIC_IPC_MBX_DESC_FW_ERR DESC_BIT(2)
|
||||
#define FBNIC_IPC_MBX_DESC_FW_CMPL DESC_BIT(1)
|
||||
#define FBNIC_IPC_MBX_DESC_HOST_CMPL DESC_BIT(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -539,8 +539,8 @@ static void fbnic_dbg_fw_mbx_display(struct seq_file *s,
|
|||
/* Generate header */
|
||||
seq_puts(s, mbx_idx == FBNIC_IPC_MBX_RX_IDX ? "Rx\n" : "Tx\n");
|
||||
|
||||
seq_printf(s, "Rdy: %d Head: %d Tail: %d\n",
|
||||
mbx->ready, mbx->head, mbx->tail);
|
||||
seq_printf(s, "Rdy: %d Head: %d Tail: %d resp_error: %llu\n",
|
||||
mbx->ready, mbx->head, mbx->tail, mbx->resp_error);
|
||||
|
||||
snprintf(hdr, sizeof(hdr), "%3s %-4s %s %-12s %s %-3s %-16s\n",
|
||||
"Idx", "Len", "E", "Addr", "F", "H", "Raw");
|
||||
|
|
|
|||
|
|
@ -292,6 +292,12 @@ static void fbnic_mbx_process_tx_msgs(struct fbnic_dev *fbd)
|
|||
if (!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL))
|
||||
break;
|
||||
|
||||
if (desc & FBNIC_IPC_MBX_DESC_FW_ERR) {
|
||||
tx_mbx->resp_error++;
|
||||
dev_warn_ratelimited(fbd->dev,
|
||||
"FW completed a Tx mailbox request with an error\n");
|
||||
}
|
||||
|
||||
fbnic_mbx_unmap_and_free_msg(fbd, FBNIC_IPC_MBX_TX_IDX, head);
|
||||
|
||||
head++;
|
||||
|
|
@ -1673,6 +1679,13 @@ static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
|
|||
if (!(desc & FBNIC_IPC_MBX_DESC_FW_CMPL))
|
||||
break;
|
||||
|
||||
if (desc & FBNIC_IPC_MBX_DESC_FW_ERR) {
|
||||
rx_mbx->resp_error++;
|
||||
dev_warn_ratelimited(fbd->dev,
|
||||
"FW reported an error on an Rx mailbox message; dropping\n");
|
||||
goto next_page;
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(fbd->dev, rx_mbx->buf_info[head].addr,
|
||||
FBNIC_RX_PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
|
|
@ -1740,7 +1753,9 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd)
|
|||
int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
|
||||
{
|
||||
struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
|
||||
struct fbnic_fw_mbx *rx_mbx = &fbd->mbx[FBNIC_IPC_MBX_RX_IDX];
|
||||
unsigned long timeout = jiffies + 10 * HZ + 1;
|
||||
u64 tx_resp_error, rx_resp_error;
|
||||
int err, i;
|
||||
|
||||
do {
|
||||
|
|
@ -1771,6 +1786,9 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
|
|||
* mgmt.version once we get the actual version from the firmware
|
||||
* in the capabilities request message.
|
||||
*/
|
||||
send_cap_req:
|
||||
tx_resp_error = tx_mbx->resp_error;
|
||||
rx_resp_error = rx_mbx->resp_error;
|
||||
err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
|
||||
if (err)
|
||||
goto clean_mbx;
|
||||
|
|
@ -1788,9 +1806,27 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
|
|||
msleep(20);
|
||||
fbnic_mbx_poll(fbd);
|
||||
|
||||
/* A valid capabilities response ends the poll. Check it
|
||||
* before the FW_ERR retry below so a response parsed in the
|
||||
* same poll as an unrelated FW_ERR is not discarded.
|
||||
*/
|
||||
if (fbd->fw_cap.running.mgmt.version >= MIN_FW_VER_CODE)
|
||||
break;
|
||||
|
||||
/* set err, but wait till mgmt.version check to report it */
|
||||
if (!time_is_after_jiffies(timeout))
|
||||
if (!time_is_after_jiffies(timeout)) {
|
||||
err = -ETIMEDOUT;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The FW can flag our capabilities request (Tx) or its
|
||||
* response (Rx) with FW_ERR, in which case it produced no
|
||||
* usable response. The ring is not wedged, so re-issue the
|
||||
* request instead of spinning until the timeout.
|
||||
*/
|
||||
if (tx_mbx->resp_error != tx_resp_error ||
|
||||
rx_mbx->resp_error != rx_resp_error)
|
||||
goto send_cap_req;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ struct fbnic_tlv_msg;
|
|||
|
||||
struct fbnic_fw_mbx {
|
||||
u8 ready, head, tail;
|
||||
u64 resp_error;
|
||||
struct {
|
||||
struct fbnic_tlv_msg *msg;
|
||||
dma_addr_t addr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user