@@ -73,6 +73,11 @@ static void ionic_link_status_check(struct ionic_lif *lif)
u16 link_status;
bool link_up;
+ if (lif->ionic->is_mgmt_nic) {
+ clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
+ return;
+ }
+
link_status = le16_to_cpu(lif->info->status.link_status);
link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
@@ -81,20 +86,28 @@ static void ionic_link_status_check(struct ionic_lif *lif)
goto link_out;
if (link_up) {
- netdev_info(netdev, "Link up - %d Gbps\n",
- le32_to_cpu(lif->info->status.link_speed) / 1000);
+ u32 link_speed;
- if (test_bit(IONIC_LIF_F_UP, lif->state)) {
- netif_tx_wake_all_queues(lif->netdev);
- netif_carrier_on(netdev);
+ link_speed = le16_to_cpu(lif->info->status.link_speed);
+ netdev_info(netdev, "Link up - %d Gbps\n", link_speed / 1000);
+
+ if (!test_bit(IONIC_LIF_F_UP, lif->state) &&
+ netif_running(netdev)) {
+ rtnl_lock();
+ ionic_open(netdev);
+ rtnl_unlock();
}
+
+ netif_carrier_on(netdev);
} else {
netdev_info(netdev, "Link down\n");
-
- /* carrier off first to avoid watchdog timeout */
netif_carrier_off(netdev);
- if (test_bit(IONIC_LIF_F_UP, lif->state))
- netif_tx_stop_all_queues(netdev);
+
+ if (test_bit(IONIC_LIF_F_UP, lif->state)) {
+ rtnl_lock();
+ ionic_stop(netdev);
+ rtnl_unlock();
+ }
}
link_out:
@@ -275,8 +288,10 @@ static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
if (qcq->flags & IONIC_QCQ_F_INTR) {
ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
IONIC_INTR_MASK_SET);
+ irq_set_affinity_hint(qcq->intr.vector, NULL);
devm_free_irq(dev, qcq->intr.vector, &qcq->napi);
netif_napi_del(&qcq->napi);
+ qcq->intr.vector = 0;
}
qcq->flags &= ~IONIC_QCQ_F_INITED;
@@ -318,19 +333,21 @@ static void ionic_qcqs_free(struct ionic_lif *lif)
lif->adminqcq = NULL;
}
- for (i = 0; i < lif->nxqs; i++)
- if (lif->rxqcqs[i].stats)
- devm_kfree(dev, lif->rxqcqs[i].stats);
-
- devm_kfree(dev, lif->rxqcqs);
- lif->rxqcqs = NULL;
-
- for (i = 0; i < lif->nxqs; i++)
- if (lif->txqcqs[i].stats)
- devm_kfree(dev, lif->txqcqs[i].stats);
+ if (lif->rxqcqs) {
+ for (i = 0; i < lif->nxqs; i++)
+ if (lif->rxqcqs[i].stats)
+ devm_kfree(dev, lif->rxqcqs[i].stats);
+ devm_kfree(dev, lif->rxqcqs);
+ lif->rxqcqs = NULL;
+ }
- devm_kfree(dev, lif->txqcqs);
- lif->txqcqs = NULL;
+ if (lif->txqcqs) {
+ for (i = 0; i < lif->nxqs; i++)
+ if (lif->txqcqs[i].stats)
+ devm_kfree(dev, lif->txqcqs[i].stats);
+ devm_kfree(dev, lif->txqcqs);
+ lif->txqcqs = NULL;
+ }
}
static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
@@ -1573,7 +1590,17 @@ int ionic_open(struct net_device *netdev)
struct ionic_lif *lif = netdev_priv(netdev);
int err;
- netif_carrier_off(netdev);
+ if (test_bit(IONIC_LIF_F_UP, lif->state)) {
+ dev_dbg(lif->ionic->dev, "%s: %s called when state=UP\n",
+ __func__, lif->name);
+ return 0;
+ }
+
+ ionic_link_status_check_request(lif);
+
+ /* wait until carrier is up before creating rx and tx queues */
+ if (!netif_carrier_ok(lif->netdev))
+ return 0;
err = ionic_txrx_alloc(lif);
if (err)
@@ -1592,7 +1619,6 @@ int ionic_open(struct net_device *netdev)
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);
@@ -1611,7 +1637,7 @@ int ionic_stop(struct net_device *netdev)
int err = 0;
if (!test_bit(IONIC_LIF_F_UP, lif->state)) {
- dev_dbg(lif->ionic->dev, "%s: %s state=DOWN\n",
+ dev_dbg(lif->ionic->dev, "%s: %s called when state=DOWN\n",
__func__, lif->name);
return 0;
}
@@ -1922,6 +1948,8 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
ionic_ethtool_set_ops(netdev);
netdev->watchdog_timeo = 2 * HZ;
+ netif_carrier_off(netdev);
+
netdev->min_mtu = IONIC_MIN_MTU;
netdev->max_mtu = IONIC_MAX_MTU;
@@ -240,11 +240,16 @@ static void ionic_adminq_cb(struct ionic_queue *q,
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;
WARN_ON(in_interrupt());
+ if (!lif->adminqcq)
+ return -EIO;
+
+ adminq = &lif->adminqcq->q;
+
spin_lock(&lif->adminq_lock);
if (!ionic_q_has_space(adminq, 1)) {
err = -ENOSPC;
When link goes down, tear down the Tx and Rx queues. When link comes back up, rebuild the queues. This lets us release memory resources for devices that aren't going to use them, and prepares us for support of fw upgrade. We also add a couple of checks on tear down to watch out for structs already torn down. Signed-off-by: Shannon Nelson <snelson@pensando.io> --- .../net/ethernet/pensando/ionic/ionic_lif.c | 76 +++++++++++++------ .../net/ethernet/pensando/ionic/ionic_main.c | 7 +- 2 files changed, 58 insertions(+), 25 deletions(-)