mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
sfc: Log all unexpected MCDI errors
Split each of efx_mcdi_rpc, efx_mcdi_rpc_finish, and efx_mcdi_rpc_async into a normal and a _quiet version; made the former log MCDI errors with netif_err (and include the raw MCDI error code), and the latter never log them at all. Changed various callers; any where some errors are expected (but others are not) call the _quiet version and then if necessary log the MCDI error themselves. Said logging is done by new efx_mcdi_display_error. Callers of efx_mcdi_rpc*_quiet functions which may want to log the error need to ensure that their outbuf is big enough to hold an MCDI error; to this end, they now use MCDI_DECLARE_BUF_OUT_OR_ERR, which always allocates at least 8 bytes. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
parent
8d13a377b8
commit
1e0b8120b2
5 changed files with 290 additions and 254 deletions
|
@ -278,11 +278,17 @@ static int efx_ef10_probe(struct efx_nic *efx)
|
|||
|
||||
static int efx_ef10_free_vis(struct efx_nic *efx)
|
||||
{
|
||||
int rc = efx_mcdi_rpc(efx, MC_CMD_FREE_VIS, NULL, 0, NULL, 0, NULL);
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
|
||||
size_t outlen;
|
||||
int rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FREE_VIS, NULL, 0,
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
|
||||
/* -EALREADY means nothing to free, so ignore */
|
||||
if (rc == -EALREADY)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
efx_mcdi_display_error(efx, MC_CMD_FREE_VIS, 0, outbuf, outlen,
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1244,7 +1250,6 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
|
|||
|
||||
fail:
|
||||
WARN_ON(true);
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
}
|
||||
|
||||
static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
|
||||
|
@ -1258,7 +1263,7 @@ static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
|
|||
MCDI_SET_DWORD(inbuf, FINI_TXQ_IN_INSTANCE,
|
||||
tx_queue->queue);
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_TXQ, inbuf, sizeof(inbuf),
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_TXQ, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
|
||||
if (rc && rc != -EALREADY)
|
||||
|
@ -1267,7 +1272,8 @@ static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
|
|||
return;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
efx_mcdi_display_error(efx, MC_CMD_FINI_TXQ, MC_CMD_FINI_TXQ_IN_LEN,
|
||||
outbuf, outlen, rc);
|
||||
}
|
||||
|
||||
static void efx_ef10_tx_remove(struct efx_tx_queue *tx_queue)
|
||||
|
@ -1482,14 +1488,9 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, inlen,
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
goto fail;
|
||||
WARN_ON(rc);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
WARN_ON(true);
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
}
|
||||
|
||||
static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
|
||||
|
@ -1503,7 +1504,7 @@ static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
|
|||
MCDI_SET_DWORD(inbuf, FINI_RXQ_IN_INSTANCE,
|
||||
efx_rx_queue_index(rx_queue));
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_RXQ, inbuf, sizeof(inbuf),
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_RXQ, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
|
||||
if (rc && rc != -EALREADY)
|
||||
|
@ -1512,7 +1513,8 @@ static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
|
|||
return;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
efx_mcdi_display_error(efx, MC_CMD_FINI_RXQ, MC_CMD_FINI_RXQ_IN_LEN,
|
||||
outbuf, outlen, rc);
|
||||
}
|
||||
|
||||
static void efx_ef10_rx_remove(struct efx_rx_queue *rx_queue)
|
||||
|
@ -1649,15 +1651,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_EVQ, inbuf, inlen,
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* IRQ return is ignored */
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1671,7 +1665,7 @@ static void efx_ef10_ev_fini(struct efx_channel *channel)
|
|||
|
||||
MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel);
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf),
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
|
||||
if (rc && rc != -EALREADY)
|
||||
|
@ -1680,7 +1674,8 @@ static void efx_ef10_ev_fini(struct efx_channel *channel)
|
|||
return;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN,
|
||||
outbuf, outlen, rc);
|
||||
}
|
||||
|
||||
static void efx_ef10_ev_remove(struct efx_channel *channel)
|
||||
|
|
|
@ -42,6 +42,7 @@ struct efx_mcdi_async_param {
|
|||
unsigned int cmd;
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
bool quiet;
|
||||
efx_mcdi_async_completer *complete;
|
||||
unsigned long cookie;
|
||||
/* followed by request/response buffer */
|
||||
|
@ -402,8 +403,9 @@ static bool 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;
|
||||
size_t hdr_len, data_len, err_len;
|
||||
efx_dword_t *outbuf;
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
|
||||
int rc;
|
||||
|
||||
if (cmpxchg(&mcdi->state,
|
||||
|
@ -444,6 +446,13 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
|
|||
outbuf = (efx_dword_t *)(async + 1);
|
||||
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
|
||||
min(async->outlen, data_len));
|
||||
if (!timeout && rc && !async->quiet) {
|
||||
err_len = min(sizeof(errbuf), data_len);
|
||||
efx->type->mcdi_read_response(efx, errbuf, hdr_len,
|
||||
sizeof(errbuf));
|
||||
efx_mcdi_display_error(efx, async->cmd, async->inlen, errbuf,
|
||||
err_len, rc);
|
||||
}
|
||||
async->complete(efx, async->cookie, rc, outbuf, data_len);
|
||||
kfree(async);
|
||||
|
||||
|
@ -519,115 +528,12 @@ efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
return efx_mcdi_rpc_finish(efx, cmd, inlen,
|
||||
outbuf, outlen, outlen_actual);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen)
|
||||
{
|
||||
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_check_supported(efx, cmd, inlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (efx->mc_bist_for_other_fn)
|
||||
return -ENETDOWN;
|
||||
|
||||
efx_mcdi_acquire_sync(mcdi);
|
||||
efx_mcdi_send_request(efx, cmd, inbuf, inlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
|
||||
* @efx: NIC through which to issue the command
|
||||
* @cmd: Command type number
|
||||
* @inbuf: Command parameters
|
||||
* @inlen: Length of command parameters, in bytes
|
||||
* @outlen: Length to allocate for response buffer, in bytes
|
||||
* @complete: Function to be called on completion or cancellation.
|
||||
* @cookie: Arbitrary value to be passed to @complete.
|
||||
*
|
||||
* This function does not sleep and therefore may be called in atomic
|
||||
* context. It will fail if event queues are disabled or if MCDI
|
||||
* event completions have been disabled due to an error.
|
||||
*
|
||||
* If it succeeds, the @complete function will be called exactly once
|
||||
* in atomic context, when one of the following occurs:
|
||||
* (a) the completion event is received (in NAPI context)
|
||||
* (b) event queues are disabled (in the process that disables them)
|
||||
* (c) the request times-out (in timer context)
|
||||
*/
|
||||
int
|
||||
efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
|
||||
efx_mcdi_async_completer *complete, unsigned long cookie)
|
||||
{
|
||||
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
|
||||
struct efx_mcdi_async_param *async;
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_check_supported(efx, cmd, inlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (efx->mc_bist_for_other_fn)
|
||||
return -ENETDOWN;
|
||||
|
||||
async = kmalloc(sizeof(*async) + ALIGN(max(inlen, outlen), 4),
|
||||
GFP_ATOMIC);
|
||||
if (!async)
|
||||
return -ENOMEM;
|
||||
|
||||
async->cmd = cmd;
|
||||
async->inlen = inlen;
|
||||
async->outlen = outlen;
|
||||
async->complete = complete;
|
||||
async->cookie = cookie;
|
||||
memcpy(async + 1, inbuf, inlen);
|
||||
|
||||
spin_lock_bh(&mcdi->async_lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&mcdi->async_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual, bool quiet)
|
||||
{
|
||||
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
|
||||
int rc;
|
||||
|
||||
if (mcdi->mode == MCDI_MODE_POLL)
|
||||
|
@ -656,8 +562,11 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
|||
spin_unlock_bh(&mcdi->iface_lock);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
size_t hdr_len, data_len;
|
||||
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
|
||||
* we pick up changes from efx_mcdi_ev_cpl(). Protect against
|
||||
|
@ -667,25 +576,28 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
|||
rc = mcdi->resprc;
|
||||
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);
|
||||
|
||||
if (rc == 0) {
|
||||
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
|
||||
min(outlen, data_len));
|
||||
if (outlen_actual != NULL)
|
||||
*outlen_actual = data_len;
|
||||
} else if (cmd == MC_CMD_REBOOT && rc == -EIO)
|
||||
; /* Don't reset if MC_CMD_REBOOT returns EIO */
|
||||
else if (rc == -EIO || rc == -EINTR) {
|
||||
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
|
||||
min(outlen, data_len));
|
||||
if (outlen_actual)
|
||||
*outlen_actual = data_len;
|
||||
|
||||
efx->type->mcdi_read_response(efx, errbuf, hdr_len, err_len);
|
||||
|
||||
if (cmd == MC_CMD_REBOOT && rc == -EIO) {
|
||||
/* Don't reset if MC_CMD_REBOOT returns EIO */
|
||||
} else if (rc == -EIO || rc == -EINTR) {
|
||||
netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
|
||||
-rc);
|
||||
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
|
||||
} else
|
||||
netif_dbg(efx, hw, efx->net_dev,
|
||||
"MC command 0x%x inlen %d failed rc=%d\n",
|
||||
cmd, (int)inlen, -rc);
|
||||
} else if (rc && !quiet) {
|
||||
efx_mcdi_display_error(efx, cmd, inlen, errbuf, err_len,
|
||||
rc);
|
||||
}
|
||||
|
||||
if (rc == -EIO || rc == -EINTR) {
|
||||
msleep(MCDI_STATUS_SLEEP_MS);
|
||||
|
@ -698,6 +610,190 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual, bool quiet)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
|
||||
if (rc) {
|
||||
if (outlen_actual)
|
||||
*outlen_actual = 0;
|
||||
return rc;
|
||||
}
|
||||
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
|
||||
outlen_actual, quiet);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
{
|
||||
return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
|
||||
outlen_actual, false);
|
||||
}
|
||||
|
||||
/* Normally, on receiving an error code in the MCDI response,
|
||||
* efx_mcdi_rpc will log an error message containing (among other
|
||||
* things) the raw error code, by means of efx_mcdi_display_error.
|
||||
* This _quiet version suppresses that; if the caller wishes to log
|
||||
* the error conditionally on the return code, it should call this
|
||||
* function and is then responsible for calling efx_mcdi_display_error
|
||||
* as needed.
|
||||
*/
|
||||
int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
{
|
||||
return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
|
||||
outlen_actual, true);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen)
|
||||
{
|
||||
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_check_supported(efx, cmd, inlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (efx->mc_bist_for_other_fn)
|
||||
return -ENETDOWN;
|
||||
|
||||
efx_mcdi_acquire_sync(mcdi);
|
||||
efx_mcdi_send_request(efx, cmd, inbuf, inlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
size_t outlen,
|
||||
efx_mcdi_async_completer *complete,
|
||||
unsigned long cookie, bool quiet)
|
||||
{
|
||||
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
|
||||
struct efx_mcdi_async_param *async;
|
||||
int rc;
|
||||
|
||||
rc = efx_mcdi_check_supported(efx, cmd, inlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (efx->mc_bist_for_other_fn)
|
||||
return -ENETDOWN;
|
||||
|
||||
async = kmalloc(sizeof(*async) + ALIGN(max(inlen, outlen), 4),
|
||||
GFP_ATOMIC);
|
||||
if (!async)
|
||||
return -ENOMEM;
|
||||
|
||||
async->cmd = cmd;
|
||||
async->inlen = inlen;
|
||||
async->outlen = outlen;
|
||||
async->quiet = quiet;
|
||||
async->complete = complete;
|
||||
async->cookie = cookie;
|
||||
memcpy(async + 1, inbuf, inlen);
|
||||
|
||||
spin_lock_bh(&mcdi->async_lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&mcdi->async_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* efx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
|
||||
* @efx: NIC through which to issue the command
|
||||
* @cmd: Command type number
|
||||
* @inbuf: Command parameters
|
||||
* @inlen: Length of command parameters, in bytes
|
||||
* @outlen: Length to allocate for response buffer, in bytes
|
||||
* @complete: Function to be called on completion or cancellation.
|
||||
* @cookie: Arbitrary value to be passed to @complete.
|
||||
*
|
||||
* This function does not sleep and therefore may be called in atomic
|
||||
* context. It will fail if event queues are disabled or if MCDI
|
||||
* event completions have been disabled due to an error.
|
||||
*
|
||||
* If it succeeds, the @complete function will be called exactly once
|
||||
* in atomic context, when one of the following occurs:
|
||||
* (a) the completion event is received (in NAPI context)
|
||||
* (b) event queues are disabled (in the process that disables them)
|
||||
* (c) the request times-out (in timer context)
|
||||
*/
|
||||
int
|
||||
efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
|
||||
efx_mcdi_async_completer *complete, unsigned long cookie)
|
||||
{
|
||||
return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete,
|
||||
cookie, false);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
size_t outlen, efx_mcdi_async_completer *complete,
|
||||
unsigned long cookie)
|
||||
{
|
||||
return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete,
|
||||
cookie, true);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
{
|
||||
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
|
||||
outlen_actual, false);
|
||||
}
|
||||
|
||||
int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual)
|
||||
{
|
||||
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
|
||||
outlen_actual, true);
|
||||
}
|
||||
|
||||
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
|
||||
size_t inlen, efx_dword_t *outbuf,
|
||||
size_t outlen, int rc)
|
||||
{
|
||||
int code = 0, err_arg = 0;
|
||||
|
||||
if (outlen >= MC_CMD_ERR_CODE_OFST + 4)
|
||||
code = MCDI_DWORD(outbuf, ERR_CODE);
|
||||
if (outlen >= MC_CMD_ERR_ARG_OFST + 4)
|
||||
err_arg = MCDI_DWORD(outbuf, ERR_ARG);
|
||||
netif_err(efx, hw, efx->net_dev,
|
||||
"MC command 0x%x inlen %d failed rc=%d (raw=%d) arg=%d\n",
|
||||
cmd, (int)inlen, rc, code, err_arg);
|
||||
}
|
||||
|
||||
/* Switch to polled MCDI completions. This can be called in various
|
||||
* error conditions with various locks held, so it must be lockless.
|
||||
* Caller is responsible for flushing asynchronous requests later.
|
||||
|
@ -1131,13 +1227,6 @@ int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1254,7 +1343,7 @@ int efx_mcdi_nvram_test_all(struct efx_nic *efx)
|
|||
static int 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);
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
|
||||
unsigned int flags, index;
|
||||
const char *reason;
|
||||
size_t outlen;
|
||||
|
@ -1269,13 +1358,17 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
|
|||
retry = 2;
|
||||
do {
|
||||
MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
|
||||
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS,
|
||||
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
} while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
|
||||
|
||||
if (rc)
|
||||
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;
|
||||
|
||||
|
@ -1353,18 +1446,11 @@ void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
|
||||
__func__, rc);
|
||||
}
|
||||
|
||||
static int efx_mcdi_reset_port(struct efx_nic *efx)
|
||||
{
|
||||
int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
|
||||
if (rc)
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
return efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static int efx_mcdi_reset_mc(struct efx_nic *efx)
|
||||
|
@ -1381,7 +1467,6 @@ static int efx_mcdi_reset_mc(struct efx_nic *efx)
|
|||
return 0;
|
||||
if (rc == 0)
|
||||
rc = -EIO;
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1483,13 +1568,6 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1530,13 +1608,6 @@ int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
|
|||
int rc;
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1566,13 +1637,6 @@ static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1592,14 +1656,10 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
|
|||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
goto fail;
|
||||
return rc;
|
||||
|
||||
memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
||||
|
@ -1619,13 +1679,6 @@ static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
|
|||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
|
||||
ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1643,13 +1696,6 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1664,13 +1710,6 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,12 +116,19 @@ void efx_mcdi_fini(struct efx_nic *efx);
|
|||
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const efx_dword_t *inbuf,
|
||||
size_t inlen, efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual);
|
||||
int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual);
|
||||
|
||||
int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen);
|
||||
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
|
||||
efx_dword_t *outbuf, size_t outlen,
|
||||
size_t *outlen_actual);
|
||||
int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd,
|
||||
size_t inlen, efx_dword_t *outbuf,
|
||||
size_t outlen, size_t *outlen_actual);
|
||||
|
||||
typedef void efx_mcdi_async_completer(struct efx_nic *efx,
|
||||
unsigned long cookie, int rc,
|
||||
|
@ -131,6 +138,15 @@ int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
|
|||
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
|
||||
efx_mcdi_async_completer *complete,
|
||||
unsigned long cookie);
|
||||
int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
|
||||
const efx_dword_t *inbuf, size_t inlen,
|
||||
size_t outlen,
|
||||
efx_mcdi_async_completer *complete,
|
||||
unsigned long cookie);
|
||||
|
||||
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
|
||||
size_t inlen, efx_dword_t *outbuf,
|
||||
size_t outlen, int rc);
|
||||
|
||||
int efx_mcdi_poll_reboot(struct efx_nic *efx);
|
||||
void efx_mcdi_mode_poll(struct efx_nic *efx);
|
||||
|
@ -147,6 +163,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
|
|||
*/
|
||||
#define MCDI_DECLARE_BUF(_name, _len) \
|
||||
efx_dword_t _name[DIV_ROUND_UP(_len, 4)]
|
||||
#define MCDI_DECLARE_BUF_OUT_OR_ERR(_name, _len) \
|
||||
MCDI_DECLARE_BUF(_name, max_t(size_t, _len, 8))
|
||||
#define _MCDI_PTR(_buf, _offset) \
|
||||
((u8 *)(_buf) + (_offset))
|
||||
#define MCDI_PTR(_buf, _field) \
|
||||
|
|
|
@ -90,13 +90,6 @@ static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -143,17 +136,13 @@ static int efx_mcdi_mdio_read(struct net_device *net_dev,
|
|||
rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
goto fail;
|
||||
return rc;
|
||||
|
||||
if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) !=
|
||||
MC_CMD_MDIO_STATUS_GOOD)
|
||||
return -EIO;
|
||||
|
||||
return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int efx_mcdi_mdio_write(struct net_device *net_dev,
|
||||
|
@ -174,17 +163,13 @@ static int efx_mcdi_mdio_write(struct net_device *net_dev,
|
|||
rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
goto fail;
|
||||
return rc;
|
||||
|
||||
if (MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS) !=
|
||||
MC_CMD_MDIO_STATUS_GOOD)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u32 mcdi_to_ethtool_cap(u32 media, u32 cap)
|
||||
|
@ -487,17 +472,14 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
|
||||
outbuf, sizeof(outbuf), NULL);
|
||||
if (rc) {
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
|
||||
__func__, rc);
|
||||
if (rc)
|
||||
efx->link_state.up = false;
|
||||
} else {
|
||||
else
|
||||
efx_mcdi_phy_decode_link(
|
||||
efx, &efx->link_state,
|
||||
MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
|
||||
MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
|
||||
MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
|
||||
}
|
||||
|
||||
return !efx_link_state_equal(&efx->link_state, &old_state);
|
||||
}
|
||||
|
@ -531,11 +513,8 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
|
|||
BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
|
||||
outbuf, sizeof(outbuf), NULL);
|
||||
if (rc) {
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
|
||||
__func__, rc);
|
||||
if (rc)
|
||||
return;
|
||||
}
|
||||
ecmd->lp_advertising =
|
||||
mcdi_to_ethtool_cap(phy_cfg->media,
|
||||
MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
|
||||
|
@ -918,11 +897,8 @@ bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
|
||||
outbuf, sizeof(outbuf), &outlength);
|
||||
if (rc) {
|
||||
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
|
||||
__func__, rc);
|
||||
if (rc)
|
||||
return true;
|
||||
}
|
||||
|
||||
return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
|
||||
}
|
||||
|
@ -960,14 +936,6 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx,
|
|||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
netif_err(efx, hw, efx->net_dev, "%s: action %d failed rc=%d\n",
|
||||
__func__, action, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -313,6 +313,8 @@ static int efx_phc_enable(struct ptp_clock_info *ptp,
|
|||
static int efx_ptp_enable(struct efx_nic *efx)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ENABLE_LEN);
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
|
||||
int rc;
|
||||
|
||||
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ENABLE);
|
||||
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
|
||||
|
@ -320,8 +322,14 @@ static int efx_ptp_enable(struct efx_nic *efx)
|
|||
efx->ptp_data->channel->channel);
|
||||
MCDI_SET_DWORD(inbuf, PTP_IN_ENABLE_MODE, efx->ptp_data->mode);
|
||||
|
||||
return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), NULL);
|
||||
rc = (rc == -EALREADY) ? 0 : rc;
|
||||
if (rc)
|
||||
efx_mcdi_display_error(efx, MC_CMD_PTP,
|
||||
MC_CMD_PTP_IN_ENABLE_LEN,
|
||||
outbuf, sizeof(outbuf), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Disable MCDI PTP support.
|
||||
|
@ -332,11 +340,19 @@ static int efx_ptp_enable(struct efx_nic *efx)
|
|||
static int efx_ptp_disable(struct efx_nic *efx)
|
||||
{
|
||||
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_DISABLE_LEN);
|
||||
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
|
||||
int rc;
|
||||
|
||||
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_DISABLE);
|
||||
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
|
||||
return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
|
||||
NULL, 0, NULL);
|
||||
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
|
||||
outbuf, sizeof(outbuf), NULL);
|
||||
rc = (rc == -EALREADY) ? 0 : rc;
|
||||
if (rc)
|
||||
efx_mcdi_display_error(efx, MC_CMD_PTP,
|
||||
MC_CMD_PTP_IN_DISABLE_LEN,
|
||||
outbuf, sizeof(outbuf), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void efx_ptp_deliver_rx_queue(struct sk_buff_head *q)
|
||||
|
|
Loading…
Reference in a new issue