lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 12 Mar 2020 14:50:15 -0700
From:   Shannon Nelson <snelson@...sando.io>
To:     netdev@...r.kernel.org, davem@...emloft.net
Cc:     Shannon Nelson <snelson@...sando.io>
Subject: [PATCH net-next 7/7] ionic: check for link when link down

While the link is down, have the heartbeat watchdog also
check the link for changes in case no Event is sent.

Meanwhile, sometimes the link status check runs into itself
or the ionic_open() thread, and can either confuse itself,
throw incorrect error messages, or even miss the link message.
This patch cleans up the code and gets the right messages out
to the log file when they happen.

 - rearrange the link_up/link_down messages so that we announce
   link up when we first notice that the link is up when the
   driver loads, and decouple the link_up/link_down messages
   from the UP and DOWN netdev state.
 - add error checking of ionic_qcq_disable() so as to not have
   to wait too long on shutdown when everything it timeout out.
 - add a state to indicate transitions between netdev UP and
   DOWN so as to prevent recursion.
 - don't clean the dev_cmd when we notice that the fw has halted,
   it's possible it might still execute the request.

Signed-off-by: Shannon Nelson <snelson@...sando.io>
---
 .../net/ethernet/pensando/ionic/ionic_dev.c   | 10 ++-
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 78 ++++++++++++-------
 .../net/ethernet/pensando/ionic/ionic_lif.h   |  2 +
 .../net/ethernet/pensando/ionic/ionic_main.c  |  1 -
 4 files changed, 61 insertions(+), 30 deletions(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
index bb513db7163c..349b63f3ab54 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
@@ -14,11 +14,19 @@
 static void ionic_watchdog_cb(struct timer_list *t)
 {
 	struct ionic *ionic = from_timer(ionic, t, watchdog_timer);
+	struct ionic_lif *lif = ionic->master_lif;
+	int hb;
 
 	mod_timer(&ionic->watchdog_timer,
 		  round_jiffies(jiffies + ionic->watchdog_period));
 
-	ionic_heartbeat_check(ionic);
+	hb = ionic_heartbeat_check(ionic);
+
+	/* check link if we're waiting for link to come back up */
+	if (hb >= 0 && lif && netif_running(lif->netdev) &&
+	    !test_bit(IONIC_LIF_F_UP, lif->state)) {
+		ionic_link_status_check_request(lif);
+	}
 }
 
 void ionic_init_devinfo(struct ionic *ionic)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 8027b72835b6..cd349187376f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -90,40 +90,44 @@ static void ionic_link_status_check(struct ionic_lif *lif)
 	link_status = le16_to_cpu(lif->info->status.link_status);
 	link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
 
-	/* filter out the no-change cases */
-	if (link_up == netif_carrier_ok(netdev))
-		goto link_out;
-
 	if (link_up) {
 		u32 link_speed;
 
-		link_speed = le16_to_cpu(lif->info->status.link_speed);
-		netdev_info(netdev, "Link up - %d Gbps\n", link_speed / 1000);
+		if (!netif_carrier_ok(netdev)) {
+			/* force an update in shared structs */
+			ionic_port_identify(lif->ionic);
+
+			link_speed = le32_to_cpu(lif->info->status.link_speed);
+			netdev_info(netdev, "Link up - %d Gbps\n",
+				    link_speed / 1000);
+			netif_carrier_on(netdev);
+		}
 
 		if (!test_bit(IONIC_LIF_F_UP, lif->state) &&
-		    netif_running(netdev)) {
+		    netif_running(netdev) &&
+		    !test_bit(IONIC_LIF_F_TRANS, lif->state)) {
 			rtnl_lock();
 			ionic_open(netdev);
 			rtnl_unlock();
 		}
-
-		netif_carrier_on(netdev);
 	} else {
-		netdev_info(netdev, "Link down\n");
-		netif_carrier_off(netdev);
+		if (netif_carrier_ok(netdev)) {
+			netdev_info(netdev, "Link down\n");
+			netif_carrier_off(netdev);
+		}
 
-		if (test_bit(IONIC_LIF_F_UP, lif->state)) {
+		if (test_bit(IONIC_LIF_F_UP, lif->state) &&
+		    !test_bit(IONIC_LIF_F_TRANS, lif->state)) {
 			rtnl_lock();
 			ionic_stop(netdev);
 			rtnl_unlock();
 		}
 	}
 
-link_out:
 	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
 }
 
-static void ionic_link_status_check_request(struct ionic_lif *lif)
+void ionic_link_status_check_request(struct ionic_lif *lif)
 {
 	struct ionic_deferred_work *work;
 
@@ -1455,10 +1459,15 @@ static void ionic_lif_rss_deinit(struct ionic_lif *lif)
 static void ionic_txrx_disable(struct ionic_lif *lif)
 {
 	unsigned int i;
+	int err;
 
 	for (i = 0; i < lif->nxqs; i++) {
-		ionic_qcq_disable(lif->txqcqs[i].qcq);
-		ionic_qcq_disable(lif->rxqcqs[i].qcq);
+		err = ionic_qcq_disable(lif->txqcqs[i].qcq);
+		if (err == -ETIMEDOUT)
+			break;
+		err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
+		if (err == -ETIMEDOUT)
+			break;
 	}
 }
 
@@ -1581,7 +1590,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
 
 		ionic_rx_fill(&lif->rxqcqs[i].qcq->q);
 		err = ionic_qcq_enable(lif->rxqcqs[i].qcq);
-		if (err) {
+		if (err && err != -ETIMEDOUT) {
 			ionic_qcq_disable(lif->txqcqs[i].qcq);
 			goto err_out;
 		}
@@ -1591,8 +1600,12 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
 
 err_out:
 	while (i--) {
-		ionic_qcq_disable(lif->rxqcqs[i].qcq);
-		ionic_qcq_disable(lif->txqcqs[i].qcq);
+		err = ionic_qcq_disable(lif->rxqcqs[i].qcq);
+		if (err == -ETIMEDOUT)
+			break;
+		err = ionic_qcq_disable(lif->txqcqs[i].qcq);
+		if (err == -ETIMEDOUT)
+			break;
 	}
 
 	return err;
@@ -1601,7 +1614,7 @@ static int ionic_txrx_enable(struct ionic_lif *lif)
 int ionic_open(struct net_device *netdev)
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
-	int err;
+	int err = 0;
 
 	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
 		dev_dbg(lif->ionic->dev, "%s: %s called when state=UP\n",
@@ -1609,15 +1622,18 @@ int ionic_open(struct net_device *netdev)
 		return 0;
 	}
 
+	if (test_and_set_bit(IONIC_LIF_F_TRANS, lif->state))
+		return -EBUSY;
+
 	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;
+		goto open_out;
 
 	err = ionic_txrx_alloc(lif);
 	if (err)
-		return err;
+		goto open_out;
 
 	err = ionic_txrx_init(lif);
 	if (err)
@@ -1635,25 +1651,30 @@ int ionic_open(struct net_device *netdev)
 	if (netif_carrier_ok(netdev))
 		netif_tx_wake_all_queues(netdev);
 
-	return 0;
-
 err_txrx_deinit:
-	ionic_txrx_deinit(lif);
+	if (err)
+		ionic_txrx_deinit(lif);
 err_txrx_free:
-	ionic_txrx_free(lif);
+	if (err)
+		ionic_txrx_free(lif);
+open_out:
+	clear_bit(IONIC_LIF_F_TRANS, lif->state);
 	return err;
 }
 
 int ionic_stop(struct net_device *netdev)
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
-	int err = 0;
 
 	if (!test_bit(IONIC_LIF_F_UP, lif->state)) {
 		dev_dbg(lif->ionic->dev, "%s: %s called when state=DOWN\n",
 			__func__, lif->name);
 		return 0;
 	}
+
+	if (test_and_set_bit(IONIC_LIF_F_TRANS, lif->state))
+		return -EBUSY;
+
 	dev_dbg(lif->ionic->dev, "%s: %s state=UP\n", __func__, lif->name);
 	clear_bit(IONIC_LIF_F_UP, lif->state);
 
@@ -1667,7 +1688,8 @@ int ionic_stop(struct net_device *netdev)
 	ionic_txrx_deinit(lif);
 	ionic_txrx_free(lif);
 
-	return err;
+	clear_bit(IONIC_LIF_F_TRANS, lif->state);
+	return 0;
 }
 
 static int ionic_get_vf_config(struct net_device *netdev,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index fdbb25774755..7c6e8495322d 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -125,6 +125,7 @@ enum ionic_lif_state_flags {
 	IONIC_LIF_F_INITED,
 	IONIC_LIF_F_SW_DEBUG_STATS,
 	IONIC_LIF_F_UP,
+	IONIC_LIF_F_TRANS,
 	IONIC_LIF_F_LINK_CHECK_REQUESTED,
 	IONIC_LIF_F_QUEUE_RESET,
 	IONIC_LIF_F_FW_RESET,
@@ -228,6 +229,7 @@ static inline u32 ionic_coal_hw_to_usec(struct ionic *ionic, u32 units)
 
 void ionic_lif_deferred_enqueue(struct ionic_deferred *def,
 				struct ionic_deferred_work *work);
+void ionic_link_status_check_request(struct ionic_lif *lif);
 int ionic_lifs_alloc(struct ionic *ionic);
 void ionic_lifs_free(struct ionic *ionic);
 void ionic_lifs_deinit(struct ionic *ionic);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 601865db7e03..1dafc047b136 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -364,7 +364,6 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds)
 		done, duration / HZ, duration);
 
 	if (!done && hb) {
-		ionic_dev_cmd_clean(ionic);
 		dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n",
 			 ionic_opcode_to_str(opcode), opcode);
 		return -ENXIO;
-- 
2.17.1

Powered by blists - more mailing lists