drivers: rmnet_shs: Change init to Register events

Previously we used NETDEV_GOING_DOWN and NETDEV_UP events
to cover shs init/de-init scenarios. That did not cover
rmnet driver going down prematurely if rmnet vnds were
cleaned up in a non-SSR scenario.

This change will allow shs to keep track of registered vnds
and to de-init when the last vnd has been unregistered to
avoid this issue.

<6> Unable to handle kernel NULL pointer dereference at virtual address 00000000
<6> Mem abort info:
<6>   Exception class = DABT (current EL), IL = 32 bits
<6>   SET = 0, FnV = 0
<6>   EA = 0, S1PTW = 0
<6>   FSC = 5
<6> Data abort info:
<6>   ISV = 0, ISS = 0x00000005
<6>   CM = 0, WnR = 0
<6> user pgtable: 4k pages, 39-bit VAs, pgd = 00000000bafe2c18
<6> task: 00000000d6d739bd task.stack: 000000009afe105c
<2> pc : rmnet_map_dl_ind_deregister+0x24/0x68
<2> lr : rmnet_shs_exit+0x30/0x68 [rmnet_shs]
<2> Call trace:
<2>  rmnet_map_dl_ind_deregister+0x24/0x68
<2>  rmnet_shs_dev_notify_cb+0x118/0x478 [rmnet_shs]
<2>  raw_notifier_call_chain+0x3c/0x68
<2>  __dev_close_many+0x9c/0x158
<2>  dev_close_many+0x7c/0x1e0
<2>  rollback_registered_many+0xe4/0x460
<2>  unregister_netdev+0x48/0xd0
<2>  mhi_netdev_remove+0x124/0x220
<2>  mhi_driver_remove+0x178/0x250
<2>  device_release_driver_internal+0x158/0x200
<2>  device_release_driver+0x14/0x20
<2>  bus_remove_device+0xd8/0x100

CRs-Fixed: 2540066
Change-Id: I231ff0af3cb2feb955b891b628487ab4fc3377ba
Acked-by: Raul Martinez <mraul@qti.qualcomm.com>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
diff --git a/drivers/rmnet/shs/rmnet_shs_config.c b/drivers/rmnet/shs/rmnet_shs_config.c
index 341dcc9..ffa4f1d 100644
--- a/drivers/rmnet/shs/rmnet_shs_config.c
+++ b/drivers/rmnet/shs/rmnet_shs_config.c
@@ -70,26 +70,26 @@
 	struct net_device *dev = netdev_notifier_info_to_dev(data);
 	struct rmnet_priv *priv;
 	struct rmnet_port *port;
+	int ret = 0;
 
 	if (!dev) {
 		rmnet_shs_crit_err[RMNET_SHS_NETDEV_ERR]++;
 		return NOTIFY_DONE;
 	}
 
-	switch (event) {
-	case NETDEV_GOING_DOWN:
-		rmnet_shs_wq_reset_ep_active(dev);
+	if (!(strncmp(dev->name, "rmnet_data", 10) == 0 ||
+	      strncmp(dev->name, "r_rmnet_data", 12) == 0))
+		return NOTIFY_DONE;
 
-		if (strncmp(dev->name, "rmnet_data", 10) == 0)
-			rmnet_vnd_total--;
+	switch (event) {
+	case NETDEV_UNREGISTER:
+		rmnet_shs_wq_reset_ep_active(dev);
+		rmnet_vnd_total--;
 
 		/* Deinitialize if last vnd is going down or if
 		 * phy_dev is going down.
 		 */
-		if ((rmnet_is_real_dev_registered(dev) &&
-		    (!strcmp(dev->name, "rmnet_ipa0") ||
-		    !strcmp(dev->name, "rmnet_mhi0"))) &&
-		    rmnet_shs_cfg.rmnet_shs_init_complete) {
+		if (!rmnet_vnd_total && rmnet_shs_cfg.rmnet_shs_init_complete) {
 			pr_info("rmnet_shs deinit %s going down ", dev->name);
 			RCU_INIT_POINTER(rmnet_shs_skb_entry, NULL);
 			qmi_rmnet_ps_ind_deregister(rmnet_shs_cfg.port,
@@ -105,58 +105,73 @@
 		}
 		break;
 
-	case NETDEV_UP:
+	case NETDEV_REGISTER:
+		rmnet_vnd_total++;
 
-		if (strncmp(dev->name, "rmnet_data", 10) == 0){
-			rmnet_vnd_total++;
-		}
-
-		if (strncmp(dev->name, "rmnet_data", 10) == 0) {
-			/* Need separate if check to avoid
-			 * NULL dereferencing
-			 */
-
-			if (!rmnet_shs_cfg.rmnet_shs_init_complete) {
-				pr_info("rmnet_shs initializing %s", dev->name);
-				priv = netdev_priv(dev);
-				port = rmnet_get_port(priv->real_dev);
-				if (!port) {
-					pr_err("rmnet_shs: invalid rmnet_port");
-					break;
-				}
-				rmnet_shs_init(priv->real_dev, dev);
-				rmnet_shs_wq_init(priv->real_dev);
-				rmnet_shs_rx_wq_init();
-				rmnet_shs_cfg.is_timer_init = 1;
-				rmnet_shs_cfg.dl_mrk_ind_cb.priority =
-				   RMNET_SHS;
-				if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2) {
-					rmnet_shs_cfg.dl_mrk_ind_cb.dl_hdr_handler_v2 =
-						&rmnet_shs_dl_hdr_handler_v2;
-					rmnet_shs_cfg.dl_mrk_ind_cb.dl_trl_handler_v2 =
-						&rmnet_shs_dl_trl_handler_v2;
-				} else {
-					rmnet_shs_cfg.dl_mrk_ind_cb.dl_hdr_handler =
-						&rmnet_shs_dl_hdr_handler;
-					rmnet_shs_cfg.dl_mrk_ind_cb.dl_trl_handler =
-						&rmnet_shs_dl_trl_handler;
-				}
-
-				trace_rmnet_shs_high(RMNET_SHS_MODULE,
-						     RMNET_SHS_MODULE_INIT_WQ,
-						     0xDEF, 0xDEF, 0xDEF,
-						     0xDEF, NULL, NULL);
-				rmnet_shs_cfg.rmnet_idl_ind_cb.ps_on_handler =
-						&rmnet_shs_ps_on_hdlr;
-				rmnet_shs_cfg.rmnet_idl_ind_cb.ps_off_handler =
-						&rmnet_shs_ps_off_hdlr;
-				RCU_INIT_POINTER(rmnet_shs_skb_entry,
-						 rmnet_shs_assign);
-
-
+		if (rmnet_vnd_total && !rmnet_shs_cfg.rmnet_shs_init_complete) {
+			pr_info("rmnet_shs initializing %s", dev->name);
+			priv = netdev_priv(dev);
+			port = rmnet_get_port(priv->real_dev);
+			if (!port) {
+				pr_err("rmnet_shs: invalid rmnet_port");
+				break;
 			}
-			rmnet_shs_wq_set_ep_active(dev);
+			rmnet_shs_init(priv->real_dev, dev);
+			rmnet_shs_wq_init(priv->real_dev);
+			rmnet_shs_rx_wq_init();
 
+			rmnet_shs_cfg.is_timer_init = 1;
+		}
+		rmnet_shs_wq_set_ep_active(dev);
+
+		break;
+	case NETDEV_UP:
+		if (!rmnet_shs_cfg.is_reg_dl_mrk_ind &&
+		    rmnet_shs_cfg.rmnet_shs_init_complete) {
+
+			port = rmnet_shs_cfg.port;
+			if (!port) {
+				pr_err("rmnet_shs: invalid rmnet_cfg_port");
+				break;
+			}
+
+			rmnet_shs_cfg.dl_mrk_ind_cb.priority =
+				RMNET_SHS;
+			if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2) {
+				rmnet_shs_cfg.dl_mrk_ind_cb.dl_hdr_handler_v2 =
+					&rmnet_shs_dl_hdr_handler_v2;
+				rmnet_shs_cfg.dl_mrk_ind_cb.dl_trl_handler_v2 =
+					&rmnet_shs_dl_trl_handler_v2;
+			} else {
+				rmnet_shs_cfg.dl_mrk_ind_cb.dl_hdr_handler =
+					&rmnet_shs_dl_hdr_handler;
+				rmnet_shs_cfg.dl_mrk_ind_cb.dl_trl_handler =
+					&rmnet_shs_dl_trl_handler;
+			}
+			rmnet_shs_cfg.rmnet_idl_ind_cb.ps_on_handler =
+					&rmnet_shs_ps_on_hdlr;
+			rmnet_shs_cfg.rmnet_idl_ind_cb.ps_off_handler =
+					&rmnet_shs_ps_off_hdlr;
+
+			ret = rmnet_map_dl_ind_register(port,
+						        &rmnet_shs_cfg.dl_mrk_ind_cb);
+			if (ret)
+				pr_err("%s(): rmnet dl_ind registration fail\n",
+				       __func__);
+
+			ret = qmi_rmnet_ps_ind_register(port,
+						        &rmnet_shs_cfg.rmnet_idl_ind_cb);
+			if (ret)
+				pr_err("%s(): rmnet ps_ind registration fail\n",
+				       __func__);
+
+			rmnet_shs_cfg.is_reg_dl_mrk_ind = 1;
+			trace_rmnet_shs_high(RMNET_SHS_MODULE,
+					     RMNET_SHS_MODULE_INIT_WQ,
+					     0xDEF, 0xDEF, 0xDEF,
+					     0xDEF, NULL, NULL);
+					     RCU_INIT_POINTER(rmnet_shs_skb_entry,
+					     rmnet_shs_assign);
 		}
 
 		break;
diff --git a/drivers/rmnet/shs/rmnet_shs_main.c b/drivers/rmnet/shs/rmnet_shs_main.c
index 4b7734b..b52e608 100755
--- a/drivers/rmnet/shs/rmnet_shs_main.c
+++ b/drivers/rmnet/shs/rmnet_shs_main.c
@@ -1563,15 +1563,6 @@
 		return;
 	}
 
-	if (!rmnet_shs_cfg.is_reg_dl_mrk_ind) {
-		rmnet_map_dl_ind_register(port, &rmnet_shs_cfg.dl_mrk_ind_cb);
-		qmi_rmnet_ps_ind_register(port,
-					  &rmnet_shs_cfg.rmnet_idl_ind_cb);
-
-		rmnet_shs_cfg.is_reg_dl_mrk_ind = 1;
-		shs_rx_work.port = port;
-
-	}
 	/* We got the first packet after a previous successdul flush. Arm the
 	 * flushing timer.
 	 */