staticvoid _cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi, struct cdx_mcdi_cmd *cmd, struct list_head *cleanup_list)
{ /* if cancelled, the completers have already been called */ if (cdx_cmd_cancelled(cmd)) return;
if (cmd->completer) {
list_add_tail(&cmd->cleanup_list, cleanup_list);
++mcdi->outstanding_cleanups;
kref_get(&cmd->ref);
}
}
staticint cdx_mcdi_errno(struct cdx_mcdi *cdx, unsignedint mcdi_err)
{ switch (mcdi_err) { case 0: case MC_CMD_ERR_QUEUE_FULL: return mcdi_err; case MC_CMD_ERR_EPERM: return -EPERM; case MC_CMD_ERR_ENOENT: return -ENOENT; case MC_CMD_ERR_EINTR: return -EINTR; case MC_CMD_ERR_EAGAIN: return -EAGAIN; case MC_CMD_ERR_EACCES: return -EACCES; case MC_CMD_ERR_EBUSY: return -EBUSY; case MC_CMD_ERR_EINVAL: return -EINVAL; case MC_CMD_ERR_ERANGE: return -ERANGE; case MC_CMD_ERR_EDEADLK: return -EDEADLK; case MC_CMD_ERR_ENOSYS: return -EOPNOTSUPP; case MC_CMD_ERR_ETIME: return -ETIME; case MC_CMD_ERR_EALREADY: return -EALREADY; case MC_CMD_ERR_ENOSPC: return -ENOSPC; case MC_CMD_ERR_ENOMEM: return -ENOMEM; case MC_CMD_ERR_ENOTSUP: return -EOPNOTSUPP; case MC_CMD_ERR_ALLOC_FAIL: return -ENOBUFS; case MC_CMD_ERR_MAC_EXIST: return -EADDRINUSE; case MC_CMD_ERR_NO_EVB_PORT: return -EAGAIN; default: return -EPROTO;
}
}
/* Claim an extra reference for the completer to put. */
kref_get(&wait_data->ref);
rc = cdx_mcdi_rpc_async_internal(cdx, cmd_item, &handle); if (rc) {
kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); goto out;
}
if (!wait_event_timeout(wait_data->wq, wait_data->done,
cdx_mcdi_rpc_timeout(cdx, cmd)) &&
!wait_data->done) {
pr_err("MC command 0x%x inlen %zu timed out (sync)\n",
cmd, inlen);
/* * Returns true if the MCDI module is finished with the command. * (examples of false would be if the command was proxied, or it was * rejected by the MC due to lack of resources and requeued).
*/ staticbool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi, struct cdx_mcdi_cmd *cmd, struct cdx_dword *outbuf, int len, struct list_head *cleanup_list)
{
size_t resp_hdr_len, resp_data_len; struct cdx_mcdi *cdx = mcdi->cdx; unsignedint respcmd, error; bool completed = false; int rc;
/* ensure the command can't go away before this function returns */
kref_get(&cmd->ref);
/** * cdx_mcdi_rpc - Issue an MCDI command and wait for completion * @cdx: NIC through which to issue the command * @cmd: Command type number * @inbuf: Command parameters * @inlen: Length of command parameters, in bytes. Must be a multiple * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1. * @outbuf: Response buffer. May be %NULL if @outlen is 0. * @outlen: Length of response buffer, in bytes. If the actual * response is longer than @outlen & ~3, it will be truncated * to that length. * @outlen_actual: Pointer through which to return the actual response * length. May be %NULL if this is not needed. * * This function may sleep and therefore must be called in process * context. * * Return: A negative error code, or zero if successful. The error * code may come from the MCDI response or may indicate a failure * to communicate with the MC. In the former case, the response * will still be copied to @outbuf and *@outlen_actual will be * set accordingly. In the latter case, *@outlen_actual will be * set to zero.
*/ int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsignedint cmd, conststruct cdx_dword *inbuf, size_t inlen, struct cdx_dword *outbuf, size_t outlen,
size_t *outlen_actual)
{ return cdx_mcdi_rpc_sync(cdx, cmd, inbuf, inlen, outbuf, outlen,
outlen_actual, false);
}
/** * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously * @cdx: NIC through which to issue the command * @cmd: Command type number * @inbuf: Command parameters * @inlen: Length of command parameters, 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 process context, when one of the following occurs: * (a) the completion event is received (in process context) * (b) event queues are disabled (in the process that disables them)
*/ int
cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsignedint cmd, conststruct cdx_dword *inbuf, size_t inlen,
cdx_mcdi_async_completer *complete, unsignedlong cookie)
{ struct cdx_mcdi_cmd *cmd_item =
kmalloc(sizeof(struct cdx_mcdi_cmd) + inlen, GFP_ATOMIC);
if (!cmd_item) return -ENOMEM;
kref_init(&cmd_item->ref);
cmd_item->quiet = true;
cmd_item->cookie = cookie;
cmd_item->completer = complete;
cmd_item->cmd = cmd;
cmd_item->inlen = inlen; /* inbuf is probably not valid after return, so take a copy */
cmd_item->inbuf = (struct cdx_dword *)(cmd_item + 1);
memcpy(cmd_item + 1, inbuf, inlen);
staticvoid _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsignedint cmd,
size_t inlen, int raw, int arg, int err_no)
{
pr_err("MC command 0x%x inlen %d failed err_no=%d (raw=%d) arg=%d\n",
cmd, (int)inlen, err_no, raw, arg);
}
/* * Set MCDI mode to fail to prevent any new commands, then cancel any * outstanding commands. * Caller must hold the mcdi iface_lock.
*/ staticvoid cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list)
{ struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx);
if (!mcdi) return;
mcdi->mode = MCDI_MODE_FAIL;
while (!list_empty(&mcdi->cmd_list)) { struct cdx_mcdi_cmd *cmd;
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.