[PATCH 09/12] wifi: wilc1000: disable firmware power save if bluetooth is in use

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If the wlan interface exposed by wilc driver has power save enabled
(either explicitly with iw dev wlan set power_save on, or because
kernel is built with CONFIG_CFG80211_DEFAULT_PS), it will send a power
management command to the wlan firmware when corresponding interface is
brought up. The bluetooth part, if used, is supposed to work
independently from the WLAN CPU. Unfortunately, this power save
management, if applied by the WLAN side, disrupts bluetooth operations
(the bluetooth CPU does not answer any command anymore on the UART
interface)

Make sure that the bluetooth part can work independently by disabling
power save in wlan firmware when bluetooth is in use.

Signed-off-by: Alexis Lothoré <alexis.lothore@xxxxxxxxxxx>
---
 drivers/net/wireless/microchip/wilc1000/bt.c       | 29 +++++++++++++++++++---
 drivers/net/wireless/microchip/wilc1000/cfg80211.c |  5 +++-
 drivers/net/wireless/microchip/wilc1000/netdev.h   |  3 +++
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/microchip/wilc1000/bt.c b/drivers/net/wireless/microchip/wilc1000/bt.c
index b0f68a5479a5bd6f70e2390a35512037dc6c332b..f0eb5fb506eddf0f6f4f3f0b182eaa650c1c7a87 100644
--- a/drivers/net/wireless/microchip/wilc1000/bt.c
+++ b/drivers/net/wireless/microchip/wilc1000/bt.c
@@ -7,6 +7,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <net/wilc.h>
+#include "cfg80211.h"
 #include "netdev.h"
 #include "wlan_if.h"
 #include "wlan.h"
@@ -261,22 +262,36 @@ static int wilc_bt_start(struct wilc *wilc)
 int wilc_bt_init(void *wilc_wl_priv)
 {
 	struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+	struct wilc_vif *vif;
 	int ret;
 
+	wilc->bt_enabled = true;
+
 	if (!wilc->hif_func->hif_is_init(wilc)) {
 		dev_info(wilc->dev, "Initializing bus before starting BT");
 		acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
 		ret = wilc->hif_func->hif_init(wilc, false);
 		release_bus(wilc, WILC_BUS_RELEASE_ONLY);
-		if (ret)
+		if (ret) {
+			wilc->bt_enabled = false;
 			return ret;
+		}
 	}
 
+	/* Power save feature managed by WLAN firmware may disrupt
+	 * operations from the bluetooth CPU, so disable it while bluetooth
+	 * is in use (if enabled, it will be enabled back when bluetooth is
+	 * not used anymore)
+	 */
+	vif = wilc_get_wl_to_vif(wilc);
+	if (wilc->power_save_mode && wilc_set_power_mgmt(vif, false))
+		goto hif_deinit;
+
 	mutex_lock(&wilc->radio_fw_start);
 	ret = wilc_bt_power_up(wilc);
 	if (ret) {
 		dev_err(wilc->dev, "Error powering up bluetooth chip\n");
-		goto hif_deinit;
+		goto reenable_power_save;
 	}
 	ret = wilc_bt_firmware_download(wilc);
 	if (ret) {
@@ -293,10 +308,14 @@ int wilc_bt_init(void *wilc_wl_priv)
 
 power_down:
 	wilc_bt_power_down(wilc);
-hif_deinit:
+reenable_power_save:
+	if (wilc->power_save_mode_request)
+		wilc_set_power_mgmt(vif, true);
 	mutex_unlock(&wilc->radio_fw_start);
+hif_deinit:
 	if (!wilc->initialized)
 		wilc->hif_func->hif_deinit(wilc);
+	wilc->bt_enabled = false;
 	return ret;
 }
 EXPORT_SYMBOL(wilc_bt_init);
@@ -304,6 +323,7 @@ EXPORT_SYMBOL(wilc_bt_init);
 int wilc_bt_shutdown(void *wilc_wl_priv)
 {
 	struct wilc *wilc = (struct wilc *)wilc_wl_priv;
+	struct wilc_vif *vif;
 	int ret;
 
 	mutex_lock(&wilc->radio_fw_start);
@@ -313,6 +333,9 @@ int wilc_bt_shutdown(void *wilc_wl_priv)
 		dev_warn(wilc->dev, "Failed to disable BT CPU\n");
 	if (wilc_bt_power_down(wilc))
 		dev_warn(wilc->dev, "Failed to power down BT CPU\n");
+	vif = wilc_get_wl_to_vif(wilc);
+	if (wilc->power_save_mode_request && wilc_set_power_mgmt(vif, true))
+		dev_warn(wilc->dev, "Failed to set back wlan power save\n");
 	if (!wilc->initialized)
 		wilc->hif_func->hif_deinit(wilc);
 	mutex_unlock(&wilc->radio_fw_start);
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index ff8c1a40634cee9960777eb017f6b2905e6399a5..04cff3561aad847a3f58a09766d0ef0fa61603e0 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1344,11 +1344,14 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
 {
 	struct wilc_vif *vif = netdev_priv(dev);
 	struct wilc_priv *priv = &vif->priv;
+	struct wilc *wilc = vif->wilc;
 
 	if (!priv->hif_drv)
 		return -EIO;
 
-	wilc_set_power_mgmt(vif, enabled);
+	wilc->power_save_mode_request = enabled;
+	if (!wilc->bt_enabled)
+		wilc_set_power_mgmt(vif, enabled);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 5837f8ffe548dad1b756cdbd8543636f2be0e9b0..4c297eb95eeb143fc2f1248e616ee307afa52dbd 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -213,6 +213,7 @@ struct wilc {
 	struct clk *rtc_clk;
 	bool initialized;
 	u32 chipid;
+	bool power_save_mode_request;
 	bool power_save_mode;
 	int dev_irq_num;
 	int close;
@@ -289,6 +290,8 @@ struct wilc {
 	u8 nv_mac_address[ETH_ALEN];
 	/* Lock to prevent concurrent start of wlan/bluetooth firmware */
 	struct mutex radio_fw_start;
+	/* Is the bluetooth part in use ? */
+	bool bt_enabled;
 };
 
 struct wilc_wfi_mon_priv {

-- 
2.48.0





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux