|
|
|
@@ -4,6 +4,102 @@
|
|
|
|
#include "idpf.h"
|
|
|
|
#include "idpf.h"
|
|
|
|
#include "idpf_virtchnl.h"
|
|
|
|
#include "idpf_virtchnl.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define IDPF_VC_XN_MIN_TIMEOUT_MSEC 2000
|
|
|
|
|
|
|
|
#define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC (60 * 1000)
|
|
|
|
|
|
|
|
#define IDPF_VC_XN_IDX_M GENMASK(7, 0)
|
|
|
|
|
|
|
|
#define IDPF_VC_XN_SALT_M GENMASK(15, 8)
|
|
|
|
|
|
|
|
#define IDPF_VC_XN_RING_LEN U8_MAX
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* enum idpf_vc_xn_state - Virtchnl transaction status
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_WAITING: expecting a reply, not yet received
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received,
|
|
|
|
|
|
|
|
* buffer updated
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there
|
|
|
|
|
|
|
|
* was an error, buffer not updated
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down
|
|
|
|
|
|
|
|
* @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the
|
|
|
|
|
|
|
|
* return context; a callback may be provided to handle
|
|
|
|
|
|
|
|
* return
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum idpf_vc_xn_state {
|
|
|
|
|
|
|
|
IDPF_VC_XN_IDLE = 1,
|
|
|
|
|
|
|
|
IDPF_VC_XN_WAITING,
|
|
|
|
|
|
|
|
IDPF_VC_XN_COMPLETED_SUCCESS,
|
|
|
|
|
|
|
|
IDPF_VC_XN_COMPLETED_FAILED,
|
|
|
|
|
|
|
|
IDPF_VC_XN_SHUTDOWN,
|
|
|
|
|
|
|
|
IDPF_VC_XN_ASYNC,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct idpf_vc_xn;
|
|
|
|
|
|
|
|
/* Callback for asynchronous messages */
|
|
|
|
|
|
|
|
typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
|
|
|
|
|
|
|
|
const struct idpf_ctlq_msg *);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* struct idpf_vc_xn - Data structure representing virtchnl transactions
|
|
|
|
|
|
|
|
* @completed: virtchnl event loop uses that to signal when a reply is
|
|
|
|
|
|
|
|
* available, uses kernel completion API
|
|
|
|
|
|
|
|
* @state: virtchnl event loop stores the data below, protected by the
|
|
|
|
|
|
|
|
* completion's lock.
|
|
|
|
|
|
|
|
* @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
|
|
|
|
|
|
|
|
* truncated on its way to the receiver thread according to
|
|
|
|
|
|
|
|
* reply_buf.iov_len.
|
|
|
|
|
|
|
|
* @reply: Reference to the buffer(s) where the reply data should be written
|
|
|
|
|
|
|
|
* to. May be 0-length (then NULL address permitted) if the reply data
|
|
|
|
|
|
|
|
* should be ignored.
|
|
|
|
|
|
|
|
* @async_handler: if sent asynchronously, a callback can be provided to handle
|
|
|
|
|
|
|
|
* the reply when it's received
|
|
|
|
|
|
|
|
* @vc_op: corresponding opcode sent with this transaction
|
|
|
|
|
|
|
|
* @idx: index used as retrieval on reply receive, used for cookie
|
|
|
|
|
|
|
|
* @salt: changed every message to make unique, used for cookie
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct idpf_vc_xn {
|
|
|
|
|
|
|
|
struct completion completed;
|
|
|
|
|
|
|
|
enum idpf_vc_xn_state state;
|
|
|
|
|
|
|
|
size_t reply_sz;
|
|
|
|
|
|
|
|
struct kvec reply;
|
|
|
|
|
|
|
|
async_vc_cb async_handler;
|
|
|
|
|
|
|
|
u32 vc_op;
|
|
|
|
|
|
|
|
u8 idx;
|
|
|
|
|
|
|
|
u8 salt;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* struct idpf_vc_xn_params - Parameters for executing transaction
|
|
|
|
|
|
|
|
* @send_buf: kvec for send buffer
|
|
|
|
|
|
|
|
* @recv_buf: kvec for recv buffer, may be NULL, must then have zero length
|
|
|
|
|
|
|
|
* @timeout_ms: timeout to wait for reply
|
|
|
|
|
|
|
|
* @async: send message asynchronously, will not wait on completion
|
|
|
|
|
|
|
|
* @async_handler: If sent asynchronously, optional callback handler. The user
|
|
|
|
|
|
|
|
* must be careful when using async handlers as the memory for
|
|
|
|
|
|
|
|
* the recv_buf _cannot_ be on stack if this is async.
|
|
|
|
|
|
|
|
* @vc_op: virtchnl op to send
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct idpf_vc_xn_params {
|
|
|
|
|
|
|
|
struct kvec send_buf;
|
|
|
|
|
|
|
|
struct kvec recv_buf;
|
|
|
|
|
|
|
|
int timeout_ms;
|
|
|
|
|
|
|
|
bool async;
|
|
|
|
|
|
|
|
async_vc_cb async_handler;
|
|
|
|
|
|
|
|
u32 vc_op;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* struct idpf_vc_xn_manager - Manager for tracking transactions
|
|
|
|
|
|
|
|
* @ring: backing and lookup for transactions
|
|
|
|
|
|
|
|
* @free_xn_bm: bitmap for free transactions
|
|
|
|
|
|
|
|
* @xn_bm_lock: make bitmap access synchronous where necessary
|
|
|
|
|
|
|
|
* @salt: used to make cookie unique every message
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct idpf_vc_xn_manager {
|
|
|
|
|
|
|
|
struct idpf_vc_xn ring[IDPF_VC_XN_RING_LEN];
|
|
|
|
|
|
|
|
DECLARE_BITMAP(free_xn_bm, IDPF_VC_XN_RING_LEN);
|
|
|
|
|
|
|
|
spinlock_t xn_bm_lock;
|
|
|
|
|
|
|
|
u8 salt;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* idpf_recv_event_msg - Receive virtchnl event message
|
|
|
|
* idpf_recv_event_msg - Receive virtchnl event message
|
|
|
|
* @vport: virtual port structure
|
|
|
|
* @vport: virtual port structure
|
|
|
|
@@ -94,13 +190,14 @@ err_kfree:
|
|
|
|
* @op: virtchnl opcode
|
|
|
|
* @op: virtchnl opcode
|
|
|
|
* @msg_size: size of the payload
|
|
|
|
* @msg_size: size of the payload
|
|
|
|
* @msg: pointer to buffer holding the payload
|
|
|
|
* @msg: pointer to buffer holding the payload
|
|
|
|
|
|
|
|
* @cookie: unique SW generated cookie per message
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Will prepare the control queue message and initiates the send api
|
|
|
|
* Will prepare the control queue message and initiates the send api
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns 0 on success, negative on failure
|
|
|
|
* Returns 0 on success, negative on failure
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
|
|
|
|
int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
|
|
|
|
u16 msg_size, u8 *msg)
|
|
|
|
u16 msg_size, u8 *msg, u16 cookie)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct idpf_ctlq_msg *ctlq_msg;
|
|
|
|
struct idpf_ctlq_msg *ctlq_msg;
|
|
|
|
struct idpf_dma_mem *dma_mem;
|
|
|
|
struct idpf_dma_mem *dma_mem;
|
|
|
|
@@ -140,8 +237,12 @@ int idpf_send_mb_msg(struct idpf_adapter *adapter, u32 op,
|
|
|
|
err = -ENOMEM;
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto dma_alloc_error;
|
|
|
|
goto dma_alloc_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(dma_mem->va, msg, msg_size);
|
|
|
|
|
|
|
|
|
|
|
|
/* It's possible we're just sending an opcode but no buffer */
|
|
|
|
|
|
|
|
if (msg && msg_size)
|
|
|
|
|
|
|
|
memcpy(dma_mem->va, msg, msg_size);
|
|
|
|
ctlq_msg->ctx.indirect.payload = dma_mem;
|
|
|
|
ctlq_msg->ctx.indirect.payload = dma_mem;
|
|
|
|
|
|
|
|
ctlq_msg->ctx.sw_cookie.data = cookie;
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg);
|
|
|
|
err = idpf_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
@@ -362,6 +463,378 @@ static void idpf_recv_vchnl_op(struct idpf_adapter *adapter,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* API for virtchnl "transaction" support ("xn" for short).
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* We are reusing the completion lock to serialize the accesses to the
|
|
|
|
|
|
|
|
* transaction state for simplicity, but it could be its own separate synchro
|
|
|
|
|
|
|
|
* as well. For now, this API is only used from within a workqueue context;
|
|
|
|
|
|
|
|
* raw_spin_lock() is enough.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_lock - Request exclusive access to vc transaction
|
|
|
|
|
|
|
|
* @xn: struct idpf_vc_xn* to access
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define idpf_vc_xn_lock(xn) \
|
|
|
|
|
|
|
|
raw_spin_lock(&(xn)->completed.wait.lock)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_unlock - Release exclusive access to vc transaction
|
|
|
|
|
|
|
|
* @xn: struct idpf_vc_xn* to access
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define idpf_vc_xn_unlock(xn) \
|
|
|
|
|
|
|
|
raw_spin_unlock(&(xn)->completed.wait.lock)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
|
|
|
|
|
|
|
|
* reset the transaction state.
|
|
|
|
|
|
|
|
* @xn: struct idpf_vc_xn to update
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void idpf_vc_xn_release_bufs(struct idpf_vc_xn *xn)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
xn->reply.iov_base = NULL;
|
|
|
|
|
|
|
|
xn->reply.iov_len = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (xn->state != IDPF_VC_XN_SHUTDOWN)
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_IDLE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_init - Initialize virtchnl transaction object
|
|
|
|
|
|
|
|
* @vcxn_mngr: pointer to vc transaction manager struct
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
spin_lock_init(&vcxn_mngr->xn_bm_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_IDLE;
|
|
|
|
|
|
|
|
xn->idx = i;
|
|
|
|
|
|
|
|
idpf_vc_xn_release_bufs(xn);
|
|
|
|
|
|
|
|
init_completion(&xn->completed);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bitmap_fill(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_shutdown - Uninitialize virtchnl transaction object
|
|
|
|
|
|
|
|
* @vcxn_mngr: pointer to vc transaction manager struct
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* All waiting threads will be woken-up and their transaction aborted. Further
|
|
|
|
|
|
|
|
* operations on that object will fail.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&vcxn_mngr->xn_bm_lock);
|
|
|
|
|
|
|
|
bitmap_zero(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
|
|
|
|
|
|
|
|
spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vcxn_mngr->ring); i++) {
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn = &vcxn_mngr->ring[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idpf_vc_xn_lock(xn);
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_SHUTDOWN;
|
|
|
|
|
|
|
|
idpf_vc_xn_release_bufs(xn);
|
|
|
|
|
|
|
|
idpf_vc_xn_unlock(xn);
|
|
|
|
|
|
|
|
complete_all(&xn->completed);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_pop_free - Pop a free transaction from free list
|
|
|
|
|
|
|
|
* @vcxn_mngr: transaction manager to pop from
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Returns NULL if no free transactions
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static
|
|
|
|
|
|
|
|
struct idpf_vc_xn *idpf_vc_xn_pop_free(struct idpf_vc_xn_manager *vcxn_mngr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn = NULL;
|
|
|
|
|
|
|
|
unsigned long free_idx;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
spin_lock_bh(&vcxn_mngr->xn_bm_lock);
|
|
|
|
|
|
|
|
free_idx = find_first_bit(vcxn_mngr->free_xn_bm, IDPF_VC_XN_RING_LEN);
|
|
|
|
|
|
|
|
if (free_idx == IDPF_VC_XN_RING_LEN)
|
|
|
|
|
|
|
|
goto do_unlock;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clear_bit(free_idx, vcxn_mngr->free_xn_bm);
|
|
|
|
|
|
|
|
xn = &vcxn_mngr->ring[free_idx];
|
|
|
|
|
|
|
|
xn->salt = vcxn_mngr->salt++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
do_unlock:
|
|
|
|
|
|
|
|
spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return xn;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_push_free - Push a free transaction to free list
|
|
|
|
|
|
|
|
* @vcxn_mngr: transaction manager to push to
|
|
|
|
|
|
|
|
* @xn: transaction to push
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
idpf_vc_xn_release_bufs(xn);
|
|
|
|
|
|
|
|
set_bit(xn->idx, vcxn_mngr->free_xn_bm);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_exec - Perform a send/recv virtchnl transaction
|
|
|
|
|
|
|
|
* @adapter: driver specific private structure with vcxn_mngr
|
|
|
|
|
|
|
|
* @params: parameters for this particular transaction including
|
|
|
|
|
|
|
|
* -vc_op: virtchannel operation to send
|
|
|
|
|
|
|
|
* -send_buf: kvec iov for send buf and len
|
|
|
|
|
|
|
|
* -recv_buf: kvec iov for recv buf and len (ignored if NULL)
|
|
|
|
|
|
|
|
* -timeout_ms: timeout waiting for a reply (milliseconds)
|
|
|
|
|
|
|
|
* -async: don't wait for message reply, will lose caller context
|
|
|
|
|
|
|
|
* -async_handler: callback to handle async replies
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @returns >= 0 for success, the size of the initial reply (may or may not be
|
|
|
|
|
|
|
|
* >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for
|
|
|
|
|
|
|
|
* error.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter,
|
|
|
|
|
|
|
|
const struct idpf_vc_xn_params *params)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const struct kvec *send_buf = ¶ms->send_buf;
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn;
|
|
|
|
|
|
|
|
ssize_t retval;
|
|
|
|
|
|
|
|
u16 cookie;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xn = idpf_vc_xn_pop_free(adapter->vcxn_mngr);
|
|
|
|
|
|
|
|
/* no free transactions available */
|
|
|
|
|
|
|
|
if (!xn)
|
|
|
|
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idpf_vc_xn_lock(xn);
|
|
|
|
|
|
|
|
if (xn->state == IDPF_VC_XN_SHUTDOWN) {
|
|
|
|
|
|
|
|
retval = -ENXIO;
|
|
|
|
|
|
|
|
goto only_unlock;
|
|
|
|
|
|
|
|
} else if (xn->state != IDPF_VC_XN_IDLE) {
|
|
|
|
|
|
|
|
/* We're just going to clobber this transaction even though
|
|
|
|
|
|
|
|
* it's not IDLE. If we don't reuse it we could theoretically
|
|
|
|
|
|
|
|
* eventually leak all the free transactions and not be able to
|
|
|
|
|
|
|
|
* send any messages. At least this way we make an attempt to
|
|
|
|
|
|
|
|
* remain functional even though something really bad is
|
|
|
|
|
|
|
|
* happening that's corrupting what was supposed to be free
|
|
|
|
|
|
|
|
* transactions.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
WARN_ONCE(1, "There should only be idle transactions in free list (idx %d op %d)\n",
|
|
|
|
|
|
|
|
xn->idx, xn->vc_op);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xn->reply = params->recv_buf;
|
|
|
|
|
|
|
|
xn->reply_sz = 0;
|
|
|
|
|
|
|
|
xn->state = params->async ? IDPF_VC_XN_ASYNC : IDPF_VC_XN_WAITING;
|
|
|
|
|
|
|
|
xn->vc_op = params->vc_op;
|
|
|
|
|
|
|
|
xn->async_handler = params->async_handler;
|
|
|
|
|
|
|
|
idpf_vc_xn_unlock(xn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!params->async)
|
|
|
|
|
|
|
|
reinit_completion(&xn->completed);
|
|
|
|
|
|
|
|
cookie = FIELD_PREP(IDPF_VC_XN_SALT_M, xn->salt) |
|
|
|
|
|
|
|
|
FIELD_PREP(IDPF_VC_XN_IDX_M, xn->idx);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
retval = idpf_send_mb_msg(adapter, params->vc_op,
|
|
|
|
|
|
|
|
send_buf->iov_len, send_buf->iov_base,
|
|
|
|
|
|
|
|
cookie);
|
|
|
|
|
|
|
|
if (retval) {
|
|
|
|
|
|
|
|
idpf_vc_xn_lock(xn);
|
|
|
|
|
|
|
|
goto release_and_unlock;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (params->async)
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wait_for_completion_timeout(&xn->completed,
|
|
|
|
|
|
|
|
msecs_to_jiffies(params->timeout_ms));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* No need to check the return value; we check the final state of the
|
|
|
|
|
|
|
|
* transaction below. It's possible the transaction actually gets more
|
|
|
|
|
|
|
|
* timeout than specified if we get preempted here but after
|
|
|
|
|
|
|
|
* wait_for_completion_timeout returns. This should be non-issue
|
|
|
|
|
|
|
|
* however.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
idpf_vc_xn_lock(xn);
|
|
|
|
|
|
|
|
switch (xn->state) {
|
|
|
|
|
|
|
|
case IDPF_VC_XN_SHUTDOWN:
|
|
|
|
|
|
|
|
retval = -ENXIO;
|
|
|
|
|
|
|
|
goto only_unlock;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_WAITING:
|
|
|
|
|
|
|
|
dev_notice_ratelimited(&adapter->pdev->dev, "Transaction timed-out (op %d, %dms)\n",
|
|
|
|
|
|
|
|
params->vc_op, params->timeout_ms);
|
|
|
|
|
|
|
|
retval = -ETIME;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_COMPLETED_SUCCESS:
|
|
|
|
|
|
|
|
retval = xn->reply_sz;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_COMPLETED_FAILED:
|
|
|
|
|
|
|
|
dev_notice_ratelimited(&adapter->pdev->dev, "Transaction failed (op %d)\n",
|
|
|
|
|
|
|
|
params->vc_op);
|
|
|
|
|
|
|
|
retval = -EIO;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
/* Invalid state. */
|
|
|
|
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
|
|
|
|
retval = -EIO;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
release_and_unlock:
|
|
|
|
|
|
|
|
idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
|
|
|
|
|
|
|
|
/* If we receive a VC reply after here, it will be dropped. */
|
|
|
|
|
|
|
|
only_unlock:
|
|
|
|
|
|
|
|
idpf_vc_xn_unlock(xn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_forward_async - Handle async reply receives
|
|
|
|
|
|
|
|
* @adapter: private data struct
|
|
|
|
|
|
|
|
* @xn: transaction to handle
|
|
|
|
|
|
|
|
* @ctlq_msg: corresponding ctlq_msg
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* For async sends we're going to lose the caller's context so, if an
|
|
|
|
|
|
|
|
* async_handler was provided, it can deal with the reply, otherwise we'll just
|
|
|
|
|
|
|
|
* check and report if there is an error.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
|
|
idpf_vc_xn_forward_async(struct idpf_adapter *adapter, struct idpf_vc_xn *xn,
|
|
|
|
|
|
|
|
const struct idpf_ctlq_msg *ctlq_msg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Async message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
|
|
|
|
|
|
|
|
ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
|
|
|
|
|
|
|
|
xn->reply_sz = 0;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
goto release_bufs;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (xn->async_handler) {
|
|
|
|
|
|
|
|
err = xn->async_handler(adapter, xn, ctlq_msg);
|
|
|
|
|
|
|
|
goto release_bufs;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctlq_msg->cookie.mbx.chnl_retval) {
|
|
|
|
|
|
|
|
xn->reply_sz = 0;
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Async message failure (op %d)\n",
|
|
|
|
|
|
|
|
ctlq_msg->cookie.mbx.chnl_opcode);
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
release_bufs:
|
|
|
|
|
|
|
|
idpf_vc_xn_push_free(adapter->vcxn_mngr, xn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* idpf_vc_xn_forward_reply - copy a reply back to receiving thread
|
|
|
|
|
|
|
|
* @adapter: driver specific private structure with vcxn_mngr
|
|
|
|
|
|
|
|
* @ctlq_msg: controlq message to send back to receiving thread
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
|
|
idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
|
|
|
|
|
|
|
|
const struct idpf_ctlq_msg *ctlq_msg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const void *payload = NULL;
|
|
|
|
|
|
|
|
size_t payload_size = 0;
|
|
|
|
|
|
|
|
struct idpf_vc_xn *xn;
|
|
|
|
|
|
|
|
u16 msg_info;
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
u16 xn_idx;
|
|
|
|
|
|
|
|
u16 salt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg_info = ctlq_msg->ctx.sw_cookie.data;
|
|
|
|
|
|
|
|
xn_idx = FIELD_GET(IDPF_VC_XN_IDX_M, msg_info);
|
|
|
|
|
|
|
|
if (xn_idx >= ARRAY_SIZE(adapter->vcxn_mngr->ring)) {
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Out of bounds cookie received: %02x\n",
|
|
|
|
|
|
|
|
xn_idx);
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
xn = &adapter->vcxn_mngr->ring[xn_idx];
|
|
|
|
|
|
|
|
salt = FIELD_GET(IDPF_VC_XN_SALT_M, msg_info);
|
|
|
|
|
|
|
|
if (xn->salt != salt) {
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Transaction salt does not match (%02x != %02x)\n",
|
|
|
|
|
|
|
|
xn->salt, salt);
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idpf_vc_xn_lock(xn);
|
|
|
|
|
|
|
|
switch (xn->state) {
|
|
|
|
|
|
|
|
case IDPF_VC_XN_WAITING:
|
|
|
|
|
|
|
|
/* success */
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_IDLE:
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Unexpected or belated VC reply (op %d)\n",
|
|
|
|
|
|
|
|
ctlq_msg->cookie.mbx.chnl_opcode);
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_SHUTDOWN:
|
|
|
|
|
|
|
|
/* ENXIO is a bit special here as the recv msg loop uses that
|
|
|
|
|
|
|
|
* know if it should stop trying to clean the ring if we lost
|
|
|
|
|
|
|
|
* the virtchnl. We need to stop playing with registers and
|
|
|
|
|
|
|
|
* yield.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
err = -ENXIO;
|
|
|
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
case IDPF_VC_XN_ASYNC:
|
|
|
|
|
|
|
|
err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
|
|
|
|
|
|
|
|
idpf_vc_xn_unlock(xn);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Overwriting VC reply (op %d)\n",
|
|
|
|
|
|
|
|
ctlq_msg->cookie.mbx.chnl_opcode);
|
|
|
|
|
|
|
|
err = -EBUSY;
|
|
|
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctlq_msg->cookie.mbx.chnl_opcode != xn->vc_op) {
|
|
|
|
|
|
|
|
dev_err_ratelimited(&adapter->pdev->dev, "Message opcode does not match transaction opcode (msg: %d) (xn: %d)\n",
|
|
|
|
|
|
|
|
ctlq_msg->cookie.mbx.chnl_opcode, xn->vc_op);
|
|
|
|
|
|
|
|
xn->reply_sz = 0;
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_COMPLETED_FAILED;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctlq_msg->cookie.mbx.chnl_retval) {
|
|
|
|
|
|
|
|
xn->reply_sz = 0;
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_COMPLETED_FAILED;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ctlq_msg->data_len) {
|
|
|
|
|
|
|
|
payload = ctlq_msg->ctx.indirect.payload->va;
|
|
|
|
|
|
|
|
payload_size = ctlq_msg->ctx.indirect.payload->size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xn->reply_sz = payload_size;
|
|
|
|
|
|
|
|
xn->state = IDPF_VC_XN_COMPLETED_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (xn->reply.iov_base && xn->reply.iov_len && payload_size)
|
|
|
|
|
|
|
|
memcpy(xn->reply.iov_base, payload,
|
|
|
|
|
|
|
|
min_t(size_t, xn->reply.iov_len, payload_size));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
|
|
|
|
idpf_vc_xn_unlock(xn);
|
|
|
|
|
|
|
|
/* we _cannot_ hold lock while calling complete */
|
|
|
|
|
|
|
|
complete(&xn->completed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* idpf_recv_mb_msg - Receive message over mailbox
|
|
|
|
* idpf_recv_mb_msg - Receive message over mailbox
|
|
|
|
* @adapter: Driver specific private structure
|
|
|
|
* @adapter: Driver specific private structure
|
|
|
|
@@ -430,6 +903,8 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op,
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
switch (ctlq_msg.cookie.mbx.chnl_opcode) {
|
|
|
|
switch (ctlq_msg.cookie.mbx.chnl_opcode) {
|
|
|
|
case VIRTCHNL2_OP_VERSION:
|
|
|
|
case VIRTCHNL2_OP_VERSION:
|
|
|
|
|
|
|
|
err = idpf_vc_xn_forward_reply(adapter, &ctlq_msg);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case VIRTCHNL2_OP_GET_CAPS:
|
|
|
|
case VIRTCHNL2_OP_GET_CAPS:
|
|
|
|
if (ctlq_msg.cookie.mbx.chnl_retval) {
|
|
|
|
if (ctlq_msg.cookie.mbx.chnl_retval) {
|
|
|
|
dev_err(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n",
|
|
|
|
dev_err(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n",
|
|
|
|
@@ -786,7 +1261,11 @@ static int idpf_wait_for_marker_event(struct idpf_vport *vport)
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static int idpf_send_ver_msg(struct idpf_adapter *adapter)
|
|
|
|
static int idpf_send_ver_msg(struct idpf_adapter *adapter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
struct idpf_vc_xn_params xn_params = {};
|
|
|
|
struct virtchnl2_version_info vvi;
|
|
|
|
struct virtchnl2_version_info vvi;
|
|
|
|
|
|
|
|
ssize_t reply_sz;
|
|
|
|
|
|
|
|
u32 major, minor;
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (adapter->virt_ver_maj) {
|
|
|
|
if (adapter->virt_ver_maj) {
|
|
|
|
vvi.major = cpu_to_le32(adapter->virt_ver_maj);
|
|
|
|
vvi.major = cpu_to_le32(adapter->virt_ver_maj);
|
|
|
|
@@ -796,43 +1275,29 @@ static int idpf_send_ver_msg(struct idpf_adapter *adapter)
|
|
|
|
vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
|
|
|
|
vvi.minor = cpu_to_le32(IDPF_VIRTCHNL_VERSION_MINOR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_VERSION, sizeof(vvi),
|
|
|
|
xn_params.vc_op = VIRTCHNL2_OP_VERSION;
|
|
|
|
(u8 *)&vvi);
|
|
|
|
xn_params.send_buf.iov_base = &vvi;
|
|
|
|
}
|
|
|
|
xn_params.send_buf.iov_len = sizeof(vvi);
|
|
|
|
|
|
|
|
xn_params.recv_buf = xn_params.send_buf;
|
|
|
|
|
|
|
|
xn_params.timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
|
|
|
|
* idpf_recv_ver_msg - Receive virtchnl version message
|
|
|
|
if (reply_sz < 0)
|
|
|
|
* @adapter: Driver specific private structure
|
|
|
|
return reply_sz;
|
|
|
|
*
|
|
|
|
if (reply_sz < sizeof(vvi))
|
|
|
|
* Receive virtchnl version message. Returns 0 on success, -EAGAIN if we need
|
|
|
|
return -EIO;
|
|
|
|
* to send version message again, otherwise negative on failure.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int idpf_recv_ver_msg(struct idpf_adapter *adapter)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct virtchnl2_version_info vvi;
|
|
|
|
|
|
|
|
u32 major, minor;
|
|
|
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_recv_mb_msg(adapter, VIRTCHNL2_OP_VERSION, &vvi,
|
|
|
|
|
|
|
|
sizeof(vvi));
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
major = le32_to_cpu(vvi.major);
|
|
|
|
major = le32_to_cpu(vvi.major);
|
|
|
|
minor = le32_to_cpu(vvi.minor);
|
|
|
|
minor = le32_to_cpu(vvi.minor);
|
|
|
|
|
|
|
|
|
|
|
|
if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
|
|
|
|
if (major > IDPF_VIRTCHNL_VERSION_MAJOR) {
|
|
|
|
dev_warn(&adapter->pdev->dev,
|
|
|
|
dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");
|
|
|
|
"Virtchnl major version (%d) greater than supported\n",
|
|
|
|
|
|
|
|
major);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
|
|
|
|
if (major == IDPF_VIRTCHNL_VERSION_MAJOR &&
|
|
|
|
minor > IDPF_VIRTCHNL_VERSION_MINOR)
|
|
|
|
minor > IDPF_VIRTCHNL_VERSION_MINOR)
|
|
|
|
dev_warn(&adapter->pdev->dev,
|
|
|
|
dev_warn(&adapter->pdev->dev, "Virtchnl minor version didn't match\n");
|
|
|
|
"Virtchnl minor version (%d) didn't match\n", minor);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If we have a mismatch, resend version to update receiver on what
|
|
|
|
/* If we have a mismatch, resend version to update receiver on what
|
|
|
|
* version we will use.
|
|
|
|
* version we will use.
|
|
|
|
@@ -915,7 +1380,7 @@ static int idpf_send_get_caps_msg(struct idpf_adapter *adapter)
|
|
|
|
VIRTCHNL2_CAP_LOOPBACK);
|
|
|
|
VIRTCHNL2_CAP_LOOPBACK);
|
|
|
|
|
|
|
|
|
|
|
|
return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps),
|
|
|
|
return idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps),
|
|
|
|
(u8 *)&caps);
|
|
|
|
(u8 *)&caps, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@@ -1290,7 +1755,7 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CREATE_VPORT, buf_size,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CREATE_VPORT, buf_size,
|
|
|
|
(u8 *)vport_msg);
|
|
|
|
(u8 *)vport_msg, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1376,7 +1841,7 @@ int idpf_send_destroy_vport_msg(struct idpf_vport *vport)
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DESTROY_VPORT,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DESTROY_VPORT,
|
|
|
|
sizeof(v_id), (u8 *)&v_id);
|
|
|
|
sizeof(v_id), (u8 *)&v_id, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1407,7 +1872,7 @@ int idpf_send_enable_vport_msg(struct idpf_vport *vport)
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ENABLE_VPORT,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ENABLE_VPORT,
|
|
|
|
sizeof(v_id), (u8 *)&v_id);
|
|
|
|
sizeof(v_id), (u8 *)&v_id, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1438,7 +1903,7 @@ int idpf_send_disable_vport_msg(struct idpf_vport *vport)
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DISABLE_VPORT,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DISABLE_VPORT,
|
|
|
|
sizeof(v_id), (u8 *)&v_id);
|
|
|
|
sizeof(v_id), (u8 *)&v_id, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1557,7 +2022,7 @@ static int idpf_send_config_tx_queues_msg(struct idpf_vport *vport)
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(vport->adapter,
|
|
|
|
err = idpf_send_mb_msg(vport->adapter,
|
|
|
|
VIRTCHNL2_OP_CONFIG_TX_QUEUES,
|
|
|
|
VIRTCHNL2_OP_CONFIG_TX_QUEUES,
|
|
|
|
buf_sz, (u8 *)ctq);
|
|
|
|
buf_sz, (u8 *)ctq, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto mbx_error;
|
|
|
|
goto mbx_error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1709,7 +2174,7 @@ common_qi_fields:
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(vport->adapter,
|
|
|
|
err = idpf_send_mb_msg(vport->adapter,
|
|
|
|
VIRTCHNL2_OP_CONFIG_RX_QUEUES,
|
|
|
|
VIRTCHNL2_OP_CONFIG_RX_QUEUES,
|
|
|
|
buf_sz, (u8 *)crq);
|
|
|
|
buf_sz, (u8 *)crq, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto mbx_error;
|
|
|
|
goto mbx_error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1876,7 +2341,7 @@ send_msg:
|
|
|
|
qcs = &eq->chunks;
|
|
|
|
qcs = &eq->chunks;
|
|
|
|
memcpy(qcs->chunks, &qc[k], chunk_sz * num_chunks);
|
|
|
|
memcpy(qcs->chunks, &qc[k], chunk_sz * num_chunks);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, vc_op, buf_sz, (u8 *)eq);
|
|
|
|
err = idpf_send_mb_msg(adapter, vc_op, buf_sz, (u8 *)eq, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto mbx_error;
|
|
|
|
goto mbx_error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2020,7 +2485,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map)
|
|
|
|
if (map) {
|
|
|
|
if (map) {
|
|
|
|
err = idpf_send_mb_msg(adapter,
|
|
|
|
err = idpf_send_mb_msg(adapter,
|
|
|
|
VIRTCHNL2_OP_MAP_QUEUE_VECTOR,
|
|
|
|
VIRTCHNL2_OP_MAP_QUEUE_VECTOR,
|
|
|
|
buf_sz, (u8 *)vqvm);
|
|
|
|
buf_sz, (u8 *)vqvm, 0);
|
|
|
|
if (!err)
|
|
|
|
if (!err)
|
|
|
|
err = idpf_wait_for_event(adapter, vport,
|
|
|
|
err = idpf_wait_for_event(adapter, vport,
|
|
|
|
IDPF_VC_MAP_IRQ,
|
|
|
|
IDPF_VC_MAP_IRQ,
|
|
|
|
@@ -2028,7 +2493,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
err = idpf_send_mb_msg(adapter,
|
|
|
|
err = idpf_send_mb_msg(adapter,
|
|
|
|
VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR,
|
|
|
|
VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR,
|
|
|
|
buf_sz, (u8 *)vqvm);
|
|
|
|
buf_sz, (u8 *)vqvm, 0);
|
|
|
|
if (!err)
|
|
|
|
if (!err)
|
|
|
|
err =
|
|
|
|
err =
|
|
|
|
idpf_min_wait_for_event(adapter, vport,
|
|
|
|
idpf_min_wait_for_event(adapter, vport,
|
|
|
|
@@ -2158,7 +2623,7 @@ int idpf_send_delete_queues_msg(struct idpf_vport *vport)
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEL_QUEUES,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEL_QUEUES,
|
|
|
|
buf_size, (u8 *)eq);
|
|
|
|
buf_size, (u8 *)eq, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2222,7 +2687,7 @@ int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q,
|
|
|
|
mutex_lock(&((struct idpf_vport *)vport)->vc_buf_lock);
|
|
|
|
mutex_lock(&((struct idpf_vport *)vport)->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ADD_QUEUES,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ADD_QUEUES,
|
|
|
|
sizeof(struct virtchnl2_add_queues), (u8 *)&aq);
|
|
|
|
sizeof(struct virtchnl2_add_queues), (u8 *)&aq, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2281,7 +2746,7 @@ int idpf_send_alloc_vectors_msg(struct idpf_adapter *adapter, u16 num_vectors)
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ALLOC_VECTORS,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_ALLOC_VECTORS,
|
|
|
|
sizeof(ac), (u8 *)&ac);
|
|
|
|
sizeof(ac), (u8 *)&ac, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2337,7 +2802,7 @@ int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter)
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEALLOC_VECTORS, buf_size,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_DEALLOC_VECTORS, buf_size,
|
|
|
|
(u8 *)vcs);
|
|
|
|
(u8 *)vcs, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2383,7 +2848,7 @@ int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs)
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
mutex_lock(&adapter->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_SRIOV_VFS,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_SRIOV_VFS,
|
|
|
|
sizeof(svi), (u8 *)&svi);
|
|
|
|
sizeof(svi), (u8 *)&svi, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2421,7 +2886,7 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport)
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_STATS,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_STATS,
|
|
|
|
sizeof(struct virtchnl2_vport_stats),
|
|
|
|
sizeof(struct virtchnl2_vport_stats),
|
|
|
|
(u8 *)&stats_msg);
|
|
|
|
(u8 *)&stats_msg, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2490,7 +2955,7 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
|
|
|
|
rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]);
|
|
|
|
rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_LUT,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_LUT,
|
|
|
|
buf_size, (u8 *)rl);
|
|
|
|
buf_size, (u8 *)rl, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto free_mem;
|
|
|
|
goto free_mem;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2501,7 +2966,7 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_LUT,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_LUT,
|
|
|
|
buf_size, (u8 *)rl);
|
|
|
|
buf_size, (u8 *)rl, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto free_mem;
|
|
|
|
goto free_mem;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2560,7 +3025,7 @@ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get)
|
|
|
|
|
|
|
|
|
|
|
|
if (get) {
|
|
|
|
if (get) {
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_KEY,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_RSS_KEY,
|
|
|
|
buf_size, (u8 *)rk);
|
|
|
|
buf_size, (u8 *)rk, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2592,7 +3057,7 @@ int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get)
|
|
|
|
rk->key_flex[i] = rss_data->rss_key[i];
|
|
|
|
rk->key_flex[i] = rss_data->rss_key[i];
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_KEY,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_RSS_KEY,
|
|
|
|
buf_size, (u8 *)rk);
|
|
|
|
buf_size, (u8 *)rk, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2689,7 +3154,7 @@ int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport)
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_PTYPE_INFO,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_PTYPE_INFO,
|
|
|
|
sizeof(struct virtchnl2_get_ptype_info),
|
|
|
|
sizeof(struct virtchnl2_get_ptype_info),
|
|
|
|
(u8 *)&get_ptype_info);
|
|
|
|
(u8 *)&get_ptype_info, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto vc_buf_unlock;
|
|
|
|
goto vc_buf_unlock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2883,7 +3348,7 @@ int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport)
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
mutex_lock(&vport->vc_buf_lock);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_LOOPBACK,
|
|
|
|
err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_LOOPBACK,
|
|
|
|
sizeof(loopback), (u8 *)&loopback);
|
|
|
|
sizeof(loopback), (u8 *)&loopback, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto rel_lock;
|
|
|
|
goto rel_lock;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2959,7 +3424,7 @@ int idpf_init_dflt_mbx(struct idpf_adapter *adapter)
|
|
|
|
return -ENOENT;
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
adapter->state = __IDPF_STARTUP;
|
|
|
|
adapter->state = __IDPF_VER_CHECK;
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -3056,27 +3521,35 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
|
|
|
|
u16 num_max_vports;
|
|
|
|
u16 num_max_vports;
|
|
|
|
int err = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!adapter->vcxn_mngr) {
|
|
|
|
|
|
|
|
adapter->vcxn_mngr = kzalloc(sizeof(*adapter->vcxn_mngr), GFP_KERNEL);
|
|
|
|
|
|
|
|
if (!adapter->vcxn_mngr) {
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
|
|
|
goto init_failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
idpf_vc_xn_init(adapter->vcxn_mngr);
|
|
|
|
|
|
|
|
|
|
|
|
while (adapter->state != __IDPF_INIT_SW) {
|
|
|
|
while (adapter->state != __IDPF_INIT_SW) {
|
|
|
|
switch (adapter->state) {
|
|
|
|
switch (adapter->state) {
|
|
|
|
case __IDPF_STARTUP:
|
|
|
|
|
|
|
|
if (idpf_send_ver_msg(adapter))
|
|
|
|
|
|
|
|
goto init_failed;
|
|
|
|
|
|
|
|
adapter->state = __IDPF_VER_CHECK;
|
|
|
|
|
|
|
|
goto restart;
|
|
|
|
|
|
|
|
case __IDPF_VER_CHECK:
|
|
|
|
case __IDPF_VER_CHECK:
|
|
|
|
err = idpf_recv_ver_msg(adapter);
|
|
|
|
err = idpf_send_ver_msg(adapter);
|
|
|
|
if (err == -EIO) {
|
|
|
|
switch (err) {
|
|
|
|
return err;
|
|
|
|
case 0:
|
|
|
|
} else if (err == -EAGAIN) {
|
|
|
|
/* success, move state machine forward */
|
|
|
|
adapter->state = __IDPF_STARTUP;
|
|
|
|
adapter->state = __IDPF_GET_CAPS;
|
|
|
|
|
|
|
|
err = idpf_send_get_caps_msg(adapter);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
|
|
|
goto init_failed;
|
|
|
|
|
|
|
|
fallthrough;
|
|
|
|
|
|
|
|
case -EAGAIN:
|
|
|
|
goto restart;
|
|
|
|
goto restart;
|
|
|
|
} else if (err) {
|
|
|
|
default:
|
|
|
|
|
|
|
|
/* Something bad happened, try again but only a
|
|
|
|
|
|
|
|
* few times.
|
|
|
|
|
|
|
|
*/
|
|
|
|
goto init_failed;
|
|
|
|
goto init_failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (idpf_send_get_caps_msg(adapter))
|
|
|
|
|
|
|
|
goto init_failed;
|
|
|
|
|
|
|
|
adapter->state = __IDPF_GET_CAPS;
|
|
|
|
|
|
|
|
goto restart;
|
|
|
|
|
|
|
|
case __IDPF_GET_CAPS:
|
|
|
|
case __IDPF_GET_CAPS:
|
|
|
|
if (idpf_recv_get_caps_msg(adapter))
|
|
|
|
if (idpf_recv_get_caps_msg(adapter))
|
|
|
|
goto init_failed;
|
|
|
|
goto init_failed;
|
|
|
|
@@ -3169,7 +3642,9 @@ init_failed:
|
|
|
|
* register writes might not have taken effect. Retry to initialize
|
|
|
|
* register writes might not have taken effect. Retry to initialize
|
|
|
|
* the mailbox again
|
|
|
|
* the mailbox again
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
adapter->state = __IDPF_STARTUP;
|
|
|
|
adapter->state = __IDPF_VER_CHECK;
|
|
|
|
|
|
|
|
if (adapter->vcxn_mngr)
|
|
|
|
|
|
|
|
idpf_vc_xn_shutdown(adapter->vcxn_mngr);
|
|
|
|
idpf_deinit_dflt_mbx(adapter);
|
|
|
|
idpf_deinit_dflt_mbx(adapter);
|
|
|
|
set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
|
|
|
|
set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
|
|
|
|
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
|
|
|
|
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
|
|
|
|
@@ -3187,6 +3662,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
idpf_vc_xn_shutdown(adapter->vcxn_mngr);
|
|
|
|
idpf_deinit_task(adapter);
|
|
|
|
idpf_deinit_task(adapter);
|
|
|
|
idpf_intr_rel(adapter);
|
|
|
|
idpf_intr_rel(adapter);
|
|
|
|
/* Set all bits as we dont know on which vc_state the vhnl_wq is
|
|
|
|
/* Set all bits as we dont know on which vc_state the vhnl_wq is
|
|
|
|
@@ -3740,7 +4216,7 @@ int idpf_add_del_mac_filters(struct idpf_vport *vport,
|
|
|
|
if (async)
|
|
|
|
if (async)
|
|
|
|
set_bit(mac_flag, vport_config->flags);
|
|
|
|
set_bit(mac_flag, vport_config->flags);
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, vop, buf_size, (u8 *)ma_list);
|
|
|
|
err = idpf_send_mb_msg(adapter, vop, buf_size, (u8 *)ma_list, 0);
|
|
|
|
if (err)
|
|
|
|
if (err)
|
|
|
|
goto mbx_error;
|
|
|
|
goto mbx_error;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -3795,7 +4271,7 @@ int idpf_set_promiscuous(struct idpf_adapter *adapter,
|
|
|
|
|
|
|
|
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE,
|
|
|
|
err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE,
|
|
|
|
sizeof(struct virtchnl2_promisc_info),
|
|
|
|
sizeof(struct virtchnl2_promisc_info),
|
|
|
|
(u8 *)&vpi);
|
|
|
|
(u8 *)&vpi, 0);
|
|
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|