Bladeren bron

qcacld-3.0: Serialize psoc idle shutdown and restart via PLD

Serialize psoc interface inactivity idle shutdown and restart via PLD
such that platfrom driver can serialize psoc idle shutdown and restart
to driver unload and SSR events to avoid any race conditions.

Change-Id: Ibac40158ad5b94468b09c53eaf7f3d9a3cb8badf
CRs-Fixed: 2430868
Rajeev Kumar 6 jaren geleden
bovenliggende
commit
473f9afe2a

+ 20 - 2
core/hdd/inc/wlan_hdd_main.h

@@ -2858,14 +2858,15 @@ void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx);
 void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx);
 
 /**
- * hdd_psoc_idle_restart() - restart a previously shutdown idle psoc, if needed
+ * hdd_trigger_psoc_idle_restart() - trigger restart of a previously shutdown
+ *                                   idle psoc, if needed
  * @hdd_ctx: the hdd context which should be restarted
  *
  * This API does nothing if the given psoc is already active.
  *
  * Return: Errno
  */
-int hdd_psoc_idle_restart(struct hdd_context *hdd_ctx);
+int hdd_trigger_psoc_idle_restart(struct hdd_context *hdd_ctx);
 
 int hdd_start_adapter(struct hdd_adapter *adapter);
 void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num);
@@ -3669,4 +3670,21 @@ static inline void hdd_send_update_owe_info_event(struct hdd_adapter *adapter,
 }
 #endif
 
+/**
+ * hdd_psoc_idle_shutdown - perform idle shutdown after interface inactivity
+ *                          timeout
+ * @device: pointer to struct device
+ *
+ * Return: 0 for success non-zero error code for failure
+ */
+int hdd_psoc_idle_shutdown(struct device *dev);
+
+/**
+ * hdd_psoc_idle_restart - perform idle restart after idle shutdown
+ * @device: pointer to struct device
+ *
+ * Return: 0 for success non-zero error code for failure
+ */
+int hdd_psoc_idle_restart(struct device *dev);
+
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */

+ 1 - 1
core/hdd/src/wlan_hdd_cfg80211.c

@@ -14304,7 +14304,7 @@ static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
 		  qdf_opmode_str(adapter->device_mode),
 		  qdf_opmode_str(new_mode));
 
-	errno = hdd_psoc_idle_restart(hdd_ctx);
+	errno = hdd_trigger_psoc_idle_restart(hdd_ctx);
 	if (errno) {
 		hdd_err("Failed to restart psoc; errno:%d", errno);
 		return -EINVAL;

+ 29 - 0
core/hdd/src/wlan_hdd_driver_ops.c

@@ -1394,6 +1394,33 @@ static void wlan_hdd_pld_remove(struct device *dev, enum pld_bus_type bus_type)
 	hdd_exit();
 }
 
+/**
+ * wlan_hdd_pld_idle_shutdown() - wifi module idle shutdown after interface
+ *                                inactivity timeout has trigerred idle shutdown
+ * @dev: device to remove
+ * @pld_bus_type: PLD bus type
+ *
+ * Return: 0 for success and negative error code for failure
+ */
+static int wlan_hdd_pld_idle_shutdown(struct device *dev,
+				       enum pld_bus_type bus_type)
+{
+	return hdd_psoc_idle_shutdown(dev);
+}
+
+/**
+ * wlan_hdd_pld_idle_restart() - wifi module idle restart after idle shutdown
+ * @dev: device to remove
+ * @pld_bus_type: PLD bus type
+ *
+ * Return: 0 for success and negative error code for failure
+ */
+static int wlan_hdd_pld_idle_restart(struct device *dev,
+				      enum pld_bus_type bus_type)
+{
+	return hdd_psoc_idle_restart(dev);
+}
+
 /**
  * wlan_hdd_pld_shutdown() - shutdown function registered to PLD
  * @dev: device to shutdown
@@ -1689,6 +1716,8 @@ static int wlan_hdd_pld_runtime_resume(struct device *dev,
 struct pld_driver_ops wlan_drv_ops = {
 	.probe      = wlan_hdd_pld_probe,
 	.remove     = wlan_hdd_pld_remove,
+	.idle_shutdown = wlan_hdd_pld_idle_shutdown,
+	.idle_restart = wlan_hdd_pld_idle_restart,
 	.shutdown   = wlan_hdd_pld_shutdown,
 	.reinit     = wlan_hdd_pld_reinit,
 	.crash_shutdown = wlan_hdd_pld_crash_shutdown,

+ 1 - 1
core/hdd/src/wlan_hdd_hostapd.c

@@ -435,7 +435,7 @@ static int __hdd_hostapd_open(struct net_device *dev)
 		return ret;
 
 	/* ensure the physical soc is up */
-	ret = hdd_psoc_idle_restart(hdd_ctx);
+	ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
 	if (ret) {
 		hdd_err("Failed to start WLAN modules return");
 		return ret;

+ 37 - 8
core/hdd/src/wlan_hdd_main.c

@@ -2181,7 +2181,7 @@ static int __hdd_mon_open(struct net_device *dev)
 	hdd_mon_mode_ether_setup(dev);
 
 	if (con_mode == QDF_GLOBAL_MONITOR_MODE) {
-		ret = hdd_psoc_idle_restart(hdd_ctx);
+		ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
 		if (ret) {
 			hdd_err("Failed to start WLAN modules return");
 			return ret;
@@ -3164,7 +3164,7 @@ static int __hdd_open(struct net_device *dev)
 		return -EIO;
 	}
 
-	ret = hdd_psoc_idle_restart(hdd_ctx);
+	ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
 	if (ret) {
 		hdd_err("Failed to start WLAN modules return");
 		return ret;
@@ -9162,7 +9162,7 @@ enum hdd_block_shutdown {
 };
 
 /**
- * hdd_psoc_idle_shutdown() - perform an idle shutdown on the given psoc
+ * __hdd_psoc_idle_shutdown() - perform an idle shutdown on the given psoc
  * @hdd_ctx: the hdd context which should be shutdown
  *
  * When no interfaces are "up" on a psoc, an idle shutdown timer is started.
@@ -9172,7 +9172,7 @@ enum hdd_block_shutdown {
  *
  * Return: None
  */
-static void hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx)
+static int __hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx)
 {
 	struct osif_psoc_sync *psoc_sync;
 	int errno;
@@ -9197,15 +9197,43 @@ static void hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx)
 
 exit:
 	hdd_exit();
+	return errno;
 }
 
-int hdd_psoc_idle_restart(struct hdd_context *hdd_ctx)
+int hdd_psoc_idle_shutdown(struct device *dev)
 {
-	QDF_BUG(rtnl_is_locked());
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
 
+	return __hdd_psoc_idle_shutdown(hdd_ctx);
+}
+
+static int __hdd_psoc_idle_restart(struct hdd_context *hdd_ctx)
+{
 	return hdd_wlan_start_modules(hdd_ctx, false);
 }
 
+int hdd_psoc_idle_restart(struct device *dev)
+{
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+
+	return __hdd_psoc_idle_restart(hdd_ctx);
+}
+
+int hdd_trigger_psoc_idle_restart(struct hdd_context *hdd_ctx)
+{
+	QDF_BUG(rtnl_is_locked());
+
+	if (hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) {
+		hdd_psoc_idle_timer_stop(hdd_ctx);
+		hdd_info("Driver modules already Enabled");
+		return 0;
+	}
+
+	pld_idle_restart(hdd_ctx->parent_dev, hdd_psoc_idle_restart);
+
+	return 0;
+}
+
 /**
  * hdd_psoc_idle_timeout_callback() - Handler for psoc idle timeout
  * @priv: pointer to hdd context
@@ -9219,8 +9247,9 @@ static void hdd_psoc_idle_timeout_callback(void *priv)
 	if (wlan_hdd_validate_context(hdd_ctx))
 		return;
 
-	hdd_debug("Psoc idle timeout elapsed; starting psoc shutdown");
-	hdd_psoc_idle_shutdown(hdd_ctx);
+	hdd_info("Psoc idle timeout elapsed; starting psoc shutdown");
+
+	pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown);
 }
 
 #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE

+ 2 - 2
core/hdd/src/wlan_hdd_p2p.c

@@ -758,7 +758,7 @@ struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
 	}
 
 	/* ensure physcial soc is up */
-	ret = hdd_psoc_idle_restart(hdd_ctx);
+	ret = hdd_trigger_psoc_idle_restart(hdd_ctx);
 	if (ret) {
 		hdd_err("Failed to start the wlan_modules");
 		goto close_adapter;
@@ -876,7 +876,7 @@ int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
 		return errno;
 
 	/* ensure physical soc is up */
-	errno = hdd_psoc_idle_restart(hdd_ctx);
+	errno = hdd_trigger_psoc_idle_restart(hdd_ctx);
 	if (errno)
 		return errno;
 

+ 8 - 8
core/pld/inc/pld_common.h

@@ -335,9 +335,9 @@ struct pld_driver_ops {
 		     void *bdev, void *id);
 	void (*remove)(struct device *dev,
 		       enum pld_bus_type bus_type);
-	void (*idle_shutdown)(struct device *dev,
+	int (*idle_shutdown)(struct device *dev,
 			      enum pld_bus_type bus_type);
-	void (*idle_restart)(struct device *dev,
+	int (*idle_restart)(struct device *dev,
 			     enum pld_bus_type bus_type);
 	void (*shutdown)(struct device *dev,
 			 enum pld_bus_type bus_type);
@@ -649,20 +649,20 @@ bool pld_have_platform_driver_support(struct device *dev);
  * @dev: pointer to struct dev
  * @shutdown_cb: pointer to hdd psoc idle shutdown callback handler
  *
- * Return: none
+ * Return: 0 for success and non-zero negative error code for failure
  */
-void pld_idle_shutdown(struct device *dev,
-		       void (*shutdown_cb)(struct device *dev));
+int pld_idle_shutdown(struct device *dev,
+		      int (*shutdown_cb)(struct device *dev));
 
 /**
  * pld_idle_restart - request idle restart callback from platform driver
  * @dev: pointer to struct dev
  * @restart_cb: pointer to hdd psoc idle restart callback handler
  *
- * Return: none
+ * Return: 0 for success and non-zero negative error code for failure
  */
-void pld_idle_restart(struct device *dev,
-		      void (*restart_cb)(struct device *dev));
+int pld_idle_restart(struct device *dev,
+		     int (*restart_cb)(struct device *dev));
 
 #if defined(CONFIG_WCNSS_MEM_PRE_ALLOC) && defined(FEATURE_SKB_PRE_ALLOC)
 

+ 20 - 10
core/pld/src/pld_common.c

@@ -1797,42 +1797,52 @@ void pld_block_shutdown(struct device *dev, bool status)
 	}
 }
 
-void pld_idle_shutdown(struct device *dev,
-		       void (*shutdown_cb)(struct device *dev))
+int pld_idle_shutdown(struct device *dev,
+		      int (*shutdown_cb)(struct device *dev))
 {
+	int errno = -EINVAL;
 	enum pld_bus_type type;
 
 	if (!shutdown_cb)
-		return;
+		return -EINVAL;
 
 	type = pld_get_bus_type(dev);
 	switch (type) {
+		case PLD_BUS_TYPE_SDIO:
+		case PLD_BUS_TYPE_USB:
 		case PLD_BUS_TYPE_SNOC:
-			shutdown_cb(dev);
-			break;
 		case PLD_BUS_TYPE_PCIE:
+			errno = shutdown_cb(dev);
 			break;
 		default:
+			pr_err("Invalid device type %d\n", type);
 			break;
 	}
+
+	return errno;
 }
 
-void pld_idle_restart(struct device *dev,
-		      void (*restart_cb)(struct device *dev))
+int pld_idle_restart(struct device *dev,
+		     int (*restart_cb)(struct device *dev))
 {
+	int errno = -EINVAL;
 	enum pld_bus_type type;
 
 	if (!restart_cb)
-		return;
+		return -EINVAL;
 
 	type = pld_get_bus_type(dev);
 	switch (type) {
+		case PLD_BUS_TYPE_SDIO:
+		case PLD_BUS_TYPE_USB:
 		case PLD_BUS_TYPE_SNOC:
-			restart_cb(dev);
-			break;
 		case PLD_BUS_TYPE_PCIE:
+			errno = restart_cb(dev);
 			break;
 		default:
+			pr_err("Invalid device type %d\n", type);
 			break;
 	}
+
+	return errno;
 }