ionic: Add adminq action
Add AdminQ specific message requests and completion handling. Signed-off-by: Shannon Nelson <snelson@pensando.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1d062b7b6f
commit
938962d552
|
@ -44,9 +44,16 @@ struct ionic {
|
||||||
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
|
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ionic_admin_ctx {
|
||||||
|
struct completion work;
|
||||||
|
union ionic_adminq_cmd cmd;
|
||||||
|
union ionic_adminq_comp comp;
|
||||||
|
};
|
||||||
|
|
||||||
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
|
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
|
||||||
ionic_cq_done_cb done_cb, void *done_arg);
|
ionic_cq_done_cb done_cb, void *done_arg);
|
||||||
|
|
||||||
|
int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
|
||||||
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
|
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
|
||||||
int ionic_set_dma_mask(struct ionic *ionic);
|
int ionic_set_dma_mask(struct ionic *ionic);
|
||||||
int ionic_setup(struct ionic *ionic);
|
int ionic_setup(struct ionic *ionic);
|
||||||
|
|
|
@ -169,6 +169,117 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ionic_adminq_flush(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
struct ionic_queue *adminq = &lif->adminqcq->q;
|
||||||
|
|
||||||
|
spin_lock(&lif->adminq_lock);
|
||||||
|
|
||||||
|
while (adminq->tail != adminq->head) {
|
||||||
|
memset(adminq->tail->desc, 0, sizeof(union ionic_adminq_cmd));
|
||||||
|
adminq->tail->cb = NULL;
|
||||||
|
adminq->tail->cb_arg = NULL;
|
||||||
|
adminq->tail = adminq->tail->next;
|
||||||
|
}
|
||||||
|
spin_unlock(&lif->adminq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ionic_adminq_check_err(struct ionic_lif *lif,
|
||||||
|
struct ionic_admin_ctx *ctx,
|
||||||
|
bool timeout)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = lif->netdev;
|
||||||
|
const char *opcode_str;
|
||||||
|
const char *status_str;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (ctx->comp.comp.status || timeout) {
|
||||||
|
opcode_str = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
|
||||||
|
status_str = ionic_error_to_str(ctx->comp.comp.status);
|
||||||
|
err = timeout ? -ETIMEDOUT :
|
||||||
|
ionic_error_to_errno(ctx->comp.comp.status);
|
||||||
|
|
||||||
|
netdev_err(netdev, "%s (%d) failed: %s (%d)\n",
|
||||||
|
opcode_str, ctx->cmd.cmd.opcode,
|
||||||
|
timeout ? "TIMEOUT" : status_str, err);
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
ionic_adminq_flush(lif);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ionic_adminq_cb(struct ionic_queue *q,
|
||||||
|
struct ionic_desc_info *desc_info,
|
||||||
|
struct ionic_cq_info *cq_info, void *cb_arg)
|
||||||
|
{
|
||||||
|
struct ionic_admin_ctx *ctx = cb_arg;
|
||||||
|
struct ionic_admin_comp *comp;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
comp = cq_info->cq_desc;
|
||||||
|
dev = &q->lif->netdev->dev;
|
||||||
|
|
||||||
|
memcpy(&ctx->comp, comp, sizeof(*comp));
|
||||||
|
|
||||||
|
dev_dbg(dev, "comp admin queue command:\n");
|
||||||
|
dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||||
|
&ctx->comp, sizeof(ctx->comp), true);
|
||||||
|
|
||||||
|
complete_all(&ctx->work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct ionic_queue *adminq = &lif->adminqcq->q;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
WARN_ON(in_interrupt());
|
||||||
|
|
||||||
|
spin_lock(&lif->adminq_lock);
|
||||||
|
if (!ionic_q_has_space(adminq, 1)) {
|
||||||
|
err = -ENOSPC;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(adminq->head->desc, &ctx->cmd, sizeof(ctx->cmd));
|
||||||
|
|
||||||
|
dev_dbg(&lif->netdev->dev, "post admin queue command:\n");
|
||||||
|
dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||||
|
&ctx->cmd, sizeof(ctx->cmd), true);
|
||||||
|
|
||||||
|
ionic_q_post(adminq, true, ionic_adminq_cb, ctx);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
spin_unlock(&lif->adminq_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = lif->netdev;
|
||||||
|
unsigned long remaining;
|
||||||
|
const char *name;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = ionic_adminq_post(lif, ctx);
|
||||||
|
if (err) {
|
||||||
|
name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
|
||||||
|
netdev_err(netdev, "Posting of %s (%d) failed: %d\n",
|
||||||
|
name, ctx->cmd.cmd.opcode, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining = wait_for_completion_timeout(&ctx->work,
|
||||||
|
HZ * (ulong)DEVCMD_TIMEOUT);
|
||||||
|
return ionic_adminq_check_err(lif, ctx, (remaining == 0));
|
||||||
|
}
|
||||||
|
|
||||||
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
|
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
|
||||||
ionic_cq_done_cb done_cb, void *done_arg)
|
ionic_cq_done_cb done_cb, void *done_arg)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue