Ver código fonte

qcacld-3.0: Synchronize load/unload with IFF_UP from upper layer

In certain restart sequence of the modem, wlan driver is forcefully
removed and re-probed during the firmware ready. Supplicant receives
the RTM_DELLINK/RTM_NEWLINK events as part of unregistration of netdev
from remove and registration of the netdev again as part of re-probe.

As soon as the RTM_NEWLINK indication is received by the supplicant
it tries to bring up the interface, the request for bringing up
the interface is rejected by the driver since it is still in the
re-probing phase resulting in the scan failure and other failures.

To mitigate issue synchronize the interface up with the loading/unloading
of the driver.

Change-Id: Ie467e729a4736a0ee580c4df8d75099cf070d7bf
CRs-Fixed: 2058390
Arunk Khandavalli 7 anos atrás
pai
commit
16d84258e0

+ 1 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -370,6 +370,7 @@
  */
 
 extern spinlock_t hdd_context_lock;
+extern struct mutex hdd_init_deinit_lock;
 
 /* MAX OS Q block time value in msec
  * Prevent from permanent stall, resume OS Q if timer expired

+ 11 - 4
core/hdd/src/wlan_hdd_driver_ops.c

@@ -333,6 +333,7 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
 	pr_info("%s: %sprobing driver v%s\n", WLAN_MODULE_NAME,
 		reinit ? "re-" : "", QWLAN_VERSIONSTR);
 
+	mutex_lock(&hdd_init_deinit_lock);
 	hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
 
 	/*
@@ -373,13 +374,11 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
 
 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
 	hdd_remove_pm_qos(dev);
-
 	cds_set_fw_down(false);
-
 	cds_set_driver_in_bad_state(false);
 	probe_fail_cnt = 0;
 	re_init_fail_cnt = 0;
-
+	mutex_unlock(&hdd_init_deinit_lock);
 	return 0;
 
 
@@ -400,7 +399,7 @@ err_hdd_deinit:
 	hdd_remove_pm_qos(dev);
 
 	cds_set_fw_down(false);
-
+	mutex_unlock(&hdd_init_deinit_lock);
 	return ret;
 }
 
@@ -1152,7 +1151,11 @@ static int wlan_hdd_pld_probe(struct device *dev,
 static void wlan_hdd_pld_remove(struct device *dev,
 		     enum pld_bus_type bus_type)
 {
+	ENTER();
+	mutex_lock(&hdd_init_deinit_lock);
 	wlan_hdd_remove(dev);
+	mutex_unlock(&hdd_init_deinit_lock);
+	EXIT();
 }
 
 /**
@@ -1165,7 +1168,11 @@ static void wlan_hdd_pld_remove(struct device *dev,
 static void wlan_hdd_pld_shutdown(struct device *dev,
 		       enum pld_bus_type bus_type)
 {
+	ENTER();
+	mutex_lock(&hdd_init_deinit_lock);
 	wlan_hdd_shutdown();
+	mutex_unlock(&hdd_init_deinit_lock);
+	EXIT();
 }
 
 /**

+ 19 - 5
core/hdd/src/wlan_hdd_main.c

@@ -191,6 +191,7 @@ static int enable_dfs_chan_scan = -1;
  * (full description of use in wlan_hdd_main.h)
  */
 DEFINE_SPINLOCK(hdd_context_lock);
+DEFINE_MUTEX(hdd_init_deinit_lock);
 
 #define WLAN_NLINK_CESIUM 30
 
@@ -2488,15 +2489,26 @@ static int __hdd_open(struct net_device *dev)
 		return -EBUSY;
 	}
 
-	ret = wlan_hdd_validate_context(hdd_ctx);
-	if (ret)
-		return ret;
+	mutex_lock(&hdd_init_deinit_lock);
+
+	/*
+	 * This scenario can be hit in cases where in the wlan driver after
+	 * registering the netdevices and there is a failure in driver
+	 * initialization. So return error gracefully because the netdevices
+	 * will be de-registered as part of the load failure.
+	 */
+
+	if (!cds_is_driver_loaded()) {
+		hdd_err("Failed to start the wlan driver!!");
+		ret = -EIO;
+		goto err_hdd_hdd_init_deinit_lock;
+	}
 
 
 	ret = hdd_wlan_start_modules(hdd_ctx, adapter, false);
 	if (ret) {
 		hdd_err("Failed to start WLAN modules return");
-		return -ret;
+		goto err_hdd_hdd_init_deinit_lock;
 	}
 
 
@@ -2505,7 +2517,7 @@ static int __hdd_open(struct net_device *dev)
 		if (ret) {
 			hdd_err("Failed to start adapter :%d",
 				adapter->device_mode);
-			return ret;
+			goto err_hdd_hdd_init_deinit_lock;
 		}
 	}
 
@@ -2528,6 +2540,8 @@ static int __hdd_open(struct net_device *dev)
 
 	hdd_populate_wifi_pos_cfg(hdd_ctx);
 
+err_hdd_hdd_init_deinit_lock:
+	mutex_unlock(&hdd_init_deinit_lock);
 	return ret;
 }