/* 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_siena_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) {
netif_err(efx, probe, efx->net_dev, "Unable to register driver with MCPU\n"); goto fail2;
} if (already_attached) /* Not a fatal error */
netif_err(efx, probe, efx->net_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_SIENA_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_siena_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_siena_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_siena_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_siena_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_siena_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_siena_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_siena_mcdi_rpc_finish() won't */ for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
rc = efx_siena_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_siena_mcdi_poll_reboot()beingtriggered. *Ifzerowasreturnedfromthefinalcallto *efx_siena_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_siena_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_siena_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_siena_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_siena_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_FLR: if (efx->type->sriov_flr)
efx->type->sriov_flr(efx,
MCDI_EVENT_FIELD(*event, FLR_VF)); break; case MCDI_EVENT_CODE_PTP_RX: case MCDI_EVENT_CODE_PTP_FAULT: case MCDI_EVENT_CODE_PTP_PPS:
efx_siena_ptp_event(efx, event); break; case MCDI_EVENT_CODE_PTP_TIME:
efx_siena_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_siena_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;
/* 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_siena_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_siena_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_siena_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;
}
int efx_siena_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
{ return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
}
int efx_siena_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
size_t outlen; int rc;
MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); /* Always set this flag. Old firmware ignores it */
MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
rc = efx_siena_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)
netif_err(efx, drv, efx->net_dev, "NVRAM update failed verification with code 0x%x\n",
rc2); switch (rc2) { case MC_CMD_NVRAM_VERIFY_RC_SUCCESS: break; case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED: case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED: case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHECK_FAILED: case MC_CMD_NVRAM_VERIFY_RC_TRUSTED_APPROVERS_CHECK_FAILED: case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHAIN_CHECK_FAILED:
rc = -EIO; break; case MC_CMD_NVRAM_VERIFY_RC_INVALID_CMS_FORMAT: case MC_CMD_NVRAM_VERIFY_RC_BAD_MESSAGE_DIGEST:
rc = -EINVAL; break; case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES: case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS: case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH:
rc = -EPERM; break; default:
netif_err(efx, drv, efx->net_dev, "Unknown response to NVRAM_UPDATE_FINISH\n");
rc = -EIO;
}
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.49Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-03)
¤
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.