summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2010-05-16 09:19:49 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2010-05-16 09:19:49 +0000
commitc7ba6e406444881f5e4797f7f40d928a3816a24e (patch)
tree3241f9356224437e369613f0484cc3ba1e8f205b /sys/dev/ic
parent04074ae470ae88ab6da4b551a9ba405654250c65 (diff)
initial Host AP bits.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/ar5008.c109
-rw-r--r--sys/dev/ic/ar9003.c122
-rw-r--r--sys/dev/ic/athn.c85
-rw-r--r--sys/dev/ic/athnreg.h4
-rw-r--r--sys/dev/ic/athnvar.h3
5 files changed, 285 insertions, 38 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c
index 51efacdf524..00eebe4541b 100644
--- a/sys/dev/ic/ar5008.c
+++ b/sys/dev/ic/ar5008.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar5008.c,v 1.4 2010/05/16 08:55:39 damien Exp $ */
+/* $OpenBSD: ar5008.c,v 1.5 2010/05/16 09:19:48 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -86,6 +86,7 @@ void ar5008_rx_radiotap(struct athn_softc *, struct mbuf *,
void ar5008_rx_intr(struct athn_softc *);
int ar5008_tx_process(struct athn_softc *, int);
void ar5008_tx_intr(struct athn_softc *);
+int ar5008_swba_intr(struct athn_softc *);
int ar5008_intr(struct athn_softc *);
int ar5008_tx(struct athn_softc *, struct mbuf *, struct ieee80211_node *);
void ar5008_set_rf_mode(struct athn_softc *, struct ieee80211_channel *);
@@ -134,6 +135,8 @@ void athn_stop(struct ifnet *, int);
int athn_interpolate(int, int, int, int, int);
int athn_txtime(struct athn_softc *, int, int, u_int);
void athn_inc_tx_trigger_level(struct athn_softc *);
+int athn_tx_pending(struct athn_softc *, int);
+void athn_stop_tx_dma(struct athn_softc *, int);
void athn_get_delta_slope(uint32_t, uint32_t *, uint32_t *);
void athn_config_pcie(struct athn_softc *);
void athn_config_nonpcie(struct athn_softc *);
@@ -1007,6 +1010,100 @@ ar5008_tx_intr(struct athn_softc *sc)
}
}
+#ifndef IEEE80211_STA_ONLY
+/*
+ * Process Software Beacon Alert interrupts.
+ */
+int
+ar5008_swba_intr(struct athn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct athn_tx_buf *bf = sc->bcnbuf;
+ struct ieee80211_frame *wh;
+ struct ar_tx_desc *ds;
+ struct mbuf *m;
+ uint8_t ridx, hwrate;
+ int error, totlen;
+
+ if (ic->ic_dtim_count == 0)
+ ic->ic_dtim_count = ic->ic_dtim_period - 1;
+ else
+ ic->ic_dtim_count--;
+
+ /* Make sure previous beacon has been sent. */
+ if (athn_tx_pending(sc, ATHN_QID_BEACON)) {
+ DPRINTF(("beacon stuck\n"));
+ return (EBUSY);
+ }
+ /* Get new beacon. */
+ m = ieee80211_beacon_alloc(ic, ic->ic_bss);
+ if (__predict_false(m == NULL))
+ return (ENOBUFS);
+ /* Assign sequence number. */
+ wh = mtod(m, struct ieee80211_frame *);
+ *(uint16_t *)&wh->i_seq[0] =
+ htole16(ic->ic_bss->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
+ ic->ic_bss->ni_txseq++;
+
+ /* Unmap and free old beacon if any. */
+ if (__predict_true(bf->bf_m != NULL)) {
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_map, 0,
+ bf->bf_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_map);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ /* DMA map new beacon. */
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_map, m,
+ BUS_DMA_NOWAIT | BUS_DMA_WRITE);
+ if (__predict_false(error != 0)) {
+ m_freem(m);
+ return (error);
+ }
+ bf->bf_m = m;
+
+ /* Setup Tx descriptor (simplified ar5008_tx()). */
+ ds = bf->bf_descs;
+ memset(ds, 0, sizeof(*ds));
+
+ totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
+ ds->ds_ctl0 = SM(AR_TXC0_FRAME_LEN, totlen);
+ ds->ds_ctl0 |= SM(AR_TXC0_XMIT_POWER, AR_MAX_RATE_POWER);
+ ds->ds_ctl1 = SM(AR_TXC1_FRAME_TYPE, AR_FRAME_TYPE_BEACON);
+ ds->ds_ctl1 |= AR_TXC1_NO_ACK;
+ ds->ds_ctl6 = SM(AR_TXC6_ENCR_TYPE, AR_ENCR_TYPE_CLEAR);
+
+ /* Write number of tries. */
+ ds->ds_ctl2 = SM(AR_TXC2_XMIT_DATA_TRIES0, 1);
+
+ /* Write Tx rate. */
+ ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
+ ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1;
+ hwrate = athn_rates[ridx].hwrate;
+ ds->ds_ctl3 = SM(AR_TXC3_XMIT_RATE0, hwrate);
+
+ /* Write Tx chains. */
+ ds->ds_ctl7 = SM(AR_TXC7_CHAIN_SEL0, sc->txchainmask);
+
+ ds->ds_data = bf->bf_map->dm_segs[0].ds_addr;
+ /* Segment length must be a multiple of 4. */
+ ds->ds_ctl1 |= SM(AR_TXC1_BUF_LEN,
+ (bf->bf_map->dm_segs[0].ds_len + 3) & ~3);
+
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_map, 0, bf->bf_map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Stop Tx DMA before putting the new beacon on the queue. */
+ athn_stop_tx_dma(sc, ATHN_QID_BEACON);
+
+ AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr);
+
+ /* Kick Tx. */
+ AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON);
+ return (0);
+}
+#endif
+
int
ar5008_intr(struct athn_softc *sc)
{
@@ -1041,6 +1138,10 @@ ar5008_intr(struct athn_softc *sc)
if (intr == AR_INTR_SPURIOUS)
return (1);
+#ifndef IEEE80211_STA_ONLY
+ if (intr & AR_ISR_SWBA)
+ ar5008_swba_intr(sc);
+#endif
if (intr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
ar5008_rx_intr(sc);
if (intr & (AR_ISR_RXOK | AR_ISR_RXERR | AR_ISR_RXORN))
@@ -1116,10 +1217,8 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
IEEE80211_FC0_TYPE_MGT) {
+ /* NB: Beacons do not use ar5008_tx(). */
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
- IEEE80211_FC0_SUBTYPE_BEACON)
- type = AR_FRAME_TYPE_BEACON;
- else if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_PROBE_RESP)
type = AR_FRAME_TYPE_PROBE_RESP;
else if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
@@ -1148,8 +1247,6 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
qos = ieee80211_get_qos(wh);
tid = qos & IEEE80211_QOS_TID;
qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)];
- } else if (type == AR_FRAME_TYPE_BEACON) {
- qid = ATHN_QID_BEACON;
} else if (type == AR_FRAME_TYPE_PSPOLL) {
qid = ATHN_QID_PSPOLL;
} else
diff --git a/sys/dev/ic/ar9003.c b/sys/dev/ic/ar9003.c
index de38a9ba3af..1038ac987ad 100644
--- a/sys/dev/ic/ar9003.c
+++ b/sys/dev/ic/ar9003.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ar9003.c,v 1.7 2010/05/16 09:01:05 damien Exp $ */
+/* $OpenBSD: ar9003.c,v 1.8 2010/05/16 09:19:48 damien Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -90,6 +90,7 @@ int ar9003_rx_process(struct athn_softc *, int);
void ar9003_rx_intr(struct athn_softc *, int);
int ar9003_tx_process(struct athn_softc *);
void ar9003_tx_intr(struct athn_softc *);
+int ar9003_swba_intr(struct athn_softc *);
int ar9003_intr(struct athn_softc *);
int ar9003_tx(struct athn_softc *, struct mbuf *, struct ieee80211_node *);
void ar9003_set_rf_mode(struct athn_softc *, struct ieee80211_channel *);
@@ -139,6 +140,8 @@ void athn_stop(struct ifnet *, int);
int athn_interpolate(int, int, int, int, int);
int athn_txtime(struct athn_softc *, int, int, u_int);
void athn_inc_tx_trigger_level(struct athn_softc *);
+int athn_tx_pending(struct athn_softc *, int);
+void athn_stop_tx_dma(struct athn_softc *, int);
void athn_get_delta_slope(uint32_t, uint32_t *, uint32_t *);
void athn_config_pcie(struct athn_softc *);
void athn_config_nonpcie(struct athn_softc *);
@@ -1024,6 +1027,113 @@ ar9003_tx_intr(struct athn_softc *sc)
while (ar9003_tx_process(sc) == 0);
}
+#ifndef IEEE80211_STA_ONLY
+/*
+ * Process Software Beacon Alert interrupts.
+ */
+int
+ar9003_swba_intr(struct athn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct athn_tx_buf *bf = sc->bcnbuf;
+ struct ieee80211_frame *wh;
+ struct ar_tx_desc *ds;
+ struct mbuf *m;
+ uint32_t sum;
+ uint8_t ridx, hwrate;
+ int error, totlen;
+
+ if (ic->ic_dtim_count == 0)
+ ic->ic_dtim_count = ic->ic_dtim_period - 1;
+ else
+ ic->ic_dtim_count--;
+
+ /* Make sure previous beacon has been sent. */
+ if (athn_tx_pending(sc, ATHN_QID_BEACON)) {
+ DPRINTF(("beacon stuck problem\n"));
+ return (EBUSY);
+ }
+ /* Get new beacon. */
+ m = ieee80211_beacon_alloc(ic, ic->ic_bss);
+ if (__predict_false(m == NULL))
+ return (ENOBUFS);
+ /* Assign sequence number. */
+ wh = mtod(m, struct ieee80211_frame *);
+ *(uint16_t *)&wh->i_seq[0] =
+ htole16(ic->ic_bss->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
+ ic->ic_bss->ni_txseq++;
+
+ /* Unmap and free old beacon if any. */
+ if (__predict_true(bf->bf_m != NULL)) {
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_map, 0,
+ bf->bf_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_map);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ /* DMA map new beacon. */
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_map, m,
+ BUS_DMA_NOWAIT | BUS_DMA_WRITE);
+ if (__predict_false(error != 0)) {
+ m_freem(m);
+ return (error);
+ }
+ bf->bf_m = m;
+
+ /* Setup Tx descriptor (simplified ar9003_tx()). */
+ ds = bf->bf_descs;
+ memset(ds, 0, sizeof(*ds));
+
+ ds->ds_info =
+ SM(AR_TXI_DESC_ID, AR_VENDOR_ATHEROS) |
+ SM(AR_TXI_DESC_NDWORDS, 23) |
+ SM(AR_TXI_QCU_NUM, ATHN_QID_BEACON) |
+ AR_TXI_DESC_TX | AR_TXI_CTRL_STAT;
+
+ totlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
+ ds->ds_ctl11 = SM(AR_TXC11_FRAME_LEN, totlen);
+ ds->ds_ctl11 |= SM(AR_TXC11_XMIT_POWER, AR_MAX_RATE_POWER);
+ ds->ds_ctl12 = SM(AR_TXC12_FRAME_TYPE, AR_FRAME_TYPE_BEACON);
+ ds->ds_ctl12 |= AR_TXC12_NO_ACK;
+ ds->ds_ctl17 = SM(AR_TXC17_ENCR_TYPE, AR_ENCR_TYPE_CLEAR);
+
+ /* Write number of tries. */
+ ds->ds_ctl13 = SM(AR_TXC13_XMIT_DATA_TRIES0, 1);
+
+ /* Write Tx rate. */
+ ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
+ ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1;
+ hwrate = athn_rates[ridx].hwrate;
+ ds->ds_ctl14 = SM(AR_TXC14_XMIT_RATE0, hwrate);
+
+ /* Write Tx chains. */
+ ds->ds_ctl18 = SM(AR_TXC18_CHAIN_SEL0, sc->txchainmask);
+
+ ds->ds_segs[0].ds_data = bf->bf_map->dm_segs[0].ds_addr;
+ /* Segment length must be a multiple of 4. */
+ ds->ds_segs[0].ds_ctl |= SM(AR_TXC_BUF_LEN,
+ (bf->bf_map->dm_segs[0].ds_len + 3) & ~3);
+ /* Compute Tx descriptor checksum. */
+ sum = ds->ds_info;
+ sum += ds->ds_segs[0].ds_data;
+ sum += ds->ds_segs[0].ds_ctl;
+ sum = (sum >> 16) + (sum & 0xffff);
+ ds->ds_ctl10 = SM(AR_TXC10_PTR_CHK_SUM, sum);
+
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_map, 0, bf->bf_map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Stop Tx DMA before putting the new beacon on the queue. */
+ athn_stop_tx_dma(sc, ATHN_QID_BEACON);
+
+ AR_WRITE(sc, AR_QTXDP(ATHN_QID_BEACON), bf->bf_daddr);
+
+ /* Kick Tx. */
+ AR_WRITE(sc, AR_Q_TXE, 1 << ATHN_QID_BEACON);
+ return (0);
+}
+#endif
+
int
ar9003_intr(struct athn_softc *sc)
{
@@ -1058,6 +1168,10 @@ ar9003_intr(struct athn_softc *sc)
if (intr == AR_INTR_SPURIOUS)
return (1);
+#ifndef IEEE80211_STA_ONLY
+ if (intr & AR_ISR_SWBA)
+ ar9003_swba_intr(sc);
+#endif
if (intr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
ar9003_rx_intr(sc, ATHN_QID_LP);
if (intr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
@@ -1127,10 +1241,8 @@ ar9003_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
IEEE80211_FC0_TYPE_MGT) {
+ /* NB: Beacons do not use ar9003_tx(). */
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
- IEEE80211_FC0_SUBTYPE_BEACON)
- type = AR_FRAME_TYPE_BEACON;
- else if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_PROBE_RESP)
type = AR_FRAME_TYPE_PROBE_RESP;
else if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
@@ -1159,8 +1271,6 @@ ar9003_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
qos = ieee80211_get_qos(wh);
tid = qos & IEEE80211_QOS_TID;
qid = athn_ac2qid[ieee80211_up_to_ac(ic, tid)];
- } else if (type == AR_FRAME_TYPE_BEACON) {
- qid = ATHN_QID_BEACON;
} else if (type == AR_FRAME_TYPE_PSPOLL) {
qid = ATHN_QID_PSPOLL;
} else
diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c
index 2bbe3409f24..719e5558a78 100644
--- a/sys/dev/ic/athn.c
+++ b/sys/dev/ic/athn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: athn.c,v 1.41 2010/05/16 09:02:13 damien Exp $ */
+/* $OpenBSD: athn.c,v 1.42 2010/05/16 09:19:48 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -112,7 +112,8 @@ void athn_tx_reclaim(struct athn_softc *, int);
int athn_tx_pending(struct athn_softc *, int);
void athn_stop_tx_dma(struct athn_softc *, int);
int athn_txtime(struct athn_softc *, int, int, u_int);
-void athn_set_beacon_timers(struct athn_softc *);
+void athn_set_sta_timers(struct athn_softc *);
+void athn_set_hostap_timers(struct athn_softc *);
void athn_set_opmode(struct athn_softc *);
void athn_set_bss(struct athn_softc *, struct ieee80211_node *);
void athn_enable_interrupts(struct athn_softc *);
@@ -194,6 +195,7 @@ athn_attach(struct athn_softc *sc)
printf(": could not attach chip\n");
return (error);
}
+ printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
/* We can put the chip in sleep state now. */
athn_set_power_sleep(sc);
@@ -204,8 +206,9 @@ athn_attach(struct athn_softc *sc)
sc->sc_dev.dv_xname);
return (error);
}
-
- printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
+ /* Steal one Tx buffer for beacons. */
+ sc->bcnbuf = SIMPLEQ_FIRST(&sc->txbufs);
+ SIMPLEQ_REMOVE_HEAD(&sc->txbufs, bf_list);
if (sc->flags & ATHN_FLAG_RFSILENT) {
DPRINTF(("found RF switch connected to GPIO pin %d\n",
@@ -258,12 +261,15 @@ athn_attach(struct athn_softc *sc)
/* Set device capabilities. */
ic->ic_caps =
- IEEE80211_C_WEP | /* WEP */
- IEEE80211_C_RSN | /* WPA/RSN */
- IEEE80211_C_MONITOR | /* monitor mode supported */
- IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_SHPREAMBLE | /* short preamble supported */
- IEEE80211_C_PMGT; /* power saving supported */
+ IEEE80211_C_WEP | /* WEP. */
+ IEEE80211_C_RSN | /* WPA/RSN. */
+#ifndef IEEE80211_STA_ONLY
+ IEEE80211_C_HOSTAP | /* Host Ap mode supported. */
+#endif
+ IEEE80211_C_MONITOR | /* Monitor mode supported. */
+ IEEE80211_C_SHSLOT | /* Short slot time supported. */
+ IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
+ IEEE80211_C_PMGT; /* Power saving supported. */
#ifndef IEEE80211_NO_HT
if (sc->flags & ATHN_FLAG_11N) {
@@ -1688,7 +1694,6 @@ athn_txtime(struct athn_softc *sc, int len, int ridx, u_int flags)
void
athn_init_tx_queues(struct athn_softc *sc)
{
- uint32_t reg;
int qid;
for (qid = 0; qid < ATHN_QID_COUNT; qid++) {
@@ -1715,13 +1720,10 @@ athn_init_tx_queues(struct athn_softc *sc)
AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL) |
AR_D_MISC_BEACON_USE |
AR_D_MISC_POST_FR_BKOFF_DIS);
- if (AR_SREV_9380_10_OR_LATER(sc)) {
- /* CWmin and CWmax should be 0 for beacon queue. */
- reg = AR_READ(sc, AR_DLCL_IFS(ATHN_QID_BEACON));
- reg = RW(reg, AR_D_LCL_IFS_CWMIN, 0);
- reg = RW(reg, AR_D_LCL_IFS_CWMAX, 0);
- AR_WRITE(sc, AR_DLCL_IFS(ATHN_QID_BEACON), reg);
- }
+ AR_WRITE(sc, AR_DLCL_IFS(ATHN_QID_BEACON),
+ SM(AR_D_LCL_IFS_CWMIN, 0) |
+ SM(AR_D_LCL_IFS_CWMAX, 0) |
+ SM(AR_D_LCL_IFS_AIFS, 1));
/* Init CAB (Content After Beacon) queue. */
AR_SETBITS(sc, AR_QMISC(ATHN_QID_CAB),
@@ -1750,10 +1752,9 @@ athn_init_tx_queues(struct athn_softc *sc)
}
void
-athn_set_beacon_timers(struct athn_softc *sc)
+athn_set_sta_timers(struct athn_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni = ic->ic_bss;
uint32_t tsfhi, tsflo, tsftu, reg;
uint32_t intval, next_tbtt, next_dtim;
int dtim_period, dtim_count, rem_dtim_count;
@@ -1763,7 +1764,7 @@ athn_set_beacon_timers(struct athn_softc *sc)
tsftu = AR_TSF_TO_TU(tsfhi, tsflo) + AR_FUDGE;
/* Beacon interval in TU. */
- intval = ni->ni_intval;
+ intval = ic->ic_bss->ni_intval;
next_tbtt = roundup(tsftu, intval);
#ifdef notyet
@@ -1816,6 +1817,33 @@ athn_set_beacon_timers(struct athn_softc *sc)
AR_WRITE(sc, AR_TSFOOR_THRESHOLD, 0x4240);
}
+#ifndef IEEE80211_STA_ONLY
+void
+athn_set_hostap_timers(struct athn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ uint32_t intval, next_tbtt;
+
+ /* Beacon interval in TU. */
+ intval = ic->ic_bss->ni_intval;
+ next_tbtt = intval;
+
+ AR_WRITE(sc, AR_NEXT_TBTT_TIMER, next_tbtt * IEEE80211_DUR_TU);
+ AR_WRITE(sc, AR_NEXT_DMA_BEACON_ALERT,
+ (next_tbtt - AR_BEACON_DMA_DELAY) * IEEE80211_DUR_TU);
+ AR_WRITE(sc, AR_NEXT_CFP,
+ (next_tbtt - AR_SWBA_DELAY) * IEEE80211_DUR_TU);
+
+ AR_WRITE(sc, AR_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
+ AR_WRITE(sc, AR_DMA_BEACON_PERIOD, intval * IEEE80211_DUR_TU);
+ AR_WRITE(sc, AR_SWBA_PERIOD, intval * IEEE80211_DUR_TU);
+ AR_WRITE(sc, AR_NDP_PERIOD, intval * IEEE80211_DUR_TU);
+
+ AR_WRITE(sc, AR_TIMER_MODE,
+ AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);
+}
+#endif
+
void
athn_set_opmode(struct athn_softc *sc)
{
@@ -2256,9 +2284,18 @@ athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
athn_set_bss(sc, ic->ic_bss);
athn_disable_interrupts(sc);
- athn_set_beacon_timers(sc);
- /* Enable beacon miss interrupts. */
- sc->imask |= AR_IMR_BMISS;
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ athn_set_hostap_timers(sc);
+ /* Enable sotfware beacon alert interrupts. */
+ sc->imask |= AR_IMR_SWBA;
+ } else
+#endif
+ {
+ athn_set_sta_timers(sc);
+ /* Enable beacon miss interrupts. */
+ sc->imask |= AR_IMR_BMISS;
+ }
athn_enable_interrupts(sc);
/* XXX Start ANI. */
diff --git a/sys/dev/ic/athnreg.h b/sys/dev/ic/athnreg.h
index 2e2008c3042..4fcc16ca510 100644
--- a/sys/dev/ic/athnreg.h
+++ b/sys/dev/ic/athnreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: athnreg.h,v 1.10 2010/05/16 08:50:58 damien Exp $ */
+/* $OpenBSD: athnreg.h,v 1.11 2010/05/16 09:19:48 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -1280,6 +1280,8 @@
#define AR_MIN_BEACON_TIMEOUT_VAL 1
#define AR_FUDGE 2
+#define AR_BEACON_DMA_DELAY 2
+#define AR_SWBA_DELAY 10
/* Divides by 1024 (usecs to TU) without doing 64-bit arithmetic. */
#define AR_TSF_TO_TU(hi, lo) ((hi) << 22 | (lo) >> 10)
diff --git a/sys/dev/ic/athnvar.h b/sys/dev/ic/athnvar.h
index 66a4c4d377a..db931042038 100644
--- a/sys/dev/ic/athnvar.h
+++ b/sys/dev/ic/athnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: athnvar.h,v 1.11 2010/05/11 19:34:20 damien Exp $ */
+/* $OpenBSD: athnvar.h,v 1.12 2010/05/16 09:19:48 damien Exp $ */
/*-
* Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -474,6 +474,7 @@ struct athn_softc {
bus_dmamap_t map;
bus_dma_segment_t seg;
SIMPLEQ_HEAD(, athn_tx_buf) txbufs;
+ struct athn_tx_buf *bcnbuf;
struct athn_tx_buf txpool[ATHN_NTXBUFS];
bus_dmamap_t txsmap;