Commit d36a08b4 authored by Daniel Pieczko's avatar Daniel Pieczko Committed by Ben Hutchings

sfc: use MCDI epoch flag to improve MC reboot detection in the driver

The Huntington MC will reject all MCDI requests after an MC reboot until it sees
one with the NOT_EPOCH flag clear.  This flag is set by default for all requests,
and then cleared on the first request after we detect that an MC reboot has
occurred.

The old MCDI_STATUS_DELAY_COUNT gave a timeout of 10ms, which was not long enough
for the driver to detect that a reboot had occurred based on the warm boot count
while calling efx_mcdi_poll_reboot() from the loop in efx_mcdi_ev_death().
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 3de82b91
...@@ -26,9 +26,10 @@ ...@@ -26,9 +26,10 @@
/* A reboot/assertion causes the MCDI status word to be set after the /* A reboot/assertion causes the MCDI status word to be set after the
* command word is set or a REBOOT event is sent. If we notice a reboot * command word is set or a REBOOT event is sent. If we notice a reboot
* via these mechanisms then wait 10ms for the status word to be set. */ * via these mechanisms then wait 20ms for the status word to be set.
*/
#define MCDI_STATUS_DELAY_US 100 #define MCDI_STATUS_DELAY_US 100
#define MCDI_STATUS_DELAY_COUNT 100 #define MCDI_STATUS_DELAY_COUNT 200
#define MCDI_STATUS_SLEEP_MS \ #define MCDI_STATUS_SLEEP_MS \
(MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000) (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
...@@ -56,6 +57,7 @@ int efx_mcdi_init(struct efx_nic *efx) ...@@ -56,6 +57,7 @@ int efx_mcdi_init(struct efx_nic *efx)
mcdi->mode = MCDI_MODE_POLL; mcdi->mode = MCDI_MODE_POLL;
(void) efx_mcdi_poll_reboot(efx); (void) efx_mcdi_poll_reboot(efx);
mcdi->new_epoch = true;
/* Recover from a failed assertion before probing */ /* Recover from a failed assertion before probing */
return efx_mcdi_handle_assertion(efx); return efx_mcdi_handle_assertion(efx);
...@@ -85,24 +87,26 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, ...@@ -85,24 +87,26 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
if (efx->type->mcdi_max_ver == 1) { if (efx->type->mcdi_max_ver == 1) {
/* MCDI v1 */ /* MCDI v1 */
EFX_POPULATE_DWORD_6(hdr[0], EFX_POPULATE_DWORD_7(hdr[0],
MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_RESPONSE, 0,
MCDI_HEADER_RESYNC, 1, MCDI_HEADER_RESYNC, 1,
MCDI_HEADER_CODE, cmd, MCDI_HEADER_CODE, cmd,
MCDI_HEADER_DATALEN, inlen, MCDI_HEADER_DATALEN, inlen,
MCDI_HEADER_SEQ, seqno, MCDI_HEADER_SEQ, seqno,
MCDI_HEADER_XFLAGS, xflags); MCDI_HEADER_XFLAGS, xflags,
MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
hdr_len = 4; hdr_len = 4;
} else { } else {
/* MCDI v2 */ /* MCDI v2 */
BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2); BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2);
EFX_POPULATE_DWORD_6(hdr[0], EFX_POPULATE_DWORD_7(hdr[0],
MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_RESPONSE, 0,
MCDI_HEADER_RESYNC, 1, MCDI_HEADER_RESYNC, 1,
MCDI_HEADER_CODE, MC_CMD_V2_EXTN, MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
MCDI_HEADER_DATALEN, 0, MCDI_HEADER_DATALEN, 0,
MCDI_HEADER_SEQ, seqno, MCDI_HEADER_SEQ, seqno,
MCDI_HEADER_XFLAGS, xflags); MCDI_HEADER_XFLAGS, xflags,
MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
EFX_POPULATE_DWORD_2(hdr[1], EFX_POPULATE_DWORD_2(hdr[1],
MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd, MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd,
MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen); MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen);
...@@ -373,6 +377,7 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, ...@@ -373,6 +377,7 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
spin_unlock_bh(&mcdi->iface_lock); spin_unlock_bh(&mcdi->iface_lock);
efx_mcdi_copyin(efx, cmd, inbuf, inlen); efx_mcdi_copyin(efx, cmd, inbuf, inlen);
mcdi->new_epoch = false;
return 0; return 0;
} }
...@@ -435,6 +440,7 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, ...@@ -435,6 +440,7 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
if (rc == -EIO || rc == -EINTR) { if (rc == -EIO || rc == -EINTR) {
msleep(MCDI_STATUS_SLEEP_MS); msleep(MCDI_STATUS_SLEEP_MS);
efx_mcdi_poll_reboot(efx); efx_mcdi_poll_reboot(efx);
mcdi->new_epoch = true;
} }
} }
...@@ -530,6 +536,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) ...@@ -530,6 +536,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
break; break;
udelay(MCDI_STATUS_DELAY_US); udelay(MCDI_STATUS_DELAY_US);
} }
mcdi->new_epoch = true;
} }
spin_unlock(&mcdi->iface_lock); spin_unlock(&mcdi->iface_lock);
......
...@@ -36,6 +36,7 @@ enum efx_mcdi_mode { ...@@ -36,6 +36,7 @@ enum efx_mcdi_mode {
* @state: Request handling state. Waited for by @wq. * @state: Request handling state. Waited for by @wq.
* @mode: Poll for mcdi completion, or wait for an mcdi_event. * @mode: Poll for mcdi completion, or wait for an mcdi_event.
* @wq: Wait queue for threads waiting for @state != %MCDI_STATE_RUNNING * @wq: Wait queue for threads waiting for @state != %MCDI_STATE_RUNNING
* @new_epoch: Indicates start of day or start of MC reboot recovery
* @iface_lock: Serialises access to all the following fields * @iface_lock: Serialises access to all the following fields
* @seqno: The next sequence number to use for mcdi requests. * @seqno: The next sequence number to use for mcdi requests.
* @credits: Number of spurious MCDI completion events allowed before we * @credits: Number of spurious MCDI completion events allowed before we
...@@ -49,6 +50,7 @@ struct efx_mcdi_iface { ...@@ -49,6 +50,7 @@ struct efx_mcdi_iface {
enum efx_mcdi_mode mode; enum efx_mcdi_mode mode;
wait_queue_head_t wq; wait_queue_head_t wq;
spinlock_t iface_lock; spinlock_t iface_lock;
bool new_epoch;
unsigned int credits; unsigned int credits;
unsigned int seqno; unsigned int seqno;
int resprc; int resprc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment