[v3,6/7] net/netvsc: process link change messages in alarm

Message ID 20200519165230.23306-7-stephen@networkplumber.org (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series net/netvsc: VF bug fix and diagnostic support |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Stephen Hemminger May 19, 2020, 4:52 p.m. UTC
  The original code would deadlock itself if a link change event
happened with link state interrupt enabled. The problem is that
the link state changed message would be seen while reading
the host to guest ring (under lock) and then the driver would
send a query to the host to see the new link state. The response
would never be seen (stuck in a while loop) waiting for the
response.

The solution is to use the link change indication to trigger
a DPDK alarm. The alarm will happen in a different thread and
in that context it can send request for new link state and
also do interrupt callback. This is similar to how the bonding
driver is handling the same thing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/netvsc/hn_rndis.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)
  

Patch

diff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c
index 7947ca2331e2..6a850ce5f226 100644
--- a/drivers/net/netvsc/hn_rndis.c
+++ b/drivers/net/netvsc/hn_rndis.c
@@ -17,6 +17,7 @@ 
 #include <rte_memzone.h>
 #include <rte_malloc.h>
 #include <rte_atomic.h>
+#include <rte_alarm.h>
 #include <rte_branch_prediction.h>
 #include <rte_ether.h>
 #include <rte_common.h>
@@ -281,6 +282,15 @@  static int hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
 				  &nvs_rndis, sizeof(nvs_rndis), 0U, NULL);
 }
 
+/*
+ * Alarm callback to process link changed notifications.
+ * Can not directly since link_status is discovered while reading ring
+ */
+static void hn_rndis_link_alarm(void *arg)
+{
+	_rte_eth_dev_callback_process(arg, RTE_ETH_EVENT_INTR_LSC, NULL);
+}
+
 void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
 {
 	const struct rndis_status_msg *indicate = msg;
@@ -298,11 +308,8 @@  void hn_rndis_link_status(struct rte_eth_dev *dev, const void *msg)
 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
 	case RNDIS_STATUS_MEDIA_CONNECT:
 	case RNDIS_STATUS_MEDIA_DISCONNECT:
-		if (dev->data->dev_conf.intr_conf.lsc &&
-		    hn_dev_link_update(dev, 0) == 0)
-			_rte_eth_dev_callback_process(dev,
-						      RTE_ETH_EVENT_INTR_LSC,
-						      NULL);
+		if (dev->data->dev_conf.intr_conf.lsc)
+			rte_eal_alarm_set(10, hn_rndis_link_alarm, dev);
 		break;
 	default:
 		PMD_DRV_LOG(NOTICE, "unknown RNDIS indication: %#x",
@@ -1101,6 +1108,10 @@  hn_rndis_attach(struct hn_data *hv)
 void
 hn_rndis_detach(struct hn_data *hv)
 {
+	struct rte_eth_dev *dev = &rte_eth_devices[hv->port_id];
+
+	rte_eal_alarm_cancel(hn_rndis_link_alarm, dev);
+
 	/* Halt the RNDIS. */
 	hn_rndis_halt(hv);
 }