Commit 49d3b493 authored by Shannon Nelson's avatar Shannon Nelson Committed by David S. Miller

ionic: disable the queues on link down

When the link goes down, we need to disable the queues on the
NIC in addition to stopping the netdev stack.  This lets the
FW know that the driver has stopped queue activity, and then
the FW can do internal reconfiguration work, whether actually
Link related, or for other internal FW needs.  To do this,
we pull out the queue enable and disable from ionic_open()
and ionic_stop() so they can be used by other routines.

To help keep things sane, we swap the queue enables so that
the rx queue and its napi are enabled before the tx queue
which rides on the rx queues napi.

We also drop the ionic_lif_quiesce() as it doesn't do anything
more than what the queue disable has already taken care of.
Signed-off-by: default avatarShannon Nelson <snelson@pensando.io>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d5eddde5
...@@ -22,6 +22,9 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr); ...@@ -22,6 +22,9 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr); static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
static void ionic_link_status_check(struct ionic_lif *lif); static void ionic_link_status_check(struct ionic_lif *lif);
static int ionic_start_queues(struct ionic_lif *lif);
static void ionic_stop_queues(struct ionic_lif *lif);
static void ionic_lif_deferred_work(struct work_struct *work) static void ionic_lif_deferred_work(struct work_struct *work)
{ {
struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work); struct ionic_lif *lif = container_of(work, struct ionic_lif, deferred.work);
...@@ -73,6 +76,9 @@ static void ionic_link_status_check(struct ionic_lif *lif) ...@@ -73,6 +76,9 @@ static void ionic_link_status_check(struct ionic_lif *lif)
u16 link_status; u16 link_status;
bool link_up; bool link_up;
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
return;
if (lif->ionic->is_mgmt_nic) if (lif->ionic->is_mgmt_nic)
return; return;
...@@ -90,16 +96,16 @@ static void ionic_link_status_check(struct ionic_lif *lif) ...@@ -90,16 +96,16 @@ static void ionic_link_status_check(struct ionic_lif *lif)
netif_carrier_on(netdev); netif_carrier_on(netdev);
} }
if (test_bit(IONIC_LIF_F_UP, lif->state)) if (netif_running(lif->netdev))
netif_tx_wake_all_queues(lif->netdev); ionic_start_queues(lif);
} else { } else {
if (netif_carrier_ok(netdev)) { if (netif_carrier_ok(netdev)) {
netdev_info(netdev, "Link down\n"); netdev_info(netdev, "Link down\n");
netif_carrier_off(netdev); netif_carrier_off(netdev);
} }
if (test_bit(IONIC_LIF_F_UP, lif->state)) if (netif_running(lif->netdev))
netif_tx_stop_all_queues(netdev); ionic_stop_queues(lif);
} }
clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state); clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
...@@ -248,21 +254,6 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq) ...@@ -248,21 +254,6 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq)
return ionic_adminq_post_wait(lif, &ctx); return ionic_adminq_post_wait(lif, &ctx);
} }
static void ionic_lif_quiesce(struct ionic_lif *lif)
{
struct ionic_admin_ctx ctx = {
.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
.cmd.lif_setattr = {
.opcode = IONIC_CMD_LIF_SETATTR,
.attr = IONIC_LIF_ATTR_STATE,
.index = lif->index,
.state = IONIC_LIF_DISABLE
},
};
ionic_adminq_post_wait(lif, &ctx);
}
static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq) static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
{ {
struct ionic_dev *idev = &lif->ionic->idev; struct ionic_dev *idev = &lif->ionic->idev;
...@@ -615,6 +606,10 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) ...@@ -615,6 +606,10 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base); dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size); dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
q->tail = q->info;
q->head = q->tail;
cq->tail = cq->info;
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
if (err) if (err)
return err; return err;
...@@ -660,6 +655,10 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) ...@@ -660,6 +655,10 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base); dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size); dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
q->tail = q->info;
q->head = q->tail;
cq->tail = cq->info;
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
if (err) if (err)
return err; return err;
...@@ -1473,6 +1472,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif) ...@@ -1473,6 +1472,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif)
ionic_rx_empty(&lif->rxqcqs[i].qcq->q); ionic_rx_empty(&lif->rxqcqs[i].qcq->q);
} }
} }
lif->rx_mode = 0;
} }
static void ionic_txrx_free(struct ionic_lif *lif) static void ionic_txrx_free(struct ionic_lif *lif)
...@@ -1582,15 +1582,15 @@ static int ionic_txrx_enable(struct ionic_lif *lif) ...@@ -1582,15 +1582,15 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
int i, err; int i, err;
for (i = 0; i < lif->nxqs; i++) { for (i = 0; i < lif->nxqs; i++) {
err = ionic_qcq_enable(lif->txqcqs[i].qcq); ionic_rx_fill(&lif->rxqcqs[i].qcq->q);
err = ionic_qcq_enable(lif->rxqcqs[i].qcq);
if (err) if (err)
goto err_out; goto err_out;
ionic_rx_fill(&lif->rxqcqs[i].qcq->q); err = ionic_qcq_enable(lif->txqcqs[i].qcq);
err = ionic_qcq_enable(lif->rxqcqs[i].qcq);
if (err) { if (err) {
if (err != -ETIMEDOUT) if (err != -ETIMEDOUT)
ionic_qcq_disable(lif->txqcqs[i].qcq); ionic_qcq_disable(lif->rxqcqs[i].qcq);
goto err_out; goto err_out;
} }
} }
...@@ -1599,10 +1599,10 @@ static int ionic_txrx_enable(struct ionic_lif *lif) ...@@ -1599,10 +1599,10 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
err_out: err_out:
while (i--) { while (i--) {
err = ionic_qcq_disable(lif->rxqcqs[i].qcq); err = ionic_qcq_disable(lif->txqcqs[i].qcq);
if (err == -ETIMEDOUT) if (err == -ETIMEDOUT)
break; break;
err = ionic_qcq_disable(lif->txqcqs[i].qcq); err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
if (err == -ETIMEDOUT) if (err == -ETIMEDOUT)
break; break;
} }
...@@ -1610,6 +1610,23 @@ static int ionic_txrx_enable(struct ionic_lif *lif) ...@@ -1610,6 +1610,23 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
return err; return err;
} }
static int ionic_start_queues(struct ionic_lif *lif)
{
int err;
if (test_and_set_bit(IONIC_LIF_F_UP, lif->state))
return 0;
err = ionic_txrx_enable(lif);
if (err) {
clear_bit(IONIC_LIF_F_UP, lif->state);
return err;
}
netif_tx_wake_all_queues(lif->netdev);
return 0;
}
int ionic_open(struct net_device *netdev) int ionic_open(struct net_device *netdev)
{ {
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
...@@ -1621,54 +1638,42 @@ int ionic_open(struct net_device *netdev) ...@@ -1621,54 +1638,42 @@ int ionic_open(struct net_device *netdev)
err = ionic_txrx_init(lif); err = ionic_txrx_init(lif);
if (err) if (err)
goto err_txrx_free; goto err_out;
err = ionic_txrx_enable(lif); /* don't start the queues until we have link */
if (netif_carrier_ok(netdev)) {
err = ionic_start_queues(lif);
if (err) if (err)
goto err_txrx_deinit; goto err_txrx_deinit;
}
netif_set_real_num_tx_queues(netdev, lif->nxqs);
netif_set_real_num_rx_queues(netdev, lif->nxqs);
set_bit(IONIC_LIF_F_UP, lif->state);
ionic_link_status_check_request(lif);
if (netif_carrier_ok(netdev))
netif_tx_wake_all_queues(netdev);
return 0; return 0;
err_txrx_deinit: err_txrx_deinit:
ionic_txrx_deinit(lif); ionic_txrx_deinit(lif);
err_txrx_free: err_out:
ionic_txrx_free(lif); ionic_txrx_free(lif);
return err; return err;
} }
int ionic_stop(struct net_device *netdev) static void ionic_stop_queues(struct ionic_lif *lif)
{ {
struct ionic_lif *lif = netdev_priv(netdev); if (!test_and_clear_bit(IONIC_LIF_F_UP, lif->state))
int err = 0; return;
if (!test_bit(IONIC_LIF_F_UP, lif->state)) { ionic_txrx_disable(lif);
dev_dbg(lif->ionic->dev, "%s: %s state=DOWN\n", netif_tx_disable(lif->netdev);
__func__, lif->name); }
return 0;
}
dev_dbg(lif->ionic->dev, "%s: %s state=UP\n", __func__, lif->name);
clear_bit(IONIC_LIF_F_UP, lif->state);
/* carrier off before disabling queues to avoid watchdog timeout */ int ionic_stop(struct net_device *netdev)
netif_carrier_off(netdev); {
netif_tx_stop_all_queues(netdev); struct ionic_lif *lif = netdev_priv(netdev);
netif_tx_disable(netdev);
ionic_txrx_disable(lif); ionic_stop_queues(lif);
ionic_lif_quiesce(lif);
ionic_txrx_deinit(lif); ionic_txrx_deinit(lif);
ionic_txrx_free(lif); ionic_txrx_free(lif);
return err; return 0;
} }
static int ionic_get_vf_config(struct net_device *netdev, static int ionic_get_vf_config(struct net_device *netdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment