2017-10-27 11:32:48

by Amitkumar Karwar

[permalink] [raw]
Subject: [v3 0/3] rsi: WOWLAN support

From: Amitkumar Karwar <[email protected]>

This patch series adds WOWLAN support for system's S3, S4 and
S5 power states. wakeup through magic packet has been verified
in these power states.

Changes since v2:
Rebased the patch series to the latest code. Recently below patch
got accepted which causes some conflicts.
"drivers/wireless: rsi: Convert timers to use timer_setup()"

Changes since v1:
1/3 Get rid of CONFIG_RSI_WOW compiler flag (Kalle Valo)
2/3 Use ieee80211_restart_hw() instead of re-registering with mac80211 (Kalle Valo/Brian Norris)
3/3 Get rid of CONFIG_RSI_WOW compiler flag

Karun Eagalapati (3):
rsi: sdio: add WOWLAN support for S3 suspend state
rsi: sdio: Add WOWLAN support for S4 hibernate state
rsi: sdio: Add WOWLAN support for S5 shutdown state

drivers/net/wireless/rsi/rsi_91x_core.c | 8 ++
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 128 +++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_main.c | 1 +
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 67 +++++++++++--
drivers/net/wireless/rsi/rsi_91x_sdio.c | 141 ++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_common.h | 1 +
drivers/net/wireless/rsi/rsi_main.h | 12 ++-
drivers/net/wireless/rsi/rsi_mgmt.h | 31 +++++-
drivers/net/wireless/rsi/rsi_sdio.h | 1 +
9 files changed, 378 insertions(+), 12 deletions(-)

--
2.7.4


2017-10-31 18:05:43

by Amitkumar Karwar

[permalink] [raw]
Subject: Re: [v3,1/3] rsi: sdio: add WOWLAN support for S3 suspend state

On Tue, Oct 31, 2017 at 8:54 PM, Kalle Valo <[email protected]> wrote:
> Kalle Valo <[email protected]> writes:
>
>> Amitkumar Karwar <[email protected]> wrote:
>>
>>> From: Karun Eagalapati <[email protected]>
>>>
>>> WoWLAN is supported in RS9113 device through GPIO pin2.
>>> wowlan config frame is internally sent to firmware in mac80211
>>> suspend handler. Also beacon miss threshold and keep-alive time
>>> values are increased to avoid un-necessary disconnection with AP.
>>>
>>> Signed-off-by: Karun Eagalapati <[email protected]>
>>> Signed-off-by: Amitkumar Karwar <[email protected]>
>>
>> 3 patches applied to wireless-drivers-next.git, thanks.
>>
>> f3ac4e7394a1 rsi: sdio: add WOWLAN support for S3 suspend state
>> b6c8d06c8a64 rsi: sdio: Add WOWLAN support for S4 hibernate state
>> 063848c3e155 rsi: sdio: Add WOWLAN support for S5 shutdown state
>
> Kbuild bot found build problems with the first patch. (Amit should have
> the details in the mail from kbuild bot.) I need a fix by tomorrow
> (wednesday) or I need to revert these. Otherwise I cannot submit a pull
> request to Dave.
>

I'll submit a fix for this by tomorrow.

Regards,
Amit

2017-10-31 15:24:04

by Kalle Valo

[permalink] [raw]
Subject: Re: [v3,1/3] rsi: sdio: add WOWLAN support for S3 suspend state

Kalle Valo <[email protected]> writes:

> Amitkumar Karwar <[email protected]> wrote:
>
>> From: Karun Eagalapati <[email protected]>
>>
>> WoWLAN is supported in RS9113 device through GPIO pin2.
>> wowlan config frame is internally sent to firmware in mac80211
>> suspend handler. Also beacon miss threshold and keep-alive time
>> values are increased to avoid un-necessary disconnection with AP.
>>
>> Signed-off-by: Karun Eagalapati <[email protected]>
>> Signed-off-by: Amitkumar Karwar <[email protected]>
>
> 3 patches applied to wireless-drivers-next.git, thanks.
>
> f3ac4e7394a1 rsi: sdio: add WOWLAN support for S3 suspend state
> b6c8d06c8a64 rsi: sdio: Add WOWLAN support for S4 hibernate state
> 063848c3e155 rsi: sdio: Add WOWLAN support for S5 shutdown state

Kbuild bot found build problems with the first patch. (Amit should have
the details in the mail from kbuild bot.) I need a fix by tomorrow
(wednesday) or I need to revert these. Otherwise I cannot submit a pull
request to Dave.

drivers/net/wireless/rsi/rsi_91x_mac80211.c: In function
'rsi_wow_map_triggers':
>> drivers/net/wireless/rsi/rsi_91x_mac80211.c:1767:19: error:
>> 'RSI_WOW_ANY' undeclared (first use in this function)
wow_triggers |= RSI_WOW_ANY;
^~~~~~~~~~~
drivers/net/wireless/rsi/rsi_91x_mac80211.c:1767:19: note: each
undeclared identifier is reported only once for each function it
appears in
>> drivers/net/wireless/rsi/rsi_91x_mac80211.c:1769:19: error:
>> 'RSI_WOW_MAGIC_PKT' undeclared (first use in this function)
wow_triggers |= RSI_WOW_MAGIC_PKT;
^~~~~~~~~~~~~~~~~
>> drivers/net/wireless/rsi/rsi_91x_mac80211.c:1771:19: error:
>> 'RSI_WOW_DISCONNECT' undeclared (first use in this function)
wow_triggers |= RSI_WOW_DISCONNECT;
^~~~~~~~~~~~~~~~~~
>> drivers/net/wireless/rsi/rsi_91x_mac80211.c:1774:19: error:
>> 'RSI_WOW_GTK_REKEY' undeclared (first use in this function)
wow_triggers |= RSI_WOW_GTK_REKEY;
^~~~~~~~~~~~~~~~~
drivers/net/wireless/rsi/rsi_91x_mac80211.c: In function
'rsi_mac80211_attach':
>> drivers/net/wireless/rsi/rsi_91x_mac80211.c:1970:7: error: 'struct
>> wiphy' has no member named 'wowlan'
wiphy->wowlan = &rsi_wowlan_support;
^~
drivers/net/wireless/rsi/rsi_91x_mgmt.c: In function
'rsi_send_wowlan_request':
>> drivers/net/wireless/rsi/rsi_91x_mgmt.c:1623:12: error:
'RSI_WOW_GTK_REKEY' undeclared (first use in this function)
flags |= RSI_WOW_GTK_REKEY;
^~~~~~~~~~~~~~~~~
drivers/net/wireless/rsi/rsi_91x_mgmt.c:1623:12: note: each
undeclared identifier is reported only once for each function it
appears in


--
Kalle Valo

2017-10-27 11:32:59

by Amitkumar Karwar

[permalink] [raw]
Subject: [v3 1/3] rsi: sdio: add WOWLAN support for S3 suspend state

From: Karun Eagalapati <[email protected]>

WoWLAN is supported in RS9113 device through GPIO pin2.
wowlan config frame is internally sent to firmware in mac80211
suspend handler. Also beacon miss threshold and keep-alive time
values are increased to avoid un-necessary disconnection with AP.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_core.c | 6 ++
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 118 ++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 60 +++++++++++---
drivers/net/wireless/rsi/rsi_91x_sdio.c | 7 ++
drivers/net/wireless/rsi/rsi_common.h | 1 +
drivers/net/wireless/rsi/rsi_main.h | 8 +-
drivers/net/wireless/rsi/rsi_mgmt.h | 31 +++++++-
7 files changed, 220 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
index bc18a19..87e023d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_core.c
+++ b/drivers/net/wireless/rsi/rsi_91x_core.c
@@ -379,6 +379,12 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__);
goto xmit_fail;
}
+ if (common->wow_flags & RSI_WOW_ENABLED) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Blocking Tx_packets when WOWLAN is enabled\n",
+ __func__);
+ goto xmit_fail;
+ }

info = IEEE80211_SKB_CB(skb);
tx_params = (struct skb_info *)info->driver_data;
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 9427c9d..c3bd3ca 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1746,6 +1746,119 @@ static int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw)
return 0;
}

+static const struct wiphy_wowlan_support rsi_wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY |
+ WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE |
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+ WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+ WIPHY_WOWLAN_4WAY_HANDSHAKE,
+};
+
+static u16 rsi_wow_map_triggers(struct rsi_common *common,
+ struct cfg80211_wowlan *wowlan)
+{
+ u16 wow_triggers = 0;
+
+ rsi_dbg(INFO_ZONE, "Mapping wowlan triggers\n");
+
+ if (wowlan->any)
+ wow_triggers |= RSI_WOW_ANY;
+ if (wowlan->magic_pkt)
+ wow_triggers |= RSI_WOW_MAGIC_PKT;
+ if (wowlan->disconnect)
+ wow_triggers |= RSI_WOW_DISCONNECT;
+ if (wowlan->gtk_rekey_failure || wowlan->eap_identity_req ||
+ wowlan->four_way_handshake)
+ wow_triggers |= RSI_WOW_GTK_REKEY;
+
+ return wow_triggers;
+}
+
+int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan)
+{
+ struct rsi_common *common = adapter->priv;
+ u16 triggers = 0;
+ u16 rx_filter_word = 0;
+ struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf;
+
+ rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n");
+
+ if (WARN_ON(!wowlan)) {
+ rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n");
+ return -EINVAL;
+ }
+
+ triggers = rsi_wow_map_triggers(common, wowlan);
+ if (!triggers) {
+ rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__);
+ return -EINVAL;
+ }
+ if (!bss->assoc) {
+ rsi_dbg(ERR_ZONE,
+ "Cannot configure WoWLAN (Station not connected)\n");
+ common->wow_flags |= RSI_WOW_NO_CONNECTION;
+ return 0;
+ }
+ rsi_dbg(INFO_ZONE, "TRIGGERS %x\n", triggers);
+ rsi_send_wowlan_request(common, triggers, 1);
+
+ /**
+ * Increase the beacon_miss threshold & keep-alive timers in
+ * vap_update frame
+ */
+ rsi_send_vap_dynamic_update(common);
+
+ rx_filter_word = (ALLOW_DATA_ASSOC_PEER | DISALLOW_BEACONS);
+ rsi_send_rx_filter_frame(common, rx_filter_word);
+ common->wow_flags |= RSI_WOW_ENABLED;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rsi_mac80211_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ rsi_dbg(INFO_ZONE, "%s: mac80211 suspend\n", __func__);
+ mutex_lock(&common->mutex);
+ if (rsi_config_wowlan(adapter, wowlan)) {
+ rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n");
+ mutex_unlock(&common->mutex);
+ return 1;
+ }
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+static int rsi_mac80211_resume(struct ieee80211_hw *hw)
+{
+ u16 rx_filter_word = 0;
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ common->wow_flags = 0;
+
+ rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__);
+
+ mutex_lock(&common->mutex);
+ rsi_send_wowlan_request(common, 0, 0);
+
+ rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER |
+ ALLOW_MGMT_ASSOC_PEER);
+ rsi_send_rx_filter_frame(common, rx_filter_word);
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+#endif
+
static const struct ieee80211_ops mac80211_ops = {
.tx = rsi_mac80211_tx,
.start = rsi_mac80211_start,
@@ -1767,6 +1880,10 @@ static const struct ieee80211_ops mac80211_ops = {
.rfkill_poll = rsi_mac80211_rfkill_poll,
.remain_on_channel = rsi_mac80211_roc,
.cancel_remain_on_channel = rsi_mac80211_cancel_roc,
+#ifdef CONFIG_PM
+ .suspend = rsi_mac80211_suspend,
+ .resume = rsi_mac80211_resume,
+#endif
};

/**
@@ -1850,6 +1967,7 @@ int rsi_mac80211_attach(struct rsi_common *common)
wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
wiphy->reg_notifier = rsi_reg_notify;

+ wiphy->wowlan = &rsi_wowlan_support;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);

/* Wi-Fi direct parameters */
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 4b94190..1446ee3 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1094,9 +1094,18 @@ int rsi_send_vap_dynamic_update(struct rsi_common *common)
dynamic_frame->desc_dword0.frame_type = VAP_DYNAMIC_UPDATE;
dynamic_frame->desc_dword2.pkt_info =
cpu_to_le32(common->rts_threshold);
- /* Beacon miss threshold */
- dynamic_frame->frame_body.keep_alive_period =
+
+ if (common->wow_flags & RSI_WOW_ENABLED) {
+ /* Beacon miss threshold */
+ dynamic_frame->desc_dword3.token =
+ cpu_to_le16(RSI_BCN_MISS_THRESHOLD);
+ dynamic_frame->frame_body.keep_alive_period =
+ cpu_to_le16(RSI_WOW_KEEPALIVE);
+ } else {
+ dynamic_frame->frame_body.keep_alive_period =
cpu_to_le16(RSI_DEF_KEEPALIVE);
+ }
+
dynamic_frame->desc_dword3.sta_id = 0; /* vap id */

skb_put(skb, sizeof(struct rsi_dynamic_s));
@@ -1340,13 +1349,12 @@ void rsi_inform_bss_status(struct rsi_common *common,
} else {
if (opmode == RSI_OPMODE_STA)
common->hw_data_qs_blocked = true;
- rsi_hal_send_sta_notify_frame(common,
- opmode,
- STA_DISCONNECTED,
- addr,
- qos_enable,
- aid, sta_id,
- vif);
+
+ if (!(common->wow_flags & RSI_WOW_ENABLED))
+ rsi_hal_send_sta_notify_frame(common, opmode,
+ STA_DISCONNECTED, addr,
+ qos_enable, aid, sta_id,
+ vif);
if (opmode == RSI_OPMODE_STA)
rsi_send_block_unblock_frame(common, true);
}
@@ -1589,6 +1597,40 @@ static int rsi_send_beacon(struct rsi_common *common)
return 0;
}

+int rsi_send_wowlan_request(struct rsi_common *common, u16 flags,
+ u16 sleep_status)
+{
+ struct rsi_wowlan_req *cmd_frame;
+ struct sk_buff *skb;
+ u8 length;
+
+ rsi_dbg(ERR_ZONE, "%s: Sending wowlan request frame\n", __func__);
+
+ length = sizeof(*cmd_frame);
+ skb = dev_alloc_skb(length);
+ if (!skb)
+ return -ENOMEM;
+ memset(skb->data, 0, length);
+ cmd_frame = (struct rsi_wowlan_req *)skb->data;
+
+ rsi_set_len_qno(&cmd_frame->desc.desc_dword0.len_qno,
+ (length - FRAME_DESC_SZ),
+ RSI_WIFI_MGMT_Q);
+ cmd_frame->desc.desc_dword0.frame_type = WOWLAN_CONFIG_PARAMS;
+ cmd_frame->host_sleep_status = sleep_status;
+ if (common->secinfo.security_enable &&
+ common->secinfo.gtk_cipher)
+ flags |= RSI_WOW_GTK_REKEY;
+ if (sleep_status)
+ cmd_frame->wow_flags = flags;
+ rsi_dbg(INFO_ZONE, "Host_Sleep_Status : %d Flags : %d\n",
+ cmd_frame->host_sleep_status, cmd_frame->wow_flags);
+
+ skb_put(skb, length);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
/**
* rsi_handle_ta_confirm_type() - This function handles the confirm frames.
* @common: Pointer to the driver private structure.
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index b3f8006..fa6af7b 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -1124,6 +1124,8 @@ static int rsi_sdio_enable_interrupts(struct sdio_func *pfunc)
{
u8 data;
int ret;
+ struct rsi_hw *adapter = sdio_get_drvdata(pfunc);
+ struct rsi_common *common = adapter->priv;

sdio_claim_host(pfunc);
ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data);
@@ -1143,6 +1145,11 @@ static int rsi_sdio_enable_interrupts(struct sdio_func *pfunc)
goto done;
}

+ 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");
+
ret = rsi_cmd52readbyte(pfunc->card, RSI_INT_ENABLE_REGISTER, &data);
if (ret < 0) {
rsi_dbg(ERR_ZONE,
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 29acaea..70b8b4b 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -83,6 +83,7 @@ u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
struct rsi_hw *rsi_91x_init(void);
void rsi_91x_deinit(struct rsi_hw *adapter);
int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len);
+int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan);
struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr);
struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac);
void rsi_roc_timeout(struct timer_list *t);
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index a118b7a..44a199f 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -66,6 +66,8 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define FRAME_DESC_SZ 16
#define MIN_802_11_HDR_LEN 24
#define RSI_DEF_KEEPALIVE 90
+#define RSI_WOW_KEEPALIVE 5
+#define RSI_BCN_MISS_THRESHOLD 24

#define DATA_QUEUE_WATER_MARK 400
#define MIN_DATA_QUEUE_WATER_MARK 300
@@ -108,6 +110,10 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
((_q) == VI_Q) ? IEEE80211_AC_VI : \
IEEE80211_AC_VO)

+/* WoWLAN flags */
+#define RSI_WOW_ENABLED BIT(0)
+#define RSI_WOW_NO_CONNECTION BIT(1)
+
#define RSI_DEV_9113 1

struct version_info {
@@ -266,7 +272,7 @@ struct rsi_common {
u8 obm_ant_sel_val;
int tx_power;
u8 ant_in_use;
-
+ u8 wow_flags;
u16 beacon_interval;
u8 dtim_cnt;

diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index e217230..76337ce 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -45,6 +45,17 @@
#define MAGIC_WORD 0x5A
#define WLAN_EEPROM_RFTYPE_ADDR 424

+/*WOWLAN RESUME WAKEUP TYPES*/
+#define RSI_UNICAST_MAGIC_PKT BIT(0)
+#define RSI_BROADCAST_MAGICPKT BIT(1)
+#define RSI_EAPOL_PKT BIT(2)
+#define RSI_DISCONNECT_PKT BIT(3)
+#define RSI_HW_BMISS_PKT BIT(4)
+#define RSI_INSERT_SEQ_IN_FW BIT(2)
+
+#define WOW_MAX_FILTERS_PER_LIST 16
+#define WOW_PATTERN_SIZE 256
+
/* Receive Frame Types */
#define TA_CONFIRM_TYPE 0x01
#define RX_DOT11_MGMT 0x02
@@ -201,6 +212,13 @@
#define RSI_DATA_DESC_INSERT_TSF BIT(15)
#define RSI_DATA_DESC_INSERT_SEQ_NO BIT(2)

+#ifdef CONFIG_PM
+#define RSI_WOW_ANY BIT(1)
+#define RSI_WOW_GTK_REKEY BIT(3)
+#define RSI_WOW_MAGIC_PKT BIT(4)
+#define RSI_WOW_DISCONNECT BIT(5)
+#endif
+
enum opmode {
RSI_OPMODE_UNSUPPORTED = -1,
RSI_OPMODE_AP = 0,
@@ -262,7 +280,9 @@ enum cmd_frame_type {
ANT_SEL_FRAME = 0x20,
VAP_DYNAMIC_UPDATE = 0x27,
COMMON_DEV_CONFIG = 0x28,
- RADIO_PARAMS_UPDATE = 0x29
+ RADIO_PARAMS_UPDATE = 0x29,
+ WOWLAN_CONFIG_PARAMS = 0x2B,
+ WOWLAN_WAKEUP_REASON = 0xc5
};

struct rsi_mac_frame {
@@ -581,6 +601,13 @@ struct rsi_request_ps {
__le16 ps_num_dtim_intervals;
} __packed;

+struct rsi_wowlan_req {
+ struct rsi_cmd_desc desc;
+ u8 sourceid[ETH_ALEN];
+ u16 wow_flags;
+ u16 host_sleep_status;
+} __packed;
+
static inline u32 rsi_get_queueno(u8 *addr, u16 offset)
{
return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12;
@@ -641,6 +668,8 @@ int rsi_band_check(struct rsi_common *common, struct ieee80211_channel *chan);
int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word);
int rsi_send_radio_params_update(struct rsi_common *common);
int rsi_set_antenna(struct rsi_common *common, u8 antenna);
+int rsi_send_wowlan_request(struct rsi_common *common, u16 flags,
+ u16 sleep_status);
int rsi_send_ps_request(struct rsi_hw *adapter, bool enable,
struct ieee80211_vif *vif);
#endif
--
2.7.4

2017-10-27 11:33:06

by Amitkumar Karwar

[permalink] [raw]
Subject: [v3 2/3] rsi: sdio: Add WOWLAN support for S4 hibernate state

From: Karun Eagalapati <[email protected]>

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 <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_core.c | 2 +
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 9 +++
drivers/net/wireless/rsi/rsi_91x_main.c | 1 +
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 7 +-
drivers/net/wireless/rsi/rsi_91x_sdio.c | 111 ++++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_main.h | 4 +
drivers/net/wireless/rsi/rsi_sdio.h | 1 +
7 files changed, 134 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
index 87e023d..d0d2201 100644
--- a/drivers/net/wireless/rsi/rsi_91x_core.c
+++ b/drivers/net/wireless/rsi/rsi_91x_core.c
@@ -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);

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index c3bd3ca..95eb5e6 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -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);

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 2a1fbb7..0cb8e68 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -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;

diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 1446ee3..d38a09f 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -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);
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index fa6af7b..3f683d8 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -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

diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 44a199f..8cab630 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -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
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index 49c549b..8fbf90e 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -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
--
2.7.4

2017-10-30 10:50:50

by Kalle Valo

[permalink] [raw]
Subject: Re: [v3,1/3] rsi: sdio: add WOWLAN support for S3 suspend state

Amitkumar Karwar <[email protected]> wrote:

> From: Karun Eagalapati <[email protected]>
>
> WoWLAN is supported in RS9113 device through GPIO pin2.
> wowlan config frame is internally sent to firmware in mac80211
> suspend handler. Also beacon miss threshold and keep-alive time
> values are increased to avoid un-necessary disconnection with AP.
>
> Signed-off-by: Karun Eagalapati <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>

3 patches applied to wireless-drivers-next.git, thanks.

f3ac4e7394a1 rsi: sdio: add WOWLAN support for S3 suspend state
b6c8d06c8a64 rsi: sdio: Add WOWLAN support for S4 hibernate state
063848c3e155 rsi: sdio: Add WOWLAN support for S5 shutdown state

--
https://patchwork.kernel.org/patch/10029671/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-10-27 11:33:13

by Amitkumar Karwar

[permalink] [raw]
Subject: [v3 3/3] rsi: sdio: Add WOWLAN support for S5 shutdown state

From: Karun Eagalapati <[email protected]>

Unlike other power states, WoWLAN configuration does not come from
mac80211 for shutdown. Hence configuring the WoWLAN from shut down
callback it self. Remaining steps of disabling SDIO interrupts,
setting 'MMC_PM_KEEP_POWER' flag are same as other power states.

Signed-off-by: Karun Eagalapati <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1 +
drivers/net/wireless/rsi/rsi_91x_sdio.c | 31 +++++++++++++++++++++++++----
2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 95eb5e6..36c63e9 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1822,6 +1822,7 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan)

return 0;
}
+EXPORT_SYMBOL(rsi_config_wowlan);

#ifdef CONFIG_PM
static int rsi_mac80211_suspend(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 3f683d8..3288fb6 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -1218,12 +1218,11 @@ static int rsi_freeze(struct device *dev)
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)
@@ -1257,6 +1256,31 @@ static int rsi_thaw(struct device *dev)
return 0;
}

+static void rsi_shutdown(struct device *dev)
+{
+ struct sdio_func *pfunction = dev_to_sdio_func(dev);
+ struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
+ struct rsi_91x_sdiodev *sdev =
+ (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct ieee80211_hw *hw = adapter->hw;
+ struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;
+
+ rsi_dbg(ERR_ZONE, "SDIO Bus shutdown =====>\n");
+
+ if (rsi_config_wowlan(adapter, wowlan))
+ rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n");
+
+ rsi_sdio_disable_interrupts(sdev->pfunction);
+
+ if (sdev->write_fail)
+ rsi_dbg(INFO_ZONE, "###### Device is not ready #######\n");
+
+ if (rsi_set_sdio_pm_caps(adapter))
+ rsi_dbg(INFO_ZONE, "Setting power management caps failed\n");
+
+ rsi_dbg(INFO_ZONE, "***** RSI module shut down *****\n");
+}
+
int rsi_sdio_reinit_device(struct rsi_hw *adapter)
{
struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
@@ -1297,9 +1321,7 @@ static int rsi_restore(struct device *dev)
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");
@@ -1331,6 +1353,7 @@ static struct sdio_driver rsi_driver = {
#ifdef CONFIG_PM
.drv = {
.pm = &rsi_pm_ops,
+ .shutdown = rsi_shutdown,
}
#endif
};
--
2.7.4