rsi: sdio: Add WOWLAN support for S4 hibernate state
authorKarun Eagalapati <karun256@gmail.com>
Fri, 27 Oct 2017 11:25:56 +0000 (16:55 +0530)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 30 Oct 2017 10:50:12 +0000 (12:50 +0200)
We are disabling of interrupts from firmware in freeze handler.
Also setting power management capability KEEP_MMC_POWER to make
device wakeup for WoWLAN trigger.
At restore, we observed a device reset on some platforms. Hence
reloading of firmware and device initialization is performed.

Signed-off-by: Karun Eagalapati <karun256@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/rsi/rsi_91x_core.c
drivers/net/wireless/rsi/rsi_91x_mac80211.c
drivers/net/wireless/rsi/rsi_91x_main.c
drivers/net/wireless/rsi/rsi_91x_mgmt.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
drivers/net/wireless/rsi/rsi_main.h
drivers/net/wireless/rsi/rsi_sdio.h

index 87e023d601c3c879cfe8c52337ef035941649807..d0d2201830e8bbeaf8fd13cf2dd86d03d151f6fb 100644 (file)
@@ -276,6 +276,8 @@ void rsi_core_qos_processor(struct rsi_common *common)
                        rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__);
                        break;
                }
+               if (common->hibernate_resume)
+                       break;
 
                mutex_lock(&common->tx_lock);
 
index c3bd3ca9cf832acdc4527ff8ecdf3c12a46f2b59..95eb5e63999fba5a9450d04f46bf92ff8d94c9b9 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/etherdevice.h>
 #include "rsi_debugfs.h"
 #include "rsi_mgmt.h"
+#include "rsi_sdio.h"
 #include "rsi_common.h"
 #include "rsi_ps.h"
 
@@ -325,6 +326,11 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw)
 
        rsi_dbg(ERR_ZONE, "===> Interface UP <===\n");
        mutex_lock(&common->mutex);
+       if (common->hibernate_resume) {
+               common->reinit_hw = true;
+               adapter->host_intf_ops->reinit_device(adapter);
+               wait_for_completion(&adapter->priv->wlan_init_completion);
+       }
        common->iface_down = false;
        wiphy_rfkill_start_polling(hw->wiphy);
        rsi_send_rx_filter_frame(common, 0);
@@ -1846,6 +1852,9 @@ static int rsi_mac80211_resume(struct ieee80211_hw *hw)
 
        rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__);
 
+       if (common->hibernate_resume)
+               return 0;
+
        mutex_lock(&common->mutex);
        rsi_send_wowlan_request(common, 0, 0);
 
index 2a1fbb7db6c470ae9a115782a1810d6199a55609..0cb8e68bab58010bf8be8a34f48fbbebece2538d 100644 (file)
@@ -263,6 +263,7 @@ struct rsi_hw *rsi_91x_init(void)
        rsi_default_ps_params(adapter);
        spin_lock_init(&adapter->ps_lock);
        timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
+       init_completion(&common->wlan_init_completion);
        common->init_done = true;
        return adapter;
 
index 1446ee3581d036bd39b1faf1570b4dfc7c9b3e18..d38a09f15742b2cab6fcbb10617e2e169f695e8a 100644 (file)
@@ -1761,7 +1761,11 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
                        common->bb_rf_prog_count--;
                        if (!common->bb_rf_prog_count) {
                                common->fsm_state = FSM_MAC_INIT_DONE;
-                               return rsi_mac80211_attach(common);
+                               if (common->reinit_hw) {
+                                       complete(&common->wlan_init_completion);
+                               } else {
+                                       return rsi_mac80211_attach(common);
+                               }
                        }
                } else {
                        rsi_dbg(INFO_ZONE,
@@ -1839,6 +1843,7 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg)
        case TA_CONFIRM_TYPE:
                return rsi_handle_ta_confirm_type(common, msg);
        case CARD_READY_IND:
+               common->hibernate_resume = false;
                rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n",
                        __func__);
                return rsi_handle_card_ready(common, msg);
index fa6af7be61f4b074ab39f595b5558ad785773d4d..3f683d8734729b374e3c96eca52e46c56ceb629b 100644 (file)
@@ -880,6 +880,7 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = {
        .master_reg_read        = rsi_sdio_master_reg_read,
        .master_reg_write       = rsi_sdio_master_reg_write,
        .load_data_master_write = rsi_sdio_load_data_master_write,
+       .reinit_device          = rsi_sdio_reinit_device,
 };
 
 /**
@@ -936,6 +937,8 @@ static int rsi_probe(struct sdio_func *pfunction,
                return -EIO;
        }
 
+       adapter->priv->hibernate_resume = false;
+       adapter->priv->reinit_hw = false;
        return 0;
 fail:
        rsi_91x_deinit(adapter);
@@ -1198,9 +1201,117 @@ static int rsi_resume(struct device *dev)
        return 0;
 }
 
+static int rsi_freeze(struct device *dev)
+{
+       int ret;
+       struct sdio_func *pfunction = dev_to_sdio_func(dev);
+       struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
+       struct rsi_common *common;
+       struct rsi_91x_sdiodev *sdev;
+
+       rsi_dbg(INFO_ZONE, "SDIO Bus freeze ===>\n");
+
+       if (!adapter) {
+               rsi_dbg(ERR_ZONE, "Device is not ready\n");
+               return -ENODEV;
+       }
+       common = adapter->priv;
+       sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+
+#ifdef CONFIG_RSI_WOW
+       if ((common->wow_flags & RSI_WOW_ENABLED) &&
+           (common->wow_flags & RSI_WOW_NO_CONNECTION))
+               rsi_dbg(ERR_ZONE,
+                       "##### Device can not wake up through WLAN\n");
+#endif
+       ret = rsi_sdio_disable_interrupts(pfunction);
+
+       if (sdev->write_fail)
+               rsi_dbg(INFO_ZONE, "###### Device is not ready #######\n");
+
+       ret = rsi_set_sdio_pm_caps(adapter);
+       if (ret)
+               rsi_dbg(INFO_ZONE, "Setting power management caps failed\n");
+
+       rsi_dbg(INFO_ZONE, "***** RSI module freezed *****\n");
+
+       return 0;
+}
+
+static int rsi_thaw(struct device *dev)
+{
+       struct sdio_func *pfunction = dev_to_sdio_func(dev);
+       struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
+       struct rsi_common *common = adapter->priv;
+
+       rsi_dbg(ERR_ZONE, "SDIO Bus thaw =====>\n");
+
+       common->hibernate_resume = true;
+       common->fsm_state = FSM_CARD_NOT_READY;
+       common->iface_down = true;
+
+       rsi_sdio_enable_interrupts(pfunction);
+
+       rsi_dbg(INFO_ZONE, "***** RSI module thaw done *****\n");
+
+       return 0;
+}
+
+int rsi_sdio_reinit_device(struct rsi_hw *adapter)
+{
+       struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
+       struct sdio_func *pfunction = sdev->pfunction;
+       int ii;
+
+       for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
+               skb_queue_purge(&adapter->priv->tx_queue[ii]);
+
+       /* Initialize device again */
+       sdio_claim_host(pfunction);
+
+       sdio_release_irq(pfunction);
+       rsi_reset_card(pfunction);
+
+       sdio_enable_func(pfunction);
+       rsi_setupcard(adapter);
+       rsi_init_sdio_slave_regs(adapter);
+       sdio_claim_irq(pfunction, rsi_handle_interrupt);
+       rsi_hal_device_init(adapter);
+
+       sdio_release_host(pfunction);
+
+       return 0;
+}
+
+static int rsi_restore(struct device *dev)
+{
+       struct sdio_func *pfunction = dev_to_sdio_func(dev);
+       struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
+       struct rsi_common *common = adapter->priv;
+
+       rsi_dbg(INFO_ZONE, "SDIO Bus restore ======>\n");
+       common->hibernate_resume = true;
+       common->fsm_state = FSM_FW_NOT_LOADED;
+       common->iface_down = true;
+
+       adapter->sc_nvifs = 0;
+       ieee80211_restart_hw(adapter->hw);
+
+#ifdef CONFIG_RSI_WOW
+       common->wow_flags = 0;
+#endif
+       common->iface_down = false;
+
+       rsi_dbg(INFO_ZONE, "RSI module restored\n");
+
+       return 0;
+}
 static const struct dev_pm_ops rsi_pm_ops = {
        .suspend = rsi_suspend,
        .resume = rsi_resume,
+       .freeze = rsi_freeze,
+       .thaw = rsi_thaw,
+       .restore = rsi_restore,
 };
 #endif
 
index 44a199f2116ff0c4714b74da0e0c93706de1c9d9..8cab630af4a5b039ed52f5c1ed666b3ff295533a 100644 (file)
@@ -214,6 +214,7 @@ struct rsi_common {
 
        struct rsi_thread tx_thread;
        struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 2];
+       struct completion wlan_init_completion;
        /* Mutex declaration */
        struct mutex mutex;
        /* Mutex used for tx thread */
@@ -272,6 +273,8 @@ struct rsi_common {
        u8 obm_ant_sel_val;
        int tx_power;
        u8 ant_in_use;
+       bool hibernate_resume;
+       bool reinit_hw;
        u8 wow_flags;
        u16 beacon_interval;
        u8 dtim_cnt;
@@ -362,5 +365,6 @@ struct rsi_host_intf_ops {
        int (*load_data_master_write)(struct rsi_hw *adapter, u32 addr,
                                      u32 instructions_size, u16 block_size,
                                      u8 *fw);
+       int (*reinit_device)(struct rsi_hw *adapter);
 };
 #endif
index 49c549ba6682935b909d3873a67fefdd5beebf28..8fbf90eb7b42084b9c5053b95dc509ffef263638 100644 (file)
@@ -131,4 +131,5 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word);
 void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit);
 int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter);
 int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num);
+int rsi_sdio_reinit_device(struct rsi_hw *adapter);
 #endif