diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/ps.c')
| -rw-r--r-- | drivers/net/wireless/wl12xx/ps.c | 62 | 
1 files changed, 38 insertions, 24 deletions
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index c15ebf2efd40..a2bdacdd7e1d 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -25,6 +25,7 @@  #include "ps.h"  #include "io.h"  #include "tx.h" +#include "debug.h"  #define WL1271_WAKEUP_TIMEOUT 500 @@ -32,6 +33,7 @@ void wl1271_elp_work(struct work_struct *work)  {  	struct delayed_work *dwork;  	struct wl1271 *wl; +	struct wl12xx_vif *wlvif;  	dwork = container_of(work, struct delayed_work, work);  	wl = container_of(dwork, struct wl1271, elp_work); @@ -47,11 +49,18 @@ void wl1271_elp_work(struct work_struct *work)  	if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))  		goto out; -	if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || -	    (!test_bit(WL1271_FLAG_PSM, &wl->flags) && -	     !test_bit(WL1271_FLAG_IDLE, &wl->flags))) +	if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags))  		goto out; +	wl12xx_for_each_wlvif(wl, wlvif) { +		if (wlvif->bss_type == BSS_TYPE_AP_BSS) +			goto out; + +		if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && +		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) +			goto out; +	} +  	wl1271_debug(DEBUG_PSM, "chip to elp");  	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);  	set_bit(WL1271_FLAG_IN_ELP, &wl->flags); @@ -65,13 +74,20 @@ out:  /* Routines to toggle sleep mode while in ELP */  void wl1271_ps_elp_sleep(struct wl1271 *wl)  { +	struct wl12xx_vif *wlvif; +  	/* we shouldn't get consecutive sleep requests */  	if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))  		return; -	if (!test_bit(WL1271_FLAG_PSM, &wl->flags) && -	    !test_bit(WL1271_FLAG_IDLE, &wl->flags)) -		return; +	wl12xx_for_each_wlvif(wl, wlvif) { +		if (wlvif->bss_type == BSS_TYPE_AP_BSS) +			return; + +		if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && +		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) +			return; +	}  	ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,  				     msecs_to_jiffies(ELP_ENTRY_DELAY)); @@ -143,8 +159,8 @@ out:  	return 0;  } -int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, -		       u32 rates, bool send) +int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, +		       enum wl1271_cmd_ps_mode mode, u32 rates, bool send)  {  	int ret; @@ -152,39 +168,34 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,  	case STATION_POWER_SAVE_MODE:  		wl1271_debug(DEBUG_PSM, "entering psm"); -		ret = wl1271_acx_wake_up_conditions(wl); +		ret = wl1271_acx_wake_up_conditions(wl, wlvif);  		if (ret < 0) {  			wl1271_error("couldn't set wake up conditions");  			return ret;  		} -		ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); +		ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);  		if (ret < 0)  			return ret; -		set_bit(WL1271_FLAG_PSM, &wl->flags); +		set_bit(WLVIF_FLAG_PSM, &wlvif->flags);  		break;  	case STATION_ACTIVE_MODE:  	default:  		wl1271_debug(DEBUG_PSM, "leaving psm");  		/* disable beacon early termination */ -		if (wl->band == IEEE80211_BAND_2GHZ) { -			ret = wl1271_acx_bet_enable(wl, false); +		if (wlvif->band == IEEE80211_BAND_2GHZ) { +			ret = wl1271_acx_bet_enable(wl, wlvif, false);  			if (ret < 0)  				return ret;  		} -		/* disable beacon filtering */ -		ret = wl1271_acx_beacon_filter_opt(wl, false); -		if (ret < 0) -			return ret; - -		ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); +		ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);  		if (ret < 0)  			return ret; -		clear_bit(WL1271_FLAG_PSM, &wl->flags); +		clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);  		break;  	} @@ -223,9 +234,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)  	wl1271_handle_tx_low_watermark(wl);  } -void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) +void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			  u8 hlid, bool clean_queues)  {  	struct ieee80211_sta *sta; +	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);  	if (test_bit(hlid, &wl->ap_ps_map))  		return; @@ -235,7 +248,7 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)  		     clean_queues);  	rcu_read_lock(); -	sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); +	sta = ieee80211_find_sta(vif, wl->links[hlid].addr);  	if (!sta) {  		wl1271_error("could not find sta %pM for starting ps",  			     wl->links[hlid].addr); @@ -253,9 +266,10 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)  	__set_bit(hlid, &wl->ap_ps_map);  } -void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid) +void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)  {  	struct ieee80211_sta *sta; +	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);  	if (!test_bit(hlid, &wl->ap_ps_map))  		return; @@ -265,7 +279,7 @@ void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)  	__clear_bit(hlid, &wl->ap_ps_map);  	rcu_read_lock(); -	sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); +	sta = ieee80211_find_sta(vif, wl->links[hlid].addr);  	if (!sta) {  		wl1271_error("could not find sta %pM for ending ps",  			     wl->links[hlid].addr);  |