wlcore: add ability to reduce FW interrupts during suspend
Add the ability to mask FW interrupts on RX BA activity, PSM entry/exit and fast-link notifications. This is used when the host is suspended in order to decrease redundant wake ups. Signed-off-by: Ram Amrani <ramrani@ti.com> Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
		
					parent
					
						
							
								7d3b29e5c8
							
						
					
				
			
			
				commit
				
					
						6d5a748d48
					
				
			
		
					 8 changed files with 155 additions and 25 deletions
				
			
		| 
						 | 
					@ -250,6 +250,7 @@ static struct wlcore_conf wl12xx_conf = {
 | 
				
			||||||
		.keep_alive_interval         = 55000,
 | 
							.keep_alive_interval         = 55000,
 | 
				
			||||||
		.max_listen_interval         = 20,
 | 
							.max_listen_interval         = 20,
 | 
				
			||||||
		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
 | 
							.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
 | 
				
			||||||
 | 
							.suspend_rx_ba_activity      = 0,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.itrim = {
 | 
						.itrim = {
 | 
				
			||||||
		.enable = false,
 | 
							.enable = false,
 | 
				
			||||||
| 
						 | 
					@ -1728,6 +1729,8 @@ static struct wlcore_ops wl12xx_ops = {
 | 
				
			||||||
	.convert_hwaddr		= wl12xx_convert_hwaddr,
 | 
						.convert_hwaddr		= wl12xx_convert_hwaddr,
 | 
				
			||||||
	.lnk_high_prio		= wl12xx_lnk_high_prio,
 | 
						.lnk_high_prio		= wl12xx_lnk_high_prio,
 | 
				
			||||||
	.lnk_low_prio		= wl12xx_lnk_low_prio,
 | 
						.lnk_low_prio		= wl12xx_lnk_low_prio,
 | 
				
			||||||
 | 
						.interrupt_notify	= NULL,
 | 
				
			||||||
 | 
						.rx_ba_filter		= NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 | 
					static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,3 +194,59 @@ out:
 | 
				
			||||||
	kfree(acx);
 | 
						kfree(acx);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * When the host is suspended, we don't want to get any fast-link/PSM
 | 
				
			||||||
 | 
					 * notifications
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
 | 
				
			||||||
 | 
									       bool action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wl18xx_acx_interrupt_notify *acx;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acx = kzalloc(sizeof(*acx), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!acx) {
 | 
				
			||||||
 | 
							ret = -ENOMEM;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acx->enable = action;
 | 
				
			||||||
 | 
						ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							wl1271_warning("acx interrupt notify setting failed: %d", ret);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						kfree(acx);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * When the host is suspended, we can configure the FW to disable RX BA
 | 
				
			||||||
 | 
					 * notifications.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wl18xx_acx_rx_ba_filter *acx;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acx = kzalloc(sizeof(*acx), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!acx) {
 | 
				
			||||||
 | 
							ret = -ENOMEM;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acx->enable = (u32)action;
 | 
				
			||||||
 | 
						ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							wl1271_warning("acx rx ba activity filter setting failed: %d",
 | 
				
			||||||
 | 
								       ret);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						kfree(acx);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,10 @@ enum {
 | 
				
			||||||
	ACX_SIM_CONFIG			 = 0x0053,
 | 
						ACX_SIM_CONFIG			 = 0x0053,
 | 
				
			||||||
	ACX_CLEAR_STATISTICS		 = 0x0054,
 | 
						ACX_CLEAR_STATISTICS		 = 0x0054,
 | 
				
			||||||
	ACX_AUTO_RX_STREAMING		 = 0x0055,
 | 
						ACX_AUTO_RX_STREAMING		 = 0x0055,
 | 
				
			||||||
	ACX_PEER_CAP			 = 0x0056
 | 
						ACX_PEER_CAP			 = 0x0056,
 | 
				
			||||||
 | 
						ACX_INTERRUPT_NOTIFY		 = 0x0057,
 | 
				
			||||||
 | 
						ACX_RX_BA_FILTER		 = 0x0058
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* numbers of bits the length field takes (add 1 for the actual number) */
 | 
					/* numbers of bits the length field takes (add 1 for the actual number) */
 | 
				
			||||||
| 
						 | 
					@ -326,6 +329,24 @@ struct wlcore_acx_peer_cap {
 | 
				
			||||||
	u8 padding;
 | 
						u8 padding;
 | 
				
			||||||
} __packed;
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ACX_INTERRUPT_NOTIFY
 | 
				
			||||||
 | 
					 * enable/disable fast-link/PSM notification from FW
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wl18xx_acx_interrupt_notify {
 | 
				
			||||||
 | 
						struct acx_header header;
 | 
				
			||||||
 | 
						u32 enable;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ACX_RX_BA_FILTER
 | 
				
			||||||
 | 
					 * enable/disable RX BA filtering in FW
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct wl18xx_acx_rx_ba_filter {
 | 
				
			||||||
 | 
						struct acx_header header;
 | 
				
			||||||
 | 
						u32 enable;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
 | 
					int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
 | 
				
			||||||
				  u32 sdio_blk_size, u32 extra_mem_blks,
 | 
									  u32 sdio_blk_size, u32 extra_mem_blks,
 | 
				
			||||||
				  u32 len_field_size);
 | 
									  u32 len_field_size);
 | 
				
			||||||
| 
						 | 
					@ -336,5 +357,7 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
 | 
				
			||||||
			    struct ieee80211_sta_ht_cap *ht_cap,
 | 
								    struct ieee80211_sta_ht_cap *ht_cap,
 | 
				
			||||||
			    bool allow_ht_operation,
 | 
								    bool allow_ht_operation,
 | 
				
			||||||
			    u32 rate_set, u8 hlid);
 | 
								    u32 rate_set, u8 hlid);
 | 
				
			||||||
 | 
					int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);
 | 
				
			||||||
 | 
					int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __WL18XX_ACX_H__ */
 | 
					#endif /* __WL18XX_ACX_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -378,6 +378,7 @@ static struct wlcore_conf wl18xx_conf = {
 | 
				
			||||||
		.keep_alive_interval         = 55000,
 | 
							.keep_alive_interval         = 55000,
 | 
				
			||||||
		.max_listen_interval         = 20,
 | 
							.max_listen_interval         = 20,
 | 
				
			||||||
		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
 | 
							.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
 | 
				
			||||||
 | 
							.suspend_rx_ba_activity      = 0,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.itrim = {
 | 
						.itrim = {
 | 
				
			||||||
		.enable = false,
 | 
							.enable = false,
 | 
				
			||||||
| 
						 | 
					@ -1693,6 +1694,8 @@ static struct wlcore_ops wl18xx_ops = {
 | 
				
			||||||
	.smart_config_start = wl18xx_cmd_smart_config_start,
 | 
						.smart_config_start = wl18xx_cmd_smart_config_start,
 | 
				
			||||||
	.smart_config_stop  = wl18xx_cmd_smart_config_stop,
 | 
						.smart_config_stop  = wl18xx_cmd_smart_config_stop,
 | 
				
			||||||
	.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
 | 
						.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
 | 
				
			||||||
 | 
						.interrupt_notify = wl18xx_acx_interrupt_notify_config,
 | 
				
			||||||
 | 
						.rx_ba_filter	= wl18xx_acx_rx_ba_filter,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* HT cap appropriate for wide channels in 2Ghz */
 | 
					/* HT cap appropriate for wide channels in 2Ghz */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -997,6 +997,11 @@ struct conf_conn_settings {
 | 
				
			||||||
	 * whether we can go to ELP.
 | 
						 * whether we can go to ELP.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	u8 sta_sleep_auth;
 | 
						u8 sta_sleep_auth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Default RX BA Activity filter configuration
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						u8 suspend_rx_ba_activity;
 | 
				
			||||||
} __packed;
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
| 
						 | 
					@ -1347,7 +1352,7 @@ struct conf_recovery_settings {
 | 
				
			||||||
 * version, the two LSB are the lower driver's private conf
 | 
					 * version, the two LSB are the lower driver's private conf
 | 
				
			||||||
 * version.
 | 
					 * version.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define WLCORE_CONF_VERSION	(0x0005 << 16)
 | 
					#define WLCORE_CONF_VERSION	(0x0006 << 16)
 | 
				
			||||||
#define WLCORE_CONF_MASK	0xffff0000
 | 
					#define WLCORE_CONF_MASK	0xffff0000
 | 
				
			||||||
#define WLCORE_CONF_SIZE	(sizeof(struct wlcore_conf_header) +	\
 | 
					#define WLCORE_CONF_SIZE	(sizeof(struct wlcore_conf_header) +	\
 | 
				
			||||||
				 sizeof(struct wlcore_conf))
 | 
									 sizeof(struct wlcore_conf))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,6 +217,22 @@ wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 | 
				
			||||||
		wl->ops->sta_rc_update(wl, wlvif);
 | 
							wl->ops->sta_rc_update(wl, wlvif);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					wlcore_hw_interrupt_notify(struct wl1271 *wl, bool action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (wl->ops->interrupt_notify)
 | 
				
			||||||
 | 
							return wl->ops->interrupt_notify(wl, action);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (wl->ops->rx_ba_filter)
 | 
				
			||||||
 | 
							return wl->ops->rx_ba_filter(wl, action);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static inline int
 | 
				
			||||||
wlcore_hw_set_peer_cap(struct wl1271 *wl,
 | 
					wlcore_hw_set_peer_cap(struct wl1271 *wl,
 | 
				
			||||||
		       struct ieee80211_sta_ht_cap *ht_cap,
 | 
							       struct ieee80211_sta_ht_cap *ht_cap,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1685,19 +1685,15 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
 | 
				
			||||||
	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 | 
						if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = wl1271_ps_elp_wakeup(wl);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = wl1271_configure_wowlan(wl, wow);
 | 
						ret = wl1271_configure_wowlan(wl, wow);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto out_sleep;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((wl->conf.conn.suspend_wake_up_event ==
 | 
						if ((wl->conf.conn.suspend_wake_up_event ==
 | 
				
			||||||
	     wl->conf.conn.wake_up_event) &&
 | 
						     wl->conf.conn.wake_up_event) &&
 | 
				
			||||||
	    (wl->conf.conn.suspend_listen_interval ==
 | 
						    (wl->conf.conn.suspend_listen_interval ==
 | 
				
			||||||
	     wl->conf.conn.listen_interval))
 | 
						     wl->conf.conn.listen_interval))
 | 
				
			||||||
		goto out_sleep;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 | 
						ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 | 
				
			||||||
				    wl->conf.conn.suspend_wake_up_event,
 | 
									    wl->conf.conn.suspend_wake_up_event,
 | 
				
			||||||
| 
						 | 
					@ -1705,9 +1701,6 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		wl1271_error("suspend: set wake up conditions failed: %d", ret);
 | 
							wl1271_error("suspend: set wake up conditions failed: %d", ret);
 | 
				
			||||||
 | 
					 | 
				
			||||||
out_sleep:
 | 
					 | 
				
			||||||
	wl1271_ps_elp_sleep(wl);
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1721,13 +1714,8 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
 | 
				
			||||||
	if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
 | 
						if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = wl1271_ps_elp_wakeup(wl);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
 | 
						ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl1271_ps_elp_sleep(wl);
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1756,10 +1744,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 | 
				
			||||||
	if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 | 
						if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = wl1271_ps_elp_wakeup(wl);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (is_sta) {
 | 
						if (is_sta) {
 | 
				
			||||||
		wl1271_configure_wowlan(wl, NULL);
 | 
							wl1271_configure_wowlan(wl, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1767,7 +1751,7 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 | 
				
			||||||
		     wl->conf.conn.wake_up_event) &&
 | 
							     wl->conf.conn.wake_up_event) &&
 | 
				
			||||||
		    (wl->conf.conn.suspend_listen_interval ==
 | 
							    (wl->conf.conn.suspend_listen_interval ==
 | 
				
			||||||
		     wl->conf.conn.listen_interval))
 | 
							     wl->conf.conn.listen_interval))
 | 
				
			||||||
			goto out_sleep;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 | 
							ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 | 
				
			||||||
				    wl->conf.conn.wake_up_event,
 | 
									    wl->conf.conn.wake_up_event,
 | 
				
			||||||
| 
						 | 
					@ -1780,9 +1764,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 | 
				
			||||||
	} else if (is_ap) {
 | 
						} else if (is_ap) {
 | 
				
			||||||
		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
 | 
							ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
out_sleep:
 | 
					 | 
				
			||||||
	wl1271_ps_elp_sleep(wl);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int wl1271_op_suspend(struct ieee80211_hw *hw,
 | 
					static int wl1271_op_suspend(struct ieee80211_hw *hw,
 | 
				
			||||||
| 
						 | 
					@ -1804,6 +1785,11 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 | 
				
			||||||
	wl1271_tx_flush(wl);
 | 
						wl1271_tx_flush(wl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&wl->mutex);
 | 
						mutex_lock(&wl->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = wl1271_ps_elp_wakeup(wl);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl->wow_enabled = true;
 | 
						wl->wow_enabled = true;
 | 
				
			||||||
	wl12xx_for_each_wlvif(wl, wlvif) {
 | 
						wl12xx_for_each_wlvif(wl, wlvif) {
 | 
				
			||||||
		ret = wl1271_configure_suspend(wl, wlvif, wow);
 | 
							ret = wl1271_configure_suspend(wl, wlvif, wow);
 | 
				
			||||||
| 
						 | 
					@ -1813,7 +1799,27 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* disable fast link flow control notifications from FW */
 | 
				
			||||||
 | 
						ret = wlcore_hw_interrupt_notify(wl, false);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out_sleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if filtering is enabled, configure the FW to drop all RX BA frames */
 | 
				
			||||||
 | 
						ret = wlcore_hw_rx_ba_filter(wl,
 | 
				
			||||||
 | 
									     !!wl->conf.conn.suspend_rx_ba_activity);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out_sleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_sleep:
 | 
				
			||||||
 | 
						wl1271_ps_elp_sleep(wl);
 | 
				
			||||||
	mutex_unlock(&wl->mutex);
 | 
						mutex_unlock(&wl->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							wl1271_warning("couldn't prepare device to suspend");
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* flush any remaining work */
 | 
						/* flush any remaining work */
 | 
				
			||||||
	wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
 | 
						wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1887,13 +1893,29 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
 | 
				
			||||||
	if (pending_recovery) {
 | 
						if (pending_recovery) {
 | 
				
			||||||
		wl1271_warning("queuing forgotten recovery on resume");
 | 
							wl1271_warning("queuing forgotten recovery on resume");
 | 
				
			||||||
		ieee80211_queue_work(wl->hw, &wl->recovery_work);
 | 
							ieee80211_queue_work(wl->hw, &wl->recovery_work);
 | 
				
			||||||
		goto out;
 | 
							goto out_sleep;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = wl1271_ps_elp_wakeup(wl);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl12xx_for_each_wlvif(wl, wlvif) {
 | 
						wl12xx_for_each_wlvif(wl, wlvif) {
 | 
				
			||||||
		wl1271_configure_resume(wl, wlvif);
 | 
							wl1271_configure_resume(wl, wlvif);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = wlcore_hw_interrupt_notify(wl, true);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out_sleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if filtering is enabled, configure the FW to drop all RX BA frames */
 | 
				
			||||||
 | 
						ret = wlcore_hw_rx_ba_filter(wl, false);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out_sleep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_sleep:
 | 
				
			||||||
 | 
						wl1271_ps_elp_sleep(wl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	wl->wow_enabled = false;
 | 
						wl->wow_enabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,8 @@ struct wlcore_ops {
 | 
				
			||||||
			      struct wl1271_link *lnk);
 | 
								      struct wl1271_link *lnk);
 | 
				
			||||||
	bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
 | 
						bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
 | 
				
			||||||
			     struct wl1271_link *lnk);
 | 
								     struct wl1271_link *lnk);
 | 
				
			||||||
 | 
						int (*interrupt_notify)(struct wl1271 *wl, bool action);
 | 
				
			||||||
 | 
						int (*rx_ba_filter)(struct wl1271 *wl, bool action);
 | 
				
			||||||
	int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
 | 
						int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
 | 
				
			||||||
	int (*smart_config_stop)(struct wl1271 *wl);
 | 
						int (*smart_config_stop)(struct wl1271 *wl);
 | 
				
			||||||
	int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
 | 
						int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue