rsi: sdio: Add WOWLAN support for S4 hibernate state

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>
This commit is contained in:
Karun Eagalapati 2017-10-27 16:55:56 +05:30 committed by Kalle Valo
parent f3ac4e7394
commit b6c8d06c8a
7 changed files with 134 additions and 1 deletions

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

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

View 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;

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

View 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

View 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

View 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