1235680Sadrian/*- 2235680Sadrian * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3235680Sadrian * All rights reserved. 4235680Sadrian * 5235680Sadrian * Redistribution and use in source and binary forms, with or without 6235680Sadrian * modification, are permitted provided that the following conditions 7235680Sadrian * are met: 8235680Sadrian * 1. Redistributions of source code must retain the above copyright 9235680Sadrian * notice, this list of conditions and the following disclaimer, 10235680Sadrian * without modification. 11235680Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12235680Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13235680Sadrian * redistribution must be conditioned upon including a substantially 14235680Sadrian * similar Disclaimer requirement for further binary redistribution. 15235680Sadrian * 16235680Sadrian * NO WARRANTY 17235680Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18235680Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19235680Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20235680Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21235680Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22235680Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23235680Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24235680Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25235680Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26235680Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27235680Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28235680Sadrian */ 29235680Sadrian 30235680Sadrian#include <sys/cdefs.h> 31235680Sadrian__FBSDID("$FreeBSD$"); 32235680Sadrian 33235680Sadrian/* 34235680Sadrian * Driver for the Atheros Wireless LAN controller. 35235680Sadrian * 36235680Sadrian * This software is derived from work of Atsushi Onoe; his contribution 37235680Sadrian * is greatly appreciated. 38235680Sadrian */ 39235680Sadrian 40235680Sadrian#include "opt_inet.h" 41235680Sadrian#include "opt_ath.h" 42235680Sadrian/* 43235680Sadrian * This is needed for register operations which are performed 44235680Sadrian * by the driver - eg, calls to ath_hal_gettsf32(). 45235680Sadrian * 46235680Sadrian * It's also required for any AH_DEBUG checks in here, eg the 47235680Sadrian * module dependencies. 48235680Sadrian */ 49235680Sadrian#include "opt_ah.h" 50235680Sadrian#include "opt_wlan.h" 51235680Sadrian 52235680Sadrian#include <sys/param.h> 53235680Sadrian#include <sys/systm.h> 54235680Sadrian#include <sys/sysctl.h> 55235680Sadrian#include <sys/mbuf.h> 56235680Sadrian#include <sys/malloc.h> 57235680Sadrian#include <sys/lock.h> 58235680Sadrian#include <sys/mutex.h> 59235680Sadrian#include <sys/kernel.h> 60235680Sadrian#include <sys/socket.h> 61235680Sadrian#include <sys/sockio.h> 62235680Sadrian#include <sys/errno.h> 63235680Sadrian#include <sys/callout.h> 64235680Sadrian#include <sys/bus.h> 65235680Sadrian#include <sys/endian.h> 66235680Sadrian#include <sys/kthread.h> 67235680Sadrian#include <sys/taskqueue.h> 68235680Sadrian#include <sys/priv.h> 69235680Sadrian#include <sys/module.h> 70235680Sadrian#include <sys/ktr.h> 71235680Sadrian#include <sys/smp.h> /* for mp_ncpus */ 72235680Sadrian 73235680Sadrian#include <machine/bus.h> 74235680Sadrian 75235680Sadrian#include <net/if.h> 76257176Sglebius#include <net/if_var.h> 77235680Sadrian#include <net/if_dl.h> 78235680Sadrian#include <net/if_media.h> 79235680Sadrian#include <net/if_types.h> 80235680Sadrian#include <net/if_arp.h> 81235680Sadrian#include <net/ethernet.h> 82235680Sadrian#include <net/if_llc.h> 83235680Sadrian 84235680Sadrian#include <net80211/ieee80211_var.h> 85235680Sadrian#include <net80211/ieee80211_regdomain.h> 86235680Sadrian#ifdef IEEE80211_SUPPORT_SUPERG 87235680Sadrian#include <net80211/ieee80211_superg.h> 88235680Sadrian#endif 89235680Sadrian 90235680Sadrian#include <net/bpf.h> 91235680Sadrian 92235680Sadrian#ifdef INET 93235680Sadrian#include <netinet/in.h> 94235680Sadrian#include <netinet/if_ether.h> 95235680Sadrian#endif 96235680Sadrian 97235680Sadrian#include <dev/ath/if_athvar.h> 98235680Sadrian 99235680Sadrian#include <dev/ath/if_ath_debug.h> 100235680Sadrian#include <dev/ath/if_ath_misc.h> 101235680Sadrian#include <dev/ath/if_ath_tx.h> 102235680Sadrian#include <dev/ath/if_ath_beacon.h> 103235680Sadrian 104235680Sadrian#ifdef ATH_TX99_DIAG 105235680Sadrian#include <dev/ath/ath_tx99/ath_tx99.h> 106235680Sadrian#endif 107235680Sadrian 108235680Sadrian/* 109235680Sadrian * Setup a h/w transmit queue for beacons. 110235680Sadrian */ 111235680Sadrianint 112239201Sadrianath_beaconq_setup(struct ath_softc *sc) 113235680Sadrian{ 114239201Sadrian struct ath_hal *ah = sc->sc_ah; 115235680Sadrian HAL_TXQ_INFO qi; 116235680Sadrian 117235680Sadrian memset(&qi, 0, sizeof(qi)); 118235680Sadrian qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 119235680Sadrian qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 120235680Sadrian qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 121235680Sadrian /* NB: for dynamic turbo, don't enable any other interrupts */ 122235680Sadrian qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; 123239201Sadrian if (sc->sc_isedma) 124239201Sadrian qi.tqi_qflags |= HAL_TXQ_TXOKINT_ENABLE | 125239201Sadrian HAL_TXQ_TXERRINT_ENABLE; 126239201Sadrian 127235680Sadrian return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi); 128235680Sadrian} 129235680Sadrian 130235680Sadrian/* 131235680Sadrian * Setup the transmit queue parameters for the beacon queue. 132235680Sadrian */ 133235680Sadrianint 134235680Sadrianath_beaconq_config(struct ath_softc *sc) 135235680Sadrian{ 136235680Sadrian#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) 137287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 138235680Sadrian struct ath_hal *ah = sc->sc_ah; 139235680Sadrian HAL_TXQ_INFO qi; 140235680Sadrian 141235680Sadrian ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi); 142235680Sadrian if (ic->ic_opmode == IEEE80211_M_HOSTAP || 143235680Sadrian ic->ic_opmode == IEEE80211_M_MBSS) { 144235680Sadrian /* 145235680Sadrian * Always burst out beacon and CAB traffic. 146235680Sadrian */ 147235680Sadrian qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; 148235680Sadrian qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT; 149235680Sadrian qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT; 150235680Sadrian } else { 151235680Sadrian struct wmeParams *wmep = 152235680Sadrian &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE]; 153235680Sadrian /* 154235680Sadrian * Adhoc mode; important thing is to use 2x cwmin. 155235680Sadrian */ 156235680Sadrian qi.tqi_aifs = wmep->wmep_aifsn; 157235680Sadrian qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 158235680Sadrian qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 159235680Sadrian } 160235680Sadrian 161235680Sadrian if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) { 162235680Sadrian device_printf(sc->sc_dev, "unable to update parameters for " 163235680Sadrian "beacon hardware queue!\n"); 164235680Sadrian return 0; 165235680Sadrian } else { 166235680Sadrian ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ 167235680Sadrian return 1; 168235680Sadrian } 169235680Sadrian#undef ATH_EXPONENT_TO_VALUE 170235680Sadrian} 171235680Sadrian 172235680Sadrian/* 173235680Sadrian * Allocate and setup an initial beacon frame. 174235680Sadrian */ 175235680Sadrianint 176235680Sadrianath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) 177235680Sadrian{ 178235680Sadrian struct ieee80211vap *vap = ni->ni_vap; 179235680Sadrian struct ath_vap *avp = ATH_VAP(vap); 180235680Sadrian struct ath_buf *bf; 181235680Sadrian struct mbuf *m; 182235680Sadrian int error; 183235680Sadrian 184235680Sadrian bf = avp->av_bcbuf; 185235680Sadrian DPRINTF(sc, ATH_DEBUG_NODE, "%s: bf_m=%p, bf_node=%p\n", 186235680Sadrian __func__, bf->bf_m, bf->bf_node); 187235680Sadrian if (bf->bf_m != NULL) { 188235680Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 189235680Sadrian m_freem(bf->bf_m); 190235680Sadrian bf->bf_m = NULL; 191235680Sadrian } 192235680Sadrian if (bf->bf_node != NULL) { 193235680Sadrian ieee80211_free_node(bf->bf_node); 194235680Sadrian bf->bf_node = NULL; 195235680Sadrian } 196235680Sadrian 197235680Sadrian /* 198235680Sadrian * NB: the beacon data buffer must be 32-bit aligned; 199235680Sadrian * we assume the mbuf routines will return us something 200235680Sadrian * with this alignment (perhaps should assert). 201235680Sadrian */ 202288636Sadrian m = ieee80211_beacon_alloc(ni); 203235680Sadrian if (m == NULL) { 204235680Sadrian device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__); 205235680Sadrian sc->sc_stats.ast_be_nombuf++; 206235680Sadrian return ENOMEM; 207235680Sadrian } 208235680Sadrian error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 209235680Sadrian bf->bf_segs, &bf->bf_nseg, 210235680Sadrian BUS_DMA_NOWAIT); 211235680Sadrian if (error != 0) { 212235680Sadrian device_printf(sc->sc_dev, 213235680Sadrian "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n", 214235680Sadrian __func__, error); 215235680Sadrian m_freem(m); 216235680Sadrian return error; 217235680Sadrian } 218235680Sadrian 219235680Sadrian /* 220235680Sadrian * Calculate a TSF adjustment factor required for staggered 221235680Sadrian * beacons. Note that we assume the format of the beacon 222235680Sadrian * frame leaves the tstamp field immediately following the 223235680Sadrian * header. 224235680Sadrian */ 225235680Sadrian if (sc->sc_stagbeacons && avp->av_bslot > 0) { 226235680Sadrian uint64_t tsfadjust; 227235680Sadrian struct ieee80211_frame *wh; 228235680Sadrian 229235680Sadrian /* 230235680Sadrian * The beacon interval is in TU's; the TSF is in usecs. 231235680Sadrian * We figure out how many TU's to add to align the timestamp 232235680Sadrian * then convert to TSF units and handle byte swapping before 233235680Sadrian * inserting it in the frame. The hardware will then add this 234235680Sadrian * each time a beacon frame is sent. Note that we align vap's 235235680Sadrian * 1..N and leave vap 0 untouched. This means vap 0 has a 236235680Sadrian * timestamp in one beacon interval while the others get a 237235680Sadrian * timstamp aligned to the next interval. 238235680Sadrian */ 239235680Sadrian tsfadjust = ni->ni_intval * 240235680Sadrian (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF; 241235680Sadrian tsfadjust = htole64(tsfadjust << 10); /* TU -> TSF */ 242235680Sadrian 243235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 244235680Sadrian "%s: %s beacons bslot %d intval %u tsfadjust %llu\n", 245235680Sadrian __func__, sc->sc_stagbeacons ? "stagger" : "burst", 246235680Sadrian avp->av_bslot, ni->ni_intval, 247235680Sadrian (long long unsigned) le64toh(tsfadjust)); 248235680Sadrian 249235680Sadrian wh = mtod(m, struct ieee80211_frame *); 250235680Sadrian memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust)); 251235680Sadrian } 252235680Sadrian bf->bf_m = m; 253235680Sadrian bf->bf_node = ieee80211_ref_node(ni); 254235680Sadrian 255235680Sadrian return 0; 256235680Sadrian} 257235680Sadrian 258235680Sadrian/* 259235680Sadrian * Setup the beacon frame for transmit. 260235680Sadrian */ 261235680Sadrianstatic void 262235680Sadrianath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) 263235680Sadrian{ 264235680Sadrian#define USE_SHPREAMBLE(_ic) \ 265235680Sadrian (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 266235680Sadrian == IEEE80211_F_SHPREAMBLE) 267235680Sadrian struct ieee80211_node *ni = bf->bf_node; 268235680Sadrian struct ieee80211com *ic = ni->ni_ic; 269235680Sadrian struct mbuf *m = bf->bf_m; 270235680Sadrian struct ath_hal *ah = sc->sc_ah; 271235680Sadrian struct ath_desc *ds; 272235680Sadrian int flags, antenna; 273235680Sadrian const HAL_RATE_TABLE *rt; 274235680Sadrian u_int8_t rix, rate; 275239051Sadrian HAL_DMA_ADDR bufAddrList[4]; 276239051Sadrian uint32_t segLenList[4]; 277239201Sadrian HAL_11N_RATE_SERIES rc[4]; 278235680Sadrian 279235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n", 280235680Sadrian __func__, m, m->m_len); 281235680Sadrian 282235680Sadrian /* setup descriptors */ 283235680Sadrian ds = bf->bf_desc; 284235680Sadrian bf->bf_last = bf; 285235680Sadrian bf->bf_lastds = ds; 286235680Sadrian 287235680Sadrian flags = HAL_TXDESC_NOACK; 288235680Sadrian if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) { 289238609Sadrian /* self-linked descriptor */ 290238609Sadrian ath_hal_settxdesclink(sc->sc_ah, ds, bf->bf_daddr); 291235680Sadrian flags |= HAL_TXDESC_VEOL; 292235680Sadrian /* 293235680Sadrian * Let hardware handle antenna switching. 294235680Sadrian */ 295235680Sadrian antenna = sc->sc_txantenna; 296235680Sadrian } else { 297238609Sadrian ath_hal_settxdesclink(sc->sc_ah, ds, 0); 298235680Sadrian /* 299235680Sadrian * Switch antenna every 4 beacons. 300235680Sadrian * XXX assumes two antenna 301235680Sadrian */ 302235680Sadrian if (sc->sc_txantenna != 0) 303235680Sadrian antenna = sc->sc_txantenna; 304235680Sadrian else if (sc->sc_stagbeacons && sc->sc_nbcnvaps != 0) 305235680Sadrian antenna = ((sc->sc_stats.ast_be_xmit / sc->sc_nbcnvaps) & 4 ? 2 : 1); 306235680Sadrian else 307235680Sadrian antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1); 308235680Sadrian } 309235680Sadrian 310235680Sadrian KASSERT(bf->bf_nseg == 1, 311235680Sadrian ("multi-segment beacon frame; nseg %u", bf->bf_nseg)); 312239051Sadrian 313235680Sadrian /* 314235680Sadrian * Calculate rate code. 315235680Sadrian * XXX everything at min xmit rate 316235680Sadrian */ 317235680Sadrian rix = 0; 318235680Sadrian rt = sc->sc_currates; 319235680Sadrian rate = rt->info[rix].rateCode; 320235680Sadrian if (USE_SHPREAMBLE(ic)) 321235680Sadrian rate |= rt->info[rix].shortPreamble; 322235680Sadrian ath_hal_setuptxdesc(ah, ds 323235680Sadrian , m->m_len + IEEE80211_CRC_LEN /* frame length */ 324235680Sadrian , sizeof(struct ieee80211_frame)/* header length */ 325235680Sadrian , HAL_PKT_TYPE_BEACON /* Atheros packet type */ 326249569Sadrian , ieee80211_get_node_txpower(ni) /* txpower XXX */ 327235680Sadrian , rate, 1 /* series 0 rate/tries */ 328235680Sadrian , HAL_TXKEYIX_INVALID /* no encryption */ 329235680Sadrian , antenna /* antenna mode */ 330235680Sadrian , flags /* no ack, veol for beacons */ 331235680Sadrian , 0 /* rts/cts rate */ 332235680Sadrian , 0 /* rts/cts duration */ 333235680Sadrian ); 334239201Sadrian 335239201Sadrian /* 336239201Sadrian * The EDMA HAL currently assumes that _all_ rate control 337239201Sadrian * settings are done in ath_hal_set11nratescenario(), rather 338239201Sadrian * than in ath_hal_setuptxdesc(). 339239201Sadrian */ 340239201Sadrian if (sc->sc_isedma) { 341239201Sadrian memset(&rc, 0, sizeof(rc)); 342239201Sadrian 343239201Sadrian rc[0].ChSel = sc->sc_txchainmask; 344239201Sadrian rc[0].Tries = 1; 345239201Sadrian rc[0].Rate = rt->info[rix].rateCode; 346239201Sadrian rc[0].RateIndex = rix; 347239201Sadrian rc[0].tx_power_cap = 0x3f; 348239201Sadrian rc[0].PktDuration = 349239201Sadrian ath_hal_computetxtime(ah, rt, roundup(m->m_len, 4), 350239201Sadrian rix, 0); 351239201Sadrian ath_hal_set11nratescenario(ah, ds, 0, 0, rc, 4, flags); 352239201Sadrian } 353239201Sadrian 354235680Sadrian /* NB: beacon's BufLen must be a multiple of 4 bytes */ 355239051Sadrian segLenList[0] = roundup(m->m_len, 4); 356239051Sadrian segLenList[1] = segLenList[2] = segLenList[3] = 0; 357239051Sadrian bufAddrList[0] = bf->bf_segs[0].ds_addr; 358239051Sadrian bufAddrList[1] = bufAddrList[2] = bufAddrList[3] = 0; 359235680Sadrian ath_hal_filltxdesc(ah, ds 360239051Sadrian , bufAddrList 361239051Sadrian , segLenList 362239051Sadrian , 0 /* XXX desc id */ 363239051Sadrian , sc->sc_bhalq /* hardware TXQ */ 364235680Sadrian , AH_TRUE /* first segment */ 365235680Sadrian , AH_TRUE /* last segment */ 366235680Sadrian , ds /* first descriptor */ 367235680Sadrian ); 368235680Sadrian#if 0 369235680Sadrian ath_desc_swap(ds); 370235680Sadrian#endif 371235680Sadrian#undef USE_SHPREAMBLE 372235680Sadrian} 373235680Sadrian 374235680Sadrianvoid 375235680Sadrianath_beacon_update(struct ieee80211vap *vap, int item) 376235680Sadrian{ 377288095Sadrian struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 378235680Sadrian 379235680Sadrian setbit(bo->bo_flags, item); 380235680Sadrian} 381235680Sadrian 382235680Sadrian/* 383248671Sadrian * Handle a beacon miss. 384248671Sadrian */ 385265115Sadrianvoid 386248671Sadrianath_beacon_miss(struct ath_softc *sc) 387248671Sadrian{ 388248671Sadrian HAL_SURVEY_SAMPLE hs; 389248671Sadrian HAL_BOOL ret; 390248671Sadrian uint32_t hangs; 391248671Sadrian 392248671Sadrian bzero(&hs, sizeof(hs)); 393248671Sadrian 394248671Sadrian ret = ath_hal_get_mib_cycle_counts(sc->sc_ah, &hs); 395248671Sadrian 396248671Sadrian if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && hangs != 0) { 397248671Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 398248671Sadrian "%s: hang=0x%08x\n", 399248671Sadrian __func__, 400248671Sadrian hangs); 401248671Sadrian } 402248671Sadrian 403250619Sadrian#ifdef ATH_DEBUG_ALQ 404250619Sadrian if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_MISSED_BEACON)) 405250619Sadrian if_ath_alq_post(&sc->sc_alq, ATH_ALQ_MISSED_BEACON, 0, NULL); 406250619Sadrian#endif 407250619Sadrian 408248671Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 409248671Sadrian "%s: valid=%d, txbusy=%u, rxbusy=%u, chanbusy=%u, " 410248671Sadrian "extchanbusy=%u, cyclecount=%u\n", 411248671Sadrian __func__, 412248671Sadrian ret, 413248671Sadrian hs.tx_busy, 414248671Sadrian hs.rx_busy, 415248671Sadrian hs.chan_busy, 416248671Sadrian hs.ext_chan_busy, 417248671Sadrian hs.cycle_count); 418248671Sadrian} 419248671Sadrian 420248671Sadrian/* 421235680Sadrian * Transmit a beacon frame at SWBA. Dynamic updates to the 422235680Sadrian * frame contents are done as needed and the slot time is 423235680Sadrian * also adjusted based on current state. 424235680Sadrian */ 425235680Sadrianvoid 426235680Sadrianath_beacon_proc(void *arg, int pending) 427235680Sadrian{ 428235680Sadrian struct ath_softc *sc = arg; 429235680Sadrian struct ath_hal *ah = sc->sc_ah; 430235680Sadrian struct ieee80211vap *vap; 431235680Sadrian struct ath_buf *bf; 432235680Sadrian int slot, otherant; 433235680Sadrian uint32_t bfaddr; 434235680Sadrian 435235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n", 436235680Sadrian __func__, pending); 437235680Sadrian /* 438235680Sadrian * Check if the previous beacon has gone out. If 439235680Sadrian * not don't try to post another, skip this period 440235680Sadrian * and wait for the next. Missed beacons indicate 441235680Sadrian * a problem and should not occur. If we miss too 442235680Sadrian * many consecutive beacons reset the device. 443235680Sadrian */ 444235680Sadrian if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { 445235680Sadrian sc->sc_bmisscount++; 446235680Sadrian sc->sc_stats.ast_be_missed++; 447248671Sadrian ath_beacon_miss(sc); 448235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 449235680Sadrian "%s: missed %u consecutive beacons\n", 450235680Sadrian __func__, sc->sc_bmisscount); 451235680Sadrian if (sc->sc_bmisscount >= ath_bstuck_threshold) 452235680Sadrian taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); 453235680Sadrian return; 454235680Sadrian } 455235680Sadrian if (sc->sc_bmisscount != 0) { 456235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 457235680Sadrian "%s: resume beacon xmit after %u misses\n", 458235680Sadrian __func__, sc->sc_bmisscount); 459235680Sadrian sc->sc_bmisscount = 0; 460250619Sadrian#ifdef ATH_DEBUG_ALQ 461250619Sadrian if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_RESUME_BEACON)) 462250619Sadrian if_ath_alq_post(&sc->sc_alq, ATH_ALQ_RESUME_BEACON, 0, NULL); 463250619Sadrian#endif 464235680Sadrian } 465235680Sadrian 466235680Sadrian if (sc->sc_stagbeacons) { /* staggered beacons */ 467287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 468235680Sadrian uint32_t tsftu; 469235680Sadrian 470235680Sadrian tsftu = ath_hal_gettsf32(ah) >> 10; 471235680Sadrian /* XXX lintval */ 472235680Sadrian slot = ((tsftu % ic->ic_lintval) * ATH_BCBUF) / ic->ic_lintval; 473235680Sadrian vap = sc->sc_bslot[(slot+1) % ATH_BCBUF]; 474235680Sadrian bfaddr = 0; 475235680Sadrian if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) { 476235680Sadrian bf = ath_beacon_generate(sc, vap); 477235680Sadrian if (bf != NULL) 478235680Sadrian bfaddr = bf->bf_daddr; 479235680Sadrian } 480235680Sadrian } else { /* burst'd beacons */ 481235680Sadrian uint32_t *bflink = &bfaddr; 482235680Sadrian 483235680Sadrian for (slot = 0; slot < ATH_BCBUF; slot++) { 484235680Sadrian vap = sc->sc_bslot[slot]; 485235680Sadrian if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) { 486235680Sadrian bf = ath_beacon_generate(sc, vap); 487248750Sadrian /* 488248750Sadrian * XXX TODO: this should use settxdesclinkptr() 489248750Sadrian * otherwise it won't work for EDMA chipsets! 490248750Sadrian */ 491235680Sadrian if (bf != NULL) { 492238609Sadrian /* XXX should do this using the ds */ 493235680Sadrian *bflink = bf->bf_daddr; 494238609Sadrian ath_hal_gettxdesclinkptr(sc->sc_ah, 495238609Sadrian bf->bf_desc, &bflink); 496235680Sadrian } 497235680Sadrian } 498235680Sadrian } 499248750Sadrian /* 500248750Sadrian * XXX TODO: this should use settxdesclinkptr() 501248750Sadrian * otherwise it won't work for EDMA chipsets! 502248750Sadrian */ 503235680Sadrian *bflink = 0; /* terminate list */ 504235680Sadrian } 505235680Sadrian 506235680Sadrian /* 507235680Sadrian * Handle slot time change when a non-ERP station joins/leaves 508235680Sadrian * an 11g network. The 802.11 layer notifies us via callback, 509235680Sadrian * we mark updateslot, then wait one beacon before effecting 510235680Sadrian * the change. This gives associated stations at least one 511235680Sadrian * beacon interval to note the state change. 512235680Sadrian */ 513235680Sadrian /* XXX locking */ 514235680Sadrian if (sc->sc_updateslot == UPDATE) { 515235680Sadrian sc->sc_updateslot = COMMIT; /* commit next beacon */ 516235680Sadrian sc->sc_slotupdate = slot; 517235680Sadrian } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) 518235680Sadrian ath_setslottime(sc); /* commit change to h/w */ 519235680Sadrian 520235680Sadrian /* 521235680Sadrian * Check recent per-antenna transmit statistics and flip 522235680Sadrian * the default antenna if noticeably more frames went out 523235680Sadrian * on the non-default antenna. 524235680Sadrian * XXX assumes 2 anntenae 525235680Sadrian */ 526235680Sadrian if (!sc->sc_diversity && (!sc->sc_stagbeacons || slot == 0)) { 527235680Sadrian otherant = sc->sc_defant & 1 ? 2 : 1; 528235680Sadrian if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) 529235680Sadrian ath_setdefantenna(sc, otherant); 530235680Sadrian sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; 531235680Sadrian } 532235680Sadrian 533248671Sadrian /* Program the CABQ with the contents of the CABQ txq and start it */ 534248671Sadrian ATH_TXQ_LOCK(sc->sc_cabq); 535248671Sadrian ath_beacon_cabq_start(sc); 536248671Sadrian ATH_TXQ_UNLOCK(sc->sc_cabq); 537248671Sadrian 538248671Sadrian /* Program the new beacon frame if we have one for this interval */ 539235680Sadrian if (bfaddr != 0) { 540235680Sadrian /* 541235680Sadrian * Stop any current dma and put the new frame on the queue. 542235680Sadrian * This should never fail since we check above that no frames 543235680Sadrian * are still pending on the queue. 544235680Sadrian */ 545239201Sadrian if (! sc->sc_isedma) { 546239201Sadrian if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { 547239201Sadrian DPRINTF(sc, ATH_DEBUG_ANY, 548239201Sadrian "%s: beacon queue %u did not stop?\n", 549239201Sadrian __func__, sc->sc_bhalq); 550239201Sadrian } 551235680Sadrian } 552235680Sadrian /* NB: cabq traffic should already be queued and primed */ 553239201Sadrian 554235680Sadrian ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr); 555235680Sadrian ath_hal_txstart(ah, sc->sc_bhalq); 556235680Sadrian 557235680Sadrian sc->sc_stats.ast_be_xmit++; 558235680Sadrian } 559235680Sadrian} 560235680Sadrian 561248750Sadrianstatic void 562248750Sadrianath_beacon_cabq_start_edma(struct ath_softc *sc) 563248671Sadrian{ 564248750Sadrian struct ath_buf *bf, *bf_last; 565248750Sadrian struct ath_txq *cabq = sc->sc_cabq; 566248750Sadrian#if 0 567248750Sadrian struct ath_buf *bfi; 568248750Sadrian int i = 0; 569248750Sadrian#endif 570248750Sadrian 571248750Sadrian ATH_TXQ_LOCK_ASSERT(cabq); 572248750Sadrian 573248750Sadrian if (TAILQ_EMPTY(&cabq->axq_q)) 574248750Sadrian return; 575248750Sadrian bf = TAILQ_FIRST(&cabq->axq_q); 576248750Sadrian bf_last = TAILQ_LAST(&cabq->axq_q, axq_q_s); 577248750Sadrian 578248750Sadrian /* 579248750Sadrian * This is a dirty, dirty hack to push the contents of 580248750Sadrian * the cabq staging queue into the FIFO. 581248750Sadrian * 582248750Sadrian * This ideally should live in the EDMA code file 583248750Sadrian * and only push things into the CABQ if there's a FIFO 584248750Sadrian * slot. 585248750Sadrian * 586248750Sadrian * We can't treat this like a normal TX queue because 587248750Sadrian * in the case of multi-VAP traffic, we may have to flush 588248750Sadrian * the CABQ each new (staggered) beacon that goes out. 589248750Sadrian * But for non-staggered beacons, we could in theory 590248750Sadrian * handle multicast traffic for all VAPs in one FIFO 591248750Sadrian * push. Just keep all of this in mind if you're wondering 592248750Sadrian * how to correctly/better handle multi-VAP CABQ traffic 593248750Sadrian * with EDMA. 594248750Sadrian */ 595248750Sadrian 596248750Sadrian /* 597248750Sadrian * Is the CABQ FIFO free? If not, complain loudly and 598248750Sadrian * don't queue anything. Maybe we'll flush the CABQ 599248750Sadrian * traffic, maybe we won't. But that'll happen next 600248750Sadrian * beacon interval. 601248750Sadrian */ 602248750Sadrian if (cabq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) { 603248750Sadrian device_printf(sc->sc_dev, 604248750Sadrian "%s: Q%d: CAB FIFO queue=%d?\n", 605248750Sadrian __func__, 606248750Sadrian cabq->axq_qnum, 607248750Sadrian cabq->axq_fifo_depth); 608248750Sadrian return; 609248750Sadrian } 610248750Sadrian 611248750Sadrian /* 612248750Sadrian * Ok, so here's the gymnastics reqiured to make this 613248750Sadrian * all sensible. 614248750Sadrian */ 615248750Sadrian 616248750Sadrian /* 617248750Sadrian * Tag the first/last buffer appropriately. 618248750Sadrian */ 619248750Sadrian bf->bf_flags |= ATH_BUF_FIFOPTR; 620248750Sadrian bf_last->bf_flags |= ATH_BUF_FIFOEND; 621248750Sadrian 622248750Sadrian#if 0 623248750Sadrian i = 0; 624248750Sadrian TAILQ_FOREACH(bfi, &cabq->axq_q, bf_list) { 625248750Sadrian ath_printtxbuf(sc, bf, cabq->axq_qnum, i, 0); 626248750Sadrian i++; 627248750Sadrian } 628248750Sadrian#endif 629248750Sadrian 630248750Sadrian /* 631248750Sadrian * We now need to push this set of frames onto the tail 632248750Sadrian * of the FIFO queue. We don't adjust the aggregate 633248750Sadrian * count, only the queue depth counter(s). 634248750Sadrian * We also need to blank the link pointer now. 635248750Sadrian */ 636248750Sadrian TAILQ_CONCAT(&cabq->fifo.axq_q, &cabq->axq_q, bf_list); 637248750Sadrian cabq->axq_link = NULL; 638248750Sadrian cabq->fifo.axq_depth += cabq->axq_depth; 639248750Sadrian cabq->axq_depth = 0; 640248750Sadrian 641248750Sadrian /* Bump FIFO queue */ 642248750Sadrian cabq->axq_fifo_depth++; 643248750Sadrian 644248750Sadrian /* Push the first entry into the hardware */ 645248750Sadrian ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr); 646250783Sadrian cabq->axq_flags |= ATH_TXQ_PUTRUNNING; 647248750Sadrian 648248750Sadrian /* NB: gated by beacon so safe to start here */ 649248750Sadrian ath_hal_txstart(sc->sc_ah, cabq->axq_qnum); 650248750Sadrian 651248750Sadrian} 652248750Sadrian 653248750Sadrianstatic void 654248750Sadrianath_beacon_cabq_start_legacy(struct ath_softc *sc) 655248750Sadrian{ 656248671Sadrian struct ath_buf *bf; 657248671Sadrian struct ath_txq *cabq = sc->sc_cabq; 658248671Sadrian 659248671Sadrian ATH_TXQ_LOCK_ASSERT(cabq); 660248671Sadrian if (TAILQ_EMPTY(&cabq->axq_q)) 661248671Sadrian return; 662248671Sadrian bf = TAILQ_FIRST(&cabq->axq_q); 663248671Sadrian 664248671Sadrian /* Push the first entry into the hardware */ 665248671Sadrian ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr); 666250783Sadrian cabq->axq_flags |= ATH_TXQ_PUTRUNNING; 667248671Sadrian 668248671Sadrian /* NB: gated by beacon so safe to start here */ 669248671Sadrian ath_hal_txstart(sc->sc_ah, cabq->axq_qnum); 670248671Sadrian} 671248671Sadrian 672248750Sadrian/* 673248750Sadrian * Start CABQ transmission - this assumes that all frames are prepped 674248750Sadrian * and ready in the CABQ. 675248750Sadrian */ 676248750Sadrianvoid 677248750Sadrianath_beacon_cabq_start(struct ath_softc *sc) 678248750Sadrian{ 679248750Sadrian struct ath_txq *cabq = sc->sc_cabq; 680248750Sadrian 681248750Sadrian ATH_TXQ_LOCK_ASSERT(cabq); 682248750Sadrian 683248750Sadrian if (TAILQ_EMPTY(&cabq->axq_q)) 684248750Sadrian return; 685248750Sadrian 686248750Sadrian if (sc->sc_isedma) 687248750Sadrian ath_beacon_cabq_start_edma(sc); 688248750Sadrian else 689248750Sadrian ath_beacon_cabq_start_legacy(sc); 690248750Sadrian} 691248750Sadrian 692235680Sadrianstruct ath_buf * 693235680Sadrianath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) 694235680Sadrian{ 695235680Sadrian struct ath_vap *avp = ATH_VAP(vap); 696235680Sadrian struct ath_txq *cabq = sc->sc_cabq; 697235680Sadrian struct ath_buf *bf; 698235680Sadrian struct mbuf *m; 699235680Sadrian int nmcastq, error; 700235680Sadrian 701235680Sadrian KASSERT(vap->iv_state >= IEEE80211_S_RUN, 702235680Sadrian ("not running, state %d", vap->iv_state)); 703235680Sadrian KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer")); 704235680Sadrian 705235680Sadrian /* 706235680Sadrian * Update dynamic beacon contents. If this returns 707235680Sadrian * non-zero then we need to remap the memory because 708235680Sadrian * the beacon frame changed size (probably because 709235680Sadrian * of the TIM bitmap). 710235680Sadrian */ 711235680Sadrian bf = avp->av_bcbuf; 712235680Sadrian m = bf->bf_m; 713235680Sadrian /* XXX lock mcastq? */ 714235680Sadrian nmcastq = avp->av_mcastq.axq_depth; 715235680Sadrian 716288636Sadrian if (ieee80211_beacon_update(bf->bf_node, m, nmcastq)) { 717235680Sadrian /* XXX too conservative? */ 718235680Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 719235680Sadrian error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 720235680Sadrian bf->bf_segs, &bf->bf_nseg, 721235680Sadrian BUS_DMA_NOWAIT); 722235680Sadrian if (error != 0) { 723235680Sadrian if_printf(vap->iv_ifp, 724235680Sadrian "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 725235680Sadrian __func__, error); 726235680Sadrian return NULL; 727235680Sadrian } 728235680Sadrian } 729288095Sadrian if ((vap->iv_bcn_off.bo_tim[4] & 1) && cabq->axq_depth) { 730235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 731235680Sadrian "%s: cabq did not drain, mcastq %u cabq %u\n", 732235680Sadrian __func__, nmcastq, cabq->axq_depth); 733235680Sadrian sc->sc_stats.ast_cabq_busy++; 734235680Sadrian if (sc->sc_nvaps > 1 && sc->sc_stagbeacons) { 735235680Sadrian /* 736235680Sadrian * CABQ traffic from a previous vap is still pending. 737235680Sadrian * We must drain the q before this beacon frame goes 738235680Sadrian * out as otherwise this vap's stations will get cab 739235680Sadrian * frames from a different vap. 740235680Sadrian * XXX could be slow causing us to miss DBA 741235680Sadrian */ 742250783Sadrian /* 743250783Sadrian * XXX TODO: this doesn't stop CABQ DMA - it assumes 744250783Sadrian * that since we're about to transmit a beacon, we've 745250783Sadrian * already stopped transmitting on the CABQ. But this 746250783Sadrian * doesn't at all mean that the CABQ DMA QCU will 747250783Sadrian * accept a new TXDP! So what, should we do a DMA 748250783Sadrian * stop? What if it fails? 749250783Sadrian * 750250783Sadrian * More thought is required here. 751250783Sadrian */ 752270430Sadrian /* 753270430Sadrian * XXX can we even stop TX DMA here? Check what the 754270430Sadrian * reference driver does for cabq for beacons, given 755270430Sadrian * that stopping TX requires RX is paused. 756270430Sadrian */ 757235680Sadrian ath_tx_draintxq(sc, cabq); 758235680Sadrian } 759235680Sadrian } 760235680Sadrian ath_beacon_setup(sc, bf); 761235680Sadrian bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 762235680Sadrian 763235680Sadrian /* 764235680Sadrian * Enable the CAB queue before the beacon queue to 765235680Sadrian * insure cab frames are triggered by this beacon. 766235680Sadrian */ 767288095Sadrian if (vap->iv_bcn_off.bo_tim[4] & 1) { 768235680Sadrian 769235680Sadrian /* NB: only at DTIM */ 770248671Sadrian ATH_TXQ_LOCK(&avp->av_mcastq); 771235680Sadrian if (nmcastq) { 772248715Sadrian struct ath_buf *bfm, *bfc_last; 773235680Sadrian 774235680Sadrian /* 775235680Sadrian * Move frames from the s/w mcast q to the h/w cab q. 776248528Sadrian * 777248671Sadrian * XXX TODO: if we chain together multiple VAPs 778248671Sadrian * worth of CABQ traffic, should we keep the 779248671Sadrian * MORE data bit set on the last frame of each 780248671Sadrian * intermediary VAP (ie, only clear the MORE 781248671Sadrian * bit of the last frame on the last vap?) 782235680Sadrian */ 783235680Sadrian bfm = TAILQ_FIRST(&avp->av_mcastq.axq_q); 784248671Sadrian ATH_TXQ_LOCK(cabq); 785248715Sadrian 786248715Sadrian /* 787248715Sadrian * If there's already a frame on the CABQ, we 788248715Sadrian * need to link to the end of the last frame. 789248715Sadrian * We can't use axq_link here because 790248715Sadrian * EDMA descriptors require some recalculation 791248715Sadrian * (checksum) to occur. 792248715Sadrian */ 793248715Sadrian bfc_last = ATH_TXQ_LAST(cabq, axq_q_s); 794248715Sadrian if (bfc_last != NULL) { 795248715Sadrian ath_hal_settxdesclink(sc->sc_ah, 796248715Sadrian bfc_last->bf_lastds, 797248715Sadrian bfm->bf_daddr); 798248715Sadrian } 799235680Sadrian ath_txqmove(cabq, &avp->av_mcastq); 800248671Sadrian ATH_TXQ_UNLOCK(cabq); 801248671Sadrian /* 802248671Sadrian * XXX not entirely accurate, in case a mcast 803248671Sadrian * queue frame arrived before we grabbed the TX 804248671Sadrian * lock. 805248671Sadrian */ 806235680Sadrian sc->sc_stats.ast_cabq_xmit += nmcastq; 807235680Sadrian } 808248671Sadrian ATH_TXQ_UNLOCK(&avp->av_mcastq); 809235680Sadrian } 810235680Sadrian return bf; 811235680Sadrian} 812235680Sadrian 813235680Sadrianvoid 814235680Sadrianath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap) 815235680Sadrian{ 816235680Sadrian struct ath_vap *avp = ATH_VAP(vap); 817235680Sadrian struct ath_hal *ah = sc->sc_ah; 818235680Sadrian struct ath_buf *bf; 819235680Sadrian struct mbuf *m; 820235680Sadrian int error; 821235680Sadrian 822235680Sadrian KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer")); 823235680Sadrian 824235680Sadrian /* 825235680Sadrian * Update dynamic beacon contents. If this returns 826235680Sadrian * non-zero then we need to remap the memory because 827235680Sadrian * the beacon frame changed size (probably because 828235680Sadrian * of the TIM bitmap). 829235680Sadrian */ 830235680Sadrian bf = avp->av_bcbuf; 831235680Sadrian m = bf->bf_m; 832288636Sadrian if (ieee80211_beacon_update(bf->bf_node, m, 0)) { 833235680Sadrian /* XXX too conservative? */ 834235680Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 835235680Sadrian error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 836235680Sadrian bf->bf_segs, &bf->bf_nseg, 837235680Sadrian BUS_DMA_NOWAIT); 838235680Sadrian if (error != 0) { 839235680Sadrian if_printf(vap->iv_ifp, 840235680Sadrian "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 841235680Sadrian __func__, error); 842235680Sadrian return; 843235680Sadrian } 844235680Sadrian } 845235680Sadrian ath_beacon_setup(sc, bf); 846235680Sadrian bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 847235680Sadrian 848235680Sadrian /* NB: caller is known to have already stopped tx dma */ 849235680Sadrian ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); 850235680Sadrian ath_hal_txstart(ah, sc->sc_bhalq); 851235680Sadrian} 852235680Sadrian 853235680Sadrian/* 854235680Sadrian * Reclaim beacon resources and return buffer to the pool. 855235680Sadrian */ 856235680Sadrianvoid 857235680Sadrianath_beacon_return(struct ath_softc *sc, struct ath_buf *bf) 858235680Sadrian{ 859235680Sadrian 860235680Sadrian DPRINTF(sc, ATH_DEBUG_NODE, "%s: free bf=%p, bf_m=%p, bf_node=%p\n", 861235680Sadrian __func__, bf, bf->bf_m, bf->bf_node); 862235680Sadrian if (bf->bf_m != NULL) { 863235680Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 864235680Sadrian m_freem(bf->bf_m); 865235680Sadrian bf->bf_m = NULL; 866235680Sadrian } 867235680Sadrian if (bf->bf_node != NULL) { 868235680Sadrian ieee80211_free_node(bf->bf_node); 869235680Sadrian bf->bf_node = NULL; 870235680Sadrian } 871235680Sadrian TAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list); 872235680Sadrian} 873235680Sadrian 874235680Sadrian/* 875235680Sadrian * Reclaim beacon resources. 876235680Sadrian */ 877235680Sadrianvoid 878235680Sadrianath_beacon_free(struct ath_softc *sc) 879235680Sadrian{ 880235680Sadrian struct ath_buf *bf; 881235680Sadrian 882235680Sadrian TAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { 883235680Sadrian DPRINTF(sc, ATH_DEBUG_NODE, 884235680Sadrian "%s: free bf=%p, bf_m=%p, bf_node=%p\n", 885235680Sadrian __func__, bf, bf->bf_m, bf->bf_node); 886235680Sadrian if (bf->bf_m != NULL) { 887235680Sadrian bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 888235680Sadrian m_freem(bf->bf_m); 889235680Sadrian bf->bf_m = NULL; 890235680Sadrian } 891235680Sadrian if (bf->bf_node != NULL) { 892235680Sadrian ieee80211_free_node(bf->bf_node); 893235680Sadrian bf->bf_node = NULL; 894235680Sadrian } 895235680Sadrian } 896235680Sadrian} 897235680Sadrian 898235680Sadrian/* 899235680Sadrian * Configure the beacon and sleep timers. 900235680Sadrian * 901235680Sadrian * When operating as an AP this resets the TSF and sets 902235680Sadrian * up the hardware to notify us when we need to issue beacons. 903235680Sadrian * 904235680Sadrian * When operating in station mode this sets up the beacon 905235680Sadrian * timers according to the timestamp of the last received 906235680Sadrian * beacon and the current TSF, configures PCF and DTIM 907235680Sadrian * handling, programs the sleep registers so the hardware 908235680Sadrian * will wakeup in time to receive beacons, and configures 909235680Sadrian * the beacon miss handling so we'll receive a BMISS 910235680Sadrian * interrupt when we stop seeing beacons from the AP 911235680Sadrian * we've associated with. 912235680Sadrian */ 913235680Sadrianvoid 914235680Sadrianath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) 915235680Sadrian{ 916235680Sadrian#define TSF_TO_TU(_h,_l) \ 917235680Sadrian ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) 918235680Sadrian#define FUDGE 2 919235680Sadrian struct ath_hal *ah = sc->sc_ah; 920287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 921235680Sadrian struct ieee80211_node *ni; 922235680Sadrian u_int32_t nexttbtt, intval, tsftu; 923239201Sadrian u_int32_t nexttbtt_u8, intval_u8; 924265115Sadrian u_int64_t tsf, tsf_beacon; 925235680Sadrian 926235680Sadrian if (vap == NULL) 927235680Sadrian vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ 928245554Sadrian /* 929245554Sadrian * Just ensure that we aren't being called when the last 930245554Sadrian * VAP is destroyed. 931245554Sadrian */ 932245554Sadrian if (vap == NULL) { 933245554Sadrian device_printf(sc->sc_dev, "%s: called with no VAPs\n", 934245554Sadrian __func__); 935245554Sadrian return; 936245554Sadrian } 937245554Sadrian 938235680Sadrian ni = ieee80211_ref_node(vap->iv_bss); 939235680Sadrian 940265115Sadrian ATH_LOCK(sc); 941265115Sadrian ath_power_set_power_state(sc, HAL_PM_AWAKE); 942265115Sadrian ATH_UNLOCK(sc); 943265115Sadrian 944235680Sadrian /* extract tstamp from last beacon and convert to TU */ 945298359Savos nexttbtt = TSF_TO_TU(le32dec(ni->ni_tstamp.data + 4), 946298359Savos le32dec(ni->ni_tstamp.data)); 947265115Sadrian 948298359Savos tsf_beacon = ((uint64_t) le32dec(ni->ni_tstamp.data + 4)) << 32; 949298359Savos tsf_beacon |= le32dec(ni->ni_tstamp.data); 950265115Sadrian 951235680Sadrian if (ic->ic_opmode == IEEE80211_M_HOSTAP || 952235680Sadrian ic->ic_opmode == IEEE80211_M_MBSS) { 953235680Sadrian /* 954235680Sadrian * For multi-bss ap/mesh support beacons are either staggered 955235680Sadrian * evenly over N slots or burst together. For the former 956235680Sadrian * arrange for the SWBA to be delivered for each slot. 957235680Sadrian * Slots that are not occupied will generate nothing. 958235680Sadrian */ 959235680Sadrian /* NB: the beacon interval is kept internally in TU's */ 960235680Sadrian intval = ni->ni_intval & HAL_BEACON_PERIOD; 961235680Sadrian if (sc->sc_stagbeacons) 962235680Sadrian intval /= ATH_BCBUF; 963235680Sadrian } else { 964235680Sadrian /* NB: the beacon interval is kept internally in TU's */ 965235680Sadrian intval = ni->ni_intval & HAL_BEACON_PERIOD; 966235680Sadrian } 967235680Sadrian if (nexttbtt == 0) /* e.g. for ap mode */ 968235680Sadrian nexttbtt = intval; 969235680Sadrian else if (intval) /* NB: can be 0 for monitor mode */ 970235680Sadrian nexttbtt = roundup(nexttbtt, intval); 971235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", 972235680Sadrian __func__, nexttbtt, intval, ni->ni_intval); 973235680Sadrian if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) { 974235680Sadrian HAL_BEACON_STATE bs; 975235680Sadrian int dtimperiod, dtimcount; 976235680Sadrian int cfpperiod, cfpcount; 977235680Sadrian 978235680Sadrian /* 979235680Sadrian * Setup dtim and cfp parameters according to 980235680Sadrian * last beacon we received (which may be none). 981235680Sadrian */ 982235680Sadrian dtimperiod = ni->ni_dtim_period; 983235680Sadrian if (dtimperiod <= 0) /* NB: 0 if not known */ 984235680Sadrian dtimperiod = 1; 985235680Sadrian dtimcount = ni->ni_dtim_count; 986235680Sadrian if (dtimcount >= dtimperiod) /* NB: sanity check */ 987235680Sadrian dtimcount = 0; /* XXX? */ 988235680Sadrian cfpperiod = 1; /* NB: no PCF support yet */ 989235680Sadrian cfpcount = 0; 990235680Sadrian /* 991235680Sadrian * Pull nexttbtt forward to reflect the current 992235680Sadrian * TSF and calculate dtim+cfp state for the result. 993235680Sadrian */ 994235680Sadrian tsf = ath_hal_gettsf64(ah); 995235680Sadrian tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 996265115Sadrian 997265115Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 998265115Sadrian "%s: beacon tsf=%llu, hw tsf=%llu, nexttbtt=%u, tsftu=%u\n", 999265115Sadrian __func__, 1000265115Sadrian (unsigned long long) tsf_beacon, 1001265115Sadrian (unsigned long long) tsf, 1002265115Sadrian nexttbtt, 1003265115Sadrian tsftu); 1004265115Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 1005265115Sadrian "%s: beacon tsf=%llu, hw tsf=%llu, tsf delta=%lld\n", 1006265115Sadrian __func__, 1007265115Sadrian (unsigned long long) tsf_beacon, 1008265115Sadrian (unsigned long long) tsf, 1009265115Sadrian (long long) tsf - 1010265115Sadrian (long long) tsf_beacon); 1011265115Sadrian 1012265115Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 1013265115Sadrian "%s: nexttbtt=%llu, beacon tsf delta=%lld\n", 1014265115Sadrian __func__, 1015265115Sadrian (unsigned long long) nexttbtt, 1016265115Sadrian (long long) ((long long) nexttbtt * 1024LL) - (long long) tsf_beacon); 1017265115Sadrian 1018265115Sadrian /* XXX cfpcount? */ 1019265115Sadrian 1020265115Sadrian if (nexttbtt > tsftu) { 1021265115Sadrian uint32_t countdiff, oldtbtt, remainder; 1022265115Sadrian 1023265115Sadrian oldtbtt = nexttbtt; 1024265115Sadrian remainder = (nexttbtt - tsftu) % intval; 1025265115Sadrian nexttbtt = tsftu + remainder; 1026265115Sadrian 1027265115Sadrian countdiff = (oldtbtt - nexttbtt) / intval % dtimperiod; 1028265115Sadrian if (dtimcount > countdiff) { 1029265115Sadrian dtimcount -= countdiff; 1030265115Sadrian } else { 1031265115Sadrian dtimcount += dtimperiod - countdiff; 1032235680Sadrian } 1033265115Sadrian } else { //nexttbtt <= tsftu 1034265115Sadrian uint32_t countdiff, oldtbtt, remainder; 1035265115Sadrian 1036265115Sadrian oldtbtt = nexttbtt; 1037265115Sadrian remainder = (tsftu - nexttbtt) % intval; 1038265115Sadrian nexttbtt = tsftu - remainder + intval; 1039265115Sadrian countdiff = (nexttbtt - oldtbtt) / intval % dtimperiod; 1040265115Sadrian if (dtimcount > countdiff) { 1041265115Sadrian dtimcount -= countdiff; 1042265115Sadrian } else { 1043265115Sadrian dtimcount += dtimperiod - countdiff; 1044265115Sadrian } 1045265115Sadrian } 1046265115Sadrian 1047265115Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 1048265115Sadrian "%s: adj nexttbtt=%llu, rx tsf delta=%lld\n", 1049265115Sadrian __func__, 1050265115Sadrian (unsigned long long) nexttbtt, 1051265115Sadrian (long long) ((long long)nexttbtt * 1024LL) - (long long)tsf); 1052265115Sadrian 1053235680Sadrian memset(&bs, 0, sizeof(bs)); 1054235680Sadrian bs.bs_intval = intval; 1055235680Sadrian bs.bs_nexttbtt = nexttbtt; 1056235680Sadrian bs.bs_dtimperiod = dtimperiod*intval; 1057235680Sadrian bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 1058235680Sadrian bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 1059235680Sadrian bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 1060235680Sadrian bs.bs_cfpmaxduration = 0; 1061235680Sadrian#if 0 1062235680Sadrian /* 1063235680Sadrian * The 802.11 layer records the offset to the DTIM 1064235680Sadrian * bitmap while receiving beacons; use it here to 1065235680Sadrian * enable h/w detection of our AID being marked in 1066235680Sadrian * the bitmap vector (to indicate frames for us are 1067235680Sadrian * pending at the AP). 1068235680Sadrian * XXX do DTIM handling in s/w to WAR old h/w bugs 1069235680Sadrian * XXX enable based on h/w rev for newer chips 1070235680Sadrian */ 1071235680Sadrian bs.bs_timoffset = ni->ni_timoff; 1072235680Sadrian#endif 1073235680Sadrian /* 1074235680Sadrian * Calculate the number of consecutive beacons to miss 1075235680Sadrian * before taking a BMISS interrupt. 1076235680Sadrian * Note that we clamp the result to at most 10 beacons. 1077235680Sadrian */ 1078235680Sadrian bs.bs_bmissthreshold = vap->iv_bmissthreshold; 1079235680Sadrian if (bs.bs_bmissthreshold > 10) 1080235680Sadrian bs.bs_bmissthreshold = 10; 1081235680Sadrian else if (bs.bs_bmissthreshold <= 0) 1082235680Sadrian bs.bs_bmissthreshold = 1; 1083235680Sadrian 1084235680Sadrian /* 1085235680Sadrian * Calculate sleep duration. The configuration is 1086235680Sadrian * given in ms. We insure a multiple of the beacon 1087235680Sadrian * period is used. Also, if the sleep duration is 1088235680Sadrian * greater than the DTIM period then it makes senses 1089235680Sadrian * to make it a multiple of that. 1090235680Sadrian * 1091235680Sadrian * XXX fixed at 100ms 1092235680Sadrian */ 1093235680Sadrian bs.bs_sleepduration = 1094235680Sadrian roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval); 1095235680Sadrian if (bs.bs_sleepduration > bs.bs_dtimperiod) 1096235680Sadrian bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 1097235680Sadrian 1098235680Sadrian DPRINTF(sc, ATH_DEBUG_BEACON, 1099265115Sadrian "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u " 1100265115Sadrian "nextdtim %u bmiss %u sleep %u cfp:period %u " 1101265115Sadrian "maxdur %u next %u timoffset %u\n" 1102235680Sadrian , __func__ 1103265115Sadrian , tsf 1104265115Sadrian , tsftu 1105235680Sadrian , bs.bs_intval 1106235680Sadrian , bs.bs_nexttbtt 1107235680Sadrian , bs.bs_dtimperiod 1108235680Sadrian , bs.bs_nextdtim 1109235680Sadrian , bs.bs_bmissthreshold 1110235680Sadrian , bs.bs_sleepduration 1111235680Sadrian , bs.bs_cfpperiod 1112235680Sadrian , bs.bs_cfpmaxduration 1113235680Sadrian , bs.bs_cfpnext 1114235680Sadrian , bs.bs_timoffset 1115235680Sadrian ); 1116235680Sadrian ath_hal_intrset(ah, 0); 1117235680Sadrian ath_hal_beacontimers(ah, &bs); 1118235680Sadrian sc->sc_imask |= HAL_INT_BMISS; 1119235680Sadrian ath_hal_intrset(ah, sc->sc_imask); 1120235680Sadrian } else { 1121235680Sadrian ath_hal_intrset(ah, 0); 1122235680Sadrian if (nexttbtt == intval) 1123235680Sadrian intval |= HAL_BEACON_RESET_TSF; 1124235680Sadrian if (ic->ic_opmode == IEEE80211_M_IBSS) { 1125235680Sadrian /* 1126235680Sadrian * In IBSS mode enable the beacon timers but only 1127235680Sadrian * enable SWBA interrupts if we need to manually 1128235680Sadrian * prepare beacon frames. Otherwise we use a 1129235680Sadrian * self-linked tx descriptor and let the hardware 1130235680Sadrian * deal with things. 1131235680Sadrian */ 1132235680Sadrian intval |= HAL_BEACON_ENA; 1133235680Sadrian if (!sc->sc_hasveol) 1134235680Sadrian sc->sc_imask |= HAL_INT_SWBA; 1135235680Sadrian if ((intval & HAL_BEACON_RESET_TSF) == 0) { 1136235680Sadrian /* 1137235680Sadrian * Pull nexttbtt forward to reflect 1138235680Sadrian * the current TSF. 1139235680Sadrian */ 1140235680Sadrian tsf = ath_hal_gettsf64(ah); 1141235680Sadrian tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 1142235680Sadrian do { 1143235680Sadrian nexttbtt += intval; 1144235680Sadrian } while (nexttbtt < tsftu); 1145235680Sadrian } 1146235680Sadrian ath_beaconq_config(sc); 1147235680Sadrian } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 1148235680Sadrian ic->ic_opmode == IEEE80211_M_MBSS) { 1149235680Sadrian /* 1150235680Sadrian * In AP/mesh mode we enable the beacon timers 1151235680Sadrian * and SWBA interrupts to prepare beacon frames. 1152235680Sadrian */ 1153235680Sadrian intval |= HAL_BEACON_ENA; 1154235680Sadrian sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */ 1155235680Sadrian ath_beaconq_config(sc); 1156235680Sadrian } 1157239201Sadrian 1158239201Sadrian /* 1159239201Sadrian * Now dirty things because for now, the EDMA HAL has 1160239201Sadrian * nexttbtt and intval is TU/8. 1161239201Sadrian */ 1162239201Sadrian if (sc->sc_isedma) { 1163239201Sadrian nexttbtt_u8 = (nexttbtt << 3); 1164239201Sadrian intval_u8 = (intval << 3); 1165239201Sadrian if (intval & HAL_BEACON_ENA) 1166239201Sadrian intval_u8 |= HAL_BEACON_ENA; 1167239201Sadrian if (intval & HAL_BEACON_RESET_TSF) 1168239201Sadrian intval_u8 |= HAL_BEACON_RESET_TSF; 1169239201Sadrian ath_hal_beaconinit(ah, nexttbtt_u8, intval_u8); 1170239201Sadrian } else 1171239201Sadrian ath_hal_beaconinit(ah, nexttbtt, intval); 1172235680Sadrian sc->sc_bmisscount = 0; 1173235680Sadrian ath_hal_intrset(ah, sc->sc_imask); 1174235680Sadrian /* 1175235680Sadrian * When using a self-linked beacon descriptor in 1176235680Sadrian * ibss mode load it once here. 1177235680Sadrian */ 1178235680Sadrian if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) 1179235680Sadrian ath_beacon_start_adhoc(sc, vap); 1180235680Sadrian } 1181235680Sadrian ieee80211_free_node(ni); 1182265115Sadrian 1183265115Sadrian ATH_LOCK(sc); 1184265115Sadrian ath_power_restore_power_state(sc); 1185265115Sadrian ATH_UNLOCK(sc); 1186235680Sadrian#undef FUDGE 1187235680Sadrian#undef TSF_TO_TU 1188235680Sadrian} 1189