Merge branch 'ionic-error-recovery-fixes'

Shannon Nelson says:

====================
ionic error recovery fixes

These are a few little patches to make error recovery a little
more safe and successful.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-03-21 19:56:04 -07:00
commit 26922c0ef3
3 changed files with 50 additions and 22 deletions

View File

@ -228,7 +228,13 @@ DEFINE_SHOW_ATTRIBUTE(netdev);
void ionic_debugfs_add_lif(struct ionic_lif *lif) void ionic_debugfs_add_lif(struct ionic_lif *lif)
{ {
lif->dentry = debugfs_create_dir(lif->name, lif->ionic->dentry); struct dentry *lif_dentry;
lif_dentry = debugfs_create_dir(lif->name, lif->ionic->dentry);
if (IS_ERR_OR_NULL(lif_dentry))
return;
lif->dentry = lif_dentry;
debugfs_create_file("netdev", 0400, lif->dentry, debugfs_create_file("netdev", 0400, lif->dentry,
lif->netdev, &netdev_fops); lif->netdev, &netdev_fops);
} }

View File

@ -275,8 +275,10 @@ static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
if (qcq->flags & IONIC_QCQ_F_INTR) { if (qcq->flags & IONIC_QCQ_F_INTR) {
ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
IONIC_INTR_MASK_SET); IONIC_INTR_MASK_SET);
irq_set_affinity_hint(qcq->intr.vector, NULL);
devm_free_irq(dev, qcq->intr.vector, &qcq->napi); devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
netif_napi_del(&qcq->napi); netif_napi_del(&qcq->napi);
qcq->intr.vector = 0;
} }
qcq->flags &= ~IONIC_QCQ_F_INITED; qcq->flags &= ~IONIC_QCQ_F_INITED;
@ -318,19 +320,21 @@ static void ionic_qcqs_free(struct ionic_lif *lif)
lif->adminqcq = NULL; lif->adminqcq = NULL;
} }
for (i = 0; i < lif->nxqs; i++) if (lif->rxqcqs) {
if (lif->rxqcqs[i].stats) for (i = 0; i < lif->nxqs; i++)
devm_kfree(dev, lif->rxqcqs[i].stats); if (lif->rxqcqs[i].stats)
devm_kfree(dev, lif->rxqcqs[i].stats);
devm_kfree(dev, lif->rxqcqs);
lif->rxqcqs = NULL;
}
devm_kfree(dev, lif->rxqcqs); if (lif->txqcqs) {
lif->rxqcqs = NULL; for (i = 0; i < lif->nxqs; i++)
if (lif->txqcqs[i].stats)
for (i = 0; i < lif->nxqs; i++) devm_kfree(dev, lif->txqcqs[i].stats);
if (lif->txqcqs[i].stats) devm_kfree(dev, lif->txqcqs);
devm_kfree(dev, lif->txqcqs[i].stats); lif->txqcqs = NULL;
}
devm_kfree(dev, lif->txqcqs);
lif->txqcqs = NULL;
} }
static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq, static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
@ -832,7 +836,7 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN); memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
if (err) if (err && err != -EEXIST)
return err; return err;
return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx); return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
@ -862,7 +866,7 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
spin_unlock_bh(&lif->rx_filters.lock); spin_unlock_bh(&lif->rx_filters.lock);
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
if (err) if (err && err != -EEXIST)
return err; return err;
netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr, netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr,
@ -1425,10 +1429,15 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif)
static void ionic_txrx_disable(struct ionic_lif *lif) static void ionic_txrx_disable(struct ionic_lif *lif)
{ {
unsigned int i; unsigned int i;
int err;
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++) {
ionic_qcq_disable(lif->txqcqs[i].qcq); err = ionic_qcq_disable(lif->txqcqs[i].qcq);
ionic_qcq_disable(lif->rxqcqs[i].qcq); if (err == -ETIMEDOUT)
break;
err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
if (err == -ETIMEDOUT)
break;
} }
} }
@ -1552,7 +1561,8 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
ionic_rx_fill(&lif->rxqcqs[i].qcq->q); ionic_rx_fill(&lif->rxqcqs[i].qcq->q);
err = ionic_qcq_enable(lif->rxqcqs[i].qcq); err = ionic_qcq_enable(lif->rxqcqs[i].qcq);
if (err) { if (err) {
ionic_qcq_disable(lif->txqcqs[i].qcq); if (err != -ETIMEDOUT)
ionic_qcq_disable(lif->txqcqs[i].qcq);
goto err_out; goto err_out;
} }
} }
@ -1561,8 +1571,12 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
err_out: err_out:
while (i--) { while (i--) {
ionic_qcq_disable(lif->rxqcqs[i].qcq); err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
ionic_qcq_disable(lif->txqcqs[i].qcq); if (err == -ETIMEDOUT)
break;
err = ionic_qcq_disable(lif->txqcqs[i].qcq);
if (err == -ETIMEDOUT)
break;
} }
return err; return err;

View File

@ -243,11 +243,16 @@ static void ionic_adminq_cb(struct ionic_queue *q,
static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
{ {
struct ionic_queue *adminq = &lif->adminqcq->q; struct ionic_queue *adminq;
int err = 0; int err = 0;
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
if (!lif->adminqcq)
return -EIO;
adminq = &lif->adminqcq->q;
spin_lock(&lif->adminq_lock); spin_lock(&lif->adminq_lock);
if (!ionic_q_has_space(adminq, 1)) { if (!ionic_q_has_space(adminq, 1)) {
err = -ENOSPC; err = -ENOSPC;
@ -360,7 +365,10 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds)
done, duration / HZ, duration); done, duration / HZ, duration);
if (!done && hb) { if (!done && hb) {
ionic_dev_cmd_clean(ionic); /* It is possible (but unlikely) that FW was busy and missed a
* heartbeat check but is still alive and will process this
* request, so don't clean the dev_cmd in this case.
*/
dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n", dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n",
ionic_opcode_to_str(opcode), opcode); ionic_opcode_to_str(opcode), opcode);
return -ENXIO; return -ENXIO;