summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2012-08-25 12:14:32 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2012-08-25 12:14:32 +0000
commitf25d3c072ab38c54fdae4ec4d91b08f5e209bc72 (patch)
treea0edea35093f3140a9c482c9a6b469298fd9c175 /sys/dev
parent7d734daf7474e6afa9ef273b4577804ab444a1b7 (diff)
Add support for power saving in Host AP mode.
ok stsp@, deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/ar5008.c31
-rw-r--r--sys/dev/ic/ar9003.c31
-rw-r--r--sys/dev/ic/athn.c13
-rw-r--r--sys/dev/ic/athnvar.h3
4 files changed, 73 insertions, 5 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c
index 6a884fab51d..83fb33e18e3 100644
--- a/sys/dev/ic/ar5008.c
+++ b/sys/dev/ic/ar5008.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008.c,v 1.20 2011/06/19 00:27:34 matthew Exp $ */
+/* $OpenBSD: ar5008.c,v 1.21 2012/08/25 12:14:31 kettenis Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -1053,6 +1053,8 @@ int
ar5008_swba_intr(struct athn_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ struct ieee80211_node *ni = ic->ic_bss;
struct athn_tx_buf *bf = sc->bcnbuf;
struct ieee80211_frame *wh;
struct ar_tx_desc *ds;
@@ -1060,6 +1062,11 @@ ar5008_swba_intr(struct athn_softc *sc)
uint8_t ridx, hwrate;
int error, totlen;
+ if (ic->ic_tim_mcast_pending &&
+ IF_IS_EMPTY(&ni->ni_savedq) &&
+ SIMPLEQ_EMPTY(&sc->txq[ATHN_QID_CAB].head))
+ ic->ic_tim_mcast_pending = 0;
+
if (ic->ic_dtim_count == 0)
ic->ic_dtim_count = ic->ic_dtim_period - 1;
else
@@ -1133,6 +1140,26 @@ ar5008_swba_intr(struct athn_softc *sc)
AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr);
+ for(;;) {
+ if (SIMPLEQ_EMPTY(&sc->txbufs))
+ break;
+
+ IF_DEQUEUE(&ni->ni_savedq, m);
+ if (m == NULL)
+ break;
+ if (!IF_IS_EMPTY(&ni->ni_savedq)) {
+ /* more queued frames, set the more data bit */
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ }
+
+ if (sc->ops.tx(sc, m, ni, ATHN_TXFLAG_CAB) != 0) {
+ ieee80211_release_node(ic, ni);
+ ifp->if_oerrors++;
+ break;
+ }
+ }
+
/* Kick Tx. */
AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON);
AR_WRITE_BARRIER(sc);
@@ -1285,6 +1312,8 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)];
} else if (type == AR_FRAME_TYPE_PSPOLL) {
qid = ATHN_QID_PSPOLL;
+ } else if (txflags & ATHN_TXFLAG_CAB) {
+ qid = ATHN_QID_CAB;
} else
qid = ATHN_QID_AC_BE;
txq = &sc->txq[qid];
diff --git a/sys/dev/ic/ar9003.c b/sys/dev/ic/ar9003.c
index 9d94b427d16..ff547f4ab16 100644
--- a/sys/dev/ic/ar9003.c
+++ b/sys/dev/ic/ar9003.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar9003.c,v 1.22 2011/01/01 13:44:42 damien Exp $ */
+/* $OpenBSD: ar9003.c,v 1.23 2012/08/25 12:14:31 kettenis Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -1183,6 +1183,8 @@ int
ar9003_swba_intr(struct athn_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ struct ieee80211_node *ni = ic->ic_bss;
struct athn_tx_buf *bf = sc->bcnbuf;
struct ieee80211_frame *wh;
struct ar_tx_desc *ds;
@@ -1191,6 +1193,11 @@ ar9003_swba_intr(struct athn_softc *sc)
uint8_t ridx, hwrate;
int error, totlen;
+ if (ic->ic_tim_mcast_pending &&
+ IF_IS_EMPTY(&ni->ni_savedq) &&
+ SIMPLEQ_EMPTY(&sc->txq[ATHN_QID_CAB].head))
+ ic->ic_tim_mcast_pending = 0;
+
if (ic->ic_dtim_count == 0)
ic->ic_dtim_count = ic->ic_dtim_period - 1;
else
@@ -1276,6 +1283,26 @@ ar9003_swba_intr(struct athn_softc *sc)
AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr);
+ for(;;) {
+ if (SIMPLEQ_EMPTY(&sc->txbufs))
+ break;
+
+ IF_DEQUEUE(&ni->ni_savedq, m);
+ if (m == NULL)
+ break;
+ if (!IF_IS_EMPTY(&ni->ni_savedq)) {
+ /* more queued frames, set the more data bit */
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ }
+
+ if (sc->ops.tx(sc, m, ni, ATHN_TXFLAG_CAB) != 0) {
+ ieee80211_release_node(ic, ni);
+ ifp->if_oerrors++;
+ break;
+ }
+ }
+
/* Kick Tx. */
AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON);
AR_WRITE_BARRIER(sc);
@@ -1425,6 +1452,8 @@ ar9003_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)];
} else if (type == AR_FRAME_TYPE_PSPOLL) {
qid = ATHN_QID_PSPOLL;
+ } else if (txflags & ATHN_TXFLAG_CAB) {
+ qid = ATHN_QID_CAB;
} else
qid = ATHN_QID_AC_BE;
txq = &sc->txq[qid];
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index d58dc53b37f..b985a0915be 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.72 2012/06/10 21:23:36 kettenis Exp $ */
+/* $OpenBSD: athn.c,v 1.73 2012/08/25 12:14:31 kettenis Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -282,7 +282,8 @@ athn_attach(struct athn_softc *sc)
IEEE80211_C_WEP | /* WEP. */
IEEE80211_C_RSN | /* WPA/RSN. */
#ifndef IEEE80211_STA_ONLY
- IEEE80211_C_HOSTAP | /* Host Ap mode supported. */
+ IEEE80211_C_HOSTAP | /* Host AP mode supported. */
+ IEEE80211_C_APPMGT | /* Host AP power saving supported. */
#endif
IEEE80211_C_MONITOR | /* Monitor mode supported. */
IEEE80211_C_SHSLOT | /* Short slot time supported. */
@@ -2546,6 +2547,14 @@ athn_start(struct ifnet *ifp)
if (ic->ic_state != IEEE80211_S_RUN)
break;
+ IF_DEQUEUE(&ic->ic_pwrsaveq, m);
+ if (m != NULL) {
+ ni = (void *)m->m_pkthdr.rcvif;
+ goto sendit;
+ }
+ if (ic->ic_state != IEEE80211_S_RUN)
+ break;
+
/* Encapsulate and send data frames. */
IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
diff --git a/sys/dev/ic/athnvar.h b/sys/dev/ic/athnvar.h
index b21a332e29d..b9548738b92 100644
--- a/sys/dev/ic/athnvar.h
+++ b/sys/dev/ic/athnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: athnvar.h,v 1.31 2012/06/10 21:23:36 kettenis Exp $ */
+/* $OpenBSD: athnvar.h,v 1.32 2012/08/25 12:14:31 kettenis Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -83,6 +83,7 @@ struct athn_tx_buf {
struct ieee80211_node *bf_ni;
int bf_txflags;
#define ATHN_TXFLAG_PAPRD (1 << 0)
+#define ATHN_TXFLAG_CAB (1 << 1)
};
struct athn_txq {