Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e8ad333 authored by Subash Abhinov Kasiviswanathan's avatar Subash Abhinov Kasiviswanathan
Browse files

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: default avatarRaul Martinez <mraul@qti.qualcomm.com>
Signed-off-by: default avatarSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
parent efe63abb
Loading
Loading
Loading
Loading
+69 −54
Original line number Diff line number Diff line
@@ -70,26 +70,26 @@ static int rmnet_shs_dev_notify_cb(struct notifier_block *nb,
	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;
	}

	if (!(strncmp(dev->name, "rmnet_data", 10) == 0 ||
	      strncmp(dev->name, "r_rmnet_data", 12) == 0))
		return NOTIFY_DONE;

	switch (event) {
	case NETDEV_GOING_DOWN:
	case NETDEV_UNREGISTER:
		rmnet_shs_wq_reset_ep_active(dev);

		if (strncmp(dev->name, "rmnet_data", 10) == 0)
		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,18 +105,10 @@ static int rmnet_shs_dev_notify_cb(struct notifier_block *nb,
		}
		break;

	case NETDEV_UP:

		if (strncmp(dev->name, "rmnet_data", 10) == 0){
	case NETDEV_REGISTER:
		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) {
		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);
@@ -127,7 +119,22 @@ static int rmnet_shs_dev_notify_cb(struct notifier_block *nb,
			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) {
@@ -141,22 +148,30 @@ static int rmnet_shs_dev_notify_cb(struct notifier_block *nb,
				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);

			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__);

			}
			rmnet_shs_wq_set_ep_active(dev);
			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;
+0 −9
Original line number Diff line number Diff line
@@ -1563,15 +1563,6 @@ void rmnet_shs_assign(struct sk_buff *skb, struct rmnet_port *port)
		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.
	 */