/* A reboot/assertion causes the MCDI status word to be set after the *commandwordissetoraREBOOTeventissent.Ifwenoticeareboot *viathesemechanismsthenwait250msforthestatuswordtobeset.
*/ #define MCDI_STATUS_DELAY_US 100 #define MCDI_STATUS_DELAY_COUNT 2500 #define MCDI_STATUS_SLEEP_MS \
(MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
/* Recover from a failed assertion before probing */
rc = efx_mcdi_handle_assertion(efx); if (rc) goto fail2;
/* Let the MC (and BMC, if this is a LOM) know that the driver *isloaded.WeshoulddothisbeforeweresettheNIC.
*/
rc = efx_mcdi_drv_attach(efx, true, &already_attached); if (rc) {
pci_err(efx->pci_dev, "Unable to register driver with MCPU\n"); goto fail2;
} if (already_attached) /* Not a fatal error */
pci_err(efx->pci_dev, "Host already registered with MCPU\n");
if (efx->mcdi->fn_flags &
(1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY))
efx->primary = efx;
#ifdef CONFIG_SFC_MCDI_LOGGING if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) { int bytes = 0; int i; /* Lengths should always be a whole number of dwords, so scream *ifthey'renot.
*/
WARN_ON_ONCE(hdr_len % 4);
WARN_ON_ONCE(inlen % 4);
/* We own the logging buffer, as only one MCDI can be in *progressonaNICatanyonetime.Sononeedforlocking.
*/ for (i = 0; i < hdr_len / 4 && bytes < PAGE_SIZE; i++)
bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, " %08x",
le32_to_cpu(hdr[i].u32[0]));
for (i = 0; i < inlen / 4 && bytes < PAGE_SIZE; i++)
bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, " %08x",
le32_to_cpu(inbuf[i].u32[0]));
/* We own the logging buffer, as only one MCDI can be in *progressonaNICatanyonetime.Sononeedforlocking.
*/ for (i = 0; i < hdr_len && bytes < PAGE_SIZE; i++) {
efx->type->mcdi_read_response(efx, &hdr, (i * 4), 4);
bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, " %08x", le32_to_cpu(hdr.u32[0]));
}
for (i = 0; i < data_len && bytes < PAGE_SIZE; i++) {
efx->type->mcdi_read_response(efx, &hdr,
mcdi->resp_hdr_len + (i * 4), 4);
bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, " %08x", le32_to_cpu(hdr.u32[0]));
}
staticint efx_mcdi_poll(struct efx_nic *efx)
{ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsignedlong time, finish; unsignedint spins; int rc;
/* Check for a reboot atomically with respect to efx_mcdi_copyout() */
rc = efx_mcdi_poll_reboot(efx); if (rc) {
spin_lock_bh(&mcdi->iface_lock);
mcdi->resprc = rc;
mcdi->resp_hdr_len = 0;
mcdi->resp_data_len = 0;
spin_unlock_bh(&mcdi->iface_lock); return0;
}
/* Poll for completion. Poll quickly (once a us) for the 1st jiffy, *becausegenerallymcdiresponsesarefast.Afterthat,backoff *andpollonceajiffy(approximately)
*/
spins = USER_TICK_USEC;
finish = jiffies + MCDI_RPC_TIMEOUT;
while (1) { if (spins != 0) {
--spins;
udelay(1);
} else {
schedule_timeout_uninterruptible(1);
}
time = jiffies;
if (efx_mcdi_poll_once(efx)) break;
if (time_after(time, finish)) return -ETIMEDOUT;
}
/* Return rc=0 like wait_event_timeout() */ return0;
}
/* Test and clear MC-rebooted flag for this port/function; reset *softwarestateasnecessary.
*/ int efx_mcdi_poll_reboot(struct efx_nic *efx)
{ if (!efx->mcdi) return0;
if (wait_event_timeout(mcdi->wq, mcdi->state == MCDI_STATE_COMPLETED,
MCDI_RPC_TIMEOUT) == 0) return -ETIMEDOUT;
/* Check if efx_mcdi_set_mode() switched us back to polled completions. *Inwhichcase,pollforcompletionsdirectly.Ifefx_mcdi_ev_cpl() *completedtherequestfirst,thenwe'lljustendupcompletingthe *requestagain,whichissafe. * *Weneedansmp_rmb()tosynchronisewithefx_mcdi_mode_poll(),which *wait_event_timeout()implicitlyprovides.
*/ if (mcdi->mode == MCDI_MODE_POLL) return efx_mcdi_poll(efx);
return0;
}
/* If the interface is RUNNING_SYNC, switch to COMPLETED and wake the *requester.Returnwhetherthiswasdone.Doesnottakeanylocks.
*/ staticbool efx_mcdi_complete_sync(struct efx_mcdi_iface *mcdi)
{ if (cmpxchg(&mcdi->state,
MCDI_STATE_RUNNING_SYNC, MCDI_STATE_COMPLETED) ==
MCDI_STATE_RUNNING_SYNC) {
wake_up(&mcdi->wq); returntrue;
}
/* If the interface is RUNNING_ASYNC, switch to COMPLETED, call the *asynchronouscompletionfunction,andreleasetheinterface. *Returnwhetherthiswasdone.Mustbecalledinbh-disabled *context.Willtakeiface_lockandasync_lock.
*/ staticbool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
{ struct efx_nic *efx = mcdi->efx; struct efx_mcdi_async_param *async;
size_t hdr_len, data_len, err_len;
efx_dword_t *outbuf;
MCDI_DECLARE_BUF_ERR(errbuf); int rc;
if (cmpxchg(&mcdi->state,
MCDI_STATE_RUNNING_ASYNC, MCDI_STATE_COMPLETED) !=
MCDI_STATE_RUNNING_ASYNC) returnfalse;
spin_lock(&mcdi->iface_lock); if (timeout) { /* Ensure that if the completion event arrives later, *theseqnocheckinefx_mcdi_ev_cpl()willfail
*/
++mcdi->seqno;
++mcdi->credits;
rc = -ETIMEDOUT;
hdr_len = 0;
data_len = 0;
} else {
rc = mcdi->resprc;
hdr_len = mcdi->resp_hdr_len;
data_len = mcdi->resp_data_len;
}
spin_unlock(&mcdi->iface_lock);
/* Stop the timer. In case the timer function is running, we *mustwaitforittoreturnsothatthereisnopossibility *ofitabortingthenextrequest.
*/ if (!timeout)
timer_delete_sync(&mcdi->async_timer);
if ((seqno ^ mcdi->seqno) & SEQ_MASK) { if (mcdi->credits) /* The request has been cancelled */
--mcdi->credits; else
netif_err(efx, hw, efx->net_dev, "MC response mismatch tx seq 0x%x rx " "seq 0x%x\n", seqno, mcdi->seqno);
} else { if (efx->type->mcdi_max_ver >= 2) { /* MCDI v2 responses don't fit in an event */
efx_mcdi_read_response_header(efx);
} else {
mcdi->resprc = efx_mcdi_errno(mcdi_err);
mcdi->resp_hdr_len = 4;
mcdi->resp_data_len = datalen;
}
wake = true;
}
spin_unlock(&mcdi->iface_lock);
if (wake) { if (!efx_mcdi_complete_async(mcdi, false))
(void) efx_mcdi_complete_sync(mcdi);
/* If the interface isn't RUNNING_ASYNC or *RUNNING_SYNCthenwe'vereceivedaduplicate *completionafterwe'vealreadytransitionedbackto *QUIESCENT.[Asubsequentinvocationwouldincrement *seqno,sowouldhavefailedtheseqnocheck].
*/
}
}
if (mcdi->mode == MCDI_MODE_EVENTS && efx_mcdi_poll_once(efx)) {
netif_err(efx, hw, efx->net_dev, "MCDI request was completed without an event\n");
rc = 0;
}
efx_mcdi_abandon(efx);
/* Close the race with efx_mcdi_ev_cpl() executing just too late *andcompletingarequestwe'vejustcancelled,byensuring *thattheseqnocheckthereinfails.
*/
spin_lock_bh(&mcdi->iface_lock);
++mcdi->seqno;
++mcdi->credits;
spin_unlock_bh(&mcdi->iface_lock);
}
if (proxy_handle)
*proxy_handle = 0;
if (rc != 0) { if (outlen_actual)
*outlen_actual = 0;
} else {
size_t hdr_len, data_len, err_len;
/* At the very least we need a memory barrier here to ensure *wepickupchangesfromefx_mcdi_ev_cpl().Protectagainst *aspuriousefx_mcdi_ev_cpl()runningconcurrentlyby
* acquiring the iface_lock. */
spin_lock_bh(&mcdi->iface_lock);
rc = mcdi->resprc; if (raw_rc)
*raw_rc = mcdi->resprc_raw;
hdr_len = mcdi->resp_hdr_len;
data_len = mcdi->resp_data_len;
err_len = min(sizeof(errbuf), data_len);
spin_unlock_bh(&mcdi->iface_lock);
BUG_ON(rc > 0);
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
min(outlen, data_len)); if (outlen_actual)
*outlen_actual = data_len;
mcdi->proxy_rx_status = efx_mcdi_errno(status); /* Ensure the status is written before we update the handle, since the *latterisusedtocheckifwe'vefinished.
*/
wmb();
mcdi->proxy_rx_handle = handle;
wake_up(&mcdi->proxy_rx_wq);
}
if ((rc == -EPROTO) && (raw_rc == MC_CMD_ERR_NO_EVB_PORT) &&
efx->type->is_vf) { /* If the EVB port isn't available within a VF this may *meanthePFisstillbringingtheswitchup.Weshould *retryourrequestshortly.
*/ unsignedlong abort_time = jiffies + MCDI_RPC_TIMEOUT; unsignedint delay_us = 10000;
netif_dbg(efx, hw, efx->net_dev, "%s: NO_EVB_PORT; will retry request\n",
__func__);
if (mcdi->mode == MCDI_MODE_EVENTS) {
list_add_tail(&async->list, &mcdi->async_list);
/* If this is at the front of the queue, try to start it *immediately
*/ if (mcdi->async_list.next == &async->list &&
efx_mcdi_acquire_async(mcdi)) {
efx_mcdi_send_request(efx, cmd, inbuf, inlen);
mod_timer(&mcdi->async_timer,
jiffies + MCDI_RPC_TIMEOUT);
}
} else {
kfree(async);
rc = -ENETDOWN;
}
/* Switch to polled MCDI completions. This can be called in various *errorconditionswithvariouslocksheld,soitmustbelockless. *Callerisresponsibleforflushingasynchronousrequestslater.
*/ void efx_mcdi_mode_poll(struct efx_nic *efx)
{ struct efx_mcdi_iface *mcdi;
if (!efx->mcdi) return;
mcdi = efx_mcdi(efx); /* If already in polling mode, nothing to do. *Ifinfail-faststate,don'tswitchtopolledcompletion. *FLRrecoverywilldothatlater.
*/ if (mcdi->mode == MCDI_MODE_POLL || mcdi->mode == MCDI_MODE_FAIL) return;
/* We can switch from event completion to polled completion, because *mcdirequestsarealwayscompletedinsharedmemory.Wedothisby *switchingthemodetoPOLL'dthencompletingtherequest. *efx_mcdi_await_completion()willthencallefx_mcdi_poll(). * *Weneedansmp_wmb()tosynchronisewithefx_mcdi_await_completion(), *whichefx_mcdi_complete_sync()providesforus.
*/
mcdi->mode = MCDI_MODE_POLL;
efx_mcdi_complete_sync(mcdi);
}
/* Flush any running or queued asynchronous requests, after event processing *isstopped
*/ void efx_mcdi_flush_async(struct efx_nic *efx)
{ struct efx_mcdi_async_param *async, *next; struct efx_mcdi_iface *mcdi;
if (!efx->mcdi) return;
mcdi = efx_mcdi(efx);
/* We must be in poll or fail mode so no more requests can be queued */
BUG_ON(mcdi->mode == MCDI_MODE_EVENTS);
timer_delete_sync(&mcdi->async_timer);
/* If a request is still running, make sure we give the MC *timetocompleteitsothattheresponsewon'toverwriteour *nextrequest.
*/ if (mcdi->state == MCDI_STATE_RUNNING_ASYNC) {
efx_mcdi_poll(efx);
mcdi->state = MCDI_STATE_QUIESCENT;
}
/* Nothing else will access the async list now, so it is safe *towalkitwithoutholdingasync_lock.Ifweholditwhile *callingacompleterthenlockdepmaywarnthatwehave *acquiredlocksinthewrongorder.
*/
list_for_each_entry_safe(async, next, &mcdi->async_list, list) { if (async->complete)
async->complete(efx, async->cookie, -ENETDOWN, NULL, 0);
list_del(&async->list);
kfree(async);
}
}
mcdi = efx_mcdi(efx); /* If already in event completion mode, nothing to do. *Ifinfail-faststate,don'tswitchtoeventcompletion.FLR *recoverywilldothatlater.
*/ if (mcdi->mode == MCDI_MODE_EVENTS || mcdi->mode == MCDI_MODE_FAIL) return;
/* We can't switch from polled to event completion in the middle of a *request,becausethecompletionmethodisspecifiedintherequest. *Soacquiretheinterfacetoserialisetherequestors.Wedon'tneed *toacquiretheiface_locktochangethemodehere,butwedoneeda *writememorybarrierensurethatefx_mcdi_rpc()seesit,which *efx_mcdi_acquire()provides.
*/
efx_mcdi_acquire_sync(mcdi);
mcdi->mode = MCDI_MODE_EVENTS;
efx_mcdi_release(mcdi);
}
/* If there is an outstanding MCDI request, it has been terminated *eitherbyaBADASSERTorREBOOTevent.Ifthemcdiinterfaceis *inpolledmode,thendonothingbecausetheMCreboothandlerwill *settheheadercorrectly.However,ifthemcdiinterfaceiswaiting *foraCMDDONEeventitwon'treceiveit[andsinceallMCDIevents *aresenttothesamequeue,wecan'tberacingwith *efx_mcdi_ev_cpl()] * *Ifthereisanoutstandingasynchronousrequest,wecan't *completeitnow(efx_mcdi_complete()woulddeadlock).The *resetprocesswilltakecareofthis. * *There'saraceherewithefx_mcdi_send_request(),because *wemightreceiveaREBOOTevent*before*therequesthas *beencopiedout.Inpolledmode(duringstartup)thisis *irrelevant,becauseefx_mcdi_complete_sync()isignored.In *eventmode,thisconditionisjustanedge-caseof *receivingaREBOOTeventafterpostingtheMCDI *request.Didthemcrebootbeforeorafterthecopyout?The *bestwecandoalwaysisjustreturnfailure. * *Ifthereisanoutstandingproxyresponseexpecteditisnotgoing *toarrive.Weshouldthusabortit.
*/
spin_lock(&mcdi->iface_lock);
efx_mcdi_proxy_abort(mcdi);
if (efx_mcdi_complete_sync(mcdi)) { if (mcdi->mode == MCDI_MODE_EVENTS) {
mcdi->resprc = rc;
mcdi->resp_hdr_len = 0;
mcdi->resp_data_len = 0;
++mcdi->credits;
}
} else { int count;
/* Consume the status word since efx_mcdi_rpc_finish() won't */ for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
rc = efx_mcdi_poll_reboot(efx); if (rc) break;
udelay(MCDI_STATUS_DELAY_US);
}
/* On EF10, a CODE_MC_REBOOT event can be received without the *rebootdetectioninefx_mcdi_poll_reboot()beingtriggered. *Ifzerowasreturnedfromthefinalcallto *efx_mcdi_poll_reboot(),theMCrebootwasn'tnoticedbutthe *MChasdefinitelyrebootedsoprepareforthereset.
*/ if (!rc && efx->type->mcdi_reboot_detected)
efx->type->mcdi_reboot_detected(efx);
mcdi->new_epoch = true;
/* Nobody was waiting for an MCDI request, so trigger a reset */
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
}
spin_unlock(&mcdi->iface_lock);
}
/* The MC is going down in to BIST mode. set the BIST flag to block *newMCDI,cancelanyoutstandingMCDIandscheduleaBIST-typereset *(whichdoesn'tactuallyexecuteareset,itwaitsforthecontrolling *functiontoresetit).
*/ staticvoid efx_mcdi_ev_bist(struct efx_nic *efx)
{ struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
/* MCDI timeouts seen, so make all MCDI calls fail-fast and issue an FLR to try *torecover.
*/ staticvoid efx_mcdi_abandon(struct efx_nic *efx)
{ struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
if (xchg(&mcdi->mode, MCDI_MODE_FAIL) == MCDI_MODE_FAIL) return; /* it had already been done */
netif_dbg(efx, hw, efx->net_dev, "MCDI is timing out; trying to recover\n");
efx_schedule_reset(efx, RESET_TYPE_MCDI_TIMEOUT);
}
staticvoid efx_handle_drain_event(struct efx_nic *efx)
{ if (atomic_dec_and_test(&efx->active_queues))
wake_up(&efx->flush_wq);
WARN_ON(atomic_read(&efx->active_queues) < 0);
}
/* Called from efx_farch_ev_process and efx_ef10_ev_process for MCDI events */ void efx_mcdi_process_event(struct efx_channel *channel,
efx_qword_t *event)
{ struct efx_nic *efx = channel->efx; int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
switch (code) { case MCDI_EVENT_CODE_BADSSERT:
netif_err(efx, hw, efx->net_dev, "MC watchdog or assertion failure at 0x%x\n", data);
efx_mcdi_ev_death(efx, -EINTR); break;
case MCDI_EVENT_CODE_PMNOTICE:
netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n"); break;
case MCDI_EVENT_CODE_CMDDONE:
efx_mcdi_ev_cpl(efx,
MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO)); break;
case MCDI_EVENT_CODE_LINKCHANGE:
efx_mcdi_process_link_change(efx, event); break; case MCDI_EVENT_CODE_SENSOREVT:
efx_sensor_event(efx, event); break; case MCDI_EVENT_CODE_SCHEDERR:
netif_dbg(efx, hw, efx->net_dev, "MC Scheduler alert (0x%x)\n", data); break; case MCDI_EVENT_CODE_REBOOT: case MCDI_EVENT_CODE_MC_REBOOT:
netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
efx_mcdi_ev_death(efx, -EIO); break; case MCDI_EVENT_CODE_MC_BIST:
netif_info(efx, hw, efx->net_dev, "MC entered BIST mode\n");
efx_mcdi_ev_bist(efx); break; case MCDI_EVENT_CODE_MAC_STATS_DMA: /* MAC stats are gather lazily. We can ignore this. */ break; case MCDI_EVENT_CODE_PTP_FAULT: case MCDI_EVENT_CODE_PTP_PPS:
efx_ptp_event(efx, event); break; case MCDI_EVENT_CODE_PTP_TIME:
efx_time_sync_event(channel, event); break; case MCDI_EVENT_CODE_TX_FLUSH: case MCDI_EVENT_CODE_RX_FLUSH: /* Two flush events will be sent: one to the same event *queueascompletions,andonetoeventqueue0. *Inthelattercasethe{RX,TX}_FLUSH_TO_DRIVER *flagwillbeset,andweshouldignoretheevent *becausewewanttowaitforallcompletions.
*/
BUILD_BUG_ON(MCDI_EVENT_TX_FLUSH_TO_DRIVER_LBN !=
MCDI_EVENT_RX_FLUSH_TO_DRIVER_LBN); if (!MCDI_EVENT_FIELD(*event, TX_FLUSH_TO_DRIVER))
efx_handle_drain_event(efx); break; case MCDI_EVENT_CODE_TX_ERR: case MCDI_EVENT_CODE_RX_ERR:
netif_err(efx, hw, efx->net_dev, "%s DMA error (event: "EFX_QWORD_FMT")\n",
code == MCDI_EVENT_CODE_TX_ERR ? "TX" : "RX",
EFX_QWORD_VAL(*event));
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR); break; case MCDI_EVENT_CODE_PROXY_RESPONSE:
efx_mcdi_ev_proxy_response(efx,
MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_HANDLE),
MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_RC)); break; default:
netif_err(efx, hw, efx->net_dev, "Unknown MCDI event " EFX_QWORD_FMT "\n",
EFX_QWORD_VAL(*event));
}
}
if (efx->type->print_additional_fwver)
offset += efx->type->print_additional_fwver(efx, buf + offset,
len - offset);
/* It's theoretically possible for the string to exceed 31 *characters,thoughinpracticethefirstthreeversion *componentsareshortenoughthatthisdoesn'thappen.
*/ if (WARN_ON(offset >= len))
buf[0] = 0;
/* This function finds types using the new NVRAM_PARTITIONS mcdi. */ staticint efx_new_mcdi_nvram_types(struct efx_nic *efx, u32 *number,
u32 *nvram_types)
{
efx_dword_t *outbuf = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2,
GFP_KERNEL);
size_t outlen; int rc;
switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) { case MC_CMD_NVRAM_TEST_PASS: case MC_CMD_NVRAM_TEST_NOTSUPP: return0; default: return -EIO;
}
}
/* This function tests nvram partitions using the new mcdi partition lookup scheme */ int efx_new_mcdi_nvram_test_all(struct efx_nic *efx)
{
u32 *nvram_types = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2,
GFP_KERNEL); unsignedint number; int rc, i;
if (!nvram_types) return -ENOMEM;
rc = efx_new_mcdi_nvram_types(efx, &number, nvram_types); if (rc) goto fail;
/* Require at least one check */
rc = -EAGAIN;
for (i = 0; i < number; i++) { if (nvram_types[i] == NVRAM_PARTITION_TYPE_PARTITION_MAP ||
nvram_types[i] == NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG) continue;
rc = efx_mcdi_nvram_test(efx, nvram_types[i]); if (rc) goto fail;
}
fail:
kfree(nvram_types); return rc;
}
int efx_mcdi_nvram_test_all(struct efx_nic *efx)
{
u32 nvram_types; unsignedint type; int rc;
rc = efx_mcdi_nvram_types(efx, &nvram_types); if (rc) goto fail1;
type = 0; while (nvram_types != 0) { if (nvram_types & 1) {
rc = efx_mcdi_nvram_test(efx, type); if (rc) goto fail2;
}
type++;
nvram_types >>= 1;
}
/* Returns 1 if an assertion was read, 0 if no assertion had fired, *negativeonerror.
*/ staticint efx_mcdi_read_assertion(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN); unsignedint flags, index; constchar *reason;
size_t outlen; int retry; int rc;
/* Attempt to read any stored assertion state before we reboot *themcfwoutoftheassertionhandler.Retrytwice,once *becauseaboot-timeassertionmightcausethiscommandtofail *withEINTR.AndonceagainbecauseGET_ASSERTScanracewith
* MC_CMD_REBOOT running on the other port. */
retry = 2; do {
MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS,
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
outbuf, sizeof(outbuf), &outlen); if (rc == -EPERM) return0;
} while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
if (rc) {
efx_mcdi_display_error(efx, MC_CMD_GET_ASSERTS,
MC_CMD_GET_ASSERTS_IN_LEN, outbuf,
outlen, rc); return rc;
} if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) return -EIO;
/* Print out any recorded assertion state */
flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS); if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) return0;
staticint efx_mcdi_reset_mc(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN); int rc;
BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
NULL, 0, NULL); /* White is black, and up is down */ if (rc == -EIO) return0; if (rc == 0)
rc = -EIO; return rc;
}
if (impl_out)
*impl_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_IMPLEMENTED);
if (enabled_out)
*enabled_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_ENABLED);
return0;
fail: /* Older firmware lacks GET_WORKAROUNDS and this isn't especially *terrifying.Thecallsitewillhavetodealwithitthough.
*/
netif_cond_dbg(efx, hw, efx->net_dev, rc == -ENOSYS, err, "%s: failed rc=%d\n", __func__, rc); return rc;
}
/* Failure to read a privilege mask is never fatal, because we can always *carryonasthoughwedidn'thavetheprivilegewewereinterestedin. *Souseefx_mcdi_rpc_quiet().
*/ int efx_mcdi_get_privilege_mask(struct efx_nic *efx, u32 *mask)
{
MCDI_DECLARE_BUF(fi_outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN);
MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN);
size_t outlen;
u16 pf, vf; int rc;
if (!efx || !mask) return -EINVAL;
/* Get our function number */
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_FUNCTION_INFO, NULL, 0,
fi_outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN,
&outlen); if (rc != 0) return rc; if (outlen < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) return -EIO;
int efx_mcdi_nvram_update_finish_polled(struct efx_nic *efx, unsignedint type)
{ unsignedint delay = EFX_MCDI_NVRAM_UPDATE_FINISH_INITIAL_POLL_DELAY_MS; unsignedint retry = 0; int rc;
/* NVRAM updates can take a long time (e.g. up to 1 minute for bundle *images).PollingforNVRAMupdatecompletionensuresthatotherMCDI *commandscanbeissuedbeforethebackgroundNVRAMupdatecompletes. * *Theinitialcalleithercompletestheupdatesynchronously,or *returns-EAGAINtoindicateprocessingiscontinuing.Inthelatter *case,wepollforatleast900seconds,atincreasingintervals *(5ms,50ms,500ms,5s).
*/
rc = efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_BACKGROUND); while (rc == -EAGAIN) { if (retry > EFX_MCDI_NVRAM_UPDATE_FINISH_RETRIES) return -ETIMEDOUT;
retry++;
msleep(delay); if (delay < EFX_MCDI_NVRAM_UPDATE_FINISH_MAX_POLL_DELAY_MS)
delay *= 10;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.56Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.