From owner-svn-src-all@FreeBSD.ORG Thu Apr 24 01:39:54 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 679A3CA4; Thu, 24 Apr 2014 01:39:54 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 47B2011F9; Thu, 24 Apr 2014 01:39:54 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3O1dssW052384; Thu, 24 Apr 2014 01:39:54 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3O1drcg052381; Thu, 24 Apr 2014 01:39:53 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201404240139.s3O1drcg052381@svn.freebsd.org> From: Adrian Chadd Date: Thu, 24 Apr 2014 01:39:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264855 - head/sys/net80211 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Apr 2014 01:39:54 -0000 Author: adrian Date: Thu Apr 24 01:39:53 2014 New Revision: 264855 URL: http://svnweb.freebsd.org/changeset/base/264855 Log: Begin fleshing out support for net80211 provided (legacy) sleep management. This transitions the VAP in and out of SLEEP state based on: * whether there's been an active transmission in the last (hardcoded) 500ms; * whether the TIM from the AP indicates there is data available. It uses the beacon reception to trigger the active traffic check. This way there's no further timer running to wake up the CPU from its own sleep states. Right now the VAP isn't woken up for multicast traffic - mostly because the only NIC I plan on doing this for right will auto wakeup and stay awake for multicast traffic indicated in the TIM. So I don't have to manually keep the hardware awake. This doesn't do anything if the NIC doesn't advertise it implements the new SWSLEEP capability AND if the VAP doesn't have powersave enabled. It also doesn't do much with ath(4) as it doesn't currently implement the SLEEP state. Tested: * AR5416, STA mode (with local ath(4) changes) Modified: head/sys/net80211/ieee80211_power.c head/sys/net80211/ieee80211_power.h head/sys/net80211/ieee80211_sta.c Modified: head/sys/net80211/ieee80211_power.c ============================================================================== --- head/sys/net80211/ieee80211_power.c Thu Apr 24 01:28:39 2014 (r264854) +++ head/sys/net80211/ieee80211_power.c Thu Apr 24 01:39:53 2014 (r264855) @@ -555,3 +555,89 @@ ieee80211_sta_pwrsave(struct ieee80211va ieee80211_send_nulldata(ieee80211_ref_node(ni)); } } + +/* + * Handle being notified that we have data available for us in a TIM/ATIM. + * + * This may schedule a transition from _SLEEP -> _RUN if it's appropriate. + */ +void +ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set) +{ + /* + * Schedule the driver state change. It'll happen at some point soon. + * Since the hardware shouldn't know that we're running just yet + * (and thus tell the peer that we're awake before we actually wake + * up said hardware), we leave the actual node state transition + * up to the transition to RUN. + * + * XXX TODO: verify that the transition to RUN will wake up the + * BSS node! + */ + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, "%s: TIM=%d\n", __func__, set); + IEEE80211_LOCK(vap->iv_ic); + if (set == 1 && vap->iv_state == IEEE80211_S_SLEEP) { + ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0); + } + IEEE80211_UNLOCK(vap->iv_ic); +} + +/* + * Timer check on whether the VAP has had any transmit activity. + * + * This may schedule a transition from _RUN -> _SLEEP if it's appropriate. + */ +void +ieee80211_sta_ps_timer_check(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + + /* XXX lock assert */ + + /* For no, only do this in STA mode */ + if (! (vap->iv_caps & IEEE80211_C_SWSLEEP)) + goto out; + + if (vap->iv_opmode != IEEE80211_M_STA) + goto out; + + /* If we're not at run state, bail */ + if (vap->iv_state != IEEE80211_S_RUN) + goto out; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: lastdata=%llu, ticks=%llu\n", + __func__, (unsigned long long) ic->ic_lastdata, + (unsigned long long) ticks); + + /* If powersave is disabled on the VAP, don't bother */ + if (! (vap->iv_flags & IEEE80211_F_PMGTON)) + goto out; + + /* If we've done any data within our idle interval, bail */ + /* XXX hard-coded to one second for now, ew! */ + if (time_after(ic->ic_lastdata + 500, ticks)) + goto out; + + /* + * Signify we're going into power save and transition the + * node to powersave. + */ + if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) + vap->iv_sta_ps(vap, 1); + + /* + * XXX The driver has to handle the fact that we're going + * to sleep but frames may still be transmitted; + * hopefully it and/or us will do the right thing and mark any + * transmitted frames with PWRMGT set to 1. + */ + ieee80211_new_state_locked(vap, IEEE80211_S_SLEEP, 0); + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: time delta=%d msec\n", __func__, + (int) ticks_to_msecs(ticks - ic->ic_lastdata)); + +out: + return; +} Modified: head/sys/net80211/ieee80211_power.h ============================================================================== --- head/sys/net80211/ieee80211_power.h Thu Apr 24 01:28:39 2014 (r264854) +++ head/sys/net80211/ieee80211_power.h Thu Apr 24 01:39:53 2014 (r264855) @@ -79,6 +79,9 @@ int ieee80211_node_psq_age(struct ieee80 int ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *); void ieee80211_node_pwrsave(struct ieee80211_node *, int enable); void ieee80211_sta_pwrsave(struct ieee80211vap *, int enable); +void ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set); +void ieee80211_sta_ps_timer_check(struct ieee80211vap *vap); +/* XXX what's this? */ void ieee80211_power_poll(struct ieee80211com *); #endif /* _NET80211_IEEE80211_POWER_H_ */ Modified: head/sys/net80211/ieee80211_sta.c ============================================================================== --- head/sys/net80211/ieee80211_sta.c Thu Apr 24 01:28:39 2014 (r264854) +++ head/sys/net80211/ieee80211_sta.c Thu Apr 24 01:39:53 2014 (r264855) @@ -234,6 +234,7 @@ sta_newstate(struct ieee80211vap *vap, e switch (ostate) { case IEEE80211_S_SLEEP: /* XXX wakeup */ + /* XXX driver hook to wakeup the hardware? */ case IEEE80211_S_RUN: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC, @@ -403,6 +404,7 @@ sta_newstate(struct ieee80211vap *vap, e arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); break; case IEEE80211_S_SLEEP: + /* Wake up from sleep */ vap->iv_sta_ps(vap, 0); break; default: @@ -430,9 +432,11 @@ sta_newstate(struct ieee80211vap *vap, e ieee80211_node_authorize(ni); /* * Fake association when joining an existing bss. + * + * Don't do this if we're doing SLEEP->RUN. */ - if (ic->ic_newassoc != NULL) - ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN); + if (ic->ic_newassoc != NULL && ostate != IEEE80211_S_SLEEP) + ic->ic_newassoc(vap->iv_bss, (ostate != IEEE80211_S_RUN)); break; case IEEE80211_S_CSA: if (ostate != IEEE80211_S_RUN) @@ -1312,6 +1316,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, vap->iv_stats.is_beacon_bad++; return; } + /* * Count frame now that we know it's to be processed. */ @@ -1381,23 +1386,48 @@ sta_recv_mgmt(struct ieee80211_node *ni, } if (scan.quiet) ic->ic_set_quiet(ni, scan.quiet); + if (scan.tim != NULL) { struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) scan.tim; -#if 0 + /* + * XXX Check/debug this code; see if it's about + * the right time to force the VAP awake if we + * receive a frame destined for us? + */ int aid = IEEE80211_AID(ni->ni_associd); int ix = aid / NBBY; int min = tim->tim_bitctl &~ 1; int max = tim->tim_len + min - 4; - if ((tim->tim_bitctl&1) || + + /* + * Only do this for unicast traffic in the TIM + * The multicast traffic notification for + * the scan notification stuff should occur + * differently. + */ + if (min <= ix && ix <= max && + isset(tim->tim_bitmap - min, aid)) { + ieee80211_sta_tim_notify(vap, 1); + ic->ic_lastdata = ticks; + } + + /* + * XXX TODO: do a separate notification + * for the multicast bit being set. + */ +#if 0 + if ((tim->tim_bitctl & 1) || (min <= ix && ix <= max && isset(tim->tim_bitmap - min, aid))) { /* * XXX Do not let bg scan kick off * we are expecting data. */ + ieee80211_sta_tim_notify(vap, 1); ic->ic_lastdata = ticks; - vap->iv_sta_ps(vap, 0); + // XXX not yet? +// vap->iv_sta_ps(vap, 0); } #endif ni->ni_dtim_count = tim->tim_count; @@ -1446,6 +1476,14 @@ sta_recv_mgmt(struct ieee80211_node *ni, } /* + * Put the station to sleep if we haven't seen + * traffic in a while. + */ + IEEE80211_LOCK(ic); + ieee80211_sta_ps_timer_check(vap); + IEEE80211_UNLOCK(ic); + + /* * If we've had a channel width change (eg HT20<->HT40) * then schedule a delayed driver notification. */