15591b213SSam Leffler /*- 210ad9a77SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 35591b213SSam Leffler * All rights reserved. 45591b213SSam Leffler * 55591b213SSam Leffler * Redistribution and use in source and binary forms, with or without 65591b213SSam Leffler * modification, are permitted provided that the following conditions 75591b213SSam Leffler * are met: 85591b213SSam Leffler * 1. Redistributions of source code must retain the above copyright 95591b213SSam Leffler * notice, this list of conditions and the following disclaimer, 105591b213SSam Leffler * without modification. 115591b213SSam Leffler * 2. Redistributions in binary form must reproduce at minimum a disclaimer 125591b213SSam Leffler * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 135591b213SSam Leffler * redistribution must be conditioned upon including a substantially 145591b213SSam Leffler * similar Disclaimer requirement for further binary redistribution. 155591b213SSam Leffler * 165591b213SSam Leffler * NO WARRANTY 175591b213SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 185591b213SSam Leffler * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 195591b213SSam Leffler * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 205591b213SSam Leffler * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 215591b213SSam Leffler * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 225591b213SSam Leffler * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 235591b213SSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 245591b213SSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 255591b213SSam Leffler * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 265591b213SSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 275591b213SSam Leffler * THE POSSIBILITY OF SUCH DAMAGES. 285591b213SSam Leffler */ 295591b213SSam Leffler 305591b213SSam Leffler #include <sys/cdefs.h> 315591b213SSam Leffler __FBSDID("$FreeBSD$"); 325591b213SSam Leffler 335591b213SSam Leffler /* 345591b213SSam Leffler * Driver for the Atheros Wireless LAN controller. 355f3721d5SSam Leffler * 365f3721d5SSam Leffler * This software is derived from work of Atsushi Onoe; his contribution 375f3721d5SSam Leffler * is greatly appreciated. 385591b213SSam Leffler */ 395591b213SSam Leffler 405591b213SSam Leffler #include "opt_inet.h" 41a585a9a1SSam Leffler #include "opt_ath.h" 42584f7327SSam Leffler #include "opt_wlan.h" 435591b213SSam Leffler 445591b213SSam Leffler #include <sys/param.h> 455591b213SSam Leffler #include <sys/systm.h> 465591b213SSam Leffler #include <sys/sysctl.h> 475591b213SSam Leffler #include <sys/mbuf.h> 485591b213SSam Leffler #include <sys/malloc.h> 495591b213SSam Leffler #include <sys/lock.h> 505591b213SSam Leffler #include <sys/mutex.h> 515591b213SSam Leffler #include <sys/kernel.h> 525591b213SSam Leffler #include <sys/socket.h> 535591b213SSam Leffler #include <sys/sockio.h> 545591b213SSam Leffler #include <sys/errno.h> 555591b213SSam Leffler #include <sys/callout.h> 565591b213SSam Leffler #include <sys/bus.h> 575591b213SSam Leffler #include <sys/endian.h> 580bbf5441SSam Leffler #include <sys/kthread.h> 590bbf5441SSam Leffler #include <sys/taskqueue.h> 603fc21fedSSam Leffler #include <sys/priv.h> 61dba9c859SAdrian Chadd #include <sys/module.h> 625591b213SSam Leffler 635591b213SSam Leffler #include <machine/bus.h> 645591b213SSam Leffler 655591b213SSam Leffler #include <net/if.h> 665591b213SSam Leffler #include <net/if_dl.h> 675591b213SSam Leffler #include <net/if_media.h> 68fc74a9f9SBrooks Davis #include <net/if_types.h> 695591b213SSam Leffler #include <net/if_arp.h> 705591b213SSam Leffler #include <net/ethernet.h> 715591b213SSam Leffler #include <net/if_llc.h> 725591b213SSam Leffler 735591b213SSam Leffler #include <net80211/ieee80211_var.h> 7459efa8b5SSam Leffler #include <net80211/ieee80211_regdomain.h> 75339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 76339ccfb3SSam Leffler #include <net80211/ieee80211_superg.h> 77339ccfb3SSam Leffler #endif 78584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 7910ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h> 8010ad9a77SSam Leffler #endif 815591b213SSam Leffler 825591b213SSam Leffler #include <net/bpf.h> 835591b213SSam Leffler 845591b213SSam Leffler #ifdef INET 855591b213SSam Leffler #include <netinet/in.h> 865591b213SSam Leffler #include <netinet/if_ether.h> 875591b213SSam Leffler #endif 885591b213SSam Leffler 895591b213SSam Leffler #include <dev/ath/if_athvar.h> 9033644623SSam Leffler #include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 910dbe9289SAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h> 925591b213SSam Leffler 935bc8125aSAdrian Chadd #include <dev/ath/if_ath_debug.h> 94b8e788a5SAdrian Chadd #include <dev/ath/if_ath_misc.h> 95b8e788a5SAdrian Chadd #include <dev/ath/if_ath_tx.h> 966079fdbeSAdrian Chadd #include <dev/ath/if_ath_sysctl.h> 97d2d7a00aSAdrian Chadd #include <dev/ath/if_ath_keycache.h> 98*48237774SAdrian Chadd #include <dev/ath/if_athdfs.h> 995bc8125aSAdrian Chadd 10086e07743SSam Leffler #ifdef ATH_TX99_DIAG 10186e07743SSam Leffler #include <dev/ath/ath_tx99/ath_tx99.h> 10286e07743SSam Leffler #endif 10386e07743SSam Leffler 104*48237774SAdrian Chadd 105b032f27cSSam Leffler /* 106b032f27cSSam Leffler * ATH_BCBUF determines the number of vap's that can transmit 107b032f27cSSam Leffler * beacons and also (currently) the number of vap's that can 108b032f27cSSam Leffler * have unique mac addresses/bssid. When staggering beacons 109b032f27cSSam Leffler * 4 is probably a good max as otherwise the beacons become 110b032f27cSSam Leffler * very closely spaced and there is limited time for cab q traffic 111b032f27cSSam Leffler * to go out. You can burst beacons instead but that is not good 112b032f27cSSam Leffler * for stations in power save and at some point you really want 113b032f27cSSam Leffler * another radio (and channel). 114b032f27cSSam Leffler * 115b032f27cSSam Leffler * The limit on the number of mac addresses is tied to our use of 116b032f27cSSam Leffler * the U/L bit and tracking addresses in a byte; it would be 117b032f27cSSam Leffler * worthwhile to allow more for applications like proxy sta. 118b032f27cSSam Leffler */ 119b032f27cSSam Leffler CTASSERT(ATH_BCBUF <= 8); 120b032f27cSSam Leffler 121b032f27cSSam Leffler static struct ieee80211vap *ath_vap_create(struct ieee80211com *, 122b032f27cSSam Leffler const char name[IFNAMSIZ], int unit, int opmode, 123b032f27cSSam Leffler int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], 124b032f27cSSam Leffler const uint8_t mac[IEEE80211_ADDR_LEN]); 125b032f27cSSam Leffler static void ath_vap_delete(struct ieee80211vap *); 1265591b213SSam Leffler static void ath_init(void *); 127c42a7b7eSSam Leffler static void ath_stop_locked(struct ifnet *); 1285591b213SSam Leffler static void ath_stop(struct ifnet *); 1295591b213SSam Leffler static void ath_start(struct ifnet *); 130b032f27cSSam Leffler static int ath_reset_vap(struct ieee80211vap *, u_long); 1315591b213SSam Leffler static int ath_media_change(struct ifnet *); 1322e986da5SSam Leffler static void ath_watchdog(void *); 1335591b213SSam Leffler static int ath_ioctl(struct ifnet *, u_long, caddr_t); 1345591b213SSam Leffler static void ath_fatal_proc(void *, int); 135b032f27cSSam Leffler static void ath_bmiss_vap(struct ieee80211vap *); 1365591b213SSam Leffler static void ath_bmiss_proc(void *, int); 137b032f27cSSam Leffler static void ath_key_update_begin(struct ieee80211vap *); 138b032f27cSSam Leffler static void ath_key_update_end(struct ieee80211vap *); 139b032f27cSSam Leffler static void ath_update_mcast(struct ifnet *); 140b032f27cSSam Leffler static void ath_update_promisc(struct ifnet *); 1415591b213SSam Leffler static void ath_mode_init(struct ath_softc *); 142c42a7b7eSSam Leffler static void ath_setslottime(struct ath_softc *); 143c42a7b7eSSam Leffler static void ath_updateslot(struct ifnet *); 14480d2765fSSam Leffler static int ath_beaconq_setup(struct ath_hal *); 1455591b213SSam Leffler static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); 146b032f27cSSam Leffler static void ath_beacon_update(struct ieee80211vap *, int item); 147c42a7b7eSSam Leffler static void ath_beacon_setup(struct ath_softc *, struct ath_buf *); 1485591b213SSam Leffler static void ath_beacon_proc(void *, int); 149b032f27cSSam Leffler static struct ath_buf *ath_beacon_generate(struct ath_softc *, 150b032f27cSSam Leffler struct ieee80211vap *); 151c42a7b7eSSam Leffler static void ath_bstuck_proc(void *, int); 152b032f27cSSam Leffler static void ath_beacon_return(struct ath_softc *, struct ath_buf *); 1535591b213SSam Leffler static void ath_beacon_free(struct ath_softc *); 154b032f27cSSam Leffler static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *); 155c42a7b7eSSam Leffler static void ath_descdma_cleanup(struct ath_softc *sc, 156c42a7b7eSSam Leffler struct ath_descdma *, ath_bufhead *); 1575591b213SSam Leffler static int ath_desc_alloc(struct ath_softc *); 1585591b213SSam Leffler static void ath_desc_free(struct ath_softc *); 15938c208f8SSam Leffler static struct ieee80211_node *ath_node_alloc(struct ieee80211vap *, 16038c208f8SSam Leffler const uint8_t [IEEE80211_ADDR_LEN]); 161c42a7b7eSSam Leffler static void ath_node_free(struct ieee80211_node *); 16268e8e04eSSam Leffler static void ath_node_getsignal(const struct ieee80211_node *, 16368e8e04eSSam Leffler int8_t *, int8_t *); 1645591b213SSam Leffler static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *); 165b032f27cSSam Leffler static void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, 1665463c4a4SSam Leffler int subtype, int rssi, int nf); 167c42a7b7eSSam Leffler static void ath_setdefantenna(struct ath_softc *, u_int); 1685591b213SSam Leffler static void ath_rx_proc(void *, int); 169622b3fd2SSam Leffler static void ath_txq_init(struct ath_softc *sc, struct ath_txq *, int); 170c42a7b7eSSam Leffler static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype); 171c42a7b7eSSam Leffler static int ath_tx_setup(struct ath_softc *, int, int); 172c42a7b7eSSam Leffler static int ath_wme_update(struct ieee80211com *); 173c42a7b7eSSam Leffler static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *); 174c42a7b7eSSam Leffler static void ath_tx_cleanup(struct ath_softc *); 175c42a7b7eSSam Leffler static void ath_tx_proc_q0(void *, int); 176c42a7b7eSSam Leffler static void ath_tx_proc_q0123(void *, int); 1775591b213SSam Leffler static void ath_tx_proc(void *, int); 178b032f27cSSam Leffler static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *); 1795591b213SSam Leffler static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *); 1805591b213SSam Leffler static void ath_draintxq(struct ath_softc *); 1815591b213SSam Leffler static void ath_stoprecv(struct ath_softc *); 1825591b213SSam Leffler static int ath_startrecv(struct ath_softc *); 183c42a7b7eSSam Leffler static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *); 18468e8e04eSSam Leffler static void ath_scan_start(struct ieee80211com *); 18568e8e04eSSam Leffler static void ath_scan_end(struct ieee80211com *); 18668e8e04eSSam Leffler static void ath_set_channel(struct ieee80211com *); 1875591b213SSam Leffler static void ath_calibrate(void *); 188b032f27cSSam Leffler static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int); 189e8fd88a3SSam Leffler static void ath_setup_stationkey(struct ieee80211_node *); 190e9962332SSam Leffler static void ath_newassoc(struct ieee80211_node *, int); 191b032f27cSSam Leffler static int ath_setregdomain(struct ieee80211com *, 192b032f27cSSam Leffler struct ieee80211_regdomain *, int, 193b032f27cSSam Leffler struct ieee80211_channel []); 1945fe9f044SSam Leffler static void ath_getradiocaps(struct ieee80211com *, int, int *, 195b032f27cSSam Leffler struct ieee80211_channel []); 196b032f27cSSam Leffler static int ath_getchannels(struct ath_softc *); 1973e50ec2cSSam Leffler static void ath_led_event(struct ath_softc *, int); 1985591b213SSam Leffler 199c42a7b7eSSam Leffler static int ath_rate_setup(struct ath_softc *, u_int mode); 2005591b213SSam Leffler static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); 201c42a7b7eSSam Leffler 202c42a7b7eSSam Leffler static void ath_announce(struct ath_softc *); 2035591b213SSam Leffler 204*48237774SAdrian Chadd static void ath_dfs_tasklet(void *, int); 205*48237774SAdrian Chadd 206584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 20710ad9a77SSam Leffler static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, 20810ad9a77SSam Leffler u_int32_t bintval); 20910ad9a77SSam Leffler static void ath_tdma_bintvalsetup(struct ath_softc *sc, 21010ad9a77SSam Leffler const struct ieee80211_tdma_state *tdma); 21110ad9a77SSam Leffler static void ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap); 21210ad9a77SSam Leffler static void ath_tdma_update(struct ieee80211_node *ni, 2132bc3ce77SSam Leffler const struct ieee80211_tdma_param *tdma, int); 21410ad9a77SSam Leffler static void ath_tdma_beacon_send(struct ath_softc *sc, 21510ad9a77SSam Leffler struct ieee80211vap *vap); 21610ad9a77SSam Leffler 21710ad9a77SSam Leffler static __inline void 21810ad9a77SSam Leffler ath_hal_setcca(struct ath_hal *ah, int ena) 21910ad9a77SSam Leffler { 22010ad9a77SSam Leffler /* 22110ad9a77SSam Leffler * NB: fill me in; this is not provided by default because disabling 22210ad9a77SSam Leffler * CCA in most locales violates regulatory. 22310ad9a77SSam Leffler */ 22410ad9a77SSam Leffler } 22510ad9a77SSam Leffler 22610ad9a77SSam Leffler static __inline int 22710ad9a77SSam Leffler ath_hal_getcca(struct ath_hal *ah) 22810ad9a77SSam Leffler { 22910ad9a77SSam Leffler u_int32_t diag; 23010ad9a77SSam Leffler if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) 23110ad9a77SSam Leffler return 1; 23210ad9a77SSam Leffler return ((diag & 0x500000) == 0); 23310ad9a77SSam Leffler } 23410ad9a77SSam Leffler 23510ad9a77SSam Leffler #define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */ 23610ad9a77SSam Leffler #define TDMA_LPF_LEN 6 23710ad9a77SSam Leffler #define TDMA_DUMMY_MARKER 0x127 23810ad9a77SSam Leffler #define TDMA_EP_MUL(x, mul) ((x) * (mul)) 23910ad9a77SSam Leffler #define TDMA_IN(x) (TDMA_EP_MUL((x), TDMA_EP_MULTIPLIER)) 24010ad9a77SSam Leffler #define TDMA_LPF(x, y, len) \ 24110ad9a77SSam Leffler ((x != TDMA_DUMMY_MARKER) ? (((x) * ((len)-1) + (y)) / (len)) : (y)) 24210ad9a77SSam Leffler #define TDMA_SAMPLE(x, y) do { \ 24310ad9a77SSam Leffler x = TDMA_LPF((x), TDMA_IN(y), TDMA_LPF_LEN); \ 24410ad9a77SSam Leffler } while (0) 24510ad9a77SSam Leffler #define TDMA_EP_RND(x,mul) \ 24610ad9a77SSam Leffler ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) 24710ad9a77SSam Leffler #define TDMA_AVG(x) TDMA_EP_RND(x, TDMA_EP_MULTIPLIER) 248584f7327SSam Leffler #endif /* IEEE80211_SUPPORT_TDMA */ 24910ad9a77SSam Leffler 2505591b213SSam Leffler SYSCTL_DECL(_hw_ath); 2515591b213SSam Leffler 2525591b213SSam Leffler /* XXX validate sysctl values */ 2532dc7fcc4SSam Leffler static int ath_longcalinterval = 30; /* long cals every 30 secs */ 2542dc7fcc4SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, longcal, CTLFLAG_RW, &ath_longcalinterval, 2552dc7fcc4SSam Leffler 0, "long chip calibration interval (secs)"); 2562dc7fcc4SSam Leffler static int ath_shortcalinterval = 100; /* short cals every 100 ms */ 2572dc7fcc4SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, shortcal, CTLFLAG_RW, &ath_shortcalinterval, 2582dc7fcc4SSam Leffler 0, "short chip calibration interval (msecs)"); 2592dc7fcc4SSam Leffler static int ath_resetcalinterval = 20*60; /* reset cal state 20 mins */ 2602dc7fcc4SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, resetcal, CTLFLAG_RW, &ath_resetcalinterval, 2612dc7fcc4SSam Leffler 0, "reset chip calibration results (secs)"); 262a108ab63SAdrian Chadd static int ath_anicalinterval = 100; /* ANI calibration - 100 msec */ 263a108ab63SAdrian Chadd SYSCTL_INT(_hw_ath, OID_AUTO, anical, CTLFLAG_RW, &ath_anicalinterval, 264a108ab63SAdrian Chadd 0, "ANI calibration (msecs)"); 2655591b213SSam Leffler 266e2d787faSSam Leffler static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */ 267aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf, 268e2d787faSSam Leffler 0, "rx buffers allocated"); 269e2d787faSSam Leffler TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf); 270e2d787faSSam Leffler static int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */ 271aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf, 272e2d787faSSam Leffler 0, "tx buffers allocated"); 273e2d787faSSam Leffler TUNABLE_INT("hw.ath.txbuf", &ath_txbuf); 274e2d787faSSam Leffler 275a32ac9d3SSam Leffler static int ath_bstuck_threshold = 4; /* max missed beacons */ 276a32ac9d3SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold, 277a32ac9d3SSam Leffler 0, "max missed beacon xmits before chip reset"); 278a32ac9d3SSam Leffler 279c42a7b7eSSam Leffler MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers"); 280c42a7b7eSSam Leffler 28167397d39SAdrian Chadd #define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20) 28267397d39SAdrian Chadd #define HAL_MODE_HT40 \ 28367397d39SAdrian Chadd (HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \ 28467397d39SAdrian Chadd HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS) 2855591b213SSam Leffler int 2865591b213SSam Leffler ath_attach(u_int16_t devid, struct ath_softc *sc) 2875591b213SSam Leffler { 288fc74a9f9SBrooks Davis struct ifnet *ifp; 289b032f27cSSam Leffler struct ieee80211com *ic; 290fc74a9f9SBrooks Davis struct ath_hal *ah = NULL; 2915591b213SSam Leffler HAL_STATUS status; 292c42a7b7eSSam Leffler int error = 0, i; 293411373ebSSam Leffler u_int wmodes; 29429aca940SSam Leffler uint8_t macaddr[IEEE80211_ADDR_LEN]; 2955591b213SSam Leffler 296c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); 2975591b213SSam Leffler 298b032f27cSSam Leffler ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 299fc74a9f9SBrooks Davis if (ifp == NULL) { 300fc74a9f9SBrooks Davis device_printf(sc->sc_dev, "can not if_alloc()\n"); 301fc74a9f9SBrooks Davis error = ENOSPC; 302fc74a9f9SBrooks Davis goto bad; 303fc74a9f9SBrooks Davis } 304b032f27cSSam Leffler ic = ifp->if_l2com; 305fc74a9f9SBrooks Davis 3065591b213SSam Leffler /* set these up early for if_printf use */ 3079bf40edeSBrooks Davis if_initname(ifp, device_get_name(sc->sc_dev), 3089bf40edeSBrooks Davis device_get_unit(sc->sc_dev)); 3095591b213SSam Leffler 31088117a53SAdrian Chadd ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, sc->sc_eepromdata, &status); 3115591b213SSam Leffler if (ah == NULL) { 3125591b213SSam Leffler if_printf(ifp, "unable to attach hardware; HAL status %u\n", 3135591b213SSam Leffler status); 3145591b213SSam Leffler error = ENXIO; 3155591b213SSam Leffler goto bad; 3165591b213SSam Leffler } 3175591b213SSam Leffler sc->sc_ah = ah; 318b58b3803SSam Leffler sc->sc_invalid = 0; /* ready to go, enable interrupt handling */ 3193297be13SSam Leffler #ifdef ATH_DEBUG 3203297be13SSam Leffler sc->sc_debug = ath_debug; 3213297be13SSam Leffler #endif 3225591b213SSam Leffler 3235591b213SSam Leffler /* 324c42a7b7eSSam Leffler * Check if the MAC has multi-rate retry support. 325c42a7b7eSSam Leffler * We do this by trying to setup a fake extended 326c42a7b7eSSam Leffler * descriptor. MAC's that don't have support will 327c42a7b7eSSam Leffler * return false w/o doing anything. MAC's that do 328c42a7b7eSSam Leffler * support it will return true w/o doing anything. 329c42a7b7eSSam Leffler */ 330c42a7b7eSSam Leffler sc->sc_mrretry = ath_hal_setupxtxdesc(ah, NULL, 0,0, 0,0, 0,0); 331c42a7b7eSSam Leffler 332c42a7b7eSSam Leffler /* 333c42a7b7eSSam Leffler * Check if the device has hardware counters for PHY 334c42a7b7eSSam Leffler * errors. If so we need to enable the MIB interrupt 335c42a7b7eSSam Leffler * so we can act on stat triggers. 336c42a7b7eSSam Leffler */ 337c42a7b7eSSam Leffler if (ath_hal_hwphycounters(ah)) 338c42a7b7eSSam Leffler sc->sc_needmib = 1; 339c42a7b7eSSam Leffler 340c42a7b7eSSam Leffler /* 341c42a7b7eSSam Leffler * Get the hardware key cache size. 342c42a7b7eSSam Leffler */ 343c42a7b7eSSam Leffler sc->sc_keymax = ath_hal_keycachesize(ah); 344e8fd88a3SSam Leffler if (sc->sc_keymax > ATH_KEYMAX) { 345e8fd88a3SSam Leffler if_printf(ifp, "Warning, using only %u of %u key cache slots\n", 346e8fd88a3SSam Leffler ATH_KEYMAX, sc->sc_keymax); 347e8fd88a3SSam Leffler sc->sc_keymax = ATH_KEYMAX; 348c42a7b7eSSam Leffler } 349c42a7b7eSSam Leffler /* 350c42a7b7eSSam Leffler * Reset the key cache since some parts do not 351c42a7b7eSSam Leffler * reset the contents on initial power up. 352c42a7b7eSSam Leffler */ 353c42a7b7eSSam Leffler for (i = 0; i < sc->sc_keymax; i++) 354c42a7b7eSSam Leffler ath_hal_keyreset(ah, i); 355c42a7b7eSSam Leffler 356c42a7b7eSSam Leffler /* 357b032f27cSSam Leffler * Collect the default channel list. 3585591b213SSam Leffler */ 359b032f27cSSam Leffler error = ath_getchannels(sc); 3605591b213SSam Leffler if (error != 0) 3615591b213SSam Leffler goto bad; 3625591b213SSam Leffler 3635591b213SSam Leffler /* 3645591b213SSam Leffler * Setup rate tables for all potential media types. 3655591b213SSam Leffler */ 3665591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11A); 3675591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11B); 3685591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11G); 369c42a7b7eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_TURBO_A); 370c42a7b7eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_TURBO_G); 37168e8e04eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_STURBO_A); 37268e8e04eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11NA); 37368e8e04eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11NG); 374724c193aSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_HALF); 375724c193aSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_QUARTER); 376aaa70f2fSSam Leffler 377c42a7b7eSSam Leffler /* NB: setup here so ath_rate_update is happy */ 378c42a7b7eSSam Leffler ath_setcurmode(sc, IEEE80211_MODE_11A); 3795591b213SSam Leffler 380c42a7b7eSSam Leffler /* 381c42a7b7eSSam Leffler * Allocate tx+rx descriptors and populate the lists. 382c42a7b7eSSam Leffler */ 3835591b213SSam Leffler error = ath_desc_alloc(sc); 3845591b213SSam Leffler if (error != 0) { 3855591b213SSam Leffler if_printf(ifp, "failed to allocate descriptors: %d\n", error); 3865591b213SSam Leffler goto bad; 3875591b213SSam Leffler } 3882e986da5SSam Leffler callout_init_mtx(&sc->sc_cal_ch, &sc->sc_mtx, 0); 3892e986da5SSam Leffler callout_init_mtx(&sc->sc_wd_ch, &sc->sc_mtx, 0); 3905591b213SSam Leffler 391f0b2a0beSSam Leffler ATH_TXBUF_LOCK_INIT(sc); 3925591b213SSam Leffler 3930bbf5441SSam Leffler sc->sc_tq = taskqueue_create("ath_taskq", M_NOWAIT, 3940bbf5441SSam Leffler taskqueue_thread_enqueue, &sc->sc_tq); 3950bbf5441SSam Leffler taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, 3960bbf5441SSam Leffler "%s taskq", ifp->if_xname); 3970bbf5441SSam Leffler 3985591b213SSam Leffler TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, sc); 3995591b213SSam Leffler TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc); 400c42a7b7eSSam Leffler TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc); 4015591b213SSam Leffler 4025591b213SSam Leffler /* 403c42a7b7eSSam Leffler * Allocate hardware transmit queues: one queue for 404c42a7b7eSSam Leffler * beacon frames and one data queue for each QoS 4054fa8d4efSDaniel Eischen * priority. Note that the hal handles resetting 406c42a7b7eSSam Leffler * these queues at the needed time. 407c42a7b7eSSam Leffler * 408c42a7b7eSSam Leffler * XXX PS-Poll 4095591b213SSam Leffler */ 41080d2765fSSam Leffler sc->sc_bhalq = ath_beaconq_setup(ah); 4115591b213SSam Leffler if (sc->sc_bhalq == (u_int) -1) { 4125591b213SSam Leffler if_printf(ifp, "unable to setup a beacon xmit queue!\n"); 413c42a7b7eSSam Leffler error = EIO; 414b28b4653SSam Leffler goto bad2; 4155591b213SSam Leffler } 416c42a7b7eSSam Leffler sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0); 417c42a7b7eSSam Leffler if (sc->sc_cabq == NULL) { 418c42a7b7eSSam Leffler if_printf(ifp, "unable to setup CAB xmit queue!\n"); 419c42a7b7eSSam Leffler error = EIO; 420c42a7b7eSSam Leffler goto bad2; 421c42a7b7eSSam Leffler } 422c42a7b7eSSam Leffler /* NB: insure BK queue is the lowest priority h/w queue */ 423c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { 424c42a7b7eSSam Leffler if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", 425c42a7b7eSSam Leffler ieee80211_wme_acnames[WME_AC_BK]); 426c42a7b7eSSam Leffler error = EIO; 427c42a7b7eSSam Leffler goto bad2; 428c42a7b7eSSam Leffler } 429c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) || 430c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) || 431c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) { 432c42a7b7eSSam Leffler /* 433c42a7b7eSSam Leffler * Not enough hardware tx queues to properly do WME; 434c42a7b7eSSam Leffler * just punt and assign them all to the same h/w queue. 435c42a7b7eSSam Leffler * We could do a better job of this if, for example, 436c42a7b7eSSam Leffler * we allocate queues when we switch from station to 437c42a7b7eSSam Leffler * AP mode. 438c42a7b7eSSam Leffler */ 439c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_VI] != NULL) 440c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_VI]); 441c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != NULL) 442c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_BE]); 443c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK]; 444c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK]; 445c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK]; 446c42a7b7eSSam Leffler } 447c42a7b7eSSam Leffler 448c42a7b7eSSam Leffler /* 449c42a7b7eSSam Leffler * Special case certain configurations. Note the 450c42a7b7eSSam Leffler * CAB queue is handled by these specially so don't 451c42a7b7eSSam Leffler * include them when checking the txq setup mask. 452c42a7b7eSSam Leffler */ 453c42a7b7eSSam Leffler switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) { 454c42a7b7eSSam Leffler case 0x01: 455c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc); 456c42a7b7eSSam Leffler break; 457c42a7b7eSSam Leffler case 0x0f: 458c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc); 459c42a7b7eSSam Leffler break; 460c42a7b7eSSam Leffler default: 461c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc); 462c42a7b7eSSam Leffler break; 463c42a7b7eSSam Leffler } 464c42a7b7eSSam Leffler 465c42a7b7eSSam Leffler /* 466c42a7b7eSSam Leffler * Setup rate control. Some rate control modules 467c42a7b7eSSam Leffler * call back to change the anntena state so expose 468c42a7b7eSSam Leffler * the necessary entry points. 469c42a7b7eSSam Leffler * XXX maybe belongs in struct ath_ratectrl? 470c42a7b7eSSam Leffler */ 471c42a7b7eSSam Leffler sc->sc_setdefantenna = ath_setdefantenna; 472c42a7b7eSSam Leffler sc->sc_rc = ath_rate_attach(sc); 473c42a7b7eSSam Leffler if (sc->sc_rc == NULL) { 474c42a7b7eSSam Leffler error = EIO; 475c42a7b7eSSam Leffler goto bad2; 476c42a7b7eSSam Leffler } 477c42a7b7eSSam Leffler 478*48237774SAdrian Chadd /* Attach DFS module */ 479*48237774SAdrian Chadd if (! ath_dfs_attach(sc)) { 480*48237774SAdrian Chadd device_printf(sc->sc_dev, "%s: unable to attach DFS\n", __func__); 481*48237774SAdrian Chadd error = EIO; 482*48237774SAdrian Chadd goto bad2; 483*48237774SAdrian Chadd } 484*48237774SAdrian Chadd 485*48237774SAdrian Chadd /* Start DFS processing tasklet */ 486*48237774SAdrian Chadd TASK_INIT(&sc->sc_dfstask, 0, ath_dfs_tasklet, sc); 487*48237774SAdrian Chadd 4883e50ec2cSSam Leffler sc->sc_blinking = 0; 489c42a7b7eSSam Leffler sc->sc_ledstate = 1; 4903e50ec2cSSam Leffler sc->sc_ledon = 0; /* low true */ 4913e50ec2cSSam Leffler sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */ 4923e50ec2cSSam Leffler callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE); 493c42a7b7eSSam Leffler /* 494c42a7b7eSSam Leffler * Auto-enable soft led processing for IBM cards and for 495c42a7b7eSSam Leffler * 5211 minipci cards. Users can also manually enable/disable 496c42a7b7eSSam Leffler * support with a sysctl. 497c42a7b7eSSam Leffler */ 498c42a7b7eSSam Leffler sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID); 499c42a7b7eSSam Leffler if (sc->sc_softled) { 500869ff02eSSam Leffler ath_hal_gpioCfgOutput(ah, sc->sc_ledpin, 501869ff02eSSam Leffler HAL_GPIO_MUX_MAC_NETWORK_LED); 5023e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); 503c42a7b7eSSam Leffler } 5045591b213SSam Leffler 5055591b213SSam Leffler ifp->if_softc = sc; 5065591b213SSam Leffler ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; 5075591b213SSam Leffler ifp->if_start = ath_start; 5085591b213SSam Leffler ifp->if_ioctl = ath_ioctl; 5095591b213SSam Leffler ifp->if_init = ath_init; 510e50d35e6SMaxim Sobolev IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 511e50d35e6SMaxim Sobolev ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 512154b8df2SMax Laier IFQ_SET_READY(&ifp->if_snd); 5135591b213SSam Leffler 514c42a7b7eSSam Leffler ic->ic_ifp = ifp; 5155591b213SSam Leffler /* XXX not right but it's not used anywhere important */ 5165591b213SSam Leffler ic->ic_phytype = IEEE80211_T_OFDM; 5175591b213SSam Leffler ic->ic_opmode = IEEE80211_M_STA; 518c42a7b7eSSam Leffler ic->ic_caps = 519c43feedeSSam Leffler IEEE80211_C_STA /* station mode */ 520c43feedeSSam Leffler | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 521fe32c3efSSam Leffler | IEEE80211_C_HOSTAP /* hostap mode */ 522fe32c3efSSam Leffler | IEEE80211_C_MONITOR /* monitor mode */ 5237a04dc27SSam Leffler | IEEE80211_C_AHDEMO /* adhoc demo mode */ 524b032f27cSSam Leffler | IEEE80211_C_WDS /* 4-address traffic works */ 52559aa14a9SRui Paulo | IEEE80211_C_MBSS /* mesh point link mode */ 526fe32c3efSSam Leffler | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 527c42a7b7eSSam Leffler | IEEE80211_C_SHSLOT /* short slot time supported */ 528c42a7b7eSSam Leffler | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 52968e8e04eSSam Leffler | IEEE80211_C_BGSCAN /* capable of bg scanning */ 53068e8e04eSSam Leffler | IEEE80211_C_TXFRAG /* handle tx frags */ 53101e7e035SSam Leffler ; 532c42a7b7eSSam Leffler /* 533c42a7b7eSSam Leffler * Query the hal to figure out h/w crypto support. 534c42a7b7eSSam Leffler */ 535c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP)) 536b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP; 537c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB)) 538b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_AES_OCB; 539c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM)) 540b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_AES_CCM; 541c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP)) 542b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_CKIP; 543c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) { 544b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIP; 545c42a7b7eSSam Leffler /* 546c42a7b7eSSam Leffler * Check if h/w does the MIC and/or whether the 547c42a7b7eSSam Leffler * separate key cache entries are required to 548c42a7b7eSSam Leffler * handle both tx+rx MIC keys. 549c42a7b7eSSam Leffler */ 550c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) 551b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIPMIC; 5525901d2d3SSam Leffler /* 5535901d2d3SSam Leffler * If the h/w supports storing tx+rx MIC keys 5545901d2d3SSam Leffler * in one cache slot automatically enable use. 5555901d2d3SSam Leffler */ 5565901d2d3SSam Leffler if (ath_hal_hastkipsplit(ah) || 5575901d2d3SSam Leffler !ath_hal_settkipsplit(ah, AH_FALSE)) 558c42a7b7eSSam Leffler sc->sc_splitmic = 1; 559b032f27cSSam Leffler /* 560b032f27cSSam Leffler * If the h/w can do TKIP MIC together with WME then 561b032f27cSSam Leffler * we use it; otherwise we force the MIC to be done 562b032f27cSSam Leffler * in software by the net80211 layer. 563b032f27cSSam Leffler */ 564b032f27cSSam Leffler if (ath_hal_haswmetkipmic(ah)) 565b032f27cSSam Leffler sc->sc_wmetkipmic = 1; 566c42a7b7eSSam Leffler } 567e8fd88a3SSam Leffler sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR); 5689ac01d39SRui Paulo /* 5691ac5dac2SRui Paulo * Check for multicast key search support. 5709ac01d39SRui Paulo */ 5719ac01d39SRui Paulo if (ath_hal_hasmcastkeysearch(sc->sc_ah) && 5729ac01d39SRui Paulo !ath_hal_getmcastkeysearch(sc->sc_ah)) { 5739ac01d39SRui Paulo ath_hal_setmcastkeysearch(sc->sc_ah, 1); 5749ac01d39SRui Paulo } 575e8fd88a3SSam Leffler sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah); 576c42a7b7eSSam Leffler /* 5775901d2d3SSam Leffler * Mark key cache slots associated with global keys 5785901d2d3SSam Leffler * as in use. If we knew TKIP was not to be used we 5795901d2d3SSam Leffler * could leave the +32, +64, and +32+64 slots free. 5805901d2d3SSam Leffler */ 5815901d2d3SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) { 5825901d2d3SSam Leffler setbit(sc->sc_keymap, i); 5835901d2d3SSam Leffler setbit(sc->sc_keymap, i+64); 5845901d2d3SSam Leffler if (sc->sc_splitmic) { 5855901d2d3SSam Leffler setbit(sc->sc_keymap, i+32); 5865901d2d3SSam Leffler setbit(sc->sc_keymap, i+32+64); 5875901d2d3SSam Leffler } 5885901d2d3SSam Leffler } 5895901d2d3SSam Leffler /* 590c42a7b7eSSam Leffler * TPC support can be done either with a global cap or 591c42a7b7eSSam Leffler * per-packet support. The latter is not available on 592c42a7b7eSSam Leffler * all parts. We're a bit pedantic here as all parts 593c42a7b7eSSam Leffler * support a global cap. 594c42a7b7eSSam Leffler */ 595c59005e9SSam Leffler if (ath_hal_hastpc(ah) || ath_hal_hastxpowlimit(ah)) 596c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TXPMGT; 597c42a7b7eSSam Leffler 598c42a7b7eSSam Leffler /* 599c42a7b7eSSam Leffler * Mark WME capability only if we have sufficient 600c42a7b7eSSam Leffler * hardware queues to do proper priority scheduling. 601c42a7b7eSSam Leffler */ 602c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != sc->sc_ac2q[WME_AC_BK]) 603c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_WME; 604c42a7b7eSSam Leffler /* 605e8fd88a3SSam Leffler * Check for misc other capabilities. 606c42a7b7eSSam Leffler */ 607c42a7b7eSSam Leffler if (ath_hal_hasbursting(ah)) 608c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_BURST; 609b032f27cSSam Leffler sc->sc_hasbmask = ath_hal_hasbssidmask(ah); 61059aa14a9SRui Paulo sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah); 611b032f27cSSam Leffler sc->sc_hastsfadd = ath_hal_hastsfadjust(ah); 6128a2a6beeSAdrian Chadd sc->sc_rxslink = ath_hal_self_linked_final_rxdesc(ah); 61368e8e04eSSam Leffler if (ath_hal_hasfastframes(ah)) 61468e8e04eSSam Leffler ic->ic_caps |= IEEE80211_C_FF; 61559efa8b5SSam Leffler wmodes = ath_hal_getwirelessmodes(ah); 616411373ebSSam Leffler if (wmodes & (HAL_MODE_108G|HAL_MODE_TURBO)) 61768e8e04eSSam Leffler ic->ic_caps |= IEEE80211_C_TURBOP; 618584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 61910ad9a77SSam Leffler if (ath_hal_macversion(ah) > 0x78) { 62010ad9a77SSam Leffler ic->ic_caps |= IEEE80211_C_TDMA; /* capable of TDMA */ 62110ad9a77SSam Leffler ic->ic_tdma_update = ath_tdma_update; 62210ad9a77SSam Leffler } 62310ad9a77SSam Leffler #endif 62467397d39SAdrian Chadd 62567397d39SAdrian Chadd /* 62667397d39SAdrian Chadd * The if_ath 11n support is completely not ready for normal use. 62767397d39SAdrian Chadd * Enabling this option will likely break everything and everything. 62867397d39SAdrian Chadd * Don't think of doing that unless you know what you're doing. 62967397d39SAdrian Chadd */ 63067397d39SAdrian Chadd 6318fd67f92SAdrian Chadd #ifdef ATH_ENABLE_11N 63267397d39SAdrian Chadd /* 63367397d39SAdrian Chadd * Query HT capabilities 63467397d39SAdrian Chadd */ 63567397d39SAdrian Chadd if (ath_hal_getcapability(ah, HAL_CAP_HT, 0, NULL) == HAL_OK && 63667397d39SAdrian Chadd (wmodes & (HAL_MODE_HT20 | HAL_MODE_HT40))) { 63767397d39SAdrian Chadd int rxs, txs; 63867397d39SAdrian Chadd 63967397d39SAdrian Chadd device_printf(sc->sc_dev, "[HT] enabling HT modes\n"); 64067397d39SAdrian Chadd ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */ 64167397d39SAdrian Chadd | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */ 64267397d39SAdrian Chadd | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */ 64367397d39SAdrian Chadd | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ 64467397d39SAdrian Chadd | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */ 64567397d39SAdrian Chadd ; 64667397d39SAdrian Chadd 64776355edbSAdrian Chadd /* 64876355edbSAdrian Chadd * Enable short-GI for HT20 only if the hardware 64976355edbSAdrian Chadd * advertises support. 65076355edbSAdrian Chadd * Notably, anything earlier than the AR9287 doesn't. 65176355edbSAdrian Chadd */ 65276355edbSAdrian Chadd if ((ath_hal_getcapability(ah, 65376355edbSAdrian Chadd HAL_CAP_HT20_SGI, 0, NULL) == HAL_OK) && 65476355edbSAdrian Chadd (wmodes & HAL_MODE_HT20)) { 65576355edbSAdrian Chadd device_printf(sc->sc_dev, 65676355edbSAdrian Chadd "[HT] enabling short-GI in 20MHz mode\n"); 65776355edbSAdrian Chadd ic->ic_htcaps |= IEEE80211_HTCAP_SHORTGI20; 65876355edbSAdrian Chadd } 65976355edbSAdrian Chadd 66067397d39SAdrian Chadd if (wmodes & HAL_MODE_HT40) 66167397d39SAdrian Chadd ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40 66267397d39SAdrian Chadd | IEEE80211_HTCAP_SHORTGI40; 66367397d39SAdrian Chadd 66467397d39SAdrian Chadd /* 66567397d39SAdrian Chadd * rx/tx stream is not currently used anywhere; it needs to be taken 66667397d39SAdrian Chadd * into account when negotiating which MCS rates it'll receive and 66767397d39SAdrian Chadd * what MCS rates are available for TX. 66867397d39SAdrian Chadd */ 66967397d39SAdrian Chadd (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 0, &rxs); 67067397d39SAdrian Chadd (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 1, &txs); 67167397d39SAdrian Chadd 67267397d39SAdrian Chadd ath_hal_getrxchainmask(ah, &sc->sc_rxchainmask); 67367397d39SAdrian Chadd ath_hal_gettxchainmask(ah, &sc->sc_txchainmask); 67467397d39SAdrian Chadd 67567397d39SAdrian Chadd ic->ic_txstream = txs; 67667397d39SAdrian Chadd ic->ic_rxstream = rxs; 67767397d39SAdrian Chadd 67867397d39SAdrian Chadd device_printf(sc->sc_dev, "[HT] %d RX streams; %d TX streams\n", rxs, txs); 67967397d39SAdrian Chadd } 68067397d39SAdrian Chadd #endif 68167397d39SAdrian Chadd 682c42a7b7eSSam Leffler /* 683c42a7b7eSSam Leffler * Indicate we need the 802.11 header padded to a 684c42a7b7eSSam Leffler * 32-bit boundary for 4-address and QoS frames. 685c42a7b7eSSam Leffler */ 686c42a7b7eSSam Leffler ic->ic_flags |= IEEE80211_F_DATAPAD; 687c42a7b7eSSam Leffler 688c42a7b7eSSam Leffler /* 689c42a7b7eSSam Leffler * Query the hal about antenna support. 690c42a7b7eSSam Leffler */ 691c42a7b7eSSam Leffler sc->sc_defant = ath_hal_getdefantenna(ah); 692c42a7b7eSSam Leffler 693c42a7b7eSSam Leffler /* 694c42a7b7eSSam Leffler * Not all chips have the VEOL support we want to 695c42a7b7eSSam Leffler * use with IBSS beacons; check here for it. 696c42a7b7eSSam Leffler */ 697c42a7b7eSSam Leffler sc->sc_hasveol = ath_hal_hasveol(ah); 6985591b213SSam Leffler 6995591b213SSam Leffler /* get mac address from hardware */ 70029aca940SSam Leffler ath_hal_getmac(ah, macaddr); 701b032f27cSSam Leffler if (sc->sc_hasbmask) 702b032f27cSSam Leffler ath_hal_getbssidmask(ah, sc->sc_hwbssidmask); 7035591b213SSam Leffler 704b032f27cSSam Leffler /* NB: used to size node table key mapping array */ 705b032f27cSSam Leffler ic->ic_max_keyix = sc->sc_keymax; 7065591b213SSam Leffler /* call MI attach routine. */ 70729aca940SSam Leffler ieee80211_ifattach(ic, macaddr); 708b032f27cSSam Leffler ic->ic_setregdomain = ath_setregdomain; 709b032f27cSSam Leffler ic->ic_getradiocaps = ath_getradiocaps; 710b032f27cSSam Leffler sc->sc_opmode = HAL_M_STA; 711b032f27cSSam Leffler 7125591b213SSam Leffler /* override default methods */ 713b032f27cSSam Leffler ic->ic_newassoc = ath_newassoc; 714b032f27cSSam Leffler ic->ic_updateslot = ath_updateslot; 715b032f27cSSam Leffler ic->ic_wme.wme_update = ath_wme_update; 716b032f27cSSam Leffler ic->ic_vap_create = ath_vap_create; 717b032f27cSSam Leffler ic->ic_vap_delete = ath_vap_delete; 718b032f27cSSam Leffler ic->ic_raw_xmit = ath_raw_xmit; 719b032f27cSSam Leffler ic->ic_update_mcast = ath_update_mcast; 720b032f27cSSam Leffler ic->ic_update_promisc = ath_update_promisc; 7215591b213SSam Leffler ic->ic_node_alloc = ath_node_alloc; 7221e774079SSam Leffler sc->sc_node_free = ic->ic_node_free; 7235591b213SSam Leffler ic->ic_node_free = ath_node_free; 72468e8e04eSSam Leffler ic->ic_node_getsignal = ath_node_getsignal; 72568e8e04eSSam Leffler ic->ic_scan_start = ath_scan_start; 72668e8e04eSSam Leffler ic->ic_scan_end = ath_scan_end; 72768e8e04eSSam Leffler ic->ic_set_channel = ath_set_channel; 7285591b213SSam Leffler 7295463c4a4SSam Leffler ieee80211_radiotap_attach(ic, 7305463c4a4SSam Leffler &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), 7315463c4a4SSam Leffler ATH_TX_RADIOTAP_PRESENT, 7325463c4a4SSam Leffler &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 7335463c4a4SSam Leffler ATH_RX_RADIOTAP_PRESENT); 7345463c4a4SSam Leffler 7354866e6c2SSam Leffler /* 7364866e6c2SSam Leffler * Setup dynamic sysctl's now that country code and 7374866e6c2SSam Leffler * regdomain are available from the hal. 7384866e6c2SSam Leffler */ 7394866e6c2SSam Leffler ath_sysctlattach(sc); 740e8dabfbeSAdrian Chadd ath_sysctl_stats_attach(sc); 74173454c73SSam Leffler 742c42a7b7eSSam Leffler if (bootverbose) 743c42a7b7eSSam Leffler ieee80211_announce(ic); 744c42a7b7eSSam Leffler ath_announce(sc); 7455591b213SSam Leffler return 0; 746b28b4653SSam Leffler bad2: 747c42a7b7eSSam Leffler ath_tx_cleanup(sc); 748b28b4653SSam Leffler ath_desc_free(sc); 7495591b213SSam Leffler bad: 7505591b213SSam Leffler if (ah) 7515591b213SSam Leffler ath_hal_detach(ah); 752fc74a9f9SBrooks Davis if (ifp != NULL) 753fc74a9f9SBrooks Davis if_free(ifp); 7545591b213SSam Leffler sc->sc_invalid = 1; 7555591b213SSam Leffler return error; 7565591b213SSam Leffler } 7575591b213SSam Leffler 7585591b213SSam Leffler int 7595591b213SSam Leffler ath_detach(struct ath_softc *sc) 7605591b213SSam Leffler { 761fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 7625591b213SSam Leffler 763c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 764c42a7b7eSSam Leffler __func__, ifp->if_flags); 7655591b213SSam Leffler 766c42a7b7eSSam Leffler /* 767c42a7b7eSSam Leffler * NB: the order of these is important: 76871b85077SSam Leffler * o stop the chip so no more interrupts will fire 769c42a7b7eSSam Leffler * o call the 802.11 layer before detaching the hal to 770c42a7b7eSSam Leffler * insure callbacks into the driver to delete global 771c42a7b7eSSam Leffler * key cache entries can be handled 77271b85077SSam Leffler * o free the taskqueue which drains any pending tasks 773c42a7b7eSSam Leffler * o reclaim the tx queue data structures after calling 774c42a7b7eSSam Leffler * the 802.11 layer as we'll get called back to reclaim 775c42a7b7eSSam Leffler * node state and potentially want to use them 776c42a7b7eSSam Leffler * o to cleanup the tx queues the hal is called, so detach 777c42a7b7eSSam Leffler * it last 778c42a7b7eSSam Leffler * Other than that, it's straightforward... 779c42a7b7eSSam Leffler */ 78071b85077SSam Leffler ath_stop(ifp); 781b032f27cSSam Leffler ieee80211_ifdetach(ifp->if_l2com); 78271b85077SSam Leffler taskqueue_free(sc->sc_tq); 78386e07743SSam Leffler #ifdef ATH_TX99_DIAG 78486e07743SSam Leffler if (sc->sc_tx99 != NULL) 78586e07743SSam Leffler sc->sc_tx99->detach(sc->sc_tx99); 78686e07743SSam Leffler #endif 787c42a7b7eSSam Leffler ath_rate_detach(sc->sc_rc); 788*48237774SAdrian Chadd 789*48237774SAdrian Chadd ath_dfs_detach(sc); 7905591b213SSam Leffler ath_desc_free(sc); 791c42a7b7eSSam Leffler ath_tx_cleanup(sc); 79271b85077SSam Leffler ath_hal_detach(sc->sc_ah); /* NB: sets chip in full sleep */ 793c4c6f08fSRuslan Ermilov if_free(ifp); 794f0b2a0beSSam Leffler 7955591b213SSam Leffler return 0; 7965591b213SSam Leffler } 7975591b213SSam Leffler 798b032f27cSSam Leffler /* 799b032f27cSSam Leffler * MAC address handling for multiple BSS on the same radio. 800b032f27cSSam Leffler * The first vap uses the MAC address from the EEPROM. For 801b032f27cSSam Leffler * subsequent vap's we set the U/L bit (bit 1) in the MAC 802b032f27cSSam Leffler * address and use the next six bits as an index. 803b032f27cSSam Leffler */ 804b032f27cSSam Leffler static void 805b032f27cSSam Leffler assign_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN], int clone) 806b032f27cSSam Leffler { 807b032f27cSSam Leffler int i; 808b032f27cSSam Leffler 809b032f27cSSam Leffler if (clone && sc->sc_hasbmask) { 810b032f27cSSam Leffler /* NB: we only do this if h/w supports multiple bssid */ 811b032f27cSSam Leffler for (i = 0; i < 8; i++) 812b032f27cSSam Leffler if ((sc->sc_bssidmask & (1<<i)) == 0) 813b032f27cSSam Leffler break; 814b032f27cSSam Leffler if (i != 0) 815b032f27cSSam Leffler mac[0] |= (i << 2)|0x2; 816b032f27cSSam Leffler } else 817b032f27cSSam Leffler i = 0; 818b032f27cSSam Leffler sc->sc_bssidmask |= 1<<i; 819b032f27cSSam Leffler sc->sc_hwbssidmask[0] &= ~mac[0]; 820b032f27cSSam Leffler if (i == 0) 821b032f27cSSam Leffler sc->sc_nbssid0++; 822b032f27cSSam Leffler } 823b032f27cSSam Leffler 824b032f27cSSam Leffler static void 825b032f27cSSam Leffler reclaim_address(struct ath_softc *sc, const uint8_t mac[IEEE80211_ADDR_LEN]) 826b032f27cSSam Leffler { 827b032f27cSSam Leffler int i = mac[0] >> 2; 828b032f27cSSam Leffler uint8_t mask; 829b032f27cSSam Leffler 830b032f27cSSam Leffler if (i != 0 || --sc->sc_nbssid0 == 0) { 831b032f27cSSam Leffler sc->sc_bssidmask &= ~(1<<i); 832b032f27cSSam Leffler /* recalculate bssid mask from remaining addresses */ 833b032f27cSSam Leffler mask = 0xff; 834b032f27cSSam Leffler for (i = 1; i < 8; i++) 835b032f27cSSam Leffler if (sc->sc_bssidmask & (1<<i)) 836b032f27cSSam Leffler mask &= ~((i<<2)|0x2); 837b032f27cSSam Leffler sc->sc_hwbssidmask[0] |= mask; 838b032f27cSSam Leffler } 839b032f27cSSam Leffler } 840b032f27cSSam Leffler 841b032f27cSSam Leffler /* 842b032f27cSSam Leffler * Assign a beacon xmit slot. We try to space out 843b032f27cSSam Leffler * assignments so when beacons are staggered the 844b032f27cSSam Leffler * traffic coming out of the cab q has maximal time 845b032f27cSSam Leffler * to go out before the next beacon is scheduled. 846b032f27cSSam Leffler */ 847b032f27cSSam Leffler static int 848b032f27cSSam Leffler assign_bslot(struct ath_softc *sc) 849b032f27cSSam Leffler { 850b032f27cSSam Leffler u_int slot, free; 851b032f27cSSam Leffler 852b032f27cSSam Leffler free = 0; 853b032f27cSSam Leffler for (slot = 0; slot < ATH_BCBUF; slot++) 854b032f27cSSam Leffler if (sc->sc_bslot[slot] == NULL) { 855b032f27cSSam Leffler if (sc->sc_bslot[(slot+1)%ATH_BCBUF] == NULL && 856b032f27cSSam Leffler sc->sc_bslot[(slot-1)%ATH_BCBUF] == NULL) 857b032f27cSSam Leffler return slot; 858b032f27cSSam Leffler free = slot; 859b032f27cSSam Leffler /* NB: keep looking for a double slot */ 860b032f27cSSam Leffler } 861b032f27cSSam Leffler return free; 862b032f27cSSam Leffler } 863b032f27cSSam Leffler 864b032f27cSSam Leffler static struct ieee80211vap * 865b032f27cSSam Leffler ath_vap_create(struct ieee80211com *ic, 866b032f27cSSam Leffler const char name[IFNAMSIZ], int unit, int opmode, int flags, 867b032f27cSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN], 868b032f27cSSam Leffler const uint8_t mac0[IEEE80211_ADDR_LEN]) 869b032f27cSSam Leffler { 870b032f27cSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 871b032f27cSSam Leffler struct ath_vap *avp; 872b032f27cSSam Leffler struct ieee80211vap *vap; 873b032f27cSSam Leffler uint8_t mac[IEEE80211_ADDR_LEN]; 874b032f27cSSam Leffler int ic_opmode, needbeacon, error; 875b032f27cSSam Leffler 876b032f27cSSam Leffler avp = (struct ath_vap *) malloc(sizeof(struct ath_vap), 877b032f27cSSam Leffler M_80211_VAP, M_WAITOK | M_ZERO); 878b032f27cSSam Leffler needbeacon = 0; 879b032f27cSSam Leffler IEEE80211_ADDR_COPY(mac, mac0); 880b032f27cSSam Leffler 881b032f27cSSam Leffler ATH_LOCK(sc); 882a8962181SSam Leffler ic_opmode = opmode; /* default to opmode of new vap */ 883b032f27cSSam Leffler switch (opmode) { 884b032f27cSSam Leffler case IEEE80211_M_STA: 885a8962181SSam Leffler if (sc->sc_nstavaps != 0) { /* XXX only 1 for now */ 886b032f27cSSam Leffler device_printf(sc->sc_dev, "only 1 sta vap supported\n"); 887b032f27cSSam Leffler goto bad; 888b032f27cSSam Leffler } 889b032f27cSSam Leffler if (sc->sc_nvaps) { 890b032f27cSSam Leffler /* 891a8962181SSam Leffler * With multiple vaps we must fall back 892a8962181SSam Leffler * to s/w beacon miss handling. 893b032f27cSSam Leffler */ 894b032f27cSSam Leffler flags |= IEEE80211_CLONE_NOBEACONS; 895b032f27cSSam Leffler } 896a8962181SSam Leffler if (flags & IEEE80211_CLONE_NOBEACONS) { 897a8962181SSam Leffler /* 898a8962181SSam Leffler * Station mode w/o beacons are implemented w/ AP mode. 899a8962181SSam Leffler */ 900b032f27cSSam Leffler ic_opmode = IEEE80211_M_HOSTAP; 901a8962181SSam Leffler } 902b032f27cSSam Leffler break; 903b032f27cSSam Leffler case IEEE80211_M_IBSS: 904b032f27cSSam Leffler if (sc->sc_nvaps != 0) { /* XXX only 1 for now */ 905b032f27cSSam Leffler device_printf(sc->sc_dev, 906b032f27cSSam Leffler "only 1 ibss vap supported\n"); 907b032f27cSSam Leffler goto bad; 908b032f27cSSam Leffler } 909b032f27cSSam Leffler needbeacon = 1; 910b032f27cSSam Leffler break; 911b032f27cSSam Leffler case IEEE80211_M_AHDEMO: 912584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 91310ad9a77SSam Leffler if (flags & IEEE80211_CLONE_TDMA) { 914a8962181SSam Leffler if (sc->sc_nvaps != 0) { 915a8962181SSam Leffler device_printf(sc->sc_dev, 916a8962181SSam Leffler "only 1 tdma vap supported\n"); 917a8962181SSam Leffler goto bad; 918a8962181SSam Leffler } 91910ad9a77SSam Leffler needbeacon = 1; 92010ad9a77SSam Leffler flags |= IEEE80211_CLONE_NOBEACONS; 92110ad9a77SSam Leffler } 922b032f27cSSam Leffler /* fall thru... */ 92310ad9a77SSam Leffler #endif 924b032f27cSSam Leffler case IEEE80211_M_MONITOR: 925b032f27cSSam Leffler if (sc->sc_nvaps != 0 && ic->ic_opmode != opmode) { 926a8962181SSam Leffler /* 927a8962181SSam Leffler * Adopt existing mode. Adding a monitor or ahdemo 928a8962181SSam Leffler * vap to an existing configuration is of dubious 929a8962181SSam Leffler * value but should be ok. 930a8962181SSam Leffler */ 931b032f27cSSam Leffler /* XXX not right for monitor mode */ 932b032f27cSSam Leffler ic_opmode = ic->ic_opmode; 933a8962181SSam Leffler } 934b032f27cSSam Leffler break; 935b032f27cSSam Leffler case IEEE80211_M_HOSTAP: 93659aa14a9SRui Paulo case IEEE80211_M_MBSS: 937b032f27cSSam Leffler needbeacon = 1; 938a8962181SSam Leffler break; 939b032f27cSSam Leffler case IEEE80211_M_WDS: 940a8962181SSam Leffler if (sc->sc_nvaps != 0 && ic->ic_opmode == IEEE80211_M_STA) { 941b032f27cSSam Leffler device_printf(sc->sc_dev, 942b032f27cSSam Leffler "wds not supported in sta mode\n"); 943b032f27cSSam Leffler goto bad; 944b032f27cSSam Leffler } 945b032f27cSSam Leffler /* 946b032f27cSSam Leffler * Silently remove any request for a unique 947b032f27cSSam Leffler * bssid; WDS vap's always share the local 948b032f27cSSam Leffler * mac address. 949b032f27cSSam Leffler */ 950b032f27cSSam Leffler flags &= ~IEEE80211_CLONE_BSSID; 951a8962181SSam Leffler if (sc->sc_nvaps == 0) 952b032f27cSSam Leffler ic_opmode = IEEE80211_M_HOSTAP; 953a8962181SSam Leffler else 954a8962181SSam Leffler ic_opmode = ic->ic_opmode; 9557d261891SRui Paulo break; 956b032f27cSSam Leffler default: 957b032f27cSSam Leffler device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 958b032f27cSSam Leffler goto bad; 959b032f27cSSam Leffler } 960b032f27cSSam Leffler /* 961b032f27cSSam Leffler * Check that a beacon buffer is available; the code below assumes it. 962b032f27cSSam Leffler */ 963b032f27cSSam Leffler if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) { 964b032f27cSSam Leffler device_printf(sc->sc_dev, "no beacon buffer available\n"); 965b032f27cSSam Leffler goto bad; 966b032f27cSSam Leffler } 967b032f27cSSam Leffler 968b032f27cSSam Leffler /* STA, AHDEMO? */ 96959aa14a9SRui Paulo if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_MBSS) { 970b032f27cSSam Leffler assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID); 971b032f27cSSam Leffler ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask); 972b032f27cSSam Leffler } 973b032f27cSSam Leffler 974b032f27cSSam Leffler vap = &avp->av_vap; 975b032f27cSSam Leffler /* XXX can't hold mutex across if_alloc */ 976b032f27cSSam Leffler ATH_UNLOCK(sc); 977b032f27cSSam Leffler error = ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, 978b032f27cSSam Leffler bssid, mac); 979b032f27cSSam Leffler ATH_LOCK(sc); 980b032f27cSSam Leffler if (error != 0) { 981b032f27cSSam Leffler device_printf(sc->sc_dev, "%s: error %d creating vap\n", 982b032f27cSSam Leffler __func__, error); 983b032f27cSSam Leffler goto bad2; 984b032f27cSSam Leffler } 985b032f27cSSam Leffler 986b032f27cSSam Leffler /* h/w crypto support */ 987b032f27cSSam Leffler vap->iv_key_alloc = ath_key_alloc; 988b032f27cSSam Leffler vap->iv_key_delete = ath_key_delete; 989b032f27cSSam Leffler vap->iv_key_set = ath_key_set; 990b032f27cSSam Leffler vap->iv_key_update_begin = ath_key_update_begin; 991b032f27cSSam Leffler vap->iv_key_update_end = ath_key_update_end; 992b032f27cSSam Leffler 993b032f27cSSam Leffler /* override various methods */ 994b032f27cSSam Leffler avp->av_recv_mgmt = vap->iv_recv_mgmt; 995b032f27cSSam Leffler vap->iv_recv_mgmt = ath_recv_mgmt; 996b032f27cSSam Leffler vap->iv_reset = ath_reset_vap; 997b032f27cSSam Leffler vap->iv_update_beacon = ath_beacon_update; 998b032f27cSSam Leffler avp->av_newstate = vap->iv_newstate; 999b032f27cSSam Leffler vap->iv_newstate = ath_newstate; 1000b032f27cSSam Leffler avp->av_bmiss = vap->iv_bmiss; 1001b032f27cSSam Leffler vap->iv_bmiss = ath_bmiss_vap; 1002b032f27cSSam Leffler 10039be25f4aSAdrian Chadd /* Set default parameters */ 10049be25f4aSAdrian Chadd 10059be25f4aSAdrian Chadd /* 10069be25f4aSAdrian Chadd * Anything earlier than some AR9300 series MACs don't 10079be25f4aSAdrian Chadd * support a smaller MPDU density. 10089be25f4aSAdrian Chadd */ 10099be25f4aSAdrian Chadd vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_8; 10109be25f4aSAdrian Chadd /* 10119be25f4aSAdrian Chadd * All NICs can handle the maximum size, however 10129be25f4aSAdrian Chadd * AR5416 based MACs can only TX aggregates w/ RTS 10139be25f4aSAdrian Chadd * protection when the total aggregate size is <= 8k. 10149be25f4aSAdrian Chadd * However, for now that's enforced by the TX path. 10159be25f4aSAdrian Chadd */ 10169be25f4aSAdrian Chadd vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; 10179be25f4aSAdrian Chadd 1018b032f27cSSam Leffler avp->av_bslot = -1; 1019b032f27cSSam Leffler if (needbeacon) { 1020b032f27cSSam Leffler /* 1021b032f27cSSam Leffler * Allocate beacon state and setup the q for buffered 1022b032f27cSSam Leffler * multicast frames. We know a beacon buffer is 1023b032f27cSSam Leffler * available because we checked above. 1024b032f27cSSam Leffler */ 1025b032f27cSSam Leffler avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf); 1026b032f27cSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list); 1027b032f27cSSam Leffler if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) { 1028b032f27cSSam Leffler /* 1029b032f27cSSam Leffler * Assign the vap to a beacon xmit slot. As above 1030b032f27cSSam Leffler * this cannot fail to find a free one. 1031b032f27cSSam Leffler */ 1032b032f27cSSam Leffler avp->av_bslot = assign_bslot(sc); 1033b032f27cSSam Leffler KASSERT(sc->sc_bslot[avp->av_bslot] == NULL, 1034b032f27cSSam Leffler ("beacon slot %u not empty", avp->av_bslot)); 1035b032f27cSSam Leffler sc->sc_bslot[avp->av_bslot] = vap; 1036b032f27cSSam Leffler sc->sc_nbcnvaps++; 1037b032f27cSSam Leffler } 1038b032f27cSSam Leffler if (sc->sc_hastsfadd && sc->sc_nbcnvaps > 0) { 1039b032f27cSSam Leffler /* 1040b032f27cSSam Leffler * Multple vaps are to transmit beacons and we 1041b032f27cSSam Leffler * have h/w support for TSF adjusting; enable 1042b032f27cSSam Leffler * use of staggered beacons. 1043b032f27cSSam Leffler */ 1044b032f27cSSam Leffler sc->sc_stagbeacons = 1; 1045b032f27cSSam Leffler } 1046b032f27cSSam Leffler ath_txq_init(sc, &avp->av_mcastq, ATH_TXQ_SWQ); 1047b032f27cSSam Leffler } 1048b032f27cSSam Leffler 1049b032f27cSSam Leffler ic->ic_opmode = ic_opmode; 1050b032f27cSSam Leffler if (opmode != IEEE80211_M_WDS) { 1051b032f27cSSam Leffler sc->sc_nvaps++; 1052b032f27cSSam Leffler if (opmode == IEEE80211_M_STA) 1053b032f27cSSam Leffler sc->sc_nstavaps++; 1054fe0dd789SSam Leffler if (opmode == IEEE80211_M_MBSS) 1055fe0dd789SSam Leffler sc->sc_nmeshvaps++; 1056b032f27cSSam Leffler } 1057b032f27cSSam Leffler switch (ic_opmode) { 1058b032f27cSSam Leffler case IEEE80211_M_IBSS: 1059b032f27cSSam Leffler sc->sc_opmode = HAL_M_IBSS; 1060b032f27cSSam Leffler break; 1061b032f27cSSam Leffler case IEEE80211_M_STA: 1062b032f27cSSam Leffler sc->sc_opmode = HAL_M_STA; 1063b032f27cSSam Leffler break; 1064b032f27cSSam Leffler case IEEE80211_M_AHDEMO: 1065584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 106610ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 106710ad9a77SSam Leffler sc->sc_tdma = 1; 106810ad9a77SSam Leffler /* NB: disable tsf adjust */ 106910ad9a77SSam Leffler sc->sc_stagbeacons = 0; 107010ad9a77SSam Leffler } 107110ad9a77SSam Leffler /* 107210ad9a77SSam Leffler * NB: adhoc demo mode is a pseudo mode; to the hal it's 107310ad9a77SSam Leffler * just ap mode. 107410ad9a77SSam Leffler */ 107510ad9a77SSam Leffler /* fall thru... */ 107610ad9a77SSam Leffler #endif 1077b032f27cSSam Leffler case IEEE80211_M_HOSTAP: 107859aa14a9SRui Paulo case IEEE80211_M_MBSS: 1079b032f27cSSam Leffler sc->sc_opmode = HAL_M_HOSTAP; 1080b032f27cSSam Leffler break; 1081b032f27cSSam Leffler case IEEE80211_M_MONITOR: 1082b032f27cSSam Leffler sc->sc_opmode = HAL_M_MONITOR; 1083b032f27cSSam Leffler break; 1084b032f27cSSam Leffler default: 1085b032f27cSSam Leffler /* XXX should not happen */ 1086b032f27cSSam Leffler break; 1087b032f27cSSam Leffler } 1088b032f27cSSam Leffler if (sc->sc_hastsfadd) { 1089b032f27cSSam Leffler /* 1090b032f27cSSam Leffler * Configure whether or not TSF adjust should be done. 1091b032f27cSSam Leffler */ 1092b032f27cSSam Leffler ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons); 1093b032f27cSSam Leffler } 109410ad9a77SSam Leffler if (flags & IEEE80211_CLONE_NOBEACONS) { 109510ad9a77SSam Leffler /* 109610ad9a77SSam Leffler * Enable s/w beacon miss handling. 109710ad9a77SSam Leffler */ 109810ad9a77SSam Leffler sc->sc_swbmiss = 1; 109910ad9a77SSam Leffler } 1100b032f27cSSam Leffler ATH_UNLOCK(sc); 1101b032f27cSSam Leffler 1102b032f27cSSam Leffler /* complete setup */ 1103b032f27cSSam Leffler ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status); 1104b032f27cSSam Leffler return vap; 1105b032f27cSSam Leffler bad2: 1106b032f27cSSam Leffler reclaim_address(sc, mac); 1107b032f27cSSam Leffler ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask); 1108b032f27cSSam Leffler bad: 1109b032f27cSSam Leffler free(avp, M_80211_VAP); 1110b032f27cSSam Leffler ATH_UNLOCK(sc); 1111b032f27cSSam Leffler return NULL; 1112b032f27cSSam Leffler } 1113b032f27cSSam Leffler 1114b032f27cSSam Leffler static void 1115b032f27cSSam Leffler ath_vap_delete(struct ieee80211vap *vap) 1116b032f27cSSam Leffler { 1117b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 1118b032f27cSSam Leffler struct ifnet *ifp = ic->ic_ifp; 1119b032f27cSSam Leffler struct ath_softc *sc = ifp->if_softc; 1120b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 1121b032f27cSSam Leffler struct ath_vap *avp = ATH_VAP(vap); 1122b032f27cSSam Leffler 1123b032f27cSSam Leffler if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1124b032f27cSSam Leffler /* 1125b032f27cSSam Leffler * Quiesce the hardware while we remove the vap. In 1126b032f27cSSam Leffler * particular we need to reclaim all references to 1127b032f27cSSam Leffler * the vap state by any frames pending on the tx queues. 1128b032f27cSSam Leffler */ 1129b032f27cSSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 1130b032f27cSSam Leffler ath_draintxq(sc); /* stop xmit side */ 1131b032f27cSSam Leffler ath_stoprecv(sc); /* stop recv side */ 1132b032f27cSSam Leffler } 1133b032f27cSSam Leffler 1134b032f27cSSam Leffler ieee80211_vap_detach(vap); 1135b032f27cSSam Leffler ATH_LOCK(sc); 1136b032f27cSSam Leffler /* 1137b032f27cSSam Leffler * Reclaim beacon state. Note this must be done before 1138b032f27cSSam Leffler * the vap instance is reclaimed as we may have a reference 1139b032f27cSSam Leffler * to it in the buffer for the beacon frame. 1140b032f27cSSam Leffler */ 1141b032f27cSSam Leffler if (avp->av_bcbuf != NULL) { 1142b032f27cSSam Leffler if (avp->av_bslot != -1) { 1143b032f27cSSam Leffler sc->sc_bslot[avp->av_bslot] = NULL; 1144b032f27cSSam Leffler sc->sc_nbcnvaps--; 1145b032f27cSSam Leffler } 1146b032f27cSSam Leffler ath_beacon_return(sc, avp->av_bcbuf); 1147b032f27cSSam Leffler avp->av_bcbuf = NULL; 1148b032f27cSSam Leffler if (sc->sc_nbcnvaps == 0) { 1149b032f27cSSam Leffler sc->sc_stagbeacons = 0; 1150b032f27cSSam Leffler if (sc->sc_hastsfadd) 1151b032f27cSSam Leffler ath_hal_settsfadjust(sc->sc_ah, 0); 1152b032f27cSSam Leffler } 1153b032f27cSSam Leffler /* 1154b032f27cSSam Leffler * Reclaim any pending mcast frames for the vap. 1155b032f27cSSam Leffler */ 1156b032f27cSSam Leffler ath_tx_draintxq(sc, &avp->av_mcastq); 1157b032f27cSSam Leffler ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq); 1158b032f27cSSam Leffler } 1159b032f27cSSam Leffler /* 1160b032f27cSSam Leffler * Update bookkeeping. 1161b032f27cSSam Leffler */ 1162b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) { 1163b032f27cSSam Leffler sc->sc_nstavaps--; 1164b032f27cSSam Leffler if (sc->sc_nstavaps == 0 && sc->sc_swbmiss) 1165b032f27cSSam Leffler sc->sc_swbmiss = 0; 116659aa14a9SRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 116759aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 1168b032f27cSSam Leffler reclaim_address(sc, vap->iv_myaddr); 1169b032f27cSSam Leffler ath_hal_setbssidmask(ah, sc->sc_hwbssidmask); 1170fe0dd789SSam Leffler if (vap->iv_opmode == IEEE80211_M_MBSS) 1171fe0dd789SSam Leffler sc->sc_nmeshvaps--; 1172b032f27cSSam Leffler } 1173b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) 1174b032f27cSSam Leffler sc->sc_nvaps--; 1175584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 117610ad9a77SSam Leffler /* TDMA operation ceases when the last vap is destroyed */ 117710ad9a77SSam Leffler if (sc->sc_tdma && sc->sc_nvaps == 0) { 117810ad9a77SSam Leffler sc->sc_tdma = 0; 117910ad9a77SSam Leffler sc->sc_swbmiss = 0; 118010ad9a77SSam Leffler } 118110ad9a77SSam Leffler #endif 1182b032f27cSSam Leffler ATH_UNLOCK(sc); 1183b032f27cSSam Leffler free(avp, M_80211_VAP); 1184b032f27cSSam Leffler 1185b032f27cSSam Leffler if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1186b032f27cSSam Leffler /* 1187b032f27cSSam Leffler * Restart rx+tx machines if still running (RUNNING will 1188b032f27cSSam Leffler * be reset if we just destroyed the last vap). 1189b032f27cSSam Leffler */ 1190b032f27cSSam Leffler if (ath_startrecv(sc) != 0) 1191b032f27cSSam Leffler if_printf(ifp, "%s: unable to restart recv logic\n", 1192b032f27cSSam Leffler __func__); 1193c89b957aSSam Leffler if (sc->sc_beacons) { /* restart beacons */ 1194c89b957aSSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 1195c89b957aSSam Leffler if (sc->sc_tdma) 1196c89b957aSSam Leffler ath_tdma_config(sc, NULL); 1197c89b957aSSam Leffler else 1198c89b957aSSam Leffler #endif 1199b032f27cSSam Leffler ath_beacon_config(sc, NULL); 1200c89b957aSSam Leffler } 1201b032f27cSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 1202b032f27cSSam Leffler } 1203b032f27cSSam Leffler } 1204b032f27cSSam Leffler 12055591b213SSam Leffler void 12065591b213SSam Leffler ath_suspend(struct ath_softc *sc) 12075591b213SSam Leffler { 1208fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 1209d3ac945bSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 12105591b213SSam Leffler 1211c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 1212c42a7b7eSSam Leffler __func__, ifp->if_flags); 12135591b213SSam Leffler 1214d3ac945bSSam Leffler sc->sc_resume_up = (ifp->if_flags & IFF_UP) != 0; 1215d3ac945bSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 12165591b213SSam Leffler ath_stop(ifp); 1217d3ac945bSSam Leffler else 1218d3ac945bSSam Leffler ieee80211_suspend_all(ic); 1219d3ac945bSSam Leffler /* 1220d3ac945bSSam Leffler * NB: don't worry about putting the chip in low power 1221d3ac945bSSam Leffler * mode; pci will power off our socket on suspend and 1222f29b8b7fSWarner Losh * CardBus detaches the device. 1223d3ac945bSSam Leffler */ 1224d3ac945bSSam Leffler } 1225d3ac945bSSam Leffler 1226d3ac945bSSam Leffler /* 1227d3ac945bSSam Leffler * Reset the key cache since some parts do not reset the 1228d3ac945bSSam Leffler * contents on resume. First we clear all entries, then 1229d3ac945bSSam Leffler * re-load keys that the 802.11 layer assumes are setup 1230d3ac945bSSam Leffler * in h/w. 1231d3ac945bSSam Leffler */ 1232d3ac945bSSam Leffler static void 1233d3ac945bSSam Leffler ath_reset_keycache(struct ath_softc *sc) 1234d3ac945bSSam Leffler { 1235d3ac945bSSam Leffler struct ifnet *ifp = sc->sc_ifp; 1236d3ac945bSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 1237d3ac945bSSam Leffler struct ath_hal *ah = sc->sc_ah; 1238d3ac945bSSam Leffler int i; 1239d3ac945bSSam Leffler 1240d3ac945bSSam Leffler for (i = 0; i < sc->sc_keymax; i++) 1241d3ac945bSSam Leffler ath_hal_keyreset(ah, i); 1242d3ac945bSSam Leffler ieee80211_crypto_reload_keys(ic); 12435591b213SSam Leffler } 12445591b213SSam Leffler 12455591b213SSam Leffler void 12465591b213SSam Leffler ath_resume(struct ath_softc *sc) 12475591b213SSam Leffler { 1248fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 1249d3ac945bSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 1250d3ac945bSSam Leffler struct ath_hal *ah = sc->sc_ah; 1251d3ac945bSSam Leffler HAL_STATUS status; 12525591b213SSam Leffler 1253c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 1254c42a7b7eSSam Leffler __func__, ifp->if_flags); 12555591b213SSam Leffler 1256d3ac945bSSam Leffler /* 1257d3ac945bSSam Leffler * Must reset the chip before we reload the 1258d3ac945bSSam Leffler * keycache as we were powered down on suspend. 1259d3ac945bSSam Leffler */ 1260054d7b69SSam Leffler ath_hal_reset(ah, sc->sc_opmode, 1261054d7b69SSam Leffler sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan, 1262054d7b69SSam Leffler AH_FALSE, &status); 1263d3ac945bSSam Leffler ath_reset_keycache(sc); 1264d3ac945bSSam Leffler if (sc->sc_resume_up) { 1265d3ac945bSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) { 1266fc74a9f9SBrooks Davis ath_init(sc); 1267394f34a5SSam Leffler /* 1268394f34a5SSam Leffler * Program the beacon registers using the last rx'd 1269394f34a5SSam Leffler * beacon frame and enable sync on the next beacon 1270394f34a5SSam Leffler * we see. This should handle the case where we 1271394f34a5SSam Leffler * wakeup and find the same AP and also the case where 1272394f34a5SSam Leffler * we wakeup and need to roam. For the latter we 1273394f34a5SSam Leffler * should get bmiss events that trigger a roam. 1274394f34a5SSam Leffler */ 1275394f34a5SSam Leffler ath_beacon_config(sc, NULL); 1276394f34a5SSam Leffler sc->sc_syncbeacon = 1; 1277d3ac945bSSam Leffler } else 1278d3ac945bSSam Leffler ieee80211_resume_all(ic); 12795591b213SSam Leffler } 1280b50c8bdeSSam Leffler if (sc->sc_softled) { 1281869ff02eSSam Leffler ath_hal_gpioCfgOutput(ah, sc->sc_ledpin, 1282869ff02eSSam Leffler HAL_GPIO_MUX_MAC_NETWORK_LED); 1283d3ac945bSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); 1284b50c8bdeSSam Leffler } 12856b59f5e3SSam Leffler } 12865591b213SSam Leffler 12875591b213SSam Leffler void 12885591b213SSam Leffler ath_shutdown(struct ath_softc *sc) 12895591b213SSam Leffler { 1290fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 12915591b213SSam Leffler 1292c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 1293c42a7b7eSSam Leffler __func__, ifp->if_flags); 12945591b213SSam Leffler 12955591b213SSam Leffler ath_stop(ifp); 1296d3ac945bSSam Leffler /* NB: no point powering down chip as we're about to reboot */ 12975591b213SSam Leffler } 12985591b213SSam Leffler 1299c42a7b7eSSam Leffler /* 1300c42a7b7eSSam Leffler * Interrupt handler. Most of the actual processing is deferred. 1301c42a7b7eSSam Leffler */ 13025591b213SSam Leffler void 13035591b213SSam Leffler ath_intr(void *arg) 13045591b213SSam Leffler { 13055591b213SSam Leffler struct ath_softc *sc = arg; 1306fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 13075591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 13086f5fe81eSAdrian Chadd HAL_INT status = 0; 13095591b213SSam Leffler 13105591b213SSam Leffler if (sc->sc_invalid) { 13115591b213SSam Leffler /* 1312b58b3803SSam Leffler * The hardware is not ready/present, don't touch anything. 1313b58b3803SSam Leffler * Note this can happen early on if the IRQ is shared. 13145591b213SSam Leffler */ 1315c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid; ignored\n", __func__); 13165591b213SSam Leffler return; 13175591b213SSam Leffler } 1318fdd758d4SSam Leffler if (!ath_hal_intrpend(ah)) /* shared irq, not for us */ 1319fdd758d4SSam Leffler return; 132068e8e04eSSam Leffler if ((ifp->if_flags & IFF_UP) == 0 || 132168e8e04eSSam Leffler (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 132268e8e04eSSam Leffler HAL_INT status; 132368e8e04eSSam Leffler 1324c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 1325c42a7b7eSSam Leffler __func__, ifp->if_flags); 13265591b213SSam Leffler ath_hal_getisr(ah, &status); /* clear ISR */ 13275591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable further intr's */ 13285591b213SSam Leffler return; 13295591b213SSam Leffler } 1330c42a7b7eSSam Leffler /* 1331c42a7b7eSSam Leffler * Figure out the reason(s) for the interrupt. Note 1332c42a7b7eSSam Leffler * that the hal returns a pseudo-ISR that may include 1333c42a7b7eSSam Leffler * bits we haven't explicitly enabled so we mask the 1334c42a7b7eSSam Leffler * value to insure we only process bits we requested. 1335c42a7b7eSSam Leffler */ 13365591b213SSam Leffler ath_hal_getisr(ah, &status); /* NB: clears ISR too */ 1337c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status); 1338ecddff40SSam Leffler status &= sc->sc_imask; /* discard unasked for bits */ 13396f5fe81eSAdrian Chadd 13406f5fe81eSAdrian Chadd /* Short-circuit un-handled interrupts */ 13416f5fe81eSAdrian Chadd if (status == 0x0) 13426f5fe81eSAdrian Chadd return; 13436f5fe81eSAdrian Chadd 13445591b213SSam Leffler if (status & HAL_INT_FATAL) { 13455591b213SSam Leffler sc->sc_stats.ast_hardware++; 13465591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable intr's until reset */ 134716c8acaaSSam Leffler ath_fatal_proc(sc, 0); 13485591b213SSam Leffler } else { 1349c42a7b7eSSam Leffler if (status & HAL_INT_SWBA) { 1350c42a7b7eSSam Leffler /* 1351c42a7b7eSSam Leffler * Software beacon alert--time to send a beacon. 1352c42a7b7eSSam Leffler * Handle beacon transmission directly; deferring 1353c42a7b7eSSam Leffler * this is too slow to meet timing constraints 1354c42a7b7eSSam Leffler * under load. 1355c42a7b7eSSam Leffler */ 1356584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 135710ad9a77SSam Leffler if (sc->sc_tdma) { 135810ad9a77SSam Leffler if (sc->sc_tdmaswba == 0) { 135910ad9a77SSam Leffler struct ieee80211com *ic = ifp->if_l2com; 136010ad9a77SSam Leffler struct ieee80211vap *vap = 136110ad9a77SSam Leffler TAILQ_FIRST(&ic->ic_vaps); 136210ad9a77SSam Leffler ath_tdma_beacon_send(sc, vap); 136310ad9a77SSam Leffler sc->sc_tdmaswba = 136410ad9a77SSam Leffler vap->iv_tdma->tdma_bintval; 136510ad9a77SSam Leffler } else 136610ad9a77SSam Leffler sc->sc_tdmaswba--; 136710ad9a77SSam Leffler } else 136810ad9a77SSam Leffler #endif 1369339ccfb3SSam Leffler { 1370c42a7b7eSSam Leffler ath_beacon_proc(sc, 0); 1371339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 1372339ccfb3SSam Leffler /* 1373339ccfb3SSam Leffler * Schedule the rx taskq in case there's no 1374339ccfb3SSam Leffler * traffic so any frames held on the staging 1375339ccfb3SSam Leffler * queue are aged and potentially flushed. 1376339ccfb3SSam Leffler */ 1377339ccfb3SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 1378339ccfb3SSam Leffler #endif 1379339ccfb3SSam Leffler } 1380c42a7b7eSSam Leffler } 13815591b213SSam Leffler if (status & HAL_INT_RXEOL) { 13825591b213SSam Leffler /* 13835591b213SSam Leffler * NB: the hardware should re-read the link when 13845591b213SSam Leffler * RXE bit is written, but it doesn't work at 13855591b213SSam Leffler * least on older hardware revs. 13865591b213SSam Leffler */ 13875591b213SSam Leffler sc->sc_stats.ast_rxeol++; 13885591b213SSam Leffler sc->sc_rxlink = NULL; 13895591b213SSam Leffler } 13905591b213SSam Leffler if (status & HAL_INT_TXURN) { 13915591b213SSam Leffler sc->sc_stats.ast_txurn++; 13925591b213SSam Leffler /* bump tx trigger level */ 13935591b213SSam Leffler ath_hal_updatetxtriglevel(ah, AH_TRUE); 13945591b213SSam Leffler } 13955591b213SSam Leffler if (status & HAL_INT_RX) 13960bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 13975591b213SSam Leffler if (status & HAL_INT_TX) 13980bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask); 13995591b213SSam Leffler if (status & HAL_INT_BMISS) { 14005591b213SSam Leffler sc->sc_stats.ast_bmiss++; 14010bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bmisstask); 14025591b213SSam Leffler } 14036ad02dbaSAdrian Chadd if (status & HAL_INT_GTT) 14046ad02dbaSAdrian Chadd sc->sc_stats.ast_tx_timeout++; 14055594f5c0SAdrian Chadd if (status & HAL_INT_CST) 14065594f5c0SAdrian Chadd sc->sc_stats.ast_tx_cst++; 1407c42a7b7eSSam Leffler if (status & HAL_INT_MIB) { 1408c42a7b7eSSam Leffler sc->sc_stats.ast_mib++; 1409c42a7b7eSSam Leffler /* 1410c42a7b7eSSam Leffler * Disable interrupts until we service the MIB 1411c42a7b7eSSam Leffler * interrupt; otherwise it will continue to fire. 1412c42a7b7eSSam Leffler */ 1413c42a7b7eSSam Leffler ath_hal_intrset(ah, 0); 1414c42a7b7eSSam Leffler /* 1415c42a7b7eSSam Leffler * Let the hal handle the event. We assume it will 1416c42a7b7eSSam Leffler * clear whatever condition caused the interrupt. 1417c42a7b7eSSam Leffler */ 1418ffa2cab6SSam Leffler ath_hal_mibevent(ah, &sc->sc_halstats); 1419c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 1420c42a7b7eSSam Leffler } 14219c4fc1e8SSam Leffler if (status & HAL_INT_RXORN) { 14229c4fc1e8SSam Leffler /* NB: hal marks HAL_INT_FATAL when RXORN is fatal */ 14239c4fc1e8SSam Leffler sc->sc_stats.ast_rxorn++; 14249c4fc1e8SSam Leffler } 14255591b213SSam Leffler } 14265591b213SSam Leffler } 14275591b213SSam Leffler 14285591b213SSam Leffler static void 14295591b213SSam Leffler ath_fatal_proc(void *arg, int pending) 14305591b213SSam Leffler { 14315591b213SSam Leffler struct ath_softc *sc = arg; 1432fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 143316c8acaaSSam Leffler u_int32_t *state; 143416c8acaaSSam Leffler u_int32_t len; 143568e8e04eSSam Leffler void *sp; 14365591b213SSam Leffler 1437c42a7b7eSSam Leffler if_printf(ifp, "hardware error; resetting\n"); 143816c8acaaSSam Leffler /* 143916c8acaaSSam Leffler * Fatal errors are unrecoverable. Typically these 144016c8acaaSSam Leffler * are caused by DMA errors. Collect h/w state from 144116c8acaaSSam Leffler * the hal so we can diagnose what's going on. 144216c8acaaSSam Leffler */ 144368e8e04eSSam Leffler if (ath_hal_getfatalstate(sc->sc_ah, &sp, &len)) { 144416c8acaaSSam Leffler KASSERT(len >= 6*sizeof(u_int32_t), ("len %u bytes", len)); 144568e8e04eSSam Leffler state = sp; 144616c8acaaSSam Leffler if_printf(ifp, "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", 144716c8acaaSSam Leffler state[0], state[1] , state[2], state[3], 144816c8acaaSSam Leffler state[4], state[5]); 144916c8acaaSSam Leffler } 1450c42a7b7eSSam Leffler ath_reset(ifp); 14515591b213SSam Leffler } 14525591b213SSam Leffler 14535591b213SSam Leffler static void 1454b032f27cSSam Leffler ath_bmiss_vap(struct ieee80211vap *vap) 14555591b213SSam Leffler { 145659fbb257SSam Leffler /* 145759fbb257SSam Leffler * Workaround phantom bmiss interrupts by sanity-checking 145859fbb257SSam Leffler * the time of our last rx'd frame. If it is within the 145959fbb257SSam Leffler * beacon miss interval then ignore the interrupt. If it's 146059fbb257SSam Leffler * truly a bmiss we'll get another interrupt soon and that'll 146159fbb257SSam Leffler * be dispatched up for processing. Note this applies only 146259fbb257SSam Leffler * for h/w beacon miss events. 146359fbb257SSam Leffler */ 146459fbb257SSam Leffler if ((vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) == 0) { 1465a7ace843SSam Leffler struct ifnet *ifp = vap->iv_ic->ic_ifp; 1466a7ace843SSam Leffler struct ath_softc *sc = ifp->if_softc; 1467d7736e13SSam Leffler u_int64_t lastrx = sc->sc_lastrx; 1468d7736e13SSam Leffler u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); 1469d7736e13SSam Leffler u_int bmisstimeout = 1470b032f27cSSam Leffler vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024; 1471d7736e13SSam Leffler 1472d7736e13SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 1473d7736e13SSam Leffler "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", 1474d7736e13SSam Leffler __func__, (unsigned long long) tsf, 1475d7736e13SSam Leffler (unsigned long long)(tsf - lastrx), 1476d7736e13SSam Leffler (unsigned long long) lastrx, bmisstimeout); 147759fbb257SSam Leffler 147859fbb257SSam Leffler if (tsf - lastrx <= bmisstimeout) { 1479d7736e13SSam Leffler sc->sc_stats.ast_bmiss_phantom++; 148059fbb257SSam Leffler return; 148159fbb257SSam Leffler } 148259fbb257SSam Leffler } 148359fbb257SSam Leffler ATH_VAP(vap)->av_bmiss(vap); 1484e585d188SSam Leffler } 1485b032f27cSSam Leffler 1486459bc4f0SSam Leffler static int 1487459bc4f0SSam Leffler ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs) 1488459bc4f0SSam Leffler { 1489459bc4f0SSam Leffler uint32_t rsize; 1490459bc4f0SSam Leffler void *sp; 1491459bc4f0SSam Leffler 149225c96056SAdrian Chadd if (!ath_hal_getdiagstate(ah, HAL_DIAG_CHECK_HANGS, &mask, sizeof(mask), &sp, &rsize)) 1493459bc4f0SSam Leffler return 0; 1494459bc4f0SSam Leffler KASSERT(rsize == sizeof(uint32_t), ("resultsize %u", rsize)); 1495459bc4f0SSam Leffler *hangs = *(uint32_t *)sp; 1496459bc4f0SSam Leffler return 1; 1497459bc4f0SSam Leffler } 1498459bc4f0SSam Leffler 1499b032f27cSSam Leffler static void 1500b032f27cSSam Leffler ath_bmiss_proc(void *arg, int pending) 1501b032f27cSSam Leffler { 1502b032f27cSSam Leffler struct ath_softc *sc = arg; 1503b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 1504459bc4f0SSam Leffler uint32_t hangs; 1505b032f27cSSam Leffler 1506b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); 1507459bc4f0SSam Leffler 1508459bc4f0SSam Leffler if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) { 15094fa8d4efSDaniel Eischen if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs); 1510459bc4f0SSam Leffler ath_reset(ifp); 1511459bc4f0SSam Leffler } else 1512b032f27cSSam Leffler ieee80211_beacon_miss(ifp->if_l2com); 15135591b213SSam Leffler } 15145591b213SSam Leffler 1515724c193aSSam Leffler /* 1516b032f27cSSam Leffler * Handle TKIP MIC setup to deal hardware that doesn't do MIC 1517b032f27cSSam Leffler * calcs together with WME. If necessary disable the crypto 1518b032f27cSSam Leffler * hardware and mark the 802.11 state so keys will be setup 1519b032f27cSSam Leffler * with the MIC work done in software. 1520b032f27cSSam Leffler */ 1521b032f27cSSam Leffler static void 1522b032f27cSSam Leffler ath_settkipmic(struct ath_softc *sc) 1523b032f27cSSam Leffler { 1524b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 1525b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 1526b032f27cSSam Leffler 1527b032f27cSSam Leffler if ((ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP) && !sc->sc_wmetkipmic) { 1528b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_WME) { 1529b032f27cSSam Leffler ath_hal_settkipmic(sc->sc_ah, AH_FALSE); 1530b032f27cSSam Leffler ic->ic_cryptocaps &= ~IEEE80211_CRYPTO_TKIPMIC; 1531b032f27cSSam Leffler } else { 1532b032f27cSSam Leffler ath_hal_settkipmic(sc->sc_ah, AH_TRUE); 1533b032f27cSSam Leffler ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIPMIC; 1534b032f27cSSam Leffler } 1535b032f27cSSam Leffler } 1536b032f27cSSam Leffler } 1537b032f27cSSam Leffler 15385591b213SSam Leffler static void 15395591b213SSam Leffler ath_init(void *arg) 15405591b213SSam Leffler { 15415591b213SSam Leffler struct ath_softc *sc = (struct ath_softc *) arg; 1542fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 1543b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 15445591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 15455591b213SSam Leffler HAL_STATUS status; 15465591b213SSam Leffler 1547c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 1548c42a7b7eSSam Leffler __func__, ifp->if_flags); 15495591b213SSam Leffler 1550f0b2a0beSSam Leffler ATH_LOCK(sc); 15515591b213SSam Leffler /* 15525591b213SSam Leffler * Stop anything previously setup. This is safe 15535591b213SSam Leffler * whether this is the first time through or not. 15545591b213SSam Leffler */ 1555c42a7b7eSSam Leffler ath_stop_locked(ifp); 15565591b213SSam Leffler 15575591b213SSam Leffler /* 15585591b213SSam Leffler * The basic interface to setting the hardware in a good 15595591b213SSam Leffler * state is ``reset''. On return the hardware is known to 15605591b213SSam Leffler * be powered up and with interrupts disabled. This must 15615591b213SSam Leffler * be followed by initialization of the appropriate bits 15625591b213SSam Leffler * and then setup of the interrupt mask. 15635591b213SSam Leffler */ 1564b032f27cSSam Leffler ath_settkipmic(sc); 156559efa8b5SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) { 15665591b213SSam Leffler if_printf(ifp, "unable to reset hardware; hal status %u\n", 15675591b213SSam Leffler status); 1568b032f27cSSam Leffler ATH_UNLOCK(sc); 1569b032f27cSSam Leffler return; 15705591b213SSam Leffler } 1571b032f27cSSam Leffler ath_chan_change(sc, ic->ic_curchan); 15725591b213SSam Leffler 1573*48237774SAdrian Chadd /* Let DFS at it in case it's a DFS channel */ 1574*48237774SAdrian Chadd ath_dfs_radar_enable(sc, ic->ic_curchan); 1575*48237774SAdrian Chadd 15765591b213SSam Leffler /* 1577c59005e9SSam Leffler * Likewise this is set during reset so update 1578c59005e9SSam Leffler * state cached in the driver. 1579c59005e9SSam Leffler */ 1580c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 15812dc7fcc4SSam Leffler sc->sc_lastlongcal = 0; 15822dc7fcc4SSam Leffler sc->sc_resetcal = 1; 15832dc7fcc4SSam Leffler sc->sc_lastcalreset = 0; 1584a108ab63SAdrian Chadd sc->sc_lastani = 0; 1585a108ab63SAdrian Chadd sc->sc_lastshortcal = 0; 1586a108ab63SAdrian Chadd sc->sc_doresetcal = AH_FALSE; 1587c42a7b7eSSam Leffler 1588c42a7b7eSSam Leffler /* 15895591b213SSam Leffler * Setup the hardware after reset: the key cache 15905591b213SSam Leffler * is filled as needed and the receive engine is 15915591b213SSam Leffler * set going. Frame transmit is handled entirely 15925591b213SSam Leffler * in the frame output path; there's nothing to do 15935591b213SSam Leffler * here except setup the interrupt mask. 15945591b213SSam Leffler */ 15955591b213SSam Leffler if (ath_startrecv(sc) != 0) { 15965591b213SSam Leffler if_printf(ifp, "unable to start recv logic\n"); 1597b032f27cSSam Leffler ATH_UNLOCK(sc); 1598b032f27cSSam Leffler return; 15995591b213SSam Leffler } 16005591b213SSam Leffler 16015591b213SSam Leffler /* 16025591b213SSam Leffler * Enable interrupts. 16035591b213SSam Leffler */ 16045591b213SSam Leffler sc->sc_imask = HAL_INT_RX | HAL_INT_TX 16055591b213SSam Leffler | HAL_INT_RXEOL | HAL_INT_RXORN 16065591b213SSam Leffler | HAL_INT_FATAL | HAL_INT_GLOBAL; 1607c42a7b7eSSam Leffler /* 1608c42a7b7eSSam Leffler * Enable MIB interrupts when there are hardware phy counters. 1609c42a7b7eSSam Leffler * Note we only do this (at the moment) for station mode. 1610c42a7b7eSSam Leffler */ 1611c42a7b7eSSam Leffler if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) 1612c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_MIB; 16135591b213SSam Leffler 16145594f5c0SAdrian Chadd /* Enable global TX timeout and carrier sense timeout if available */ 16156ad02dbaSAdrian Chadd if (ath_hal_gtxto_supported(ah)) 16163788ebedSAdrian Chadd sc->sc_imask |= HAL_INT_GTT; 1617d0a0ebc6SAdrian Chadd 1618d0a0ebc6SAdrian Chadd DPRINTF(sc, ATH_DEBUG_RESET, "%s: imask=0x%x\n", 1619d0a0ebc6SAdrian Chadd __func__, sc->sc_imask); 16206ad02dbaSAdrian Chadd 162113f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 16222e986da5SSam Leffler callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc); 1623b032f27cSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 16245591b213SSam Leffler 1625b032f27cSSam Leffler ATH_UNLOCK(sc); 1626b032f27cSSam Leffler 162786e07743SSam Leffler #ifdef ATH_TX99_DIAG 162886e07743SSam Leffler if (sc->sc_tx99 != NULL) 162986e07743SSam Leffler sc->sc_tx99->start(sc->sc_tx99); 163086e07743SSam Leffler else 163186e07743SSam Leffler #endif 1632b032f27cSSam Leffler ieee80211_start_all(ic); /* start all vap's */ 16335591b213SSam Leffler } 16345591b213SSam Leffler 16355591b213SSam Leffler static void 1636c42a7b7eSSam Leffler ath_stop_locked(struct ifnet *ifp) 16375591b213SSam Leffler { 16385591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 16395591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 16405591b213SSam Leffler 1641c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", 1642c42a7b7eSSam Leffler __func__, sc->sc_invalid, ifp->if_flags); 16435591b213SSam Leffler 1644c42a7b7eSSam Leffler ATH_LOCK_ASSERT(sc); 164513f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 16465591b213SSam Leffler /* 16475591b213SSam Leffler * Shutdown the hardware and driver: 1648c42a7b7eSSam Leffler * reset 802.11 state machine 16495591b213SSam Leffler * turn off timers 1650c42a7b7eSSam Leffler * disable interrupts 1651c42a7b7eSSam Leffler * turn off the radio 16525591b213SSam Leffler * clear transmit machinery 16535591b213SSam Leffler * clear receive machinery 16545591b213SSam Leffler * drain and release tx queues 16555591b213SSam Leffler * reclaim beacon resources 16565591b213SSam Leffler * power down hardware 16575591b213SSam Leffler * 16585591b213SSam Leffler * Note that some of this work is not possible if the 16595591b213SSam Leffler * hardware is gone (invalid). 16605591b213SSam Leffler */ 166186e07743SSam Leffler #ifdef ATH_TX99_DIAG 166286e07743SSam Leffler if (sc->sc_tx99 != NULL) 166386e07743SSam Leffler sc->sc_tx99->stop(sc->sc_tx99); 166486e07743SSam Leffler #endif 16652e986da5SSam Leffler callout_stop(&sc->sc_wd_ch); 16662e986da5SSam Leffler sc->sc_wd_timer = 0; 166713f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1668c42a7b7eSSam Leffler if (!sc->sc_invalid) { 16693e50ec2cSSam Leffler if (sc->sc_softled) { 16703e50ec2cSSam Leffler callout_stop(&sc->sc_ledtimer); 16713e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, 16723e50ec2cSSam Leffler !sc->sc_ledon); 16733e50ec2cSSam Leffler sc->sc_blinking = 0; 16743e50ec2cSSam Leffler } 16755591b213SSam Leffler ath_hal_intrset(ah, 0); 1676c42a7b7eSSam Leffler } 16775591b213SSam Leffler ath_draintxq(sc); 1678c42a7b7eSSam Leffler if (!sc->sc_invalid) { 16795591b213SSam Leffler ath_stoprecv(sc); 1680c42a7b7eSSam Leffler ath_hal_phydisable(ah); 1681c42a7b7eSSam Leffler } else 16825591b213SSam Leffler sc->sc_rxlink = NULL; 1683b032f27cSSam Leffler ath_beacon_free(sc); /* XXX not needed */ 1684c42a7b7eSSam Leffler } 1685c42a7b7eSSam Leffler } 1686c42a7b7eSSam Leffler 1687c42a7b7eSSam Leffler static void 1688c42a7b7eSSam Leffler ath_stop(struct ifnet *ifp) 1689c42a7b7eSSam Leffler { 1690c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1691c42a7b7eSSam Leffler 1692c42a7b7eSSam Leffler ATH_LOCK(sc); 1693c42a7b7eSSam Leffler ath_stop_locked(ifp); 1694f0b2a0beSSam Leffler ATH_UNLOCK(sc); 16955591b213SSam Leffler } 16965591b213SSam Leffler 16975591b213SSam Leffler /* 16985591b213SSam Leffler * Reset the hardware w/o losing operational state. This is 16995591b213SSam Leffler * basically a more efficient way of doing ath_stop, ath_init, 17005591b213SSam Leffler * followed by state transitions to the current 802.11 1701c42a7b7eSSam Leffler * operational state. Used to recover from various errors and 1702c42a7b7eSSam Leffler * to reset or reload hardware state. 17035591b213SSam Leffler */ 17046079fdbeSAdrian Chadd int 1705c42a7b7eSSam Leffler ath_reset(struct ifnet *ifp) 17065591b213SSam Leffler { 1707c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1708b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 17095591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 17105591b213SSam Leffler HAL_STATUS status; 17115591b213SSam Leffler 17125591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 17135591b213SSam Leffler ath_draintxq(sc); /* stop xmit side */ 17145591b213SSam Leffler ath_stoprecv(sc); /* stop recv side */ 1715b032f27cSSam Leffler ath_settkipmic(sc); /* configure TKIP MIC handling */ 17165591b213SSam Leffler /* NB: indicate channel change so we do a full reset */ 171759efa8b5SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_TRUE, &status)) 17185591b213SSam Leffler if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", 17195591b213SSam Leffler __func__, status); 1720c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 1721*48237774SAdrian Chadd 1722*48237774SAdrian Chadd /* Let DFS at it in case it's a DFS channel */ 1723*48237774SAdrian Chadd ath_dfs_radar_enable(sc, ic->ic_curchan); 1724*48237774SAdrian Chadd 172568e8e04eSSam Leffler if (ath_startrecv(sc) != 0) /* restart recv */ 172668e8e04eSSam Leffler if_printf(ifp, "%s: unable to start recv logic\n", __func__); 1727c42a7b7eSSam Leffler /* 1728c42a7b7eSSam Leffler * We may be doing a reset in response to an ioctl 1729c42a7b7eSSam Leffler * that changes the channel so update any state that 1730c42a7b7eSSam Leffler * might change as a result. 1731c42a7b7eSSam Leffler */ 1732724c193aSSam Leffler ath_chan_change(sc, ic->ic_curchan); 1733c89b957aSSam Leffler if (sc->sc_beacons) { /* restart beacons */ 1734584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 173510ad9a77SSam Leffler if (sc->sc_tdma) 173610ad9a77SSam Leffler ath_tdma_config(sc, NULL); 173710ad9a77SSam Leffler else 173810ad9a77SSam Leffler #endif 1739c89b957aSSam Leffler ath_beacon_config(sc, NULL); 174010ad9a77SSam Leffler } 1741c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 1742c42a7b7eSSam Leffler 1743c42a7b7eSSam Leffler ath_start(ifp); /* restart xmit */ 1744c42a7b7eSSam Leffler return 0; 17455591b213SSam Leffler } 17465591b213SSam Leffler 174768e8e04eSSam Leffler static int 1748b032f27cSSam Leffler ath_reset_vap(struct ieee80211vap *vap, u_long cmd) 1749b032f27cSSam Leffler { 17504b54a231SSam Leffler struct ieee80211com *ic = vap->iv_ic; 17514b54a231SSam Leffler struct ifnet *ifp = ic->ic_ifp; 17524b54a231SSam Leffler struct ath_softc *sc = ifp->if_softc; 17534b54a231SSam Leffler struct ath_hal *ah = sc->sc_ah; 17544b54a231SSam Leffler 17554b54a231SSam Leffler switch (cmd) { 17564b54a231SSam Leffler case IEEE80211_IOC_TXPOWER: 17574b54a231SSam Leffler /* 17584b54a231SSam Leffler * If per-packet TPC is enabled, then we have nothing 17594b54a231SSam Leffler * to do; otherwise we need to force the global limit. 17604b54a231SSam Leffler * All this can happen directly; no need to reset. 17614b54a231SSam Leffler */ 17624b54a231SSam Leffler if (!ath_hal_gettpc(ah)) 17634b54a231SSam Leffler ath_hal_settxpowlimit(ah, ic->ic_txpowlimit); 17644b54a231SSam Leffler return 0; 17654b54a231SSam Leffler } 17664b54a231SSam Leffler return ath_reset(ifp); 1767b032f27cSSam Leffler } 1768b032f27cSSam Leffler 1769b8e788a5SAdrian Chadd struct ath_buf * 177010ad9a77SSam Leffler _ath_getbuf_locked(struct ath_softc *sc) 177110ad9a77SSam Leffler { 177210ad9a77SSam Leffler struct ath_buf *bf; 177310ad9a77SSam Leffler 177410ad9a77SSam Leffler ATH_TXBUF_LOCK_ASSERT(sc); 177510ad9a77SSam Leffler 177610ad9a77SSam Leffler bf = STAILQ_FIRST(&sc->sc_txbuf); 177710ad9a77SSam Leffler if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0) 177810ad9a77SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); 177910ad9a77SSam Leffler else 178010ad9a77SSam Leffler bf = NULL; 178110ad9a77SSam Leffler if (bf == NULL) { 178210ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: %s\n", __func__, 178310ad9a77SSam Leffler STAILQ_FIRST(&sc->sc_txbuf) == NULL ? 178410ad9a77SSam Leffler "out of xmit buffers" : "xmit buffer busy"); 178510ad9a77SSam Leffler } 178610ad9a77SSam Leffler return bf; 178710ad9a77SSam Leffler } 178810ad9a77SSam Leffler 1789b8e788a5SAdrian Chadd struct ath_buf * 179010ad9a77SSam Leffler ath_getbuf(struct ath_softc *sc) 179110ad9a77SSam Leffler { 179210ad9a77SSam Leffler struct ath_buf *bf; 179310ad9a77SSam Leffler 179410ad9a77SSam Leffler ATH_TXBUF_LOCK(sc); 179510ad9a77SSam Leffler bf = _ath_getbuf_locked(sc); 179610ad9a77SSam Leffler if (bf == NULL) { 179710ad9a77SSam Leffler struct ifnet *ifp = sc->sc_ifp; 179810ad9a77SSam Leffler 179910ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: stop queue\n", __func__); 180010ad9a77SSam Leffler sc->sc_stats.ast_tx_qstop++; 180110ad9a77SSam Leffler ifp->if_drv_flags |= IFF_DRV_OACTIVE; 180210ad9a77SSam Leffler } 180310ad9a77SSam Leffler ATH_TXBUF_UNLOCK(sc); 180410ad9a77SSam Leffler return bf; 180510ad9a77SSam Leffler } 180610ad9a77SSam Leffler 18075591b213SSam Leffler static void 18085591b213SSam Leffler ath_start(struct ifnet *ifp) 18095591b213SSam Leffler { 18105591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 18115591b213SSam Leffler struct ieee80211_node *ni; 18125591b213SSam Leffler struct ath_buf *bf; 181368e8e04eSSam Leffler struct mbuf *m, *next; 181468e8e04eSSam Leffler ath_bufhead frags; 18155591b213SSam Leffler 181613f4c340SRobert Watson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) 18175591b213SSam Leffler return; 18185591b213SSam Leffler for (;;) { 18195591b213SSam Leffler /* 18205591b213SSam Leffler * Grab a TX buffer and associated resources. 18215591b213SSam Leffler */ 182210ad9a77SSam Leffler bf = ath_getbuf(sc); 182310ad9a77SSam Leffler if (bf == NULL) 18245591b213SSam Leffler break; 18252b9411e2SSam Leffler 1826b032f27cSSam Leffler IFQ_DEQUEUE(&ifp->if_snd, m); 1827b032f27cSSam Leffler if (m == NULL) { 1828b032f27cSSam Leffler ATH_TXBUF_LOCK(sc); 182910ad9a77SSam Leffler STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); 1830b032f27cSSam Leffler ATH_TXBUF_UNLOCK(sc); 1831b032f27cSSam Leffler break; 1832b032f27cSSam Leffler } 1833b032f27cSSam Leffler ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 183468e8e04eSSam Leffler /* 183568e8e04eSSam Leffler * Check for fragmentation. If this frame 183668e8e04eSSam Leffler * has been broken up verify we have enough 183768e8e04eSSam Leffler * buffers to send all the fragments so all 183868e8e04eSSam Leffler * go out or none... 183968e8e04eSSam Leffler */ 1840339ccfb3SSam Leffler STAILQ_INIT(&frags); 184168e8e04eSSam Leffler if ((m->m_flags & M_FRAG) && 184268e8e04eSSam Leffler !ath_txfrag_setup(sc, &frags, m, ni)) { 184368e8e04eSSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 184468e8e04eSSam Leffler "%s: out of txfrag buffers\n", __func__); 184536c6be9aSSam Leffler sc->sc_stats.ast_tx_nofrag++; 18469cb93076SSam Leffler ifp->if_oerrors++; 184768e8e04eSSam Leffler ath_freetx(m); 184868e8e04eSSam Leffler goto bad; 184968e8e04eSSam Leffler } 1850339ccfb3SSam Leffler ifp->if_opackets++; 185168e8e04eSSam Leffler nextfrag: 185268e8e04eSSam Leffler /* 185368e8e04eSSam Leffler * Pass the frame to the h/w for transmission. 185468e8e04eSSam Leffler * Fragmented frames have each frag chained together 185568e8e04eSSam Leffler * with m_nextpkt. We know there are sufficient ath_buf's 185668e8e04eSSam Leffler * to send all the frags because of work done by 185768e8e04eSSam Leffler * ath_txfrag_setup. We leave m_nextpkt set while 185868e8e04eSSam Leffler * calling ath_tx_start so it can use it to extend the 185968e8e04eSSam Leffler * the tx duration to cover the subsequent frag and 186068e8e04eSSam Leffler * so it can reclaim all the mbufs in case of an error; 186168e8e04eSSam Leffler * ath_tx_start clears m_nextpkt once it commits to 186268e8e04eSSam Leffler * handing the frame to the hardware. 186368e8e04eSSam Leffler */ 186468e8e04eSSam Leffler next = m->m_nextpkt; 18655591b213SSam Leffler if (ath_tx_start(sc, ni, bf, m)) { 18665591b213SSam Leffler bad: 18675591b213SSam Leffler ifp->if_oerrors++; 1868c42a7b7eSSam Leffler reclaim: 186968e8e04eSSam Leffler bf->bf_m = NULL; 187068e8e04eSSam Leffler bf->bf_node = NULL; 1871c42a7b7eSSam Leffler ATH_TXBUF_LOCK(sc); 187210ad9a77SSam Leffler STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); 187368e8e04eSSam Leffler ath_txfrag_cleanup(sc, &frags, ni); 1874c42a7b7eSSam Leffler ATH_TXBUF_UNLOCK(sc); 1875c42a7b7eSSam Leffler if (ni != NULL) 1876c42a7b7eSSam Leffler ieee80211_free_node(ni); 18775591b213SSam Leffler continue; 18785591b213SSam Leffler } 187968e8e04eSSam Leffler if (next != NULL) { 188068e8e04eSSam Leffler /* 188168e8e04eSSam Leffler * Beware of state changing between frags. 188268e8e04eSSam Leffler * XXX check sta power-save state? 188368e8e04eSSam Leffler */ 1884b032f27cSSam Leffler if (ni->ni_vap->iv_state != IEEE80211_S_RUN) { 188568e8e04eSSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 188668e8e04eSSam Leffler "%s: flush fragmented packet, state %s\n", 188768e8e04eSSam Leffler __func__, 1888b032f27cSSam Leffler ieee80211_state_name[ni->ni_vap->iv_state]); 188968e8e04eSSam Leffler ath_freetx(next); 189068e8e04eSSam Leffler goto reclaim; 189168e8e04eSSam Leffler } 189268e8e04eSSam Leffler m = next; 189368e8e04eSSam Leffler bf = STAILQ_FIRST(&frags); 189468e8e04eSSam Leffler KASSERT(bf != NULL, ("no buf for txfrag")); 189568e8e04eSSam Leffler STAILQ_REMOVE_HEAD(&frags, bf_list); 189668e8e04eSSam Leffler goto nextfrag; 189768e8e04eSSam Leffler } 18985591b213SSam Leffler 18992e986da5SSam Leffler sc->sc_wd_timer = 5; 19005591b213SSam Leffler } 19015591b213SSam Leffler } 19025591b213SSam Leffler 19035591b213SSam Leffler static int 19045591b213SSam Leffler ath_media_change(struct ifnet *ifp) 19055591b213SSam Leffler { 1906b032f27cSSam Leffler int error = ieee80211_media_change(ifp); 1907b032f27cSSam Leffler /* NB: only the fixed rate can change and that doesn't need a reset */ 1908b032f27cSSam Leffler return (error == ENETRESET ? 0 : error); 19095591b213SSam Leffler } 19105591b213SSam Leffler 1911c42a7b7eSSam Leffler /* 1912c42a7b7eSSam Leffler * Block/unblock tx+rx processing while a key change is done. 1913c42a7b7eSSam Leffler * We assume the caller serializes key management operations 1914c42a7b7eSSam Leffler * so we only need to worry about synchronization with other 1915c42a7b7eSSam Leffler * uses that originate in the driver. 1916c42a7b7eSSam Leffler */ 1917c42a7b7eSSam Leffler static void 1918b032f27cSSam Leffler ath_key_update_begin(struct ieee80211vap *vap) 1919c42a7b7eSSam Leffler { 1920b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ic->ic_ifp; 1921c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1922c42a7b7eSSam Leffler 1923c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1924b032f27cSSam Leffler taskqueue_block(sc->sc_tq); 1925c42a7b7eSSam Leffler IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */ 1926c42a7b7eSSam Leffler } 1927c42a7b7eSSam Leffler 1928c42a7b7eSSam Leffler static void 1929b032f27cSSam Leffler ath_key_update_end(struct ieee80211vap *vap) 1930c42a7b7eSSam Leffler { 1931b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ic->ic_ifp; 1932c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1933c42a7b7eSSam Leffler 1934c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1935c42a7b7eSSam Leffler IF_UNLOCK(&ifp->if_snd); 1936b032f27cSSam Leffler taskqueue_unblock(sc->sc_tq); 1937c42a7b7eSSam Leffler } 19385591b213SSam Leffler 19394bc0e754SSam Leffler /* 19404bc0e754SSam Leffler * Calculate the receive filter according to the 19414bc0e754SSam Leffler * operating mode and state: 19424bc0e754SSam Leffler * 19434bc0e754SSam Leffler * o always accept unicast, broadcast, and multicast traffic 1944b032f27cSSam Leffler * o accept PHY error frames when hardware doesn't have MIB support 1945411373ebSSam Leffler * to count and we need them for ANI (sta mode only until recently) 1946b032f27cSSam Leffler * and we are not scanning (ANI is disabled) 1947411373ebSSam Leffler * NB: older hal's add rx filter bits out of sight and we need to 1948411373ebSSam Leffler * blindly preserve them 19494bc0e754SSam Leffler * o probe request frames are accepted only when operating in 195059aa14a9SRui Paulo * hostap, adhoc, mesh, or monitor modes 1951b032f27cSSam Leffler * o enable promiscuous mode 1952b032f27cSSam Leffler * - when in monitor mode 1953b032f27cSSam Leffler * - if interface marked PROMISC (assumes bridge setting is filtered) 19544bc0e754SSam Leffler * o accept beacons: 19554bc0e754SSam Leffler * - when operating in station mode for collecting rssi data when 19564bc0e754SSam Leffler * the station is otherwise quiet, or 1957b032f27cSSam Leffler * - when operating in adhoc mode so the 802.11 layer creates 1958b032f27cSSam Leffler * node table entries for peers, 19594bc0e754SSam Leffler * - when scanning 1960b032f27cSSam Leffler * - when doing s/w beacon miss (e.g. for ap+sta) 1961b032f27cSSam Leffler * - when operating in ap mode in 11g to detect overlapping bss that 1962b032f27cSSam Leffler * require protection 196359aa14a9SRui Paulo * - when operating in mesh mode to detect neighbors 19646f48c956SSam Leffler * o accept control frames: 19656f48c956SSam Leffler * - when in monitor mode 1966b032f27cSSam Leffler * XXX HT protection for 11n 19674bc0e754SSam Leffler */ 19684bc0e754SSam Leffler static u_int32_t 196968e8e04eSSam Leffler ath_calcrxfilter(struct ath_softc *sc) 19704bc0e754SSam Leffler { 1971fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 1972b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 19734bc0e754SSam Leffler u_int32_t rfilt; 19744bc0e754SSam Leffler 1975b032f27cSSam Leffler rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 1976411373ebSSam Leffler if (!sc->sc_needmib && !sc->sc_scanning) 1977411373ebSSam Leffler rfilt |= HAL_RX_FILTER_PHYERR; 19784bc0e754SSam Leffler if (ic->ic_opmode != IEEE80211_M_STA) 19794bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROBEREQ; 19805463c4a4SSam Leffler /* XXX ic->ic_monvaps != 0? */ 1981b032f27cSSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC)) 19824bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROM; 19834bc0e754SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA || 198447db982fSSam Leffler ic->ic_opmode == IEEE80211_M_IBSS || 1985b032f27cSSam Leffler sc->sc_swbmiss || sc->sc_scanning) 1986b032f27cSSam Leffler rfilt |= HAL_RX_FILTER_BEACON; 1987b032f27cSSam Leffler /* 1988b032f27cSSam Leffler * NB: We don't recalculate the rx filter when 1989b032f27cSSam Leffler * ic_protmode changes; otherwise we could do 1990b032f27cSSam Leffler * this only when ic_protmode != NONE. 1991b032f27cSSam Leffler */ 1992b032f27cSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 1993b032f27cSSam Leffler IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) 19944bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_BEACON; 1995f378d4c8SAdrian Chadd 1996f378d4c8SAdrian Chadd /* 19974aa18e9dSAdrian Chadd * Enable hardware PS-POLL RX only for hostap mode; 1998f378d4c8SAdrian Chadd * STA mode sends PS-POLL frames but never 19994aa18e9dSAdrian Chadd * receives them. 2000f378d4c8SAdrian Chadd */ 2001dce0bccaSAdrian Chadd if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PSPOLL, 2002f378d4c8SAdrian Chadd 0, NULL) == HAL_OK && 2003f378d4c8SAdrian Chadd ic->ic_opmode == IEEE80211_M_HOSTAP) 2004f378d4c8SAdrian Chadd rfilt |= HAL_RX_FILTER_PSPOLL; 2005f378d4c8SAdrian Chadd 2006fe0dd789SSam Leffler if (sc->sc_nmeshvaps) { 200759aa14a9SRui Paulo rfilt |= HAL_RX_FILTER_BEACON; 200859aa14a9SRui Paulo if (sc->sc_hasbmatch) 200959aa14a9SRui Paulo rfilt |= HAL_RX_FILTER_BSSID; 201059aa14a9SRui Paulo else 201159aa14a9SRui Paulo rfilt |= HAL_RX_FILTER_PROM; 201259aa14a9SRui Paulo } 20136f48c956SSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) 20146f48c956SSam Leffler rfilt |= HAL_RX_FILTER_CONTROL; 2015f378d4c8SAdrian Chadd 2016f378d4c8SAdrian Chadd /* 2017f378d4c8SAdrian Chadd * Enable RX of compressed BAR frames only when doing 2018f378d4c8SAdrian Chadd * 802.11n. Required for A-MPDU. 2019f378d4c8SAdrian Chadd */ 2020a83df4d3SAdrian Chadd if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) 2021a83df4d3SAdrian Chadd rfilt |= HAL_RX_FILTER_COMPBAR; 2022f378d4c8SAdrian Chadd 2023b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n", 2024b032f27cSSam Leffler __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags); 20254bc0e754SSam Leffler return rfilt; 2026b032f27cSSam Leffler } 2027b032f27cSSam Leffler 2028b032f27cSSam Leffler static void 2029b032f27cSSam Leffler ath_update_promisc(struct ifnet *ifp) 2030b032f27cSSam Leffler { 2031b032f27cSSam Leffler struct ath_softc *sc = ifp->if_softc; 2032b032f27cSSam Leffler u_int32_t rfilt; 2033b032f27cSSam Leffler 2034b032f27cSSam Leffler /* configure rx filter */ 2035b032f27cSSam Leffler rfilt = ath_calcrxfilter(sc); 2036b032f27cSSam Leffler ath_hal_setrxfilter(sc->sc_ah, rfilt); 2037b032f27cSSam Leffler 2038b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); 2039b032f27cSSam Leffler } 2040b032f27cSSam Leffler 2041b032f27cSSam Leffler static void 2042b032f27cSSam Leffler ath_update_mcast(struct ifnet *ifp) 2043b032f27cSSam Leffler { 2044b032f27cSSam Leffler struct ath_softc *sc = ifp->if_softc; 2045b032f27cSSam Leffler u_int32_t mfilt[2]; 2046b032f27cSSam Leffler 2047b032f27cSSam Leffler /* calculate and install multicast filter */ 2048b032f27cSSam Leffler if ((ifp->if_flags & IFF_ALLMULTI) == 0) { 2049b032f27cSSam Leffler struct ifmultiaddr *ifma; 2050b032f27cSSam Leffler /* 2051b032f27cSSam Leffler * Merge multicast addresses to form the hardware filter. 2052b032f27cSSam Leffler */ 2053b032f27cSSam Leffler mfilt[0] = mfilt[1] = 0; 2054eb956cd0SRobert Watson if_maddr_rlock(ifp); /* XXX need some fiddling to remove? */ 2055b032f27cSSam Leffler TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2056b032f27cSSam Leffler caddr_t dl; 2057b032f27cSSam Leffler u_int32_t val; 2058b032f27cSSam Leffler u_int8_t pos; 2059b032f27cSSam Leffler 2060b032f27cSSam Leffler /* calculate XOR of eight 6bit values */ 2061b032f27cSSam Leffler dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2062b032f27cSSam Leffler val = LE_READ_4(dl + 0); 2063b032f27cSSam Leffler pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 2064b032f27cSSam Leffler val = LE_READ_4(dl + 3); 2065b032f27cSSam Leffler pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 2066b032f27cSSam Leffler pos &= 0x3f; 2067b032f27cSSam Leffler mfilt[pos / 32] |= (1 << (pos % 32)); 2068b032f27cSSam Leffler } 2069eb956cd0SRobert Watson if_maddr_runlock(ifp); 2070b032f27cSSam Leffler } else 2071b032f27cSSam Leffler mfilt[0] = mfilt[1] = ~0; 2072b032f27cSSam Leffler ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]); 2073b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n", 2074b032f27cSSam Leffler __func__, mfilt[0], mfilt[1]); 20754bc0e754SSam Leffler } 20764bc0e754SSam Leffler 20775591b213SSam Leffler static void 20785591b213SSam Leffler ath_mode_init(struct ath_softc *sc) 20795591b213SSam Leffler { 2080fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2081b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 2082b032f27cSSam Leffler u_int32_t rfilt; 20835591b213SSam Leffler 20844bc0e754SSam Leffler /* configure rx filter */ 208568e8e04eSSam Leffler rfilt = ath_calcrxfilter(sc); 20864bc0e754SSam Leffler ath_hal_setrxfilter(ah, rfilt); 20874bc0e754SSam Leffler 20885591b213SSam Leffler /* configure operational mode */ 2089c42a7b7eSSam Leffler ath_hal_setopmode(ah); 2090c42a7b7eSSam Leffler 209129aca940SSam Leffler /* handle any link-level address change */ 209229aca940SSam Leffler ath_hal_setmac(ah, IF_LLADDR(ifp)); 20935591b213SSam Leffler 20945591b213SSam Leffler /* calculate and install multicast filter */ 2095b032f27cSSam Leffler ath_update_mcast(ifp); 20965591b213SSam Leffler } 20975591b213SSam Leffler 2098c42a7b7eSSam Leffler /* 2099c42a7b7eSSam Leffler * Set the slot time based on the current setting. 2100c42a7b7eSSam Leffler */ 2101c42a7b7eSSam Leffler static void 2102c42a7b7eSSam Leffler ath_setslottime(struct ath_softc *sc) 2103c42a7b7eSSam Leffler { 2104b032f27cSSam Leffler struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2105c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2106aaa70f2fSSam Leffler u_int usec; 2107c42a7b7eSSam Leffler 2108aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) 2109aaa70f2fSSam Leffler usec = 13; 2110aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) 2111aaa70f2fSSam Leffler usec = 21; 2112724c193aSSam Leffler else if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) { 2113724c193aSSam Leffler /* honor short/long slot time only in 11g */ 2114724c193aSSam Leffler /* XXX shouldn't honor on pure g or turbo g channel */ 2115724c193aSSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 2116aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_9; 2117aaa70f2fSSam Leffler else 2118aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_20; 2119724c193aSSam Leffler } else 2120724c193aSSam Leffler usec = HAL_SLOT_TIME_9; 2121aaa70f2fSSam Leffler 2122aaa70f2fSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 2123aaa70f2fSSam Leffler "%s: chan %u MHz flags 0x%x %s slot, %u usec\n", 2124aaa70f2fSSam Leffler __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags, 2125aaa70f2fSSam Leffler ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec); 2126aaa70f2fSSam Leffler 2127aaa70f2fSSam Leffler ath_hal_setslottime(ah, usec); 2128c42a7b7eSSam Leffler sc->sc_updateslot = OK; 2129c42a7b7eSSam Leffler } 2130c42a7b7eSSam Leffler 2131c42a7b7eSSam Leffler /* 2132c42a7b7eSSam Leffler * Callback from the 802.11 layer to update the 2133c42a7b7eSSam Leffler * slot time based on the current setting. 2134c42a7b7eSSam Leffler */ 2135c42a7b7eSSam Leffler static void 2136c42a7b7eSSam Leffler ath_updateslot(struct ifnet *ifp) 2137c42a7b7eSSam Leffler { 2138c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 2139b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 2140c42a7b7eSSam Leffler 2141c42a7b7eSSam Leffler /* 2142c42a7b7eSSam Leffler * When not coordinating the BSS, change the hardware 2143c42a7b7eSSam Leffler * immediately. For other operation we defer the change 2144c42a7b7eSSam Leffler * until beacon updates have propagated to the stations. 2145c42a7b7eSSam Leffler */ 214659aa14a9SRui Paulo if (ic->ic_opmode == IEEE80211_M_HOSTAP || 214759aa14a9SRui Paulo ic->ic_opmode == IEEE80211_M_MBSS) 2148c42a7b7eSSam Leffler sc->sc_updateslot = UPDATE; 2149c42a7b7eSSam Leffler else 2150c42a7b7eSSam Leffler ath_setslottime(sc); 2151c42a7b7eSSam Leffler } 2152c42a7b7eSSam Leffler 2153c42a7b7eSSam Leffler /* 215480d2765fSSam Leffler * Setup a h/w transmit queue for beacons. 215580d2765fSSam Leffler */ 215680d2765fSSam Leffler static int 215780d2765fSSam Leffler ath_beaconq_setup(struct ath_hal *ah) 215880d2765fSSam Leffler { 215980d2765fSSam Leffler HAL_TXQ_INFO qi; 216080d2765fSSam Leffler 216180d2765fSSam Leffler memset(&qi, 0, sizeof(qi)); 216280d2765fSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 216380d2765fSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 216480d2765fSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 21650f2e86fbSSam Leffler /* NB: for dynamic turbo, don't enable any other interrupts */ 2166bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; 216780d2765fSSam Leffler return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi); 216880d2765fSSam Leffler } 216980d2765fSSam Leffler 217080d2765fSSam Leffler /* 21710f2e86fbSSam Leffler * Setup the transmit queue parameters for the beacon queue. 21720f2e86fbSSam Leffler */ 21730f2e86fbSSam Leffler static int 21740f2e86fbSSam Leffler ath_beaconq_config(struct ath_softc *sc) 21750f2e86fbSSam Leffler { 21760f2e86fbSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) 2177b032f27cSSam Leffler struct ieee80211com *ic = sc->sc_ifp->if_l2com; 21780f2e86fbSSam Leffler struct ath_hal *ah = sc->sc_ah; 21790f2e86fbSSam Leffler HAL_TXQ_INFO qi; 21800f2e86fbSSam Leffler 21810f2e86fbSSam Leffler ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi); 218259aa14a9SRui Paulo if (ic->ic_opmode == IEEE80211_M_HOSTAP || 218359aa14a9SRui Paulo ic->ic_opmode == IEEE80211_M_MBSS) { 21840f2e86fbSSam Leffler /* 21850f2e86fbSSam Leffler * Always burst out beacon and CAB traffic. 21860f2e86fbSSam Leffler */ 21870f2e86fbSSam Leffler qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; 21880f2e86fbSSam Leffler qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT; 21890f2e86fbSSam Leffler qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT; 21900f2e86fbSSam Leffler } else { 21910f2e86fbSSam Leffler struct wmeParams *wmep = 21920f2e86fbSSam Leffler &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE]; 21930f2e86fbSSam Leffler /* 21940f2e86fbSSam Leffler * Adhoc mode; important thing is to use 2x cwmin. 21950f2e86fbSSam Leffler */ 21960f2e86fbSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 21970f2e86fbSSam Leffler qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 21980f2e86fbSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 21990f2e86fbSSam Leffler } 22000f2e86fbSSam Leffler 22010f2e86fbSSam Leffler if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) { 22020f2e86fbSSam Leffler device_printf(sc->sc_dev, "unable to update parameters for " 22030f2e86fbSSam Leffler "beacon hardware queue!\n"); 22040f2e86fbSSam Leffler return 0; 22050f2e86fbSSam Leffler } else { 22060f2e86fbSSam Leffler ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ 22070f2e86fbSSam Leffler return 1; 22080f2e86fbSSam Leffler } 22090f2e86fbSSam Leffler #undef ATH_EXPONENT_TO_VALUE 22100f2e86fbSSam Leffler } 22110f2e86fbSSam Leffler 22120f2e86fbSSam Leffler /* 2213c42a7b7eSSam Leffler * Allocate and setup an initial beacon frame. 2214c42a7b7eSSam Leffler */ 22155591b213SSam Leffler static int 22165591b213SSam Leffler ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) 22175591b213SSam Leffler { 2218b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2219b032f27cSSam Leffler struct ath_vap *avp = ATH_VAP(vap); 22205591b213SSam Leffler struct ath_buf *bf; 22215591b213SSam Leffler struct mbuf *m; 2222c42a7b7eSSam Leffler int error; 22235591b213SSam Leffler 2224b032f27cSSam Leffler bf = avp->av_bcbuf; 2225b032f27cSSam Leffler if (bf->bf_m != NULL) { 2226b032f27cSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2227b032f27cSSam Leffler m_freem(bf->bf_m); 2228b032f27cSSam Leffler bf->bf_m = NULL; 2229c42a7b7eSSam Leffler } 2230b032f27cSSam Leffler if (bf->bf_node != NULL) { 2231b032f27cSSam Leffler ieee80211_free_node(bf->bf_node); 2232b032f27cSSam Leffler bf->bf_node = NULL; 2233b032f27cSSam Leffler } 2234b032f27cSSam Leffler 22355591b213SSam Leffler /* 22365591b213SSam Leffler * NB: the beacon data buffer must be 32-bit aligned; 22375591b213SSam Leffler * we assume the mbuf routines will return us something 22385591b213SSam Leffler * with this alignment (perhaps should assert). 22395591b213SSam Leffler */ 2240b032f27cSSam Leffler m = ieee80211_beacon_alloc(ni, &avp->av_boff); 22415591b213SSam Leffler if (m == NULL) { 2242b032f27cSSam Leffler device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__); 22435591b213SSam Leffler sc->sc_stats.ast_be_nombuf++; 22445591b213SSam Leffler return ENOMEM; 22455591b213SSam Leffler } 2246f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2247f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 22485591b213SSam Leffler BUS_DMA_NOWAIT); 2249b032f27cSSam Leffler if (error != 0) { 2250b032f27cSSam Leffler device_printf(sc->sc_dev, 2251b032f27cSSam Leffler "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n", 2252b032f27cSSam Leffler __func__, error); 2253b032f27cSSam Leffler m_freem(m); 2254b032f27cSSam Leffler return error; 2255b032f27cSSam Leffler } 2256b032f27cSSam Leffler 2257b032f27cSSam Leffler /* 2258b032f27cSSam Leffler * Calculate a TSF adjustment factor required for staggered 2259b032f27cSSam Leffler * beacons. Note that we assume the format of the beacon 2260b032f27cSSam Leffler * frame leaves the tstamp field immediately following the 2261b032f27cSSam Leffler * header. 2262b032f27cSSam Leffler */ 2263b032f27cSSam Leffler if (sc->sc_stagbeacons && avp->av_bslot > 0) { 2264b032f27cSSam Leffler uint64_t tsfadjust; 2265b032f27cSSam Leffler struct ieee80211_frame *wh; 2266b032f27cSSam Leffler 2267b032f27cSSam Leffler /* 2268b032f27cSSam Leffler * The beacon interval is in TU's; the TSF is in usecs. 2269b032f27cSSam Leffler * We figure out how many TU's to add to align the timestamp 2270b032f27cSSam Leffler * then convert to TSF units and handle byte swapping before 2271b032f27cSSam Leffler * inserting it in the frame. The hardware will then add this 2272b032f27cSSam Leffler * each time a beacon frame is sent. Note that we align vap's 2273b032f27cSSam Leffler * 1..N and leave vap 0 untouched. This means vap 0 has a 2274b032f27cSSam Leffler * timestamp in one beacon interval while the others get a 2275b032f27cSSam Leffler * timstamp aligned to the next interval. 2276b032f27cSSam Leffler */ 2277b032f27cSSam Leffler tsfadjust = ni->ni_intval * 2278b032f27cSSam Leffler (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF; 2279b032f27cSSam Leffler tsfadjust = htole64(tsfadjust << 10); /* TU -> TSF */ 2280b032f27cSSam Leffler 2281b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2282b032f27cSSam Leffler "%s: %s beacons bslot %d intval %u tsfadjust %llu\n", 2283b032f27cSSam Leffler __func__, sc->sc_stagbeacons ? "stagger" : "burst", 22843627e321SSam Leffler avp->av_bslot, ni->ni_intval, 22853627e321SSam Leffler (long long unsigned) le64toh(tsfadjust)); 2286b032f27cSSam Leffler 2287b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 2288b032f27cSSam Leffler memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust)); 2289b032f27cSSam Leffler } 2290c42a7b7eSSam Leffler bf->bf_m = m; 2291f818612bSSam Leffler bf->bf_node = ieee80211_ref_node(ni); 2292b032f27cSSam Leffler 2293b032f27cSSam Leffler return 0; 22945591b213SSam Leffler } 2295c42a7b7eSSam Leffler 2296c42a7b7eSSam Leffler /* 2297c42a7b7eSSam Leffler * Setup the beacon frame for transmit. 2298c42a7b7eSSam Leffler */ 2299c42a7b7eSSam Leffler static void 2300c42a7b7eSSam Leffler ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) 2301c42a7b7eSSam Leffler { 2302c42a7b7eSSam Leffler #define USE_SHPREAMBLE(_ic) \ 2303c42a7b7eSSam Leffler (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 2304c42a7b7eSSam Leffler == IEEE80211_F_SHPREAMBLE) 2305c42a7b7eSSam Leffler struct ieee80211_node *ni = bf->bf_node; 2306c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2307c42a7b7eSSam Leffler struct mbuf *m = bf->bf_m; 2308c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2309c42a7b7eSSam Leffler struct ath_desc *ds; 2310c42a7b7eSSam Leffler int flags, antenna; 231155f63772SSam Leffler const HAL_RATE_TABLE *rt; 231255f63772SSam Leffler u_int8_t rix, rate; 2313c42a7b7eSSam Leffler 23144a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n", 2315c42a7b7eSSam Leffler __func__, m, m->m_len); 23165591b213SSam Leffler 23175591b213SSam Leffler /* setup descriptors */ 23185591b213SSam Leffler ds = bf->bf_desc; 23195591b213SSam Leffler 2320c42a7b7eSSam Leffler flags = HAL_TXDESC_NOACK; 2321c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) { 2322c42a7b7eSSam Leffler ds->ds_link = bf->bf_daddr; /* self-linked */ 2323c42a7b7eSSam Leffler flags |= HAL_TXDESC_VEOL; 2324c42a7b7eSSam Leffler /* 2325c42a7b7eSSam Leffler * Let hardware handle antenna switching. 2326c42a7b7eSSam Leffler */ 23274866e6c2SSam Leffler antenna = sc->sc_txantenna; 2328c42a7b7eSSam Leffler } else { 23295591b213SSam Leffler ds->ds_link = 0; 2330c42a7b7eSSam Leffler /* 2331c42a7b7eSSam Leffler * Switch antenna every 4 beacons. 2332c42a7b7eSSam Leffler * XXX assumes two antenna 2333c42a7b7eSSam Leffler */ 2334b032f27cSSam Leffler if (sc->sc_txantenna != 0) 2335b032f27cSSam Leffler antenna = sc->sc_txantenna; 2336b032f27cSSam Leffler else if (sc->sc_stagbeacons && sc->sc_nbcnvaps != 0) 2337b032f27cSSam Leffler antenna = ((sc->sc_stats.ast_be_xmit / sc->sc_nbcnvaps) & 4 ? 2 : 1); 2338b032f27cSSam Leffler else 2339b032f27cSSam Leffler antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1); 2340c42a7b7eSSam Leffler } 2341c42a7b7eSSam Leffler 2342c42a7b7eSSam Leffler KASSERT(bf->bf_nseg == 1, 2343c42a7b7eSSam Leffler ("multi-segment beacon frame; nseg %u", bf->bf_nseg)); 23445591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 23455591b213SSam Leffler /* 23465591b213SSam Leffler * Calculate rate code. 23475591b213SSam Leffler * XXX everything at min xmit rate 23485591b213SSam Leffler */ 2349b032f27cSSam Leffler rix = 0; 235055f63772SSam Leffler rt = sc->sc_currates; 235155f63772SSam Leffler rate = rt->info[rix].rateCode; 2352c42a7b7eSSam Leffler if (USE_SHPREAMBLE(ic)) 235355f63772SSam Leffler rate |= rt->info[rix].shortPreamble; 23545591b213SSam Leffler ath_hal_setuptxdesc(ah, ds 2355c42a7b7eSSam Leffler , m->m_len + IEEE80211_CRC_LEN /* frame length */ 23565591b213SSam Leffler , sizeof(struct ieee80211_frame)/* header length */ 23575591b213SSam Leffler , HAL_PKT_TYPE_BEACON /* Atheros packet type */ 2358c42a7b7eSSam Leffler , ni->ni_txpower /* txpower XXX */ 23595591b213SSam Leffler , rate, 1 /* series 0 rate/tries */ 23605591b213SSam Leffler , HAL_TXKEYIX_INVALID /* no encryption */ 2361c42a7b7eSSam Leffler , antenna /* antenna mode */ 2362c42a7b7eSSam Leffler , flags /* no ack, veol for beacons */ 23635591b213SSam Leffler , 0 /* rts/cts rate */ 23645591b213SSam Leffler , 0 /* rts/cts duration */ 23655591b213SSam Leffler ); 23665591b213SSam Leffler /* NB: beacon's BufLen must be a multiple of 4 bytes */ 23675591b213SSam Leffler ath_hal_filltxdesc(ah, ds 2368c42a7b7eSSam Leffler , roundup(m->m_len, 4) /* buffer length */ 23695591b213SSam Leffler , AH_TRUE /* first segment */ 23705591b213SSam Leffler , AH_TRUE /* last segment */ 2371c42a7b7eSSam Leffler , ds /* first descriptor */ 23725591b213SSam Leffler ); 2373b032f27cSSam Leffler #if 0 2374b032f27cSSam Leffler ath_desc_swap(ds); 2375b032f27cSSam Leffler #endif 2376c42a7b7eSSam Leffler #undef USE_SHPREAMBLE 23775591b213SSam Leffler } 23785591b213SSam Leffler 2379b105a069SSam Leffler static void 2380b032f27cSSam Leffler ath_beacon_update(struct ieee80211vap *vap, int item) 2381b105a069SSam Leffler { 2382b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff; 2383b105a069SSam Leffler 2384b105a069SSam Leffler setbit(bo->bo_flags, item); 2385b105a069SSam Leffler } 2386b105a069SSam Leffler 2387c42a7b7eSSam Leffler /* 2388622b3fd2SSam Leffler * Append the contents of src to dst; both queues 2389622b3fd2SSam Leffler * are assumed to be locked. 2390622b3fd2SSam Leffler */ 2391622b3fd2SSam Leffler static void 2392622b3fd2SSam Leffler ath_txqmove(struct ath_txq *dst, struct ath_txq *src) 2393622b3fd2SSam Leffler { 2394622b3fd2SSam Leffler STAILQ_CONCAT(&dst->axq_q, &src->axq_q); 2395622b3fd2SSam Leffler dst->axq_link = src->axq_link; 2396622b3fd2SSam Leffler src->axq_link = NULL; 2397622b3fd2SSam Leffler dst->axq_depth += src->axq_depth; 2398622b3fd2SSam Leffler src->axq_depth = 0; 2399622b3fd2SSam Leffler } 2400622b3fd2SSam Leffler 2401622b3fd2SSam Leffler /* 2402c42a7b7eSSam Leffler * Transmit a beacon frame at SWBA. Dynamic updates to the 2403c42a7b7eSSam Leffler * frame contents are done as needed and the slot time is 2404c42a7b7eSSam Leffler * also adjusted based on current state. 2405c42a7b7eSSam Leffler */ 24065591b213SSam Leffler static void 24075591b213SSam Leffler ath_beacon_proc(void *arg, int pending) 24085591b213SSam Leffler { 24095591b213SSam Leffler struct ath_softc *sc = arg; 24105591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 2411b032f27cSSam Leffler struct ieee80211vap *vap; 2412b032f27cSSam Leffler struct ath_buf *bf; 2413b032f27cSSam Leffler int slot, otherant; 2414b032f27cSSam Leffler uint32_t bfaddr; 24155591b213SSam Leffler 2416c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n", 2417c42a7b7eSSam Leffler __func__, pending); 2418c42a7b7eSSam Leffler /* 2419c42a7b7eSSam Leffler * Check if the previous beacon has gone out. If 2420c66c48cbSSam Leffler * not don't try to post another, skip this period 2421c66c48cbSSam Leffler * and wait for the next. Missed beacons indicate 2422c66c48cbSSam Leffler * a problem and should not occur. If we miss too 2423c66c48cbSSam Leffler * many consecutive beacons reset the device. 2424c42a7b7eSSam Leffler */ 2425c42a7b7eSSam Leffler if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { 2426c42a7b7eSSam Leffler sc->sc_bmisscount++; 24277ec4e6b8SAdrian Chadd sc->sc_stats.ast_be_missed++; 24284a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2429c42a7b7eSSam Leffler "%s: missed %u consecutive beacons\n", 2430c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2431a32ac9d3SSam Leffler if (sc->sc_bmisscount >= ath_bstuck_threshold) 24320bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); 2433c42a7b7eSSam Leffler return; 2434c42a7b7eSSam Leffler } 2435c42a7b7eSSam Leffler if (sc->sc_bmisscount != 0) { 2436c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2437c42a7b7eSSam Leffler "%s: resume beacon xmit after %u misses\n", 2438c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2439c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 2440c42a7b7eSSam Leffler } 2441c42a7b7eSSam Leffler 2442b032f27cSSam Leffler if (sc->sc_stagbeacons) { /* staggered beacons */ 2443b032f27cSSam Leffler struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2444b032f27cSSam Leffler uint32_t tsftu; 2445b032f27cSSam Leffler 2446b032f27cSSam Leffler tsftu = ath_hal_gettsf32(ah) >> 10; 2447b032f27cSSam Leffler /* XXX lintval */ 2448b032f27cSSam Leffler slot = ((tsftu % ic->ic_lintval) * ATH_BCBUF) / ic->ic_lintval; 2449b032f27cSSam Leffler vap = sc->sc_bslot[(slot+1) % ATH_BCBUF]; 2450b032f27cSSam Leffler bfaddr = 0; 2451309a3e45SSam Leffler if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) { 2452b032f27cSSam Leffler bf = ath_beacon_generate(sc, vap); 2453b032f27cSSam Leffler if (bf != NULL) 2454b032f27cSSam Leffler bfaddr = bf->bf_daddr; 2455b032f27cSSam Leffler } 2456b032f27cSSam Leffler } else { /* burst'd beacons */ 2457b032f27cSSam Leffler uint32_t *bflink = &bfaddr; 2458b032f27cSSam Leffler 2459b032f27cSSam Leffler for (slot = 0; slot < ATH_BCBUF; slot++) { 2460b032f27cSSam Leffler vap = sc->sc_bslot[slot]; 2461309a3e45SSam Leffler if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) { 2462b032f27cSSam Leffler bf = ath_beacon_generate(sc, vap); 2463b032f27cSSam Leffler if (bf != NULL) { 2464b032f27cSSam Leffler *bflink = bf->bf_daddr; 2465b032f27cSSam Leffler bflink = &bf->bf_desc->ds_link; 2466c42a7b7eSSam Leffler } 2467c42a7b7eSSam Leffler } 2468b032f27cSSam Leffler } 2469b032f27cSSam Leffler *bflink = 0; /* terminate list */ 2470622b3fd2SSam Leffler } 2471c42a7b7eSSam Leffler 2472c42a7b7eSSam Leffler /* 2473c42a7b7eSSam Leffler * Handle slot time change when a non-ERP station joins/leaves 2474c42a7b7eSSam Leffler * an 11g network. The 802.11 layer notifies us via callback, 2475c42a7b7eSSam Leffler * we mark updateslot, then wait one beacon before effecting 2476c42a7b7eSSam Leffler * the change. This gives associated stations at least one 2477c42a7b7eSSam Leffler * beacon interval to note the state change. 2478c42a7b7eSSam Leffler */ 2479c42a7b7eSSam Leffler /* XXX locking */ 2480b032f27cSSam Leffler if (sc->sc_updateslot == UPDATE) { 2481c42a7b7eSSam Leffler sc->sc_updateslot = COMMIT; /* commit next beacon */ 2482b032f27cSSam Leffler sc->sc_slotupdate = slot; 2483b032f27cSSam Leffler } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) 2484c42a7b7eSSam Leffler ath_setslottime(sc); /* commit change to h/w */ 2485c42a7b7eSSam Leffler 2486c42a7b7eSSam Leffler /* 2487c42a7b7eSSam Leffler * Check recent per-antenna transmit statistics and flip 2488c42a7b7eSSam Leffler * the default antenna if noticeably more frames went out 2489c42a7b7eSSam Leffler * on the non-default antenna. 2490c42a7b7eSSam Leffler * XXX assumes 2 anntenae 2491c42a7b7eSSam Leffler */ 2492b032f27cSSam Leffler if (!sc->sc_diversity && (!sc->sc_stagbeacons || slot == 0)) { 2493c42a7b7eSSam Leffler otherant = sc->sc_defant & 1 ? 2 : 1; 2494c42a7b7eSSam Leffler if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) 2495c42a7b7eSSam Leffler ath_setdefantenna(sc, otherant); 2496c42a7b7eSSam Leffler sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; 2497b032f27cSSam Leffler } 2498c42a7b7eSSam Leffler 2499b032f27cSSam Leffler if (bfaddr != 0) { 2500c42a7b7eSSam Leffler /* 2501c42a7b7eSSam Leffler * Stop any current dma and put the new frame on the queue. 2502c42a7b7eSSam Leffler * This should never fail since we check above that no frames 2503c42a7b7eSSam Leffler * are still pending on the queue. 2504c42a7b7eSSam Leffler */ 25055591b213SSam Leffler if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { 2506c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2507c42a7b7eSSam Leffler "%s: beacon queue %u did not stop?\n", 2508c42a7b7eSSam Leffler __func__, sc->sc_bhalq); 25095591b213SSam Leffler } 2510b032f27cSSam Leffler /* NB: cabq traffic should already be queued and primed */ 2511b032f27cSSam Leffler ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr); 2512b032f27cSSam Leffler ath_hal_txstart(ah, sc->sc_bhalq); 2513b032f27cSSam Leffler 2514b032f27cSSam Leffler sc->sc_stats.ast_be_xmit++; 2515b032f27cSSam Leffler } 2516b032f27cSSam Leffler } 2517b032f27cSSam Leffler 2518b032f27cSSam Leffler static struct ath_buf * 2519b032f27cSSam Leffler ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) 2520b032f27cSSam Leffler { 2521b032f27cSSam Leffler struct ath_vap *avp = ATH_VAP(vap); 2522b032f27cSSam Leffler struct ath_txq *cabq = sc->sc_cabq; 2523b032f27cSSam Leffler struct ath_buf *bf; 2524b032f27cSSam Leffler struct mbuf *m; 2525b032f27cSSam Leffler int nmcastq, error; 2526b032f27cSSam Leffler 2527309a3e45SSam Leffler KASSERT(vap->iv_state >= IEEE80211_S_RUN, 2528b032f27cSSam Leffler ("not running, state %d", vap->iv_state)); 2529b032f27cSSam Leffler KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer")); 2530b032f27cSSam Leffler 2531b032f27cSSam Leffler /* 2532b032f27cSSam Leffler * Update dynamic beacon contents. If this returns 2533b032f27cSSam Leffler * non-zero then we need to remap the memory because 2534b032f27cSSam Leffler * the beacon frame changed size (probably because 2535b032f27cSSam Leffler * of the TIM bitmap). 2536b032f27cSSam Leffler */ 2537b032f27cSSam Leffler bf = avp->av_bcbuf; 2538b032f27cSSam Leffler m = bf->bf_m; 2539b032f27cSSam Leffler nmcastq = avp->av_mcastq.axq_depth; 2540b032f27cSSam Leffler if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, nmcastq)) { 2541b032f27cSSam Leffler /* XXX too conservative? */ 2542b032f27cSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2543b032f27cSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2544b032f27cSSam Leffler bf->bf_segs, &bf->bf_nseg, 2545b032f27cSSam Leffler BUS_DMA_NOWAIT); 2546b032f27cSSam Leffler if (error != 0) { 2547b032f27cSSam Leffler if_printf(vap->iv_ifp, 2548b032f27cSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 2549b032f27cSSam Leffler __func__, error); 2550b032f27cSSam Leffler return NULL; 2551b032f27cSSam Leffler } 2552b032f27cSSam Leffler } 2553b032f27cSSam Leffler if ((avp->av_boff.bo_tim[4] & 1) && cabq->axq_depth) { 2554b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2555b032f27cSSam Leffler "%s: cabq did not drain, mcastq %u cabq %u\n", 2556b032f27cSSam Leffler __func__, nmcastq, cabq->axq_depth); 2557b032f27cSSam Leffler sc->sc_stats.ast_cabq_busy++; 2558b032f27cSSam Leffler if (sc->sc_nvaps > 1 && sc->sc_stagbeacons) { 2559b032f27cSSam Leffler /* 2560b032f27cSSam Leffler * CABQ traffic from a previous vap is still pending. 2561b032f27cSSam Leffler * We must drain the q before this beacon frame goes 2562b032f27cSSam Leffler * out as otherwise this vap's stations will get cab 2563b032f27cSSam Leffler * frames from a different vap. 2564b032f27cSSam Leffler * XXX could be slow causing us to miss DBA 2565b032f27cSSam Leffler */ 2566b032f27cSSam Leffler ath_tx_draintxq(sc, cabq); 2567b032f27cSSam Leffler } 2568b032f27cSSam Leffler } 2569b032f27cSSam Leffler ath_beacon_setup(sc, bf); 25705591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 25715591b213SSam Leffler 2572c42a7b7eSSam Leffler /* 2573c42a7b7eSSam Leffler * Enable the CAB queue before the beacon queue to 2574c42a7b7eSSam Leffler * insure cab frames are triggered by this beacon. 2575c42a7b7eSSam Leffler */ 2576b032f27cSSam Leffler if (avp->av_boff.bo_tim[4] & 1) { 2577b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 2578b032f27cSSam Leffler 2579f3af83f7SSam Leffler /* NB: only at DTIM */ 2580622b3fd2SSam Leffler ATH_TXQ_LOCK(cabq); 2581b032f27cSSam Leffler ATH_TXQ_LOCK(&avp->av_mcastq); 2582622b3fd2SSam Leffler if (nmcastq) { 2583622b3fd2SSam Leffler struct ath_buf *bfm; 2584622b3fd2SSam Leffler 2585622b3fd2SSam Leffler /* 2586622b3fd2SSam Leffler * Move frames from the s/w mcast q to the h/w cab q. 2587b032f27cSSam Leffler * XXX MORE_DATA bit 2588622b3fd2SSam Leffler */ 2589b032f27cSSam Leffler bfm = STAILQ_FIRST(&avp->av_mcastq.axq_q); 2590622b3fd2SSam Leffler if (cabq->axq_link != NULL) { 2591622b3fd2SSam Leffler *cabq->axq_link = bfm->bf_daddr; 2592622b3fd2SSam Leffler } else 2593622b3fd2SSam Leffler ath_hal_puttxbuf(ah, cabq->axq_qnum, 2594622b3fd2SSam Leffler bfm->bf_daddr); 2595b032f27cSSam Leffler ath_txqmove(cabq, &avp->av_mcastq); 2596622b3fd2SSam Leffler 2597622b3fd2SSam Leffler sc->sc_stats.ast_cabq_xmit += nmcastq; 2598622b3fd2SSam Leffler } 2599622b3fd2SSam Leffler /* NB: gated by beacon so safe to start here */ 2600622b3fd2SSam Leffler ath_hal_txstart(ah, cabq->axq_qnum); 2601622b3fd2SSam Leffler ATH_TXQ_UNLOCK(cabq); 2602b032f27cSSam Leffler ATH_TXQ_UNLOCK(&avp->av_mcastq); 2603622b3fd2SSam Leffler } 2604b032f27cSSam Leffler return bf; 2605b032f27cSSam Leffler } 2606b032f27cSSam Leffler 2607b032f27cSSam Leffler static void 2608b032f27cSSam Leffler ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap) 2609b032f27cSSam Leffler { 2610b032f27cSSam Leffler struct ath_vap *avp = ATH_VAP(vap); 2611b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 2612b032f27cSSam Leffler struct ath_buf *bf; 2613b032f27cSSam Leffler struct mbuf *m; 2614b032f27cSSam Leffler int error; 2615b032f27cSSam Leffler 2616b032f27cSSam Leffler KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer")); 2617b032f27cSSam Leffler 2618b032f27cSSam Leffler /* 2619b032f27cSSam Leffler * Update dynamic beacon contents. If this returns 2620b032f27cSSam Leffler * non-zero then we need to remap the memory because 2621b032f27cSSam Leffler * the beacon frame changed size (probably because 2622b032f27cSSam Leffler * of the TIM bitmap). 2623b032f27cSSam Leffler */ 2624b032f27cSSam Leffler bf = avp->av_bcbuf; 2625b032f27cSSam Leffler m = bf->bf_m; 2626b032f27cSSam Leffler if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, 0)) { 2627b032f27cSSam Leffler /* XXX too conservative? */ 2628b032f27cSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2629b032f27cSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2630b032f27cSSam Leffler bf->bf_segs, &bf->bf_nseg, 2631b032f27cSSam Leffler BUS_DMA_NOWAIT); 2632b032f27cSSam Leffler if (error != 0) { 2633b032f27cSSam Leffler if_printf(vap->iv_ifp, 2634b032f27cSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 2635b032f27cSSam Leffler __func__, error); 2636b032f27cSSam Leffler return; 2637b032f27cSSam Leffler } 2638b032f27cSSam Leffler } 2639b032f27cSSam Leffler ath_beacon_setup(sc, bf); 2640b032f27cSSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 2641b032f27cSSam Leffler 2642b032f27cSSam Leffler /* NB: caller is known to have already stopped tx dma */ 26435591b213SSam Leffler ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); 26445591b213SSam Leffler ath_hal_txstart(ah, sc->sc_bhalq); 26455591b213SSam Leffler } 26465591b213SSam Leffler 2647c42a7b7eSSam Leffler /* 2648c42a7b7eSSam Leffler * Reset the hardware after detecting beacons have stopped. 2649c42a7b7eSSam Leffler */ 2650c42a7b7eSSam Leffler static void 2651c42a7b7eSSam Leffler ath_bstuck_proc(void *arg, int pending) 2652c42a7b7eSSam Leffler { 2653c42a7b7eSSam Leffler struct ath_softc *sc = arg; 2654fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2655c42a7b7eSSam Leffler 2656c42a7b7eSSam Leffler if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n", 2657c42a7b7eSSam Leffler sc->sc_bmisscount); 2658c2e34459SSam Leffler sc->sc_stats.ast_bstuck++; 2659c42a7b7eSSam Leffler ath_reset(ifp); 2660c42a7b7eSSam Leffler } 2661c42a7b7eSSam Leffler 2662c42a7b7eSSam Leffler /* 2663b032f27cSSam Leffler * Reclaim beacon resources and return buffer to the pool. 2664b032f27cSSam Leffler */ 2665b032f27cSSam Leffler static void 2666b032f27cSSam Leffler ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf) 2667b032f27cSSam Leffler { 2668b032f27cSSam Leffler 2669b032f27cSSam Leffler if (bf->bf_m != NULL) { 2670b032f27cSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2671b032f27cSSam Leffler m_freem(bf->bf_m); 2672b032f27cSSam Leffler bf->bf_m = NULL; 2673b032f27cSSam Leffler } 2674b032f27cSSam Leffler if (bf->bf_node != NULL) { 2675b032f27cSSam Leffler ieee80211_free_node(bf->bf_node); 2676b032f27cSSam Leffler bf->bf_node = NULL; 2677b032f27cSSam Leffler } 2678b032f27cSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list); 2679b032f27cSSam Leffler } 2680b032f27cSSam Leffler 2681b032f27cSSam Leffler /* 2682c42a7b7eSSam Leffler * Reclaim beacon resources. 2683c42a7b7eSSam Leffler */ 26845591b213SSam Leffler static void 26855591b213SSam Leffler ath_beacon_free(struct ath_softc *sc) 26865591b213SSam Leffler { 2687c42a7b7eSSam Leffler struct ath_buf *bf; 26885591b213SSam Leffler 2689f818612bSSam Leffler STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { 26905591b213SSam Leffler if (bf->bf_m != NULL) { 26915591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 26925591b213SSam Leffler m_freem(bf->bf_m); 26935591b213SSam Leffler bf->bf_m = NULL; 2694f818612bSSam Leffler } 2695f818612bSSam Leffler if (bf->bf_node != NULL) { 2696f818612bSSam Leffler ieee80211_free_node(bf->bf_node); 26975591b213SSam Leffler bf->bf_node = NULL; 26985591b213SSam Leffler } 26995591b213SSam Leffler } 2700f818612bSSam Leffler } 27015591b213SSam Leffler 27025591b213SSam Leffler /* 27035591b213SSam Leffler * Configure the beacon and sleep timers. 27045591b213SSam Leffler * 27055591b213SSam Leffler * When operating as an AP this resets the TSF and sets 27065591b213SSam Leffler * up the hardware to notify us when we need to issue beacons. 27075591b213SSam Leffler * 27085591b213SSam Leffler * When operating in station mode this sets up the beacon 27095591b213SSam Leffler * timers according to the timestamp of the last received 27105591b213SSam Leffler * beacon and the current TSF, configures PCF and DTIM 27115591b213SSam Leffler * handling, programs the sleep registers so the hardware 27125591b213SSam Leffler * will wakeup in time to receive beacons, and configures 27135591b213SSam Leffler * the beacon miss handling so we'll receive a BMISS 27145591b213SSam Leffler * interrupt when we stop seeing beacons from the AP 27155591b213SSam Leffler * we've associated with. 27165591b213SSam Leffler */ 27175591b213SSam Leffler static void 2718b032f27cSSam Leffler ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) 27195591b213SSam Leffler { 272080d939bfSSam Leffler #define TSF_TO_TU(_h,_l) \ 272180d939bfSSam Leffler ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) 272280d939bfSSam Leffler #define FUDGE 2 27235591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 2724b032f27cSSam Leffler struct ieee80211com *ic = sc->sc_ifp->if_l2com; 2725b032f27cSSam Leffler struct ieee80211_node *ni; 272680d939bfSSam Leffler u_int32_t nexttbtt, intval, tsftu; 272780d939bfSSam Leffler u_int64_t tsf; 27285591b213SSam Leffler 2729b032f27cSSam Leffler if (vap == NULL) 2730b032f27cSSam Leffler vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ 2731b032f27cSSam Leffler ni = vap->iv_bss; 2732b032f27cSSam Leffler 27338371372bSSam Leffler /* extract tstamp from last beacon and convert to TU */ 27348371372bSSam Leffler nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), 27358371372bSSam Leffler LE_READ_4(ni->ni_tstamp.data)); 273659aa14a9SRui Paulo if (ic->ic_opmode == IEEE80211_M_HOSTAP || 273759aa14a9SRui Paulo ic->ic_opmode == IEEE80211_M_MBSS) { 2738b032f27cSSam Leffler /* 273959aa14a9SRui Paulo * For multi-bss ap/mesh support beacons are either staggered 2740b032f27cSSam Leffler * evenly over N slots or burst together. For the former 2741b032f27cSSam Leffler * arrange for the SWBA to be delivered for each slot. 2742b032f27cSSam Leffler * Slots that are not occupied will generate nothing. 2743b032f27cSSam Leffler */ 27448371372bSSam Leffler /* NB: the beacon interval is kept internally in TU's */ 27454bacf7c1SSam Leffler intval = ni->ni_intval & HAL_BEACON_PERIOD; 2746b032f27cSSam Leffler if (sc->sc_stagbeacons) 2747b032f27cSSam Leffler intval /= ATH_BCBUF; 2748b032f27cSSam Leffler } else { 2749b032f27cSSam Leffler /* NB: the beacon interval is kept internally in TU's */ 2750b032f27cSSam Leffler intval = ni->ni_intval & HAL_BEACON_PERIOD; 2751b032f27cSSam Leffler } 2752a6c992f4SSam Leffler if (nexttbtt == 0) /* e.g. for ap mode */ 2753a6c992f4SSam Leffler nexttbtt = intval; 2754a6c992f4SSam Leffler else if (intval) /* NB: can be 0 for monitor mode */ 2755a6c992f4SSam Leffler nexttbtt = roundup(nexttbtt, intval); 2756a6c992f4SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", 2757a6c992f4SSam Leffler __func__, nexttbtt, intval, ni->ni_intval); 2758b032f27cSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) { 27595591b213SSam Leffler HAL_BEACON_STATE bs; 27608371372bSSam Leffler int dtimperiod, dtimcount; 27618371372bSSam Leffler int cfpperiod, cfpcount; 27625591b213SSam Leffler 27638371372bSSam Leffler /* 27648371372bSSam Leffler * Setup dtim and cfp parameters according to 27658371372bSSam Leffler * last beacon we received (which may be none). 27668371372bSSam Leffler */ 27678371372bSSam Leffler dtimperiod = ni->ni_dtim_period; 27688371372bSSam Leffler if (dtimperiod <= 0) /* NB: 0 if not known */ 27698371372bSSam Leffler dtimperiod = 1; 27708371372bSSam Leffler dtimcount = ni->ni_dtim_count; 27718371372bSSam Leffler if (dtimcount >= dtimperiod) /* NB: sanity check */ 27728371372bSSam Leffler dtimcount = 0; /* XXX? */ 27738371372bSSam Leffler cfpperiod = 1; /* NB: no PCF support yet */ 27748371372bSSam Leffler cfpcount = 0; 27758371372bSSam Leffler /* 27768371372bSSam Leffler * Pull nexttbtt forward to reflect the current 27778371372bSSam Leffler * TSF and calculate dtim+cfp state for the result. 27788371372bSSam Leffler */ 27798371372bSSam Leffler tsf = ath_hal_gettsf64(ah); 278080d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 27818371372bSSam Leffler do { 27828371372bSSam Leffler nexttbtt += intval; 27838371372bSSam Leffler if (--dtimcount < 0) { 27848371372bSSam Leffler dtimcount = dtimperiod - 1; 27858371372bSSam Leffler if (--cfpcount < 0) 27868371372bSSam Leffler cfpcount = cfpperiod - 1; 27878371372bSSam Leffler } 27888371372bSSam Leffler } while (nexttbtt < tsftu); 27895591b213SSam Leffler memset(&bs, 0, sizeof(bs)); 2790a6c992f4SSam Leffler bs.bs_intval = intval; 27915591b213SSam Leffler bs.bs_nexttbtt = nexttbtt; 27928371372bSSam Leffler bs.bs_dtimperiod = dtimperiod*intval; 27938371372bSSam Leffler bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 27948371372bSSam Leffler bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 27958371372bSSam Leffler bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 27968371372bSSam Leffler bs.bs_cfpmaxduration = 0; 27978371372bSSam Leffler #if 0 27985591b213SSam Leffler /* 2799c42a7b7eSSam Leffler * The 802.11 layer records the offset to the DTIM 2800c42a7b7eSSam Leffler * bitmap while receiving beacons; use it here to 2801c42a7b7eSSam Leffler * enable h/w detection of our AID being marked in 2802c42a7b7eSSam Leffler * the bitmap vector (to indicate frames for us are 2803c42a7b7eSSam Leffler * pending at the AP). 28048371372bSSam Leffler * XXX do DTIM handling in s/w to WAR old h/w bugs 28058371372bSSam Leffler * XXX enable based on h/w rev for newer chips 2806c42a7b7eSSam Leffler */ 2807c42a7b7eSSam Leffler bs.bs_timoffset = ni->ni_timoff; 28088371372bSSam Leffler #endif 2809c42a7b7eSSam Leffler /* 28105591b213SSam Leffler * Calculate the number of consecutive beacons to miss 281168e8e04eSSam Leffler * before taking a BMISS interrupt. 28125591b213SSam Leffler * Note that we clamp the result to at most 10 beacons. 28135591b213SSam Leffler */ 2814b032f27cSSam Leffler bs.bs_bmissthreshold = vap->iv_bmissthreshold; 28155591b213SSam Leffler if (bs.bs_bmissthreshold > 10) 28165591b213SSam Leffler bs.bs_bmissthreshold = 10; 28175591b213SSam Leffler else if (bs.bs_bmissthreshold <= 0) 28185591b213SSam Leffler bs.bs_bmissthreshold = 1; 28195591b213SSam Leffler 28205591b213SSam Leffler /* 28215591b213SSam Leffler * Calculate sleep duration. The configuration is 28225591b213SSam Leffler * given in ms. We insure a multiple of the beacon 28235591b213SSam Leffler * period is used. Also, if the sleep duration is 28245591b213SSam Leffler * greater than the DTIM period then it makes senses 28255591b213SSam Leffler * to make it a multiple of that. 28265591b213SSam Leffler * 28275591b213SSam Leffler * XXX fixed at 100ms 28285591b213SSam Leffler */ 28294bacf7c1SSam Leffler bs.bs_sleepduration = 28304bacf7c1SSam Leffler roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval); 28315591b213SSam Leffler if (bs.bs_sleepduration > bs.bs_dtimperiod) 28325591b213SSam Leffler bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 28335591b213SSam Leffler 2834c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 28358371372bSSam Leffler "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n" 28365591b213SSam Leffler , __func__ 28378371372bSSam Leffler , tsf, tsftu 28385591b213SSam Leffler , bs.bs_intval 28395591b213SSam Leffler , bs.bs_nexttbtt 28405591b213SSam Leffler , bs.bs_dtimperiod 28415591b213SSam Leffler , bs.bs_nextdtim 28425591b213SSam Leffler , bs.bs_bmissthreshold 28435591b213SSam Leffler , bs.bs_sleepduration 2844c42a7b7eSSam Leffler , bs.bs_cfpperiod 2845c42a7b7eSSam Leffler , bs.bs_cfpmaxduration 2846c42a7b7eSSam Leffler , bs.bs_cfpnext 2847c42a7b7eSSam Leffler , bs.bs_timoffset 2848c42a7b7eSSam Leffler ); 28495591b213SSam Leffler ath_hal_intrset(ah, 0); 2850c42a7b7eSSam Leffler ath_hal_beacontimers(ah, &bs); 28515591b213SSam Leffler sc->sc_imask |= HAL_INT_BMISS; 28525591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 28535591b213SSam Leffler } else { 28545591b213SSam Leffler ath_hal_intrset(ah, 0); 2855a6c992f4SSam Leffler if (nexttbtt == intval) 2856c42a7b7eSSam Leffler intval |= HAL_BEACON_RESET_TSF; 2857c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS) { 2858c42a7b7eSSam Leffler /* 2859c42a7b7eSSam Leffler * In IBSS mode enable the beacon timers but only 2860c42a7b7eSSam Leffler * enable SWBA interrupts if we need to manually 2861c42a7b7eSSam Leffler * prepare beacon frames. Otherwise we use a 2862c42a7b7eSSam Leffler * self-linked tx descriptor and let the hardware 2863c42a7b7eSSam Leffler * deal with things. 2864c42a7b7eSSam Leffler */ 2865c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 2866c42a7b7eSSam Leffler if (!sc->sc_hasveol) 2867c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_SWBA; 286880d939bfSSam Leffler if ((intval & HAL_BEACON_RESET_TSF) == 0) { 286980d939bfSSam Leffler /* 287080d939bfSSam Leffler * Pull nexttbtt forward to reflect 287180d939bfSSam Leffler * the current TSF. 287280d939bfSSam Leffler */ 287380d939bfSSam Leffler tsf = ath_hal_gettsf64(ah); 287480d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 287580d939bfSSam Leffler do { 287680d939bfSSam Leffler nexttbtt += intval; 287780d939bfSSam Leffler } while (nexttbtt < tsftu); 287880d939bfSSam Leffler } 28790f2e86fbSSam Leffler ath_beaconq_config(sc); 288059aa14a9SRui Paulo } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || 288159aa14a9SRui Paulo ic->ic_opmode == IEEE80211_M_MBSS) { 2882c42a7b7eSSam Leffler /* 288359aa14a9SRui Paulo * In AP/mesh mode we enable the beacon timers 288459aa14a9SRui Paulo * and SWBA interrupts to prepare beacon frames. 2885c42a7b7eSSam Leffler */ 2886c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 28875591b213SSam Leffler sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */ 28880f2e86fbSSam Leffler ath_beaconq_config(sc); 2889c42a7b7eSSam Leffler } 2890c42a7b7eSSam Leffler ath_hal_beaconinit(ah, nexttbtt, intval); 2891c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 28925591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 2893c42a7b7eSSam Leffler /* 2894c42a7b7eSSam Leffler * When using a self-linked beacon descriptor in 2895c42a7b7eSSam Leffler * ibss mode load it once here. 2896c42a7b7eSSam Leffler */ 2897c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) 2898b032f27cSSam Leffler ath_beacon_start_adhoc(sc, vap); 28995591b213SSam Leffler } 290080d939bfSSam Leffler sc->sc_syncbeacon = 0; 290180d939bfSSam Leffler #undef FUDGE 29028371372bSSam Leffler #undef TSF_TO_TU 29035591b213SSam Leffler } 29045591b213SSam Leffler 29055591b213SSam Leffler static void 29065591b213SSam Leffler ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 29075591b213SSam Leffler { 29085591b213SSam Leffler bus_addr_t *paddr = (bus_addr_t*) arg; 2909d77367bfSSam Leffler KASSERT(error == 0, ("error %u on bus_dma callback", error)); 29105591b213SSam Leffler *paddr = segs->ds_addr; 29115591b213SSam Leffler } 29125591b213SSam Leffler 29135591b213SSam Leffler static int 2914c42a7b7eSSam Leffler ath_descdma_setup(struct ath_softc *sc, 2915c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head, 2916c42a7b7eSSam Leffler const char *name, int nbuf, int ndesc) 2917c42a7b7eSSam Leffler { 2918c42a7b7eSSam Leffler #define DS2PHYS(_dd, _ds) \ 2919c42a7b7eSSam Leffler ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) 2920fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2921c42a7b7eSSam Leffler struct ath_desc *ds; 2922c42a7b7eSSam Leffler struct ath_buf *bf; 2923c42a7b7eSSam Leffler int i, bsize, error; 2924c42a7b7eSSam Leffler 2925c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n", 2926c42a7b7eSSam Leffler __func__, name, nbuf, ndesc); 2927c42a7b7eSSam Leffler 2928c42a7b7eSSam Leffler dd->dd_name = name; 2929c42a7b7eSSam Leffler dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; 2930c42a7b7eSSam Leffler 2931c42a7b7eSSam Leffler /* 2932c42a7b7eSSam Leffler * Setup DMA descriptor area. 2933c42a7b7eSSam Leffler */ 2934c2175ff5SMarius Strobl error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */ 2935c42a7b7eSSam Leffler PAGE_SIZE, 0, /* alignment, bounds */ 2936c42a7b7eSSam Leffler BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 2937c42a7b7eSSam Leffler BUS_SPACE_MAXADDR, /* highaddr */ 2938c42a7b7eSSam Leffler NULL, NULL, /* filter, filterarg */ 2939c42a7b7eSSam Leffler dd->dd_desc_len, /* maxsize */ 2940c42a7b7eSSam Leffler 1, /* nsegments */ 29416ccb8ea7SSam Leffler dd->dd_desc_len, /* maxsegsize */ 2942c42a7b7eSSam Leffler BUS_DMA_ALLOCNOW, /* flags */ 2943c42a7b7eSSam Leffler NULL, /* lockfunc */ 2944c42a7b7eSSam Leffler NULL, /* lockarg */ 2945c42a7b7eSSam Leffler &dd->dd_dmat); 2946c42a7b7eSSam Leffler if (error != 0) { 2947c42a7b7eSSam Leffler if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); 2948c42a7b7eSSam Leffler return error; 2949c42a7b7eSSam Leffler } 2950c42a7b7eSSam Leffler 2951c42a7b7eSSam Leffler /* allocate descriptors */ 2952c42a7b7eSSam Leffler error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap); 2953c42a7b7eSSam Leffler if (error != 0) { 2954c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s descriptors, " 2955c42a7b7eSSam Leffler "error %u\n", dd->dd_name, error); 2956c42a7b7eSSam Leffler goto fail0; 2957c42a7b7eSSam Leffler } 2958c42a7b7eSSam Leffler 2959c42a7b7eSSam Leffler error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc, 29600553a01fSSam Leffler BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 29610553a01fSSam Leffler &dd->dd_dmamap); 2962c42a7b7eSSam Leffler if (error != 0) { 2963c42a7b7eSSam Leffler if_printf(ifp, "unable to alloc memory for %u %s descriptors, " 2964c42a7b7eSSam Leffler "error %u\n", nbuf * ndesc, dd->dd_name, error); 2965c42a7b7eSSam Leffler goto fail1; 2966c42a7b7eSSam Leffler } 2967c42a7b7eSSam Leffler 2968c42a7b7eSSam Leffler error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap, 2969c42a7b7eSSam Leffler dd->dd_desc, dd->dd_desc_len, 2970c42a7b7eSSam Leffler ath_load_cb, &dd->dd_desc_paddr, 2971c42a7b7eSSam Leffler BUS_DMA_NOWAIT); 2972c42a7b7eSSam Leffler if (error != 0) { 2973c42a7b7eSSam Leffler if_printf(ifp, "unable to map %s descriptors, error %u\n", 2974c42a7b7eSSam Leffler dd->dd_name, error); 2975c42a7b7eSSam Leffler goto fail2; 2976c42a7b7eSSam Leffler } 2977c42a7b7eSSam Leffler 2978c42a7b7eSSam Leffler ds = dd->dd_desc; 2979c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n", 2980c42a7b7eSSam Leffler __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len, 2981c42a7b7eSSam Leffler (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len); 2982c42a7b7eSSam Leffler 2983ebecf802SSam Leffler /* allocate rx buffers */ 2984c42a7b7eSSam Leffler bsize = sizeof(struct ath_buf) * nbuf; 2985c42a7b7eSSam Leffler bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO); 2986c42a7b7eSSam Leffler if (bf == NULL) { 2987c42a7b7eSSam Leffler if_printf(ifp, "malloc of %s buffers failed, size %u\n", 2988c42a7b7eSSam Leffler dd->dd_name, bsize); 2989c42a7b7eSSam Leffler goto fail3; 2990c42a7b7eSSam Leffler } 2991c42a7b7eSSam Leffler dd->dd_bufptr = bf; 2992c42a7b7eSSam Leffler 2993c42a7b7eSSam Leffler STAILQ_INIT(head); 2994c42a7b7eSSam Leffler for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { 2995c42a7b7eSSam Leffler bf->bf_desc = ds; 2996c42a7b7eSSam Leffler bf->bf_daddr = DS2PHYS(dd, ds); 2997c42a7b7eSSam Leffler error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, 2998c42a7b7eSSam Leffler &bf->bf_dmamap); 2999c42a7b7eSSam Leffler if (error != 0) { 3000c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s " 3001c42a7b7eSSam Leffler "buffer %u, error %u\n", dd->dd_name, i, error); 3002c42a7b7eSSam Leffler ath_descdma_cleanup(sc, dd, head); 3003c42a7b7eSSam Leffler return error; 3004c42a7b7eSSam Leffler } 3005c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(head, bf, bf_list); 3006c42a7b7eSSam Leffler } 3007c42a7b7eSSam Leffler return 0; 3008c42a7b7eSSam Leffler fail3: 3009c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 3010c42a7b7eSSam Leffler fail2: 3011c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 3012c42a7b7eSSam Leffler fail1: 3013c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 3014c42a7b7eSSam Leffler fail0: 3015c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 3016c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 3017c42a7b7eSSam Leffler return error; 3018c42a7b7eSSam Leffler #undef DS2PHYS 3019c42a7b7eSSam Leffler } 3020c42a7b7eSSam Leffler 3021c42a7b7eSSam Leffler static void 3022c42a7b7eSSam Leffler ath_descdma_cleanup(struct ath_softc *sc, 3023c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head) 3024c42a7b7eSSam Leffler { 3025c42a7b7eSSam Leffler struct ath_buf *bf; 3026c42a7b7eSSam Leffler struct ieee80211_node *ni; 3027c42a7b7eSSam Leffler 3028c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 3029c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 3030c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 3031c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 3032c42a7b7eSSam Leffler 3033c42a7b7eSSam Leffler STAILQ_FOREACH(bf, head, bf_list) { 3034c42a7b7eSSam Leffler if (bf->bf_m) { 3035c42a7b7eSSam Leffler m_freem(bf->bf_m); 3036c42a7b7eSSam Leffler bf->bf_m = NULL; 3037c42a7b7eSSam Leffler } 3038c42a7b7eSSam Leffler if (bf->bf_dmamap != NULL) { 3039c42a7b7eSSam Leffler bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap); 3040c42a7b7eSSam Leffler bf->bf_dmamap = NULL; 3041c42a7b7eSSam Leffler } 3042c42a7b7eSSam Leffler ni = bf->bf_node; 3043c42a7b7eSSam Leffler bf->bf_node = NULL; 3044c42a7b7eSSam Leffler if (ni != NULL) { 3045c42a7b7eSSam Leffler /* 3046c42a7b7eSSam Leffler * Reclaim node reference. 3047c42a7b7eSSam Leffler */ 3048c42a7b7eSSam Leffler ieee80211_free_node(ni); 3049c42a7b7eSSam Leffler } 3050c42a7b7eSSam Leffler } 3051c42a7b7eSSam Leffler 3052c42a7b7eSSam Leffler STAILQ_INIT(head); 3053c42a7b7eSSam Leffler free(dd->dd_bufptr, M_ATHDEV); 3054c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 3055c42a7b7eSSam Leffler } 3056c42a7b7eSSam Leffler 3057c42a7b7eSSam Leffler static int 30585591b213SSam Leffler ath_desc_alloc(struct ath_softc *sc) 30595591b213SSam Leffler { 3060c42a7b7eSSam Leffler int error; 30615591b213SSam Leffler 3062c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, 3063e2d787faSSam Leffler "rx", ath_rxbuf, 1); 30645591b213SSam Leffler if (error != 0) 30655591b213SSam Leffler return error; 30665591b213SSam Leffler 3067c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, 3068e2d787faSSam Leffler "tx", ath_txbuf, ATH_TXDESC); 3069c42a7b7eSSam Leffler if (error != 0) { 3070c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 30715591b213SSam Leffler return error; 3072c42a7b7eSSam Leffler } 3073c42a7b7eSSam Leffler 3074c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, 3075b032f27cSSam Leffler "beacon", ATH_BCBUF, 1); 3076c42a7b7eSSam Leffler if (error != 0) { 3077c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 3078c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 3079c42a7b7eSSam Leffler return error; 3080c42a7b7eSSam Leffler } 30815591b213SSam Leffler return 0; 30825591b213SSam Leffler } 30835591b213SSam Leffler 30845591b213SSam Leffler static void 30855591b213SSam Leffler ath_desc_free(struct ath_softc *sc) 30865591b213SSam Leffler { 30875591b213SSam Leffler 3088c42a7b7eSSam Leffler if (sc->sc_bdma.dd_desc_len != 0) 3089c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); 3090c42a7b7eSSam Leffler if (sc->sc_txdma.dd_desc_len != 0) 3091c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 3092c42a7b7eSSam Leffler if (sc->sc_rxdma.dd_desc_len != 0) 3093c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 30945591b213SSam Leffler } 30955591b213SSam Leffler 30965591b213SSam Leffler static struct ieee80211_node * 309738c208f8SSam Leffler ath_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 30985591b213SSam Leffler { 309938c208f8SSam Leffler struct ieee80211com *ic = vap->iv_ic; 3100c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 3101c42a7b7eSSam Leffler const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; 3102c42a7b7eSSam Leffler struct ath_node *an; 3103c42a7b7eSSam Leffler 3104c42a7b7eSSam Leffler an = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO); 3105c42a7b7eSSam Leffler if (an == NULL) { 3106c42a7b7eSSam Leffler /* XXX stat+msg */ 3107de5af704SSam Leffler return NULL; 31085591b213SSam Leffler } 3109c42a7b7eSSam Leffler ath_rate_node_init(sc, an); 31105591b213SSam Leffler 3111c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); 3112c42a7b7eSSam Leffler return &an->an_node; 3113c42a7b7eSSam Leffler } 3114c42a7b7eSSam Leffler 31155591b213SSam Leffler static void 3116c42a7b7eSSam Leffler ath_node_free(struct ieee80211_node *ni) 31175591b213SSam Leffler { 3118c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 3119c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 31201e774079SSam Leffler 3121c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: ni %p\n", __func__, ni); 3122c42a7b7eSSam Leffler 3123c42a7b7eSSam Leffler ath_rate_node_cleanup(sc, ATH_NODE(ni)); 3124c42a7b7eSSam Leffler sc->sc_node_free(ni); 31255591b213SSam Leffler } 31265591b213SSam Leffler 312768e8e04eSSam Leffler static void 312868e8e04eSSam Leffler ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise) 312968e8e04eSSam Leffler { 313068e8e04eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 313168e8e04eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 313268e8e04eSSam Leffler struct ath_hal *ah = sc->sc_ah; 313368e8e04eSSam Leffler 3134b032f27cSSam Leffler *rssi = ic->ic_node_getrssi(ni); 313559efa8b5SSam Leffler if (ni->ni_chan != IEEE80211_CHAN_ANYC) 313659efa8b5SSam Leffler *noise = ath_hal_getchannoise(ah, ni->ni_chan); 313759efa8b5SSam Leffler else 313868e8e04eSSam Leffler *noise = -95; /* nominally correct */ 313968e8e04eSSam Leffler } 314068e8e04eSSam Leffler 31415591b213SSam Leffler static int 31425591b213SSam Leffler ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) 31435591b213SSam Leffler { 31445591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 31455591b213SSam Leffler int error; 31465591b213SSam Leffler struct mbuf *m; 31475591b213SSam Leffler struct ath_desc *ds; 31485591b213SSam Leffler 31495591b213SSam Leffler m = bf->bf_m; 31505591b213SSam Leffler if (m == NULL) { 31515591b213SSam Leffler /* 31525591b213SSam Leffler * NB: by assigning a page to the rx dma buffer we 31535591b213SSam Leffler * implicitly satisfy the Atheros requirement that 31545591b213SSam Leffler * this buffer be cache-line-aligned and sized to be 31555591b213SSam Leffler * multiple of the cache line size. Not doing this 31565591b213SSam Leffler * causes weird stuff to happen (for the 5210 at least). 31575591b213SSam Leffler */ 31585591b213SSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 31595591b213SSam Leffler if (m == NULL) { 3160c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 3161c42a7b7eSSam Leffler "%s: no mbuf/cluster\n", __func__); 31625591b213SSam Leffler sc->sc_stats.ast_rx_nombuf++; 31635591b213SSam Leffler return ENOMEM; 31645591b213SSam Leffler } 31655591b213SSam Leffler m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 31665591b213SSam Leffler 3167f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, 3168c42a7b7eSSam Leffler bf->bf_dmamap, m, 3169f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 31705591b213SSam Leffler BUS_DMA_NOWAIT); 31715591b213SSam Leffler if (error != 0) { 3172c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 3173f9e6219bSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed; error %d\n", 3174c42a7b7eSSam Leffler __func__, error); 31755591b213SSam Leffler sc->sc_stats.ast_rx_busdma++; 3176b2792ff6SSam Leffler m_freem(m); 31775591b213SSam Leffler return error; 31785591b213SSam Leffler } 3179d77367bfSSam Leffler KASSERT(bf->bf_nseg == 1, 3180d77367bfSSam Leffler ("multi-segment packet; nseg %u", bf->bf_nseg)); 3181b2792ff6SSam Leffler bf->bf_m = m; 31825591b213SSam Leffler } 31835591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD); 31845591b213SSam Leffler 318504e22a02SSam Leffler /* 318604e22a02SSam Leffler * Setup descriptors. For receive we always terminate 318704e22a02SSam Leffler * the descriptor list with a self-linked entry so we'll 318804e22a02SSam Leffler * not get overrun under high load (as can happen with a 3189c42a7b7eSSam Leffler * 5212 when ANI processing enables PHY error frames). 319004e22a02SSam Leffler * 319104e22a02SSam Leffler * To insure the last descriptor is self-linked we create 319204e22a02SSam Leffler * each descriptor as self-linked and add it to the end. As 319304e22a02SSam Leffler * each additional descriptor is added the previous self-linked 319404e22a02SSam Leffler * entry is ``fixed'' naturally. This should be safe even 319504e22a02SSam Leffler * if DMA is happening. When processing RX interrupts we 319604e22a02SSam Leffler * never remove/process the last, self-linked, entry on the 319704e22a02SSam Leffler * descriptor list. This insures the hardware always has 319804e22a02SSam Leffler * someplace to write a new frame. 319904e22a02SSam Leffler */ 32008a2a6beeSAdrian Chadd /* 32018a2a6beeSAdrian Chadd * 11N: we can no longer afford to self link the last descriptor. 32028a2a6beeSAdrian Chadd * MAC acknowledges BA status as long as it copies frames to host 32038a2a6beeSAdrian Chadd * buffer (or rx fifo). This can incorrectly acknowledge packets 32048a2a6beeSAdrian Chadd * to a sender if last desc is self-linked. 32058a2a6beeSAdrian Chadd */ 32065591b213SSam Leffler ds = bf->bf_desc; 32078a2a6beeSAdrian Chadd if (sc->sc_rxslink) 320804e22a02SSam Leffler ds->ds_link = bf->bf_daddr; /* link to self */ 32098a2a6beeSAdrian Chadd else 32108a2a6beeSAdrian Chadd ds->ds_link = 0; /* terminate the list */ 32115591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 32125591b213SSam Leffler ath_hal_setuprxdesc(ah, ds 32135591b213SSam Leffler , m->m_len /* buffer size */ 32145591b213SSam Leffler , 0 32155591b213SSam Leffler ); 32165591b213SSam Leffler 32175591b213SSam Leffler if (sc->sc_rxlink != NULL) 32185591b213SSam Leffler *sc->sc_rxlink = bf->bf_daddr; 32195591b213SSam Leffler sc->sc_rxlink = &ds->ds_link; 32205591b213SSam Leffler return 0; 32215591b213SSam Leffler } 32225591b213SSam Leffler 3223c42a7b7eSSam Leffler /* 322403ed599aSSam Leffler * Extend 15-bit time stamp from rx descriptor to 32257b0c77ecSSam Leffler * a full 64-bit TSF using the specified TSF. 322603ed599aSSam Leffler */ 322703ed599aSSam Leffler static __inline u_int64_t 32287b0c77ecSSam Leffler ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf) 322903ed599aSSam Leffler { 323003ed599aSSam Leffler if ((tsf & 0x7fff) < rstamp) 323103ed599aSSam Leffler tsf -= 0x8000; 323203ed599aSSam Leffler return ((tsf &~ 0x7fff) | rstamp); 323303ed599aSSam Leffler } 323403ed599aSSam Leffler 323503ed599aSSam Leffler /* 3236c42a7b7eSSam Leffler * Intercept management frames to collect beacon rssi data 3237c42a7b7eSSam Leffler * and to do ibss merges. 3238c42a7b7eSSam Leffler */ 3239c42a7b7eSSam Leffler static void 3240b032f27cSSam Leffler ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, 32415463c4a4SSam Leffler int subtype, int rssi, int nf) 3242c42a7b7eSSam Leffler { 3243b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 3244b032f27cSSam Leffler struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; 3245c42a7b7eSSam Leffler 3246c42a7b7eSSam Leffler /* 3247c42a7b7eSSam Leffler * Call up first so subsequent work can use information 3248c42a7b7eSSam Leffler * potentially stored in the node (e.g. for ibss merge). 3249c42a7b7eSSam Leffler */ 32505463c4a4SSam Leffler ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf); 3251c42a7b7eSSam Leffler switch (subtype) { 3252c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_BEACON: 3253c42a7b7eSSam Leffler /* update rssi statistics for use by the hal */ 3254ffa2cab6SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); 325580d939bfSSam Leffler if (sc->sc_syncbeacon && 3256b032f27cSSam Leffler ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) { 325780d939bfSSam Leffler /* 325880d939bfSSam Leffler * Resync beacon timers using the tsf of the beacon 325980d939bfSSam Leffler * frame we just received. 326080d939bfSSam Leffler */ 3261b032f27cSSam Leffler ath_beacon_config(sc, vap); 326280d939bfSSam Leffler } 3263c42a7b7eSSam Leffler /* fall thru... */ 3264c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 3265b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS && 3266b032f27cSSam Leffler vap->iv_state == IEEE80211_S_RUN) { 32677041d50cSBernhard Schmidt uint32_t rstamp = sc->sc_lastrs->rs_tstamp; 32687041d50cSBernhard Schmidt uint64_t tsf = ath_extend_tsf(rstamp, 32697b0c77ecSSam Leffler ath_hal_gettsf64(sc->sc_ah)); 3270c42a7b7eSSam Leffler /* 3271c42a7b7eSSam Leffler * Handle ibss merge as needed; check the tsf on the 3272c42a7b7eSSam Leffler * frame before attempting the merge. The 802.11 spec 3273c42a7b7eSSam Leffler * says the station should change it's bssid to match 3274c42a7b7eSSam Leffler * the oldest station with the same ssid, where oldest 3275f818612bSSam Leffler * is determined by the tsf. Note that hardware 3276f818612bSSam Leffler * reconfiguration happens through callback to 327703ed599aSSam Leffler * ath_newstate as the state machine will go from 327803ed599aSSam Leffler * RUN -> RUN when this happens. 3279c42a7b7eSSam Leffler */ 328003ed599aSSam Leffler if (le64toh(ni->ni_tstamp.tsf) >= tsf) { 328103ed599aSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 328233d7d80cSTai-hwa Liang "ibss merge, rstamp %u tsf %ju " 328333d7d80cSTai-hwa Liang "tstamp %ju\n", rstamp, (uintmax_t)tsf, 328433d7d80cSTai-hwa Liang (uintmax_t)ni->ni_tstamp.tsf); 3285641b4d0bSSam Leffler (void) ieee80211_ibss_merge(ni); 3286c42a7b7eSSam Leffler } 328703ed599aSSam Leffler } 3288c42a7b7eSSam Leffler break; 3289c42a7b7eSSam Leffler } 3290c42a7b7eSSam Leffler } 3291c42a7b7eSSam Leffler 3292c42a7b7eSSam Leffler /* 3293c42a7b7eSSam Leffler * Set the default antenna. 3294c42a7b7eSSam Leffler */ 3295c42a7b7eSSam Leffler static void 3296c42a7b7eSSam Leffler ath_setdefantenna(struct ath_softc *sc, u_int antenna) 3297c42a7b7eSSam Leffler { 3298c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3299c42a7b7eSSam Leffler 3300c42a7b7eSSam Leffler /* XXX block beacon interrupts */ 3301c42a7b7eSSam Leffler ath_hal_setdefantenna(ah, antenna); 3302c42a7b7eSSam Leffler if (sc->sc_defant != antenna) 3303c42a7b7eSSam Leffler sc->sc_stats.ast_ant_defswitch++; 3304c42a7b7eSSam Leffler sc->sc_defant = antenna; 3305c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 3306c42a7b7eSSam Leffler } 3307c42a7b7eSSam Leffler 33085463c4a4SSam Leffler static void 3309b032f27cSSam Leffler ath_rx_tap(struct ifnet *ifp, struct mbuf *m, 331065f9edeeSSam Leffler const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) 33117b0c77ecSSam Leffler { 3312e387d629SSam Leffler #define CHAN_HT20 htole32(IEEE80211_CHAN_HT20) 3313e387d629SSam Leffler #define CHAN_HT40U htole32(IEEE80211_CHAN_HT40U) 3314e387d629SSam Leffler #define CHAN_HT40D htole32(IEEE80211_CHAN_HT40D) 331546d4d74cSSam Leffler #define CHAN_HT (CHAN_HT20|CHAN_HT40U|CHAN_HT40D) 3316b032f27cSSam Leffler struct ath_softc *sc = ifp->if_softc; 331746d4d74cSSam Leffler const HAL_RATE_TABLE *rt; 331846d4d74cSSam Leffler uint8_t rix; 33197b0c77ecSSam Leffler 332046d4d74cSSam Leffler rt = sc->sc_currates; 332146d4d74cSSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 332246d4d74cSSam Leffler rix = rt->rateCodeToIndex[rs->rs_rate]; 332368e8e04eSSam Leffler sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; 33247b0c77ecSSam Leffler sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; 332546d4d74cSSam Leffler #ifdef AH_SUPPORT_AR5416 3326e387d629SSam Leffler sc->sc_rx_th.wr_chan_flags &= ~CHAN_HT; 332746d4d74cSSam Leffler if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */ 332859efa8b5SSam Leffler struct ieee80211com *ic = ifp->if_l2com; 332959efa8b5SSam Leffler 3330e387d629SSam Leffler if ((rs->rs_flags & HAL_RX_2040) == 0) 3331e387d629SSam Leffler sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; 333259efa8b5SSam Leffler else if (IEEE80211_IS_CHAN_HT40U(ic->ic_curchan)) 3333e387d629SSam Leffler sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U; 3334e387d629SSam Leffler else 3335e387d629SSam Leffler sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D; 333668e8e04eSSam Leffler if ((rs->rs_flags & HAL_RX_GI) == 0) 3337e387d629SSam Leffler sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; 333868e8e04eSSam Leffler } 333968e8e04eSSam Leffler #endif 334068e8e04eSSam Leffler sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf)); 334165f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 33427b0c77ecSSam Leffler sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; 33437b0c77ecSSam Leffler /* XXX propagate other error flags from descriptor */ 33447b0c77ecSSam Leffler sc->sc_rx_th.wr_antnoise = nf; 33455463c4a4SSam Leffler sc->sc_rx_th.wr_antsignal = nf + rs->rs_rssi; 334665f9edeeSSam Leffler sc->sc_rx_th.wr_antenna = rs->rs_antenna; 334746d4d74cSSam Leffler #undef CHAN_HT 3348e387d629SSam Leffler #undef CHAN_HT20 3349e387d629SSam Leffler #undef CHAN_HT40U 3350e387d629SSam Leffler #undef CHAN_HT40D 33517b0c77ecSSam Leffler } 33527b0c77ecSSam Leffler 33535591b213SSam Leffler static void 3354b032f27cSSam Leffler ath_handle_micerror(struct ieee80211com *ic, 3355b032f27cSSam Leffler struct ieee80211_frame *wh, int keyix) 3356b032f27cSSam Leffler { 3357b032f27cSSam Leffler struct ieee80211_node *ni; 3358b032f27cSSam Leffler 3359b032f27cSSam Leffler /* XXX recheck MIC to deal w/ chips that lie */ 3360b032f27cSSam Leffler /* XXX discard MIC errors on !data frames */ 3361b032f27cSSam Leffler ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh); 3362b032f27cSSam Leffler if (ni != NULL) { 3363b032f27cSSam Leffler ieee80211_notify_michael_failure(ni->ni_vap, wh, keyix); 3364b032f27cSSam Leffler ieee80211_free_node(ni); 3365b032f27cSSam Leffler } 3366b032f27cSSam Leffler } 3367b032f27cSSam Leffler 3368b032f27cSSam Leffler static void 33695591b213SSam Leffler ath_rx_proc(void *arg, int npending) 33705591b213SSam Leffler { 33718cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 3372c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 3373c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 33745591b213SSam Leffler struct ath_softc *sc = arg; 33755591b213SSam Leffler struct ath_buf *bf; 3376fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 3377b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 33785591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 33795591b213SSam Leffler struct ath_desc *ds; 338065f9edeeSSam Leffler struct ath_rx_status *rs; 33815591b213SSam Leffler struct mbuf *m; 33820a915fadSSam Leffler struct ieee80211_node *ni; 3383d7736e13SSam Leffler int len, type, ngood; 33845591b213SSam Leffler HAL_STATUS status; 33857b0c77ecSSam Leffler int16_t nf; 33867b0c77ecSSam Leffler u_int64_t tsf; 33875591b213SSam Leffler 3388c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); 3389d7736e13SSam Leffler ngood = 0; 339059efa8b5SSam Leffler nf = ath_hal_getchannoise(ah, sc->sc_curchan); 339184784be1SSam Leffler sc->sc_stats.ast_rx_noise = nf; 33927b0c77ecSSam Leffler tsf = ath_hal_gettsf64(ah); 33935591b213SSam Leffler do { 3394c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 33958a2a6beeSAdrian Chadd if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ 3396c42a7b7eSSam Leffler if_printf(ifp, "%s: no buffer!\n", __func__); 33975591b213SSam Leffler break; 33988a2a6beeSAdrian Chadd } else if (bf == NULL) { 33998a2a6beeSAdrian Chadd /* 34008a2a6beeSAdrian Chadd * End of List: 34018a2a6beeSAdrian Chadd * this can happen for non-self-linked RX chains 34028a2a6beeSAdrian Chadd */ 34038a2a6beeSAdrian Chadd sc->sc_stats.ast_rx_hitqueueend++; 34048a2a6beeSAdrian Chadd break; 34055591b213SSam Leffler } 3406b2792ff6SSam Leffler m = bf->bf_m; 3407b2792ff6SSam Leffler if (m == NULL) { /* NB: shouldn't happen */ 3408b2792ff6SSam Leffler /* 3409b2792ff6SSam Leffler * If mbuf allocation failed previously there 3410b2792ff6SSam Leffler * will be no mbuf; try again to re-populate it. 3411b2792ff6SSam Leffler */ 3412b2792ff6SSam Leffler /* XXX make debug msg */ 3413b2792ff6SSam Leffler if_printf(ifp, "%s: no mbuf!\n", __func__); 3414b2792ff6SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 3415b2792ff6SSam Leffler goto rx_next; 3416b2792ff6SSam Leffler } 341704e22a02SSam Leffler ds = bf->bf_desc; 341804e22a02SSam Leffler if (ds->ds_link == bf->bf_daddr) { 341904e22a02SSam Leffler /* NB: never process the self-linked entry at the end */ 3420f77057dbSAdrian Chadd sc->sc_stats.ast_rx_hitqueueend++; 342104e22a02SSam Leffler break; 342204e22a02SSam Leffler } 34238cec0ab9SSam Leffler /* XXX sync descriptor memory */ 34248cec0ab9SSam Leffler /* 34258cec0ab9SSam Leffler * Must provide the virtual address of the current 34268cec0ab9SSam Leffler * descriptor, the physical address, and the virtual 34278cec0ab9SSam Leffler * address of the next descriptor in the h/w chain. 34288cec0ab9SSam Leffler * This allows the HAL to look ahead to see if the 34298cec0ab9SSam Leffler * hardware is done with a descriptor by checking the 34308cec0ab9SSam Leffler * done bit in the following descriptor and the address 34318cec0ab9SSam Leffler * of the current descriptor the DMA engine is working 34328cec0ab9SSam Leffler * on. All this is necessary because of our use of 34338cec0ab9SSam Leffler * a self-linked list to avoid rx overruns. 34348cec0ab9SSam Leffler */ 343565f9edeeSSam Leffler rs = &bf->bf_status.ds_rxstat; 34368cec0ab9SSam Leffler status = ath_hal_rxprocdesc(ah, ds, 343765f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 3438a585a9a1SSam Leffler #ifdef ATH_DEBUG 3439c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_RECV_DESC) 34406902009eSSam Leffler ath_printrxbuf(sc, bf, 0, status == HAL_OK); 34415591b213SSam Leffler #endif 34425591b213SSam Leffler if (status == HAL_EINPROGRESS) 34435591b213SSam Leffler break; 3444c42a7b7eSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 3445f9aa1d90SAdrian Chadd 3446f9aa1d90SAdrian Chadd /* These aren't specifically errors */ 3447f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_GI) 3448f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_halfgi++; 3449f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_2040) 3450f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_2040++; 3451f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_DELIM_CRC_PRE) 3452f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_pre_crc_err++; 3453f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_DELIM_CRC_POST) 3454f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_post_crc_err++; 3455f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_DECRYPT_BUSY) 3456f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_decrypt_busy_err++; 3457f9aa1d90SAdrian Chadd if (rs->rs_flags & HAL_RX_HI_RX_CHAIN) 3458f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_hi_rx_chain++; 3459f9aa1d90SAdrian Chadd 346068e8e04eSSam Leffler if (rs->rs_status != 0) { 346165f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 34625591b213SSam Leffler sc->sc_stats.ast_rx_crcerr++; 346365f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_FIFO) 34645591b213SSam Leffler sc->sc_stats.ast_rx_fifoerr++; 346565f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_PHY) { 34665591b213SSam Leffler sc->sc_stats.ast_rx_phyerr++; 3467*48237774SAdrian Chadd /* Process DFS radar events */ 3468*48237774SAdrian Chadd ath_dfs_process_phy_err(sc, ds, tsf, rs); 3469*48237774SAdrian Chadd 3470f9aa1d90SAdrian Chadd /* Be suitably paranoid about receiving phy errors out of the stats array bounds */ 3471f9aa1d90SAdrian Chadd if (rs->rs_phyerr < 64) 3472f9aa1d90SAdrian Chadd sc->sc_stats.ast_rx_phy[rs->rs_phyerr]++; 347368e8e04eSSam Leffler goto rx_error; /* NB: don't count in ierrors */ 3474c42a7b7eSSam Leffler } 347565f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_DECRYPT) { 347685643802SSam Leffler /* 3477c42a7b7eSSam Leffler * Decrypt error. If the error occurred 3478c42a7b7eSSam Leffler * because there was no hardware key, then 3479c42a7b7eSSam Leffler * let the frame through so the upper layers 3480c42a7b7eSSam Leffler * can process it. This is necessary for 5210 3481c42a7b7eSSam Leffler * parts which have no way to setup a ``clear'' 3482c42a7b7eSSam Leffler * key cache entry. 3483c42a7b7eSSam Leffler * 3484c42a7b7eSSam Leffler * XXX do key cache faulting 348585643802SSam Leffler */ 348665f9edeeSSam Leffler if (rs->rs_keyix == HAL_RXKEYIX_INVALID) 3487c42a7b7eSSam Leffler goto rx_accept; 3488c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badcrypt++; 34895591b213SSam Leffler } 349065f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_MIC) { 3491c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badmic++; 3492c42a7b7eSSam Leffler /* 3493c42a7b7eSSam Leffler * Do minimal work required to hand off 34945463c4a4SSam Leffler * the 802.11 header for notification. 3495c42a7b7eSSam Leffler */ 3496c42a7b7eSSam Leffler /* XXX frag's and qos frames */ 349765f9edeeSSam Leffler len = rs->rs_datalen; 3498c42a7b7eSSam Leffler if (len >= sizeof (struct ieee80211_frame)) { 3499c42a7b7eSSam Leffler bus_dmamap_sync(sc->sc_dmat, 3500c42a7b7eSSam Leffler bf->bf_dmamap, 3501c42a7b7eSSam Leffler BUS_DMASYNC_POSTREAD); 3502b032f27cSSam Leffler ath_handle_micerror(ic, 3503c42a7b7eSSam Leffler mtod(m, struct ieee80211_frame *), 35040ab4040aSSam Leffler sc->sc_splitmic ? 3505b032f27cSSam Leffler rs->rs_keyix-32 : rs->rs_keyix); 3506c42a7b7eSSam Leffler } 3507c42a7b7eSSam Leffler } 3508c42a7b7eSSam Leffler ifp->if_ierrors++; 350968e8e04eSSam Leffler rx_error: 351068e8e04eSSam Leffler /* 351168e8e04eSSam Leffler * Cleanup any pending partial frame. 351268e8e04eSSam Leffler */ 351368e8e04eSSam Leffler if (sc->sc_rxpending != NULL) { 351468e8e04eSSam Leffler m_freem(sc->sc_rxpending); 351568e8e04eSSam Leffler sc->sc_rxpending = NULL; 351668e8e04eSSam Leffler } 3517c42a7b7eSSam Leffler /* 35187b0c77ecSSam Leffler * When a tap is present pass error frames 35197b0c77ecSSam Leffler * that have been requested. By default we 35207b0c77ecSSam Leffler * pass decrypt+mic errors but others may be 35217b0c77ecSSam Leffler * interesting (e.g. crc). 3522c42a7b7eSSam Leffler */ 35235463c4a4SSam Leffler if (ieee80211_radiotap_active(ic) && 352465f9edeeSSam Leffler (rs->rs_status & sc->sc_monpass)) { 35257b0c77ecSSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 35267b0c77ecSSam Leffler BUS_DMASYNC_POSTREAD); 35277b0c77ecSSam Leffler /* NB: bpf needs the mbuf length setup */ 352865f9edeeSSam Leffler len = rs->rs_datalen; 35297b0c77ecSSam Leffler m->m_pkthdr.len = m->m_len = len; 35305463c4a4SSam Leffler ath_rx_tap(ifp, m, rs, tsf, nf); 35315463c4a4SSam Leffler ieee80211_radiotap_rx_all(ic, m); 35327b0c77ecSSam Leffler } 35337b0c77ecSSam Leffler /* XXX pass MIC errors up for s/w reclaculation */ 35345591b213SSam Leffler goto rx_next; 35355591b213SSam Leffler } 3536c42a7b7eSSam Leffler rx_accept: 3537c42a7b7eSSam Leffler /* 3538c42a7b7eSSam Leffler * Sync and unmap the frame. At this point we're 3539c42a7b7eSSam Leffler * committed to passing the mbuf somewhere so clear 3540c66c48cbSSam Leffler * bf_m; this means a new mbuf must be allocated 3541c42a7b7eSSam Leffler * when the rx descriptor is setup again to receive 3542c42a7b7eSSam Leffler * another frame. 3543c42a7b7eSSam Leffler */ 35445591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 35455591b213SSam Leffler BUS_DMASYNC_POSTREAD); 35465591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 35475591b213SSam Leffler bf->bf_m = NULL; 3548c42a7b7eSSam Leffler 354965f9edeeSSam Leffler len = rs->rs_datalen; 355068e8e04eSSam Leffler m->m_len = len; 355168e8e04eSSam Leffler 355268e8e04eSSam Leffler if (rs->rs_more) { 355368e8e04eSSam Leffler /* 355468e8e04eSSam Leffler * Frame spans multiple descriptors; save 355568e8e04eSSam Leffler * it for the next completed descriptor, it 355668e8e04eSSam Leffler * will be used to construct a jumbogram. 355768e8e04eSSam Leffler */ 355868e8e04eSSam Leffler if (sc->sc_rxpending != NULL) { 355968e8e04eSSam Leffler /* NB: max frame size is currently 2 clusters */ 356068e8e04eSSam Leffler sc->sc_stats.ast_rx_toobig++; 356168e8e04eSSam Leffler m_freem(sc->sc_rxpending); 356268e8e04eSSam Leffler } 356368e8e04eSSam Leffler m->m_pkthdr.rcvif = ifp; 356468e8e04eSSam Leffler m->m_pkthdr.len = len; 356568e8e04eSSam Leffler sc->sc_rxpending = m; 356668e8e04eSSam Leffler goto rx_next; 356768e8e04eSSam Leffler } else if (sc->sc_rxpending != NULL) { 356868e8e04eSSam Leffler /* 356968e8e04eSSam Leffler * This is the second part of a jumbogram, 357068e8e04eSSam Leffler * chain it to the first mbuf, adjust the 357168e8e04eSSam Leffler * frame length, and clear the rxpending state. 357268e8e04eSSam Leffler */ 357368e8e04eSSam Leffler sc->sc_rxpending->m_next = m; 357468e8e04eSSam Leffler sc->sc_rxpending->m_pkthdr.len += len; 357568e8e04eSSam Leffler m = sc->sc_rxpending; 357668e8e04eSSam Leffler sc->sc_rxpending = NULL; 357768e8e04eSSam Leffler } else { 357868e8e04eSSam Leffler /* 357968e8e04eSSam Leffler * Normal single-descriptor receive; setup 358068e8e04eSSam Leffler * the rcvif and packet length. 358168e8e04eSSam Leffler */ 358268e8e04eSSam Leffler m->m_pkthdr.rcvif = ifp; 358368e8e04eSSam Leffler m->m_pkthdr.len = len; 358468e8e04eSSam Leffler } 358573454c73SSam Leffler 3586b032f27cSSam Leffler ifp->if_ipackets++; 358765f9edeeSSam Leffler sc->sc_stats.ast_ant_rx[rs->rs_antenna]++; 3588c42a7b7eSSam Leffler 35895463c4a4SSam Leffler /* 35905463c4a4SSam Leffler * Populate the rx status block. When there are bpf 35915463c4a4SSam Leffler * listeners we do the additional work to provide 35925463c4a4SSam Leffler * complete status. Otherwise we fill in only the 35935463c4a4SSam Leffler * material required by ieee80211_input. Note that 35945463c4a4SSam Leffler * noise setting is filled in above. 35955463c4a4SSam Leffler */ 35965463c4a4SSam Leffler if (ieee80211_radiotap_active(ic)) 35975463c4a4SSam Leffler ath_rx_tap(ifp, m, rs, tsf, nf); 35980a915fadSSam Leffler 35995591b213SSam Leffler /* 3600c42a7b7eSSam Leffler * From this point on we assume the frame is at least 3601c42a7b7eSSam Leffler * as large as ieee80211_frame_min; verify that. 36025591b213SSam Leffler */ 3603c42a7b7eSSam Leffler if (len < IEEE80211_MIN_LEN) { 36045463c4a4SSam Leffler if (!ieee80211_radiotap_active(ic)) { 36055463c4a4SSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, 36065463c4a4SSam Leffler "%s: short packet %d\n", __func__, len); 3607c42a7b7eSSam Leffler sc->sc_stats.ast_rx_tooshort++; 36085463c4a4SSam Leffler } else { 36095463c4a4SSam Leffler /* NB: in particular this captures ack's */ 36105463c4a4SSam Leffler ieee80211_radiotap_rx_all(ic, m); 36115463c4a4SSam Leffler } 3612c42a7b7eSSam Leffler m_freem(m); 3613c42a7b7eSSam Leffler goto rx_next; 36145591b213SSam Leffler } 36150a915fadSSam Leffler 3616c42a7b7eSSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) { 361746d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 361846d4d74cSSam Leffler uint8_t rix = rt->rateCodeToIndex[rs->rs_rate]; 361946d4d74cSSam Leffler 362068e8e04eSSam Leffler ieee80211_dump_pkt(ic, mtod(m, caddr_t), len, 362146d4d74cSSam Leffler sc->sc_hwmap[rix].ieeerate, rs->rs_rssi); 3622c42a7b7eSSam Leffler } 3623c42a7b7eSSam Leffler 3624c42a7b7eSSam Leffler m_adj(m, -IEEE80211_CRC_LEN); 3625de5af704SSam Leffler 3626de5af704SSam Leffler /* 3627c42a7b7eSSam Leffler * Locate the node for sender, track state, and then 3628c42a7b7eSSam Leffler * pass the (referenced) node up to the 802.11 layer 3629c42a7b7eSSam Leffler * for its use. 3630c42a7b7eSSam Leffler */ 3631c1225b52SSam Leffler ni = ieee80211_find_rxnode_withkey(ic, 3632c1225b52SSam Leffler mtod(m, const struct ieee80211_frame_min *), 363365f9edeeSSam Leffler rs->rs_keyix == HAL_RXKEYIX_INVALID ? 363465f9edeeSSam Leffler IEEE80211_KEYIX_NONE : rs->rs_keyix); 36357041d50cSBernhard Schmidt sc->sc_lastrs = rs; 3636a07e9ddbSAdrian Chadd 3637a07e9ddbSAdrian Chadd if (rs->rs_isaggr) 3638a07e9ddbSAdrian Chadd sc->sc_stats.ast_rx_agg++; 3639a07e9ddbSAdrian Chadd 3640a07e9ddbSAdrian Chadd if (ni != NULL) { 3641b032f27cSSam Leffler /* 3642e57539afSAdrian Chadd * Only punt packets for ampdu reorder processing for 3643e57539afSAdrian Chadd * 11n nodes; net80211 enforces that M_AMPDU is only 3644e57539afSAdrian Chadd * set for 11n nodes. 364500fc8705SAdrian Chadd */ 364600fc8705SAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_HT) 364700fc8705SAdrian Chadd m->m_flags |= M_AMPDU; 364800fc8705SAdrian Chadd 364900fc8705SAdrian Chadd /* 3650b032f27cSSam Leffler * Sending station is known, dispatch directly. 3651b032f27cSSam Leffler */ 36525463c4a4SSam Leffler type = ieee80211_input(ni, m, rs->rs_rssi, nf); 3653b032f27cSSam Leffler ieee80211_free_node(ni); 3654b032f27cSSam Leffler /* 3655b032f27cSSam Leffler * Arrange to update the last rx timestamp only for 3656b032f27cSSam Leffler * frames from our ap when operating in station mode. 3657b032f27cSSam Leffler * This assumes the rx key is always setup when 3658b032f27cSSam Leffler * associated. 3659b032f27cSSam Leffler */ 3660b032f27cSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA && 3661b032f27cSSam Leffler rs->rs_keyix != HAL_RXKEYIX_INVALID) 3662b032f27cSSam Leffler ngood++; 3663b032f27cSSam Leffler } else { 36645463c4a4SSam Leffler type = ieee80211_input_all(ic, m, rs->rs_rssi, nf); 3665b032f27cSSam Leffler } 3666c42a7b7eSSam Leffler /* 3667c42a7b7eSSam Leffler * Track rx rssi and do any rx antenna management. 3668de5af704SSam Leffler */ 366965f9edeeSSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi); 3670c42a7b7eSSam Leffler if (sc->sc_diversity) { 3671c42a7b7eSSam Leffler /* 3672c42a7b7eSSam Leffler * When using fast diversity, change the default rx 3673c42a7b7eSSam Leffler * antenna if diversity chooses the other antenna 3 3674c42a7b7eSSam Leffler * times in a row. 3675c42a7b7eSSam Leffler */ 367665f9edeeSSam Leffler if (sc->sc_defant != rs->rs_antenna) { 3677c42a7b7eSSam Leffler if (++sc->sc_rxotherant >= 3) 367865f9edeeSSam Leffler ath_setdefantenna(sc, rs->rs_antenna); 3679c42a7b7eSSam Leffler } else 3680c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 3681c42a7b7eSSam Leffler } 3682235ab70eSAdrian Chadd 3683235ab70eSAdrian Chadd /* Newer school diversity - kite specific for now */ 3684235ab70eSAdrian Chadd /* XXX perhaps migrate the normal diversity code to this? */ 3685235ab70eSAdrian Chadd if ((ah)->ah_rxAntCombDiversity) 3686235ab70eSAdrian Chadd (*(ah)->ah_rxAntCombDiversity)(ah, rs, ticks, hz); 3687235ab70eSAdrian Chadd 36883e50ec2cSSam Leffler if (sc->sc_softled) { 36893e50ec2cSSam Leffler /* 36903e50ec2cSSam Leffler * Blink for any data frame. Otherwise do a 36913e50ec2cSSam Leffler * heartbeat-style blink when idle. The latter 36923e50ec2cSSam Leffler * is mainly for station mode where we depend on 36933e50ec2cSSam Leffler * periodic beacon frames to trigger the poll event. 36943e50ec2cSSam Leffler */ 369531640eb7SSam Leffler if (type == IEEE80211_FC0_TYPE_DATA) { 369646d4d74cSSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 369746d4d74cSSam Leffler ath_led_event(sc, 369846d4d74cSSam Leffler rt->rateCodeToIndex[rs->rs_rate]); 36993e50ec2cSSam Leffler } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) 370046d4d74cSSam Leffler ath_led_event(sc, 0); 37013e50ec2cSSam Leffler } 37025591b213SSam Leffler rx_next: 3703c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 37045591b213SSam Leffler } while (ath_rxbuf_init(sc, bf) == 0); 37055591b213SSam Leffler 3706c42a7b7eSSam Leffler /* rx signal state monitoring */ 370759efa8b5SSam Leffler ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan); 3708d7736e13SSam Leffler if (ngood) 3709d7736e13SSam Leffler sc->sc_lastrx = tsf; 3710b5f4adb3SSam Leffler 3711*48237774SAdrian Chadd /* Queue DFS tasklet if needed */ 3712*48237774SAdrian Chadd if (ath_dfs_tasklet_needed(sc, sc->sc_curchan)) 3713*48237774SAdrian Chadd taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask); 3714*48237774SAdrian Chadd 3715339ccfb3SSam Leffler if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 3716339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 371704f19fd6SSam Leffler ieee80211_ff_age_all(ic, 100); 3718339ccfb3SSam Leffler #endif 3719339ccfb3SSam Leffler if (!IFQ_IS_EMPTY(&ifp->if_snd)) 3720cd196bb2SSam Leffler ath_start(ifp); 3721339ccfb3SSam Leffler } 37228cec0ab9SSam Leffler #undef PA2DESC 37235591b213SSam Leffler } 37245591b213SSam Leffler 3725622b3fd2SSam Leffler static void 3726622b3fd2SSam Leffler ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum) 3727622b3fd2SSam Leffler { 3728622b3fd2SSam Leffler txq->axq_qnum = qnum; 3729339ccfb3SSam Leffler txq->axq_ac = 0; 3730622b3fd2SSam Leffler txq->axq_depth = 0; 3731622b3fd2SSam Leffler txq->axq_intrcnt = 0; 3732622b3fd2SSam Leffler txq->axq_link = NULL; 3733622b3fd2SSam Leffler STAILQ_INIT(&txq->axq_q); 3734622b3fd2SSam Leffler ATH_TXQ_LOCK_INIT(sc, txq); 3735622b3fd2SSam Leffler } 3736622b3fd2SSam Leffler 37375591b213SSam Leffler /* 3738c42a7b7eSSam Leffler * Setup a h/w transmit queue. 37395591b213SSam Leffler */ 3740c42a7b7eSSam Leffler static struct ath_txq * 3741c42a7b7eSSam Leffler ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) 3742c42a7b7eSSam Leffler { 3743c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3744c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3745c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3746c42a7b7eSSam Leffler int qnum; 3747c42a7b7eSSam Leffler 3748c42a7b7eSSam Leffler memset(&qi, 0, sizeof(qi)); 3749c42a7b7eSSam Leffler qi.tqi_subtype = subtype; 3750c42a7b7eSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 3751c42a7b7eSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 3752c42a7b7eSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 3753c42a7b7eSSam Leffler /* 3754c42a7b7eSSam Leffler * Enable interrupts only for EOL and DESC conditions. 3755c42a7b7eSSam Leffler * We mark tx descriptors to receive a DESC interrupt 3756c42a7b7eSSam Leffler * when a tx queue gets deep; otherwise waiting for the 3757c42a7b7eSSam Leffler * EOL to reap descriptors. Note that this is done to 3758c42a7b7eSSam Leffler * reduce interrupt load and this only defers reaping 3759c42a7b7eSSam Leffler * descriptors, never transmitting frames. Aside from 3760c42a7b7eSSam Leffler * reducing interrupts this also permits more concurrency. 3761c42a7b7eSSam Leffler * The only potential downside is if the tx queue backs 3762c42a7b7eSSam Leffler * up in which case the top half of the kernel may backup 3763c42a7b7eSSam Leffler * due to a lack of tx descriptors. 3764c42a7b7eSSam Leffler */ 3765bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; 3766c42a7b7eSSam Leffler qnum = ath_hal_setuptxqueue(ah, qtype, &qi); 3767c42a7b7eSSam Leffler if (qnum == -1) { 3768c42a7b7eSSam Leffler /* 3769c42a7b7eSSam Leffler * NB: don't print a message, this happens 3770a614e076SSam Leffler * normally on parts with too few tx queues 3771c42a7b7eSSam Leffler */ 3772c42a7b7eSSam Leffler return NULL; 3773c42a7b7eSSam Leffler } 3774c42a7b7eSSam Leffler if (qnum >= N(sc->sc_txq)) { 37756891c875SPeter Wemm device_printf(sc->sc_dev, 37766891c875SPeter Wemm "hal qnum %u out of range, max %zu!\n", 3777c42a7b7eSSam Leffler qnum, N(sc->sc_txq)); 3778c42a7b7eSSam Leffler ath_hal_releasetxqueue(ah, qnum); 3779c42a7b7eSSam Leffler return NULL; 3780c42a7b7eSSam Leffler } 3781c42a7b7eSSam Leffler if (!ATH_TXQ_SETUP(sc, qnum)) { 3782622b3fd2SSam Leffler ath_txq_init(sc, &sc->sc_txq[qnum], qnum); 3783c42a7b7eSSam Leffler sc->sc_txqsetup |= 1<<qnum; 3784c42a7b7eSSam Leffler } 3785c42a7b7eSSam Leffler return &sc->sc_txq[qnum]; 3786c42a7b7eSSam Leffler #undef N 3787c42a7b7eSSam Leffler } 3788c42a7b7eSSam Leffler 3789c42a7b7eSSam Leffler /* 3790c42a7b7eSSam Leffler * Setup a hardware data transmit queue for the specified 3791c42a7b7eSSam Leffler * access control. The hal may not support all requested 3792c42a7b7eSSam Leffler * queues in which case it will return a reference to a 3793c42a7b7eSSam Leffler * previously setup queue. We record the mapping from ac's 3794c42a7b7eSSam Leffler * to h/w queues for use by ath_tx_start and also track 3795c42a7b7eSSam Leffler * the set of h/w queues being used to optimize work in the 3796c42a7b7eSSam Leffler * transmit interrupt handler and related routines. 3797c42a7b7eSSam Leffler */ 3798c42a7b7eSSam Leffler static int 3799c42a7b7eSSam Leffler ath_tx_setup(struct ath_softc *sc, int ac, int haltype) 3800c42a7b7eSSam Leffler { 3801c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3802c42a7b7eSSam Leffler struct ath_txq *txq; 3803c42a7b7eSSam Leffler 3804c42a7b7eSSam Leffler if (ac >= N(sc->sc_ac2q)) { 38056891c875SPeter Wemm device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n", 3806c42a7b7eSSam Leffler ac, N(sc->sc_ac2q)); 3807c42a7b7eSSam Leffler return 0; 3808c42a7b7eSSam Leffler } 3809c42a7b7eSSam Leffler txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype); 3810c42a7b7eSSam Leffler if (txq != NULL) { 3811339ccfb3SSam Leffler txq->axq_ac = ac; 3812c42a7b7eSSam Leffler sc->sc_ac2q[ac] = txq; 3813c42a7b7eSSam Leffler return 1; 3814c42a7b7eSSam Leffler } else 3815c42a7b7eSSam Leffler return 0; 3816c42a7b7eSSam Leffler #undef N 3817c42a7b7eSSam Leffler } 3818c42a7b7eSSam Leffler 3819c42a7b7eSSam Leffler /* 3820c42a7b7eSSam Leffler * Update WME parameters for a transmit queue. 3821c42a7b7eSSam Leffler */ 3822c42a7b7eSSam Leffler static int 3823c42a7b7eSSam Leffler ath_txq_update(struct ath_softc *sc, int ac) 3824c42a7b7eSSam Leffler { 3825c42a7b7eSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1) 3826c42a7b7eSSam Leffler #define ATH_TXOP_TO_US(v) (v<<5) 3827b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 3828b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 3829c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[ac]; 3830c42a7b7eSSam Leffler struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; 3831c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3832c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3833c42a7b7eSSam Leffler 3834c42a7b7eSSam Leffler ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi); 3835584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 383610ad9a77SSam Leffler if (sc->sc_tdma) { 383710ad9a77SSam Leffler /* 383810ad9a77SSam Leffler * AIFS is zero so there's no pre-transmit wait. The 383910ad9a77SSam Leffler * burst time defines the slot duration and is configured 384009be6601SSam Leffler * through net80211. The QCU is setup to not do post-xmit 384110ad9a77SSam Leffler * back off, lockout all lower-priority QCU's, and fire 384210ad9a77SSam Leffler * off the DMA beacon alert timer which is setup based 384310ad9a77SSam Leffler * on the slot configuration. 384410ad9a77SSam Leffler */ 384510ad9a77SSam Leffler qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE 384610ad9a77SSam Leffler | HAL_TXQ_TXERRINT_ENABLE 384710ad9a77SSam Leffler | HAL_TXQ_TXURNINT_ENABLE 384810ad9a77SSam Leffler | HAL_TXQ_TXEOLINT_ENABLE 384910ad9a77SSam Leffler | HAL_TXQ_DBA_GATED 385010ad9a77SSam Leffler | HAL_TXQ_BACKOFF_DISABLE 385110ad9a77SSam Leffler | HAL_TXQ_ARB_LOCKOUT_GLOBAL 385210ad9a77SSam Leffler ; 385310ad9a77SSam Leffler qi.tqi_aifs = 0; 385410ad9a77SSam Leffler /* XXX +dbaprep? */ 385510ad9a77SSam Leffler qi.tqi_readyTime = sc->sc_tdmaslotlen; 385610ad9a77SSam Leffler qi.tqi_burstTime = qi.tqi_readyTime; 385710ad9a77SSam Leffler } else { 385810ad9a77SSam Leffler #endif 385910ad9a77SSam Leffler qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE 386010ad9a77SSam Leffler | HAL_TXQ_TXERRINT_ENABLE 386110ad9a77SSam Leffler | HAL_TXQ_TXDESCINT_ENABLE 386210ad9a77SSam Leffler | HAL_TXQ_TXURNINT_ENABLE 386310ad9a77SSam Leffler ; 3864c42a7b7eSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 3865c42a7b7eSSam Leffler qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 3866c42a7b7eSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 386710ad9a77SSam Leffler qi.tqi_readyTime = 0; 3868c42a7b7eSSam Leffler qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit); 3869584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 387010ad9a77SSam Leffler } 387110ad9a77SSam Leffler #endif 387210ad9a77SSam Leffler 387310ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 387410ad9a77SSam Leffler "%s: Q%u qflags 0x%x aifs %u cwmin %u cwmax %u burstTime %u\n", 387510ad9a77SSam Leffler __func__, txq->axq_qnum, qi.tqi_qflags, 387610ad9a77SSam Leffler qi.tqi_aifs, qi.tqi_cwmin, qi.tqi_cwmax, qi.tqi_burstTime); 3877c42a7b7eSSam Leffler 3878c42a7b7eSSam Leffler if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) { 3879b032f27cSSam Leffler if_printf(ifp, "unable to update hardware queue " 3880c42a7b7eSSam Leffler "parameters for %s traffic!\n", 3881c42a7b7eSSam Leffler ieee80211_wme_acnames[ac]); 3882c42a7b7eSSam Leffler return 0; 3883c42a7b7eSSam Leffler } else { 3884c42a7b7eSSam Leffler ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */ 3885c42a7b7eSSam Leffler return 1; 3886c42a7b7eSSam Leffler } 3887c42a7b7eSSam Leffler #undef ATH_TXOP_TO_US 3888c42a7b7eSSam Leffler #undef ATH_EXPONENT_TO_VALUE 3889c42a7b7eSSam Leffler } 3890c42a7b7eSSam Leffler 3891c42a7b7eSSam Leffler /* 3892c42a7b7eSSam Leffler * Callback from the 802.11 layer to update WME parameters. 3893c42a7b7eSSam Leffler */ 3894c42a7b7eSSam Leffler static int 3895c42a7b7eSSam Leffler ath_wme_update(struct ieee80211com *ic) 3896c42a7b7eSSam Leffler { 3897c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 3898c42a7b7eSSam Leffler 3899c42a7b7eSSam Leffler return !ath_txq_update(sc, WME_AC_BE) || 3900c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_BK) || 3901c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VI) || 3902c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VO) ? EIO : 0; 3903c42a7b7eSSam Leffler } 3904c42a7b7eSSam Leffler 3905c42a7b7eSSam Leffler /* 3906c42a7b7eSSam Leffler * Reclaim resources for a setup queue. 3907c42a7b7eSSam Leffler */ 3908c42a7b7eSSam Leffler static void 3909c42a7b7eSSam Leffler ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) 3910c42a7b7eSSam Leffler { 3911c42a7b7eSSam Leffler 3912c42a7b7eSSam Leffler ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum); 3913c42a7b7eSSam Leffler ATH_TXQ_LOCK_DESTROY(txq); 3914c42a7b7eSSam Leffler sc->sc_txqsetup &= ~(1<<txq->axq_qnum); 3915c42a7b7eSSam Leffler } 3916c42a7b7eSSam Leffler 3917c42a7b7eSSam Leffler /* 3918c42a7b7eSSam Leffler * Reclaim all tx queue resources. 3919c42a7b7eSSam Leffler */ 3920c42a7b7eSSam Leffler static void 3921c42a7b7eSSam Leffler ath_tx_cleanup(struct ath_softc *sc) 3922c42a7b7eSSam Leffler { 3923c42a7b7eSSam Leffler int i; 3924c42a7b7eSSam Leffler 3925c42a7b7eSSam Leffler ATH_TXBUF_LOCK_DESTROY(sc); 3926c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 3927c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 3928c42a7b7eSSam Leffler ath_tx_cleanupq(sc, &sc->sc_txq[i]); 3929c42a7b7eSSam Leffler } 39305591b213SSam Leffler 393199d258fdSSam Leffler /* 3932ab06fdf2SSam Leffler * Return h/w rate index for an IEEE rate (w/o basic rate bit) 3933ab06fdf2SSam Leffler * using the current rates in sc_rixmap. 39348b5341deSSam Leffler */ 3935b8e788a5SAdrian Chadd int 3936ab06fdf2SSam Leffler ath_tx_findrix(const struct ath_softc *sc, uint8_t rate) 39378b5341deSSam Leffler { 3938ab06fdf2SSam Leffler int rix = sc->sc_rixmap[rate]; 3939ab06fdf2SSam Leffler /* NB: return lowest rix for invalid rate */ 3940ab06fdf2SSam Leffler return (rix == 0xff ? 0 : rix); 39418b5341deSSam Leffler } 39428b5341deSSam Leffler 394368e8e04eSSam Leffler /* 3944c42a7b7eSSam Leffler * Process completed xmit descriptors from the specified queue. 3945c42a7b7eSSam Leffler */ 3946d7736e13SSam Leffler static int 3947c42a7b7eSSam Leffler ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) 39485591b213SSam Leffler { 39495591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 3950b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 3951b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 395210ad9a77SSam Leffler struct ath_buf *bf, *last; 3953c4c3cb46SSam Leffler struct ath_desc *ds, *ds0; 395465f9edeeSSam Leffler struct ath_tx_status *ts; 39555591b213SSam Leffler struct ieee80211_node *ni; 39565591b213SSam Leffler struct ath_node *an; 3957d7736e13SSam Leffler int sr, lr, pri, nacked; 39585591b213SSam Leffler HAL_STATUS status; 39595591b213SSam Leffler 3960c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n", 3961c42a7b7eSSam Leffler __func__, txq->axq_qnum, 3962c42a7b7eSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum), 3963c42a7b7eSSam Leffler txq->axq_link); 3964d7736e13SSam Leffler nacked = 0; 39655591b213SSam Leffler for (;;) { 3966c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 3967c42a7b7eSSam Leffler txq->axq_intrcnt = 0; /* reset periodic desc intr count */ 3968c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 39695591b213SSam Leffler if (bf == NULL) { 3970c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39715591b213SSam Leffler break; 39725591b213SSam Leffler } 3973c4c3cb46SSam Leffler ds0 = &bf->bf_desc[0]; 39745591b213SSam Leffler ds = &bf->bf_desc[bf->bf_nseg - 1]; 397565f9edeeSSam Leffler ts = &bf->bf_status.ds_txstat; 397665f9edeeSSam Leffler status = ath_hal_txprocdesc(ah, ds, ts); 3977a585a9a1SSam Leffler #ifdef ATH_DEBUG 3978c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 39796902009eSSam Leffler ath_printtxbuf(sc, bf, txq->axq_qnum, 0, 39806902009eSSam Leffler status == HAL_OK); 39815591b213SSam Leffler #endif 39825591b213SSam Leffler if (status == HAL_EINPROGRESS) { 3983c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39845591b213SSam Leffler break; 39855591b213SSam Leffler } 3986c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 3987584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 398810ad9a77SSam Leffler if (txq->axq_depth > 0) { 398910ad9a77SSam Leffler /* 399010ad9a77SSam Leffler * More frames follow. Mark the buffer busy 399110ad9a77SSam Leffler * so it's not re-used while the hardware may 399210ad9a77SSam Leffler * still re-read the link field in the descriptor. 399310ad9a77SSam Leffler */ 399410ad9a77SSam Leffler bf->bf_flags |= ATH_BUF_BUSY; 399510ad9a77SSam Leffler } else 399610ad9a77SSam Leffler #else 3997ebecf802SSam Leffler if (txq->axq_depth == 0) 399810ad9a77SSam Leffler #endif 39991539af1eSSam Leffler txq->axq_link = NULL; 4000c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 40015591b213SSam Leffler 40025591b213SSam Leffler ni = bf->bf_node; 40035591b213SSam Leffler if (ni != NULL) { 4004c42a7b7eSSam Leffler an = ATH_NODE(ni); 400565f9edeeSSam Leffler if (ts->ts_status == 0) { 400665f9edeeSSam Leffler u_int8_t txant = ts->ts_antenna; 4007c42a7b7eSSam Leffler sc->sc_stats.ast_ant_tx[txant]++; 4008c42a7b7eSSam Leffler sc->sc_ant_tx[txant]++; 4009f6cbf16aSSam Leffler if (ts->ts_finaltsi != 0) 4010c42a7b7eSSam Leffler sc->sc_stats.ast_tx_altrate++; 4011c42a7b7eSSam Leffler pri = M_WME_GETAC(bf->bf_m); 4012c42a7b7eSSam Leffler if (pri >= WME_AC_VO) 4013c42a7b7eSSam Leffler ic->ic_wme.wme_hipri_traffic++; 4014ad80c0aaSSam Leffler if ((bf->bf_txflags & HAL_TXDESC_NOACK) == 0) 4015c42a7b7eSSam Leffler ni->ni_inact = ni->ni_inact_reload; 40165591b213SSam Leffler } else { 401765f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_XRETRY) 40185591b213SSam Leffler sc->sc_stats.ast_tx_xretries++; 401965f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FIFO) 40205591b213SSam Leffler sc->sc_stats.ast_tx_fifoerr++; 402165f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FILT) 40225591b213SSam Leffler sc->sc_stats.ast_tx_filtered++; 4023e9d1191fSAdrian Chadd if (ts->ts_status & HAL_TXERR_XTXOP) 4024e9d1191fSAdrian Chadd sc->sc_stats.ast_tx_xtxop++; 4025e9d1191fSAdrian Chadd if (ts->ts_status & HAL_TXERR_TIMER_EXPIRED) 4026e9d1191fSAdrian Chadd sc->sc_stats.ast_tx_timerexpired++; 4027e9d1191fSAdrian Chadd 4028e9d1191fSAdrian Chadd /* XXX HAL_TX_DATA_UNDERRUN */ 4029e9d1191fSAdrian Chadd /* XXX HAL_TX_DELIM_UNDERRUN */ 4030e9d1191fSAdrian Chadd 403168e8e04eSSam Leffler if (bf->bf_m->m_flags & M_FF) 403268e8e04eSSam Leffler sc->sc_stats.ast_ff_txerr++; 40335591b213SSam Leffler } 4034e9d1191fSAdrian Chadd /* XXX when is this valid? */ 4035e9d1191fSAdrian Chadd if (ts->ts_status & HAL_TX_DESC_CFG_ERR) 4036e9d1191fSAdrian Chadd sc->sc_stats.ast_tx_desccfgerr++; 4037e9d1191fSAdrian Chadd 403865f9edeeSSam Leffler sr = ts->ts_shortretry; 403965f9edeeSSam Leffler lr = ts->ts_longretry; 40405591b213SSam Leffler sc->sc_stats.ast_tx_shortretry += sr; 40415591b213SSam Leffler sc->sc_stats.ast_tx_longretry += lr; 4042c42a7b7eSSam Leffler /* 4043c42a7b7eSSam Leffler * Hand the descriptor to the rate control algorithm. 4044c42a7b7eSSam Leffler */ 404565f9edeeSSam Leffler if ((ts->ts_status & HAL_TXERR_FILT) == 0 && 404680c07f23SSam Leffler (bf->bf_txflags & HAL_TXDESC_NOACK) == 0) { 4047d7736e13SSam Leffler /* 404884784be1SSam Leffler * If frame was ack'd update statistics, 404984784be1SSam Leffler * including the last rx time used to 405084784be1SSam Leffler * workaround phantom bmiss interrupts. 4051d7736e13SSam Leffler */ 405284784be1SSam Leffler if (ts->ts_status == 0) { 4053d7736e13SSam Leffler nacked++; 405484784be1SSam Leffler sc->sc_stats.ast_tx_rssi = ts->ts_rssi; 405584784be1SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, 405684784be1SSam Leffler ts->ts_rssi); 405784784be1SSam Leffler } 405865f9edeeSSam Leffler ath_rate_tx_complete(sc, an, bf); 4059d7736e13SSam Leffler } 40600a915fadSSam Leffler /* 406168e8e04eSSam Leffler * Do any tx complete callback. Note this must 406268e8e04eSSam Leffler * be done before releasing the node reference. 406368e8e04eSSam Leffler */ 406468e8e04eSSam Leffler if (bf->bf_m->m_flags & M_TXCB) 406568e8e04eSSam Leffler ieee80211_process_callback(ni, bf->bf_m, 406674eca0c2SSam Leffler (bf->bf_txflags & HAL_TXDESC_NOACK) == 0 ? 406774eca0c2SSam Leffler ts->ts_status : HAL_TXERR_XRETRY); 4068c42a7b7eSSam Leffler ieee80211_free_node(ni); 40695591b213SSam Leffler } 40705591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 40715591b213SSam Leffler BUS_DMASYNC_POSTWRITE); 40725591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 407368e8e04eSSam Leffler 40745591b213SSam Leffler m_freem(bf->bf_m); 40755591b213SSam Leffler bf->bf_m = NULL; 40765591b213SSam Leffler bf->bf_node = NULL; 40775591b213SSam Leffler 4078f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 407910ad9a77SSam Leffler last = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list); 408010ad9a77SSam Leffler if (last != NULL) 408110ad9a77SSam Leffler last->bf_flags &= ~ATH_BUF_BUSY; 4082c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4083f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 40845591b213SSam Leffler } 4085339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 408668e8e04eSSam Leffler /* 408768e8e04eSSam Leffler * Flush fast-frame staging queue when traffic slows. 408868e8e04eSSam Leffler */ 408968e8e04eSSam Leffler if (txq->axq_depth <= 1) 409004f19fd6SSam Leffler ieee80211_ff_flush(ic, txq->axq_ac); 4091339ccfb3SSam Leffler #endif 4092d7736e13SSam Leffler return nacked; 4093d7736e13SSam Leffler } 4094d7736e13SSam Leffler 4095d7736e13SSam Leffler static __inline int 4096d7736e13SSam Leffler txqactive(struct ath_hal *ah, int qnum) 4097d7736e13SSam Leffler { 4098e2815d69SSam Leffler u_int32_t txqs = 1<<qnum; 4099e2815d69SSam Leffler ath_hal_gettxintrtxqs(ah, &txqs); 41009760f8aeSSam Leffler return (txqs & (1<<qnum)); 4101c42a7b7eSSam Leffler } 4102c42a7b7eSSam Leffler 4103c42a7b7eSSam Leffler /* 4104c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4105c42a7b7eSSam Leffler * for a single hardware transmit queue (e.g. 5210 and 5211). 4106c42a7b7eSSam Leffler */ 4107c42a7b7eSSam Leffler static void 4108c42a7b7eSSam Leffler ath_tx_proc_q0(void *arg, int npending) 4109c42a7b7eSSam Leffler { 4110c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4111fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4112c42a7b7eSSam Leffler 4113d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0])) 4114d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4115d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4116d7736e13SSam Leffler ath_tx_processq(sc, sc->sc_cabq); 411713f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 41182e986da5SSam Leffler sc->sc_wd_timer = 0; 41195591b213SSam Leffler 41203e50ec2cSSam Leffler if (sc->sc_softled) 412146d4d74cSSam Leffler ath_led_event(sc, sc->sc_txrix); 41223e50ec2cSSam Leffler 41235591b213SSam Leffler ath_start(ifp); 41245591b213SSam Leffler } 41255591b213SSam Leffler 41265591b213SSam Leffler /* 4127c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4128c42a7b7eSSam Leffler * for four hardware queues, 0-3 (e.g. 5212 w/ WME support). 41295591b213SSam Leffler */ 41305591b213SSam Leffler static void 4131c42a7b7eSSam Leffler ath_tx_proc_q0123(void *arg, int npending) 4132c42a7b7eSSam Leffler { 4133c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4134fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4135d7736e13SSam Leffler int nacked; 4136c42a7b7eSSam Leffler 4137c42a7b7eSSam Leffler /* 4138c42a7b7eSSam Leffler * Process each active queue. 4139c42a7b7eSSam Leffler */ 4140d7736e13SSam Leffler nacked = 0; 4141d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0)) 4142d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[0]); 4143d7736e13SSam Leffler if (txqactive(sc->sc_ah, 1)) 4144d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[1]); 4145d7736e13SSam Leffler if (txqactive(sc->sc_ah, 2)) 4146d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[2]); 4147d7736e13SSam Leffler if (txqactive(sc->sc_ah, 3)) 4148d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[3]); 4149d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4150c42a7b7eSSam Leffler ath_tx_processq(sc, sc->sc_cabq); 4151d7736e13SSam Leffler if (nacked) 4152d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4153c42a7b7eSSam Leffler 415413f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 41552e986da5SSam Leffler sc->sc_wd_timer = 0; 4156c42a7b7eSSam Leffler 41573e50ec2cSSam Leffler if (sc->sc_softled) 415846d4d74cSSam Leffler ath_led_event(sc, sc->sc_txrix); 41593e50ec2cSSam Leffler 4160c42a7b7eSSam Leffler ath_start(ifp); 4161c42a7b7eSSam Leffler } 4162c42a7b7eSSam Leffler 4163c42a7b7eSSam Leffler /* 4164c42a7b7eSSam Leffler * Deferred processing of transmit interrupt. 4165c42a7b7eSSam Leffler */ 4166c42a7b7eSSam Leffler static void 4167c42a7b7eSSam Leffler ath_tx_proc(void *arg, int npending) 4168c42a7b7eSSam Leffler { 4169c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4170fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4171d7736e13SSam Leffler int i, nacked; 4172c42a7b7eSSam Leffler 4173c42a7b7eSSam Leffler /* 4174c42a7b7eSSam Leffler * Process each active queue. 4175c42a7b7eSSam Leffler */ 4176d7736e13SSam Leffler nacked = 0; 4177c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4178d7736e13SSam Leffler if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i)) 4179d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[i]); 4180d7736e13SSam Leffler if (nacked) 4181d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4182c42a7b7eSSam Leffler 418313f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 41842e986da5SSam Leffler sc->sc_wd_timer = 0; 4185c42a7b7eSSam Leffler 41863e50ec2cSSam Leffler if (sc->sc_softled) 418746d4d74cSSam Leffler ath_led_event(sc, sc->sc_txrix); 41883e50ec2cSSam Leffler 4189c42a7b7eSSam Leffler ath_start(ifp); 4190c42a7b7eSSam Leffler } 4191c42a7b7eSSam Leffler 4192c42a7b7eSSam Leffler static void 4193c42a7b7eSSam Leffler ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) 41945591b213SSam Leffler { 4195a585a9a1SSam Leffler #ifdef ATH_DEBUG 41965591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4197d2f6ed15SSam Leffler #endif 419823428eafSSam Leffler struct ieee80211_node *ni; 41995591b213SSam Leffler struct ath_buf *bf; 42007a4c5ed9SSam Leffler u_int ix; 42015591b213SSam Leffler 4202c42a7b7eSSam Leffler /* 4203c42a7b7eSSam Leffler * NB: this assumes output has been stopped and 42045d61b5e8SSam Leffler * we do not need to block ath_tx_proc 4205c42a7b7eSSam Leffler */ 420610ad9a77SSam Leffler ATH_TXBUF_LOCK(sc); 420710ad9a77SSam Leffler bf = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list); 420810ad9a77SSam Leffler if (bf != NULL) 420910ad9a77SSam Leffler bf->bf_flags &= ~ATH_BUF_BUSY; 421010ad9a77SSam Leffler ATH_TXBUF_UNLOCK(sc); 42117a4c5ed9SSam Leffler for (ix = 0;; ix++) { 4212c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 4213c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 42145591b213SSam Leffler if (bf == NULL) { 4215ebecf802SSam Leffler txq->axq_link = NULL; 4216c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 42175591b213SSam Leffler break; 42185591b213SSam Leffler } 4219c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 4220c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 4221a585a9a1SSam Leffler #ifdef ATH_DEBUG 42224a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 4223b032f27cSSam Leffler struct ieee80211com *ic = sc->sc_ifp->if_l2com; 4224b032f27cSSam Leffler 42256902009eSSam Leffler ath_printtxbuf(sc, bf, txq->axq_qnum, ix, 422665f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 422765f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 4228e40b6ab1SSam Leffler ieee80211_dump_pkt(ic, mtod(bf->bf_m, const uint8_t *), 42294a3ac3fcSSam Leffler bf->bf_m->m_len, 0, -1); 42304a3ac3fcSSam Leffler } 4231a585a9a1SSam Leffler #endif /* ATH_DEBUG */ 42325591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 423323428eafSSam Leffler ni = bf->bf_node; 42345591b213SSam Leffler bf->bf_node = NULL; 4235c42a7b7eSSam Leffler if (ni != NULL) { 423623428eafSSam Leffler /* 4237d50ea6acSSam Leffler * Do any callback and reclaim the node reference. 423823428eafSSam Leffler */ 4239d50ea6acSSam Leffler if (bf->bf_m->m_flags & M_TXCB) 4240d50ea6acSSam Leffler ieee80211_process_callback(ni, bf->bf_m, -1); 4241c42a7b7eSSam Leffler ieee80211_free_node(ni); 424223428eafSSam Leffler } 424368e8e04eSSam Leffler m_freem(bf->bf_m); 424468e8e04eSSam Leffler bf->bf_m = NULL; 424510ad9a77SSam Leffler bf->bf_flags &= ~ATH_BUF_BUSY; 424668e8e04eSSam Leffler 4247f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 4248c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4249f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 42505591b213SSam Leffler } 4251c42a7b7eSSam Leffler } 4252c42a7b7eSSam Leffler 4253c42a7b7eSSam Leffler static void 4254c42a7b7eSSam Leffler ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) 4255c42a7b7eSSam Leffler { 4256c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4257c42a7b7eSSam Leffler 4258c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 4259c42a7b7eSSam Leffler __func__, txq->axq_qnum, 42606891c875SPeter Wemm (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, txq->axq_qnum), 42616891c875SPeter Wemm txq->axq_link); 42624a3ac3fcSSam Leffler (void) ath_hal_stoptxdma(ah, txq->axq_qnum); 4263c42a7b7eSSam Leffler } 4264c42a7b7eSSam Leffler 4265c42a7b7eSSam Leffler /* 4266c42a7b7eSSam Leffler * Drain the transmit queues and reclaim resources. 4267c42a7b7eSSam Leffler */ 4268c42a7b7eSSam Leffler static void 4269c42a7b7eSSam Leffler ath_draintxq(struct ath_softc *sc) 4270c42a7b7eSSam Leffler { 4271c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4272fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4273c42a7b7eSSam Leffler int i; 4274c42a7b7eSSam Leffler 4275c42a7b7eSSam Leffler /* XXX return value */ 4276c42a7b7eSSam Leffler if (!sc->sc_invalid) { 4277c42a7b7eSSam Leffler /* don't touch the hardware if marked invalid */ 42784a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 42794a3ac3fcSSam Leffler __func__, sc->sc_bhalq, 42804a3ac3fcSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq), 42814a3ac3fcSSam Leffler NULL); 4282c42a7b7eSSam Leffler (void) ath_hal_stoptxdma(ah, sc->sc_bhalq); 4283c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4284c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4285c42a7b7eSSam Leffler ath_tx_stopdma(sc, &sc->sc_txq[i]); 4286c42a7b7eSSam Leffler } 4287c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4288c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4289c42a7b7eSSam Leffler ath_tx_draintxq(sc, &sc->sc_txq[i]); 42904a3ac3fcSSam Leffler #ifdef ATH_DEBUG 42914a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 42924a3ac3fcSSam Leffler struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); 42934a3ac3fcSSam Leffler if (bf != NULL && bf->bf_m != NULL) { 42946902009eSSam Leffler ath_printtxbuf(sc, bf, sc->sc_bhalq, 0, 429565f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 429665f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 4297e40b6ab1SSam Leffler ieee80211_dump_pkt(ifp->if_l2com, 4298e40b6ab1SSam Leffler mtod(bf->bf_m, const uint8_t *), bf->bf_m->m_len, 4299e40b6ab1SSam Leffler 0, -1); 43004a3ac3fcSSam Leffler } 43014a3ac3fcSSam Leffler } 43024a3ac3fcSSam Leffler #endif /* ATH_DEBUG */ 430313f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 43042e986da5SSam Leffler sc->sc_wd_timer = 0; 43055591b213SSam Leffler } 43065591b213SSam Leffler 43075591b213SSam Leffler /* 43085591b213SSam Leffler * Disable the receive h/w in preparation for a reset. 43095591b213SSam Leffler */ 43105591b213SSam Leffler static void 43115591b213SSam Leffler ath_stoprecv(struct ath_softc *sc) 43125591b213SSam Leffler { 43138cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 4314c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 4315c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 43165591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 43175591b213SSam Leffler 43185591b213SSam Leffler ath_hal_stoppcurecv(ah); /* disable PCU */ 43195591b213SSam Leffler ath_hal_setrxfilter(ah, 0); /* clear recv filter */ 43205591b213SSam Leffler ath_hal_stopdmarecv(ah); /* disable DMA engine */ 4321c42a7b7eSSam Leffler DELAY(3000); /* 3ms is long enough for 1 frame */ 4322a585a9a1SSam Leffler #ifdef ATH_DEBUG 4323c42a7b7eSSam Leffler if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) { 43245591b213SSam Leffler struct ath_buf *bf; 43257a4c5ed9SSam Leffler u_int ix; 43265591b213SSam Leffler 4327e325e530SSam Leffler printf("%s: rx queue %p, link %p\n", __func__, 432830310634SPeter Wemm (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); 43297a4c5ed9SSam Leffler ix = 0; 4330c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 43318cec0ab9SSam Leffler struct ath_desc *ds = bf->bf_desc; 433265f9edeeSSam Leffler struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; 4333c42a7b7eSSam Leffler HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, 433465f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 4335c42a7b7eSSam Leffler if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL)) 43366902009eSSam Leffler ath_printrxbuf(sc, bf, ix, status == HAL_OK); 43377a4c5ed9SSam Leffler ix++; 43385591b213SSam Leffler } 43395591b213SSam Leffler } 43405591b213SSam Leffler #endif 434168e8e04eSSam Leffler if (sc->sc_rxpending != NULL) { 434268e8e04eSSam Leffler m_freem(sc->sc_rxpending); 434368e8e04eSSam Leffler sc->sc_rxpending = NULL; 434468e8e04eSSam Leffler } 43455591b213SSam Leffler sc->sc_rxlink = NULL; /* just in case */ 43468cec0ab9SSam Leffler #undef PA2DESC 43475591b213SSam Leffler } 43485591b213SSam Leffler 43495591b213SSam Leffler /* 43505591b213SSam Leffler * Enable the receive h/w following a reset. 43515591b213SSam Leffler */ 43525591b213SSam Leffler static int 43535591b213SSam Leffler ath_startrecv(struct ath_softc *sc) 43545591b213SSam Leffler { 43555591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 43565591b213SSam Leffler struct ath_buf *bf; 43575591b213SSam Leffler 43585591b213SSam Leffler sc->sc_rxlink = NULL; 435968e8e04eSSam Leffler sc->sc_rxpending = NULL; 4360c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 43615591b213SSam Leffler int error = ath_rxbuf_init(sc, bf); 43625591b213SSam Leffler if (error != 0) { 4363c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, 4364c42a7b7eSSam Leffler "%s: ath_rxbuf_init failed %d\n", 4365c42a7b7eSSam Leffler __func__, error); 43665591b213SSam Leffler return error; 43675591b213SSam Leffler } 43685591b213SSam Leffler } 43695591b213SSam Leffler 4370c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 43715591b213SSam Leffler ath_hal_putrxbuf(ah, bf->bf_daddr); 43725591b213SSam Leffler ath_hal_rxena(ah); /* enable recv descriptors */ 43735591b213SSam Leffler ath_mode_init(sc); /* set filters, etc. */ 43745591b213SSam Leffler ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ 43755591b213SSam Leffler return 0; 43765591b213SSam Leffler } 43775591b213SSam Leffler 43785591b213SSam Leffler /* 4379c42a7b7eSSam Leffler * Update internal state after a channel change. 4380c42a7b7eSSam Leffler */ 4381c42a7b7eSSam Leffler static void 4382c42a7b7eSSam Leffler ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan) 4383c42a7b7eSSam Leffler { 4384c42a7b7eSSam Leffler enum ieee80211_phymode mode; 4385c42a7b7eSSam Leffler 4386c42a7b7eSSam Leffler /* 4387c42a7b7eSSam Leffler * Change channels and update the h/w rate map 4388c42a7b7eSSam Leffler * if we're switching; e.g. 11a to 11b/g. 4389c42a7b7eSSam Leffler */ 439068e8e04eSSam Leffler mode = ieee80211_chan2mode(chan); 4391c42a7b7eSSam Leffler if (mode != sc->sc_curmode) 4392c42a7b7eSSam Leffler ath_setcurmode(sc, mode); 439359efa8b5SSam Leffler sc->sc_curchan = chan; 4394c42a7b7eSSam Leffler } 4395c42a7b7eSSam Leffler 4396c42a7b7eSSam Leffler /* 43975591b213SSam Leffler * Set/change channels. If the channel is really being changed, 43984fa8d4efSDaniel Eischen * it's done by resetting the chip. To accomplish this we must 43995591b213SSam Leffler * first cleanup any pending DMA, then restart stuff after a la 44005591b213SSam Leffler * ath_init. 44015591b213SSam Leffler */ 44025591b213SSam Leffler static int 44035591b213SSam Leffler ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) 44045591b213SSam Leffler { 4405b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 4406b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 44075591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4408c42a7b7eSSam Leffler 440959efa8b5SSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %u (%u MHz, flags 0x%x)\n", 441059efa8b5SSam Leffler __func__, ieee80211_chan2ieee(ic, chan), 441159efa8b5SSam Leffler chan->ic_freq, chan->ic_flags); 441259efa8b5SSam Leffler if (chan != sc->sc_curchan) { 4413c42a7b7eSSam Leffler HAL_STATUS status; 44145591b213SSam Leffler /* 44155591b213SSam Leffler * To switch channels clear any pending DMA operations; 44165591b213SSam Leffler * wait long enough for the RX fifo to drain, reset the 44175591b213SSam Leffler * hardware at the new frequency, and then re-enable 44185591b213SSam Leffler * the relevant bits of the h/w. 44195591b213SSam Leffler */ 44205591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 44215591b213SSam Leffler ath_draintxq(sc); /* clear pending tx frames */ 44225591b213SSam Leffler ath_stoprecv(sc); /* turn off frame recv */ 442359efa8b5SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, chan, AH_TRUE, &status)) { 4424b032f27cSSam Leffler if_printf(ifp, "%s: unable to reset " 442579649302SGavin Atkinson "channel %u (%u MHz, flags 0x%x), hal status %u\n", 442659efa8b5SSam Leffler __func__, ieee80211_chan2ieee(ic, chan), 442759efa8b5SSam Leffler chan->ic_freq, chan->ic_flags, status); 44285591b213SSam Leffler return EIO; 44295591b213SSam Leffler } 4430c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 4431c42a7b7eSSam Leffler 4432*48237774SAdrian Chadd /* Let DFS at it in case it's a DFS channel */ 4433*48237774SAdrian Chadd ath_dfs_radar_enable(sc, ic->ic_curchan); 4434*48237774SAdrian Chadd 44355591b213SSam Leffler /* 44365591b213SSam Leffler * Re-enable rx framework. 44375591b213SSam Leffler */ 44385591b213SSam Leffler if (ath_startrecv(sc) != 0) { 4439b032f27cSSam Leffler if_printf(ifp, "%s: unable to restart recv logic\n", 4440b032f27cSSam Leffler __func__); 44415591b213SSam Leffler return EIO; 44425591b213SSam Leffler } 44435591b213SSam Leffler 44445591b213SSam Leffler /* 44455591b213SSam Leffler * Change channels and update the h/w rate map 44465591b213SSam Leffler * if we're switching; e.g. 11a to 11b/g. 44475591b213SSam Leffler */ 4448c42a7b7eSSam Leffler ath_chan_change(sc, chan); 44490a915fadSSam Leffler 44500a915fadSSam Leffler /* 44510a915fadSSam Leffler * Re-enable interrupts. 44520a915fadSSam Leffler */ 44530a915fadSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 44545591b213SSam Leffler } 44555591b213SSam Leffler return 0; 44565591b213SSam Leffler } 44575591b213SSam Leffler 44585591b213SSam Leffler /* 44595591b213SSam Leffler * Periodically recalibrate the PHY to account 44605591b213SSam Leffler * for temperature/environment changes. 44615591b213SSam Leffler */ 44625591b213SSam Leffler static void 44635591b213SSam Leffler ath_calibrate(void *arg) 44645591b213SSam Leffler { 44655591b213SSam Leffler struct ath_softc *sc = arg; 44665591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 44672dc7fcc4SSam Leffler struct ifnet *ifp = sc->sc_ifp; 44688d91de92SSam Leffler struct ieee80211com *ic = ifp->if_l2com; 44692dc7fcc4SSam Leffler HAL_BOOL longCal, isCalDone; 4470a108ab63SAdrian Chadd HAL_BOOL aniCal, shortCal = AH_FALSE; 44712dc7fcc4SSam Leffler int nextcal; 44725591b213SSam Leffler 44738d91de92SSam Leffler if (ic->ic_flags & IEEE80211_F_SCAN) /* defer, off channel */ 44748d91de92SSam Leffler goto restart; 44752dc7fcc4SSam Leffler longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz); 4476a108ab63SAdrian Chadd aniCal = (ticks - sc->sc_lastani >= ath_anicalinterval*hz/1000); 4477a108ab63SAdrian Chadd if (sc->sc_doresetcal) 4478a108ab63SAdrian Chadd shortCal = (ticks - sc->sc_lastshortcal >= ath_shortcalinterval*hz/1000); 4479a108ab63SAdrian Chadd 4480a108ab63SAdrian Chadd DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: shortCal=%d; longCal=%d; aniCal=%d\n", __func__, shortCal, longCal, aniCal); 4481a108ab63SAdrian Chadd if (aniCal) { 4482a108ab63SAdrian Chadd sc->sc_stats.ast_ani_cal++; 4483a108ab63SAdrian Chadd sc->sc_lastani = ticks; 4484a108ab63SAdrian Chadd ath_hal_ani_poll(ah, sc->sc_curchan); 4485a108ab63SAdrian Chadd } 4486a108ab63SAdrian Chadd 44872dc7fcc4SSam Leffler if (longCal) { 44885591b213SSam Leffler sc->sc_stats.ast_per_cal++; 44898197f57eSAdrian Chadd sc->sc_lastlongcal = ticks; 44905591b213SSam Leffler if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { 44915591b213SSam Leffler /* 44925591b213SSam Leffler * Rfgain is out of bounds, reset the chip 44935591b213SSam Leffler * to load new gain values. 44945591b213SSam Leffler */ 4495370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 4496370572d9SSam Leffler "%s: rfgain change\n", __func__); 44975591b213SSam Leffler sc->sc_stats.ast_per_rfgain++; 44982dc7fcc4SSam Leffler ath_reset(ifp); 44995591b213SSam Leffler } 45002dc7fcc4SSam Leffler /* 45012dc7fcc4SSam Leffler * If this long cal is after an idle period, then 45022dc7fcc4SSam Leffler * reset the data collection state so we start fresh. 45032dc7fcc4SSam Leffler */ 45042dc7fcc4SSam Leffler if (sc->sc_resetcal) { 450559efa8b5SSam Leffler (void) ath_hal_calreset(ah, sc->sc_curchan); 45062dc7fcc4SSam Leffler sc->sc_lastcalreset = ticks; 4507a108ab63SAdrian Chadd sc->sc_lastshortcal = ticks; 45082dc7fcc4SSam Leffler sc->sc_resetcal = 0; 4509a108ab63SAdrian Chadd sc->sc_doresetcal = AH_TRUE; 45102dc7fcc4SSam Leffler } 45112dc7fcc4SSam Leffler } 4512a108ab63SAdrian Chadd 4513a108ab63SAdrian Chadd /* Only call if we're doing a short/long cal, not for ANI calibration */ 4514a108ab63SAdrian Chadd if (shortCal || longCal) { 451559efa8b5SSam Leffler if (ath_hal_calibrateN(ah, sc->sc_curchan, longCal, &isCalDone)) { 45162dc7fcc4SSam Leffler if (longCal) { 45172dc7fcc4SSam Leffler /* 45182dc7fcc4SSam Leffler * Calibrate noise floor data again in case of change. 45192dc7fcc4SSam Leffler */ 45202dc7fcc4SSam Leffler ath_hal_process_noisefloor(ah); 45212dc7fcc4SSam Leffler } 45222dc7fcc4SSam Leffler } else { 4523c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 4524c42a7b7eSSam Leffler "%s: calibration of channel %u failed\n", 452559efa8b5SSam Leffler __func__, sc->sc_curchan->ic_freq); 45265591b213SSam Leffler sc->sc_stats.ast_per_calfail++; 45275591b213SSam Leffler } 4528a108ab63SAdrian Chadd if (shortCal) 4529a108ab63SAdrian Chadd sc->sc_lastshortcal = ticks; 4530a108ab63SAdrian Chadd } 45312dc7fcc4SSam Leffler if (!isCalDone) { 45328d91de92SSam Leffler restart: 45337b0c77ecSSam Leffler /* 45342dc7fcc4SSam Leffler * Use a shorter interval to potentially collect multiple 45352dc7fcc4SSam Leffler * data samples required to complete calibration. Once 45362dc7fcc4SSam Leffler * we're told the work is done we drop back to a longer 45372dc7fcc4SSam Leffler * interval between requests. We're more aggressive doing 45382dc7fcc4SSam Leffler * work when operating as an AP to improve operation right 45392dc7fcc4SSam Leffler * after startup. 45407b0c77ecSSam Leffler */ 4541a108ab63SAdrian Chadd sc->sc_lastshortcal = ticks; 4542a108ab63SAdrian Chadd nextcal = ath_shortcalinterval*hz/1000; 45432dc7fcc4SSam Leffler if (sc->sc_opmode != HAL_M_HOSTAP) 45442dc7fcc4SSam Leffler nextcal *= 10; 4545a108ab63SAdrian Chadd sc->sc_doresetcal = AH_TRUE; 45462dc7fcc4SSam Leffler } else { 4547a108ab63SAdrian Chadd /* nextcal should be the shortest time for next event */ 45482dc7fcc4SSam Leffler nextcal = ath_longcalinterval*hz; 45492dc7fcc4SSam Leffler if (sc->sc_lastcalreset == 0) 45502dc7fcc4SSam Leffler sc->sc_lastcalreset = sc->sc_lastlongcal; 45512dc7fcc4SSam Leffler else if (ticks - sc->sc_lastcalreset >= ath_resetcalinterval*hz) 45522dc7fcc4SSam Leffler sc->sc_resetcal = 1; /* setup reset next trip */ 4553a108ab63SAdrian Chadd sc->sc_doresetcal = AH_FALSE; 4554bd5a9920SSam Leffler } 4555a108ab63SAdrian Chadd /* ANI calibration may occur more often than short/long/resetcal */ 4556a108ab63SAdrian Chadd if (ath_anicalinterval > 0) 4557a108ab63SAdrian Chadd nextcal = MIN(nextcal, ath_anicalinterval*hz/1000); 4558bd5a9920SSam Leffler 45592dc7fcc4SSam Leffler if (nextcal != 0) { 45602dc7fcc4SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: next +%u (%sisCalDone)\n", 45612dc7fcc4SSam Leffler __func__, nextcal, isCalDone ? "" : "!"); 45622dc7fcc4SSam Leffler callout_reset(&sc->sc_cal_ch, nextcal, ath_calibrate, sc); 45632dc7fcc4SSam Leffler } else { 45642dc7fcc4SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: calibration disabled\n", 45652dc7fcc4SSam Leffler __func__); 45662dc7fcc4SSam Leffler /* NB: don't rearm timer */ 45672dc7fcc4SSam Leffler } 45685591b213SSam Leffler } 45695591b213SSam Leffler 457068e8e04eSSam Leffler static void 457168e8e04eSSam Leffler ath_scan_start(struct ieee80211com *ic) 457268e8e04eSSam Leffler { 457368e8e04eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 457468e8e04eSSam Leffler struct ath_softc *sc = ifp->if_softc; 457568e8e04eSSam Leffler struct ath_hal *ah = sc->sc_ah; 457668e8e04eSSam Leffler u_int32_t rfilt; 457768e8e04eSSam Leffler 457868e8e04eSSam Leffler /* XXX calibration timer? */ 457968e8e04eSSam Leffler 458068e8e04eSSam Leffler sc->sc_scanning = 1; 458168e8e04eSSam Leffler sc->sc_syncbeacon = 0; 458268e8e04eSSam Leffler rfilt = ath_calcrxfilter(sc); 458368e8e04eSSam Leffler ath_hal_setrxfilter(ah, rfilt); 458468e8e04eSSam Leffler ath_hal_setassocid(ah, ifp->if_broadcastaddr, 0); 458568e8e04eSSam Leffler 458668e8e04eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0\n", 458768e8e04eSSam Leffler __func__, rfilt, ether_sprintf(ifp->if_broadcastaddr)); 458868e8e04eSSam Leffler } 458968e8e04eSSam Leffler 459068e8e04eSSam Leffler static void 459168e8e04eSSam Leffler ath_scan_end(struct ieee80211com *ic) 459268e8e04eSSam Leffler { 459368e8e04eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 459468e8e04eSSam Leffler struct ath_softc *sc = ifp->if_softc; 459568e8e04eSSam Leffler struct ath_hal *ah = sc->sc_ah; 459668e8e04eSSam Leffler u_int32_t rfilt; 459768e8e04eSSam Leffler 459868e8e04eSSam Leffler sc->sc_scanning = 0; 459968e8e04eSSam Leffler rfilt = ath_calcrxfilter(sc); 460068e8e04eSSam Leffler ath_hal_setrxfilter(ah, rfilt); 460168e8e04eSSam Leffler ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid); 460268e8e04eSSam Leffler 460368e8e04eSSam Leffler ath_hal_process_noisefloor(ah); 460468e8e04eSSam Leffler 460568e8e04eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n", 460668e8e04eSSam Leffler __func__, rfilt, ether_sprintf(sc->sc_curbssid), 460768e8e04eSSam Leffler sc->sc_curaid); 460868e8e04eSSam Leffler } 460968e8e04eSSam Leffler 461068e8e04eSSam Leffler static void 461168e8e04eSSam Leffler ath_set_channel(struct ieee80211com *ic) 461268e8e04eSSam Leffler { 461368e8e04eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 461468e8e04eSSam Leffler struct ath_softc *sc = ifp->if_softc; 461568e8e04eSSam Leffler 461668e8e04eSSam Leffler (void) ath_chan_set(sc, ic->ic_curchan); 461768e8e04eSSam Leffler /* 461868e8e04eSSam Leffler * If we are returning to our bss channel then mark state 461968e8e04eSSam Leffler * so the next recv'd beacon's tsf will be used to sync the 462068e8e04eSSam Leffler * beacon timers. Note that since we only hear beacons in 462168e8e04eSSam Leffler * sta/ibss mode this has no effect in other operating modes. 462268e8e04eSSam Leffler */ 462368e8e04eSSam Leffler if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan) 462468e8e04eSSam Leffler sc->sc_syncbeacon = 1; 462568e8e04eSSam Leffler } 462668e8e04eSSam Leffler 4627b032f27cSSam Leffler /* 4628b032f27cSSam Leffler * Walk the vap list and check if there any vap's in RUN state. 4629b032f27cSSam Leffler */ 46305591b213SSam Leffler static int 4631b032f27cSSam Leffler ath_isanyrunningvaps(struct ieee80211vap *this) 46325591b213SSam Leffler { 4633b032f27cSSam Leffler struct ieee80211com *ic = this->iv_ic; 4634b032f27cSSam Leffler struct ieee80211vap *vap; 4635b032f27cSSam Leffler 4636b032f27cSSam Leffler IEEE80211_LOCK_ASSERT(ic); 4637b032f27cSSam Leffler 4638b032f27cSSam Leffler TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 4639309a3e45SSam Leffler if (vap != this && vap->iv_state >= IEEE80211_S_RUN) 4640b032f27cSSam Leffler return 1; 4641b032f27cSSam Leffler } 4642b032f27cSSam Leffler return 0; 4643b032f27cSSam Leffler } 4644b032f27cSSam Leffler 4645b032f27cSSam Leffler static int 4646b032f27cSSam Leffler ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 4647b032f27cSSam Leffler { 4648b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 4649b032f27cSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 4650b032f27cSSam Leffler struct ath_vap *avp = ATH_VAP(vap); 465145bbf62fSSam Leffler struct ath_hal *ah = sc->sc_ah; 4652b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 465368e8e04eSSam Leffler int i, error, stamode; 46545591b213SSam Leffler u_int32_t rfilt; 46555591b213SSam Leffler static const HAL_LED_STATE leds[] = { 46565591b213SSam Leffler HAL_LED_INIT, /* IEEE80211_S_INIT */ 46575591b213SSam Leffler HAL_LED_SCAN, /* IEEE80211_S_SCAN */ 46585591b213SSam Leffler HAL_LED_AUTH, /* IEEE80211_S_AUTH */ 46595591b213SSam Leffler HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */ 466077d5e068SSam Leffler HAL_LED_RUN, /* IEEE80211_S_CAC */ 46615591b213SSam Leffler HAL_LED_RUN, /* IEEE80211_S_RUN */ 466277d5e068SSam Leffler HAL_LED_RUN, /* IEEE80211_S_CSA */ 466377d5e068SSam Leffler HAL_LED_RUN, /* IEEE80211_S_SLEEP */ 46645591b213SSam Leffler }; 46655591b213SSam Leffler 4666c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__, 4667b032f27cSSam Leffler ieee80211_state_name[vap->iv_state], 4668c42a7b7eSSam Leffler ieee80211_state_name[nstate]); 46695591b213SSam Leffler 46702e986da5SSam Leffler callout_drain(&sc->sc_cal_ch); 46715591b213SSam Leffler ath_hal_setledstate(ah, leds[nstate]); /* set LED */ 46725591b213SSam Leffler 4673b032f27cSSam Leffler if (nstate == IEEE80211_S_SCAN) { 467458769f58SSam Leffler /* 4675b032f27cSSam Leffler * Scanning: turn off beacon miss and don't beacon. 4676b032f27cSSam Leffler * Mark beacon state so when we reach RUN state we'll 4677b032f27cSSam Leffler * [re]setup beacons. Unblock the task q thread so 4678b032f27cSSam Leffler * deferred interrupt processing is done. 467958769f58SSam Leffler */ 4680b032f27cSSam Leffler ath_hal_intrset(ah, 4681b032f27cSSam Leffler sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); 46825591b213SSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 4683b032f27cSSam Leffler sc->sc_beacons = 0; 4684b032f27cSSam Leffler taskqueue_unblock(sc->sc_tq); 46855591b213SSam Leffler } 46865591b213SSam Leffler 4687b032f27cSSam Leffler ni = vap->iv_bss; 468868e8e04eSSam Leffler rfilt = ath_calcrxfilter(sc); 4689b032f27cSSam Leffler stamode = (vap->iv_opmode == IEEE80211_M_STA || 46907b916f89SSam Leffler vap->iv_opmode == IEEE80211_M_AHDEMO || 4691b032f27cSSam Leffler vap->iv_opmode == IEEE80211_M_IBSS); 469268e8e04eSSam Leffler if (stamode && nstate == IEEE80211_S_RUN) { 469368e8e04eSSam Leffler sc->sc_curaid = ni->ni_associd; 469468e8e04eSSam Leffler IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid); 4695b032f27cSSam Leffler ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid); 4696b032f27cSSam Leffler } 469768e8e04eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n", 4698b032f27cSSam Leffler __func__, rfilt, ether_sprintf(sc->sc_curbssid), sc->sc_curaid); 469968e8e04eSSam Leffler ath_hal_setrxfilter(ah, rfilt); 470068e8e04eSSam Leffler 4701b032f27cSSam Leffler /* XXX is this to restore keycache on resume? */ 4702b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_STA && 4703b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_PRIVACY)) { 47045591b213SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) 47055591b213SSam Leffler if (ath_hal_keyisvalid(ah, i)) 470668e8e04eSSam Leffler ath_hal_keysetmac(ah, i, ni->ni_bssid); 47075591b213SSam Leffler } 4708b032f27cSSam Leffler 4709b032f27cSSam Leffler /* 4710b032f27cSSam Leffler * Invoke the parent method to do net80211 work. 4711b032f27cSSam Leffler */ 4712b032f27cSSam Leffler error = avp->av_newstate(vap, nstate, arg); 4713b032f27cSSam Leffler if (error != 0) 4714b032f27cSSam Leffler goto bad; 4715c42a7b7eSSam Leffler 471668e8e04eSSam Leffler if (nstate == IEEE80211_S_RUN) { 4717b032f27cSSam Leffler /* NB: collect bss node again, it may have changed */ 4718b032f27cSSam Leffler ni = vap->iv_bss; 47195591b213SSam Leffler 4720b032f27cSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 4721b032f27cSSam Leffler "%s(RUN): iv_flags 0x%08x bintvl %d bssid %s " 4722b032f27cSSam Leffler "capinfo 0x%04x chan %d\n", __func__, 4723b032f27cSSam Leffler vap->iv_flags, ni->ni_intval, ether_sprintf(ni->ni_bssid), 4724b032f27cSSam Leffler ni->ni_capinfo, ieee80211_chan2ieee(ic, ic->ic_curchan)); 4725b032f27cSSam Leffler 4726b032f27cSSam Leffler switch (vap->iv_opmode) { 4727584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 472810ad9a77SSam Leffler case IEEE80211_M_AHDEMO: 472910ad9a77SSam Leffler if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 473010ad9a77SSam Leffler break; 473110ad9a77SSam Leffler /* fall thru... */ 473210ad9a77SSam Leffler #endif 4733e8fd88a3SSam Leffler case IEEE80211_M_HOSTAP: 4734e8fd88a3SSam Leffler case IEEE80211_M_IBSS: 473559aa14a9SRui Paulo case IEEE80211_M_MBSS: 47365591b213SSam Leffler /* 4737e8fd88a3SSam Leffler * Allocate and setup the beacon frame. 4738e8fd88a3SSam Leffler * 4739f818612bSSam Leffler * Stop any previous beacon DMA. This may be 4740f818612bSSam Leffler * necessary, for example, when an ibss merge 4741f818612bSSam Leffler * causes reconfiguration; there will be a state 4742f818612bSSam Leffler * transition from RUN->RUN that means we may 4743f818612bSSam Leffler * be called with beacon transmission active. 4744f818612bSSam Leffler */ 4745f818612bSSam Leffler ath_hal_stoptxdma(ah, sc->sc_bhalq); 4746b032f27cSSam Leffler 47475591b213SSam Leffler error = ath_beacon_alloc(sc, ni); 47485591b213SSam Leffler if (error != 0) 47495591b213SSam Leffler goto bad; 47507a04dc27SSam Leffler /* 475180d939bfSSam Leffler * If joining an adhoc network defer beacon timer 475280d939bfSSam Leffler * configuration to the next beacon frame so we 475380d939bfSSam Leffler * have a current TSF to use. Otherwise we're 4754b032f27cSSam Leffler * starting an ibss/bss so there's no need to delay; 4755b032f27cSSam Leffler * if this is the first vap moving to RUN state, then 4756b032f27cSSam Leffler * beacon state needs to be [re]configured. 47577a04dc27SSam Leffler */ 4758b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS && 4759b032f27cSSam Leffler ni->ni_tstamp.tsf != 0) { 476080d939bfSSam Leffler sc->sc_syncbeacon = 1; 4761b032f27cSSam Leffler } else if (!sc->sc_beacons) { 4762584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 476310ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) 476410ad9a77SSam Leffler ath_tdma_config(sc, vap); 476510ad9a77SSam Leffler else 476610ad9a77SSam Leffler #endif 4767b032f27cSSam Leffler ath_beacon_config(sc, vap); 4768b032f27cSSam Leffler sc->sc_beacons = 1; 4769b032f27cSSam Leffler } 4770e8fd88a3SSam Leffler break; 4771e8fd88a3SSam Leffler case IEEE80211_M_STA: 4772e8fd88a3SSam Leffler /* 477380d939bfSSam Leffler * Defer beacon timer configuration to the next 477480d939bfSSam Leffler * beacon frame so we have a current TSF to use 477580d939bfSSam Leffler * (any TSF collected when scanning is likely old). 47767a04dc27SSam Leffler */ 477780d939bfSSam Leffler sc->sc_syncbeacon = 1; 4778e8fd88a3SSam Leffler break; 4779b032f27cSSam Leffler case IEEE80211_M_MONITOR: 4780b032f27cSSam Leffler /* 4781b032f27cSSam Leffler * Monitor mode vaps have only INIT->RUN and RUN->RUN 4782b032f27cSSam Leffler * transitions so we must re-enable interrupts here to 4783b032f27cSSam Leffler * handle the case of a single monitor mode vap. 4784b032f27cSSam Leffler */ 4785b032f27cSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 4786b032f27cSSam Leffler break; 4787b032f27cSSam Leffler case IEEE80211_M_WDS: 4788b032f27cSSam Leffler break; 4789e8fd88a3SSam Leffler default: 4790e8fd88a3SSam Leffler break; 47915591b213SSam Leffler } 47925591b213SSam Leffler /* 47937b0c77ecSSam Leffler * Let the hal process statistics collected during a 47947b0c77ecSSam Leffler * scan so it can provide calibrated noise floor data. 47957b0c77ecSSam Leffler */ 47967b0c77ecSSam Leffler ath_hal_process_noisefloor(ah); 47977b0c77ecSSam Leffler /* 4798ffa2cab6SSam Leffler * Reset rssi stats; maybe not the best place... 4799ffa2cab6SSam Leffler */ 4800ffa2cab6SSam Leffler sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; 4801ffa2cab6SSam Leffler sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; 4802ffa2cab6SSam Leffler sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; 480345bbf62fSSam Leffler /* 4804b032f27cSSam Leffler * Finally, start any timers and the task q thread 4805b032f27cSSam Leffler * (in case we didn't go through SCAN state). 480645bbf62fSSam Leffler */ 48072dc7fcc4SSam Leffler if (ath_longcalinterval != 0) { 4808c42a7b7eSSam Leffler /* start periodic recalibration timer */ 48092dc7fcc4SSam Leffler callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc); 48102dc7fcc4SSam Leffler } else { 48112dc7fcc4SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 48122dc7fcc4SSam Leffler "%s: calibration disabled\n", __func__); 4813c42a7b7eSSam Leffler } 4814b032f27cSSam Leffler taskqueue_unblock(sc->sc_tq); 4815b032f27cSSam Leffler } else if (nstate == IEEE80211_S_INIT) { 4816b032f27cSSam Leffler /* 4817b032f27cSSam Leffler * If there are no vaps left in RUN state then 4818b032f27cSSam Leffler * shutdown host/driver operation: 4819b032f27cSSam Leffler * o disable interrupts 4820b032f27cSSam Leffler * o disable the task queue thread 4821b032f27cSSam Leffler * o mark beacon processing as stopped 4822b032f27cSSam Leffler */ 4823b032f27cSSam Leffler if (!ath_isanyrunningvaps(vap)) { 4824b032f27cSSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 4825b032f27cSSam Leffler /* disable interrupts */ 4826b032f27cSSam Leffler ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL); 4827b032f27cSSam Leffler taskqueue_block(sc->sc_tq); 4828b032f27cSSam Leffler sc->sc_beacons = 0; 4829b032f27cSSam Leffler } 4830584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 483110ad9a77SSam Leffler ath_hal_setcca(ah, AH_TRUE); 483210ad9a77SSam Leffler #endif 4833b032f27cSSam Leffler } 48345591b213SSam Leffler bad: 48355591b213SSam Leffler return error; 48365591b213SSam Leffler } 48375591b213SSam Leffler 48385591b213SSam Leffler /* 4839e8fd88a3SSam Leffler * Allocate a key cache slot to the station so we can 4840e8fd88a3SSam Leffler * setup a mapping from key index to node. The key cache 4841e8fd88a3SSam Leffler * slot is needed for managing antenna state and for 4842e8fd88a3SSam Leffler * compression when stations do not use crypto. We do 4843e8fd88a3SSam Leffler * it uniliaterally here; if crypto is employed this slot 4844e8fd88a3SSam Leffler * will be reassigned. 4845e8fd88a3SSam Leffler */ 4846e8fd88a3SSam Leffler static void 4847e8fd88a3SSam Leffler ath_setup_stationkey(struct ieee80211_node *ni) 4848e8fd88a3SSam Leffler { 4849b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 4850b032f27cSSam Leffler struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; 4851c1225b52SSam Leffler ieee80211_keyix keyix, rxkeyix; 4852e8fd88a3SSam Leffler 4853b032f27cSSam Leffler if (!ath_key_alloc(vap, &ni->ni_ucastkey, &keyix, &rxkeyix)) { 4854e8fd88a3SSam Leffler /* 4855e8fd88a3SSam Leffler * Key cache is full; we'll fall back to doing 4856e8fd88a3SSam Leffler * the more expensive lookup in software. Note 4857e8fd88a3SSam Leffler * this also means no h/w compression. 4858e8fd88a3SSam Leffler */ 4859e8fd88a3SSam Leffler /* XXX msg+statistic */ 4860e8fd88a3SSam Leffler } else { 4861c1225b52SSam Leffler /* XXX locking? */ 4862e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix = keyix; 4863c1225b52SSam Leffler ni->ni_ucastkey.wk_rxkeyix = rxkeyix; 486433052833SSam Leffler /* NB: must mark device key to get called back on delete */ 486533052833SSam Leffler ni->ni_ucastkey.wk_flags |= IEEE80211_KEY_DEVKEY; 4866d3ac945bSSam Leffler IEEE80211_ADDR_COPY(ni->ni_ucastkey.wk_macaddr, ni->ni_macaddr); 4867e8fd88a3SSam Leffler /* NB: this will create a pass-thru key entry */ 4868d3ac945bSSam Leffler ath_keyset(sc, &ni->ni_ucastkey, vap->iv_bss); 4869e8fd88a3SSam Leffler } 4870e8fd88a3SSam Leffler } 4871e8fd88a3SSam Leffler 4872e8fd88a3SSam Leffler /* 48735591b213SSam Leffler * Setup driver-specific state for a newly associated node. 48745591b213SSam Leffler * Note that we're called also on a re-associate, the isnew 48755591b213SSam Leffler * param tells us if this is the first time or not. 48765591b213SSam Leffler */ 48775591b213SSam Leffler static void 4878e9962332SSam Leffler ath_newassoc(struct ieee80211_node *ni, int isnew) 48795591b213SSam Leffler { 4880b032f27cSSam Leffler struct ath_node *an = ATH_NODE(ni); 4881b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 4882b032f27cSSam Leffler struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; 4883c62362cbSSam Leffler const struct ieee80211_txparam *tp = ni->ni_txparms; 48845591b213SSam Leffler 4885ab06fdf2SSam Leffler an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate); 4886ab06fdf2SSam Leffler an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate); 4887b032f27cSSam Leffler 4888b032f27cSSam Leffler ath_rate_newassoc(sc, an, isnew); 4889e8fd88a3SSam Leffler if (isnew && 4890b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey && 4891b032f27cSSam Leffler ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE) 4892e8fd88a3SSam Leffler ath_setup_stationkey(ni); 4893e8fd88a3SSam Leffler } 48945591b213SSam Leffler 48955591b213SSam Leffler static int 489659efa8b5SSam Leffler ath_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *reg, 4897b032f27cSSam Leffler int nchans, struct ieee80211_channel chans[]) 4898b032f27cSSam Leffler { 4899b032f27cSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 4900b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 490159efa8b5SSam Leffler HAL_STATUS status; 4902b032f27cSSam Leffler 4903033022a9SSam Leffler DPRINTF(sc, ATH_DEBUG_REGDOMAIN, 490459efa8b5SSam Leffler "%s: rd %u cc %u location %c%s\n", 490559efa8b5SSam Leffler __func__, reg->regdomain, reg->country, reg->location, 490659efa8b5SSam Leffler reg->ecm ? " ecm" : ""); 4907033022a9SSam Leffler 490859efa8b5SSam Leffler status = ath_hal_set_channels(ah, chans, nchans, 490959efa8b5SSam Leffler reg->country, reg->regdomain); 491059efa8b5SSam Leffler if (status != HAL_OK) { 491159efa8b5SSam Leffler DPRINTF(sc, ATH_DEBUG_REGDOMAIN, "%s: failed, status %u\n", 491259efa8b5SSam Leffler __func__, status); 491359efa8b5SSam Leffler return EINVAL; /* XXX */ 4914b032f27cSSam Leffler } 4915b032f27cSSam Leffler return 0; 4916b032f27cSSam Leffler } 4917b032f27cSSam Leffler 4918b032f27cSSam Leffler static void 4919b032f27cSSam Leffler ath_getradiocaps(struct ieee80211com *ic, 49205fe9f044SSam Leffler int maxchans, int *nchans, struct ieee80211_channel chans[]) 4921b032f27cSSam Leffler { 4922b032f27cSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 4923b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 4924b032f27cSSam Leffler 492559efa8b5SSam Leffler DPRINTF(sc, ATH_DEBUG_REGDOMAIN, "%s: use rd %u cc %d\n", 492659efa8b5SSam Leffler __func__, SKU_DEBUG, CTRY_DEFAULT); 4927033022a9SSam Leffler 492859efa8b5SSam Leffler /* XXX check return */ 492959efa8b5SSam Leffler (void) ath_hal_getchannels(ah, chans, maxchans, nchans, 493059efa8b5SSam Leffler HAL_MODE_ALL, CTRY_DEFAULT, SKU_DEBUG, AH_TRUE); 4931033022a9SSam Leffler 4932b032f27cSSam Leffler } 4933b032f27cSSam Leffler 4934b032f27cSSam Leffler static int 4935b032f27cSSam Leffler ath_getchannels(struct ath_softc *sc) 4936b032f27cSSam Leffler { 4937b032f27cSSam Leffler struct ifnet *ifp = sc->sc_ifp; 4938b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 4939b032f27cSSam Leffler struct ath_hal *ah = sc->sc_ah; 494059efa8b5SSam Leffler HAL_STATUS status; 4941b032f27cSSam Leffler 4942b032f27cSSam Leffler /* 494359efa8b5SSam Leffler * Collect channel set based on EEPROM contents. 4944b032f27cSSam Leffler */ 494559efa8b5SSam Leffler status = ath_hal_init_channels(ah, ic->ic_channels, IEEE80211_CHAN_MAX, 494659efa8b5SSam Leffler &ic->ic_nchans, HAL_MODE_ALL, CTRY_DEFAULT, SKU_NONE, AH_TRUE); 494759efa8b5SSam Leffler if (status != HAL_OK) { 494859efa8b5SSam Leffler if_printf(ifp, "%s: unable to collect channel list from hal, " 494959efa8b5SSam Leffler "status %d\n", __func__, status); 495059efa8b5SSam Leffler return EINVAL; 495159efa8b5SSam Leffler } 4952ca876918SSam Leffler (void) ath_hal_getregdomain(ah, &sc->sc_eerd); 4953ca876918SSam Leffler ath_hal_getcountrycode(ah, &sc->sc_eecc); /* NB: cannot fail */ 495459efa8b5SSam Leffler /* XXX map Atheros sku's to net80211 SKU's */ 495559efa8b5SSam Leffler /* XXX net80211 types too small */ 495659efa8b5SSam Leffler ic->ic_regdomain.regdomain = (uint16_t) sc->sc_eerd; 495759efa8b5SSam Leffler ic->ic_regdomain.country = (uint16_t) sc->sc_eecc; 495859efa8b5SSam Leffler ic->ic_regdomain.isocc[0] = ' '; /* XXX don't know */ 495959efa8b5SSam Leffler ic->ic_regdomain.isocc[1] = ' '; 496059efa8b5SSam Leffler 4961b032f27cSSam Leffler ic->ic_regdomain.ecm = 1; 4962b032f27cSSam Leffler ic->ic_regdomain.location = 'I'; 4963033022a9SSam Leffler 4964033022a9SSam Leffler DPRINTF(sc, ATH_DEBUG_REGDOMAIN, 496559efa8b5SSam Leffler "%s: eeprom rd %u cc %u (mapped rd %u cc %u) location %c%s\n", 4966033022a9SSam Leffler __func__, sc->sc_eerd, sc->sc_eecc, 4967033022a9SSam Leffler ic->ic_regdomain.regdomain, ic->ic_regdomain.country, 496859efa8b5SSam Leffler ic->ic_regdomain.location, ic->ic_regdomain.ecm ? " ecm" : ""); 49695591b213SSam Leffler return 0; 49705591b213SSam Leffler } 49715591b213SSam Leffler 4972c42a7b7eSSam Leffler static void 49733e50ec2cSSam Leffler ath_led_done(void *arg) 4974c42a7b7eSSam Leffler { 49753e50ec2cSSam Leffler struct ath_softc *sc = arg; 49763e50ec2cSSam Leffler 49773e50ec2cSSam Leffler sc->sc_blinking = 0; 49783e50ec2cSSam Leffler } 4979c42a7b7eSSam Leffler 4980c42a7b7eSSam Leffler /* 49813e50ec2cSSam Leffler * Turn the LED off: flip the pin and then set a timer so no 49823e50ec2cSSam Leffler * update will happen for the specified duration. 4983c42a7b7eSSam Leffler */ 49843e50ec2cSSam Leffler static void 49853e50ec2cSSam Leffler ath_led_off(void *arg) 49863e50ec2cSSam Leffler { 49873e50ec2cSSam Leffler struct ath_softc *sc = arg; 49883e50ec2cSSam Leffler 49893e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); 49903e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc); 4991c42a7b7eSSam Leffler } 49923e50ec2cSSam Leffler 49933e50ec2cSSam Leffler /* 49943e50ec2cSSam Leffler * Blink the LED according to the specified on/off times. 49953e50ec2cSSam Leffler */ 49963e50ec2cSSam Leffler static void 49973e50ec2cSSam Leffler ath_led_blink(struct ath_softc *sc, int on, int off) 49983e50ec2cSSam Leffler { 49993e50ec2cSSam Leffler DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off); 50003e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon); 50013e50ec2cSSam Leffler sc->sc_blinking = 1; 50023e50ec2cSSam Leffler sc->sc_ledoff = off; 50033e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc); 50043e50ec2cSSam Leffler } 50053e50ec2cSSam Leffler 50063e50ec2cSSam Leffler static void 500746d4d74cSSam Leffler ath_led_event(struct ath_softc *sc, int rix) 50083e50ec2cSSam Leffler { 50093e50ec2cSSam Leffler sc->sc_ledevent = ticks; /* time of last event */ 50103e50ec2cSSam Leffler if (sc->sc_blinking) /* don't interrupt active blink */ 50113e50ec2cSSam Leffler return; 501246d4d74cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[rix].ledon, sc->sc_hwmap[rix].ledoff); 5013c42a7b7eSSam Leffler } 5014c42a7b7eSSam Leffler 50156c4612b9SSam Leffler static int 50166c4612b9SSam Leffler ath_rate_setup(struct ath_softc *sc, u_int mode) 50176c4612b9SSam Leffler { 50186c4612b9SSam Leffler struct ath_hal *ah = sc->sc_ah; 50196c4612b9SSam Leffler const HAL_RATE_TABLE *rt; 50206c4612b9SSam Leffler 50216c4612b9SSam Leffler switch (mode) { 50226c4612b9SSam Leffler case IEEE80211_MODE_11A: 50236c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A); 50246c4612b9SSam Leffler break; 5025724c193aSSam Leffler case IEEE80211_MODE_HALF: 5026aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE); 5027aaa70f2fSSam Leffler break; 5028724c193aSSam Leffler case IEEE80211_MODE_QUARTER: 5029aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE); 5030aaa70f2fSSam Leffler break; 50316c4612b9SSam Leffler case IEEE80211_MODE_11B: 50326c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11B); 50336c4612b9SSam Leffler break; 50346c4612b9SSam Leffler case IEEE80211_MODE_11G: 50356c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11G); 50366c4612b9SSam Leffler break; 50376c4612b9SSam Leffler case IEEE80211_MODE_TURBO_A: 503868e8e04eSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_108A); 50396c4612b9SSam Leffler break; 50406c4612b9SSam Leffler case IEEE80211_MODE_TURBO_G: 50416c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_108G); 50426c4612b9SSam Leffler break; 504368e8e04eSSam Leffler case IEEE80211_MODE_STURBO_A: 504468e8e04eSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_TURBO); 504568e8e04eSSam Leffler break; 504668e8e04eSSam Leffler case IEEE80211_MODE_11NA: 504768e8e04eSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11NA_HT20); 504868e8e04eSSam Leffler break; 504968e8e04eSSam Leffler case IEEE80211_MODE_11NG: 505068e8e04eSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11NG_HT20); 505168e8e04eSSam Leffler break; 50526c4612b9SSam Leffler default: 50536c4612b9SSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid mode %u\n", 50546c4612b9SSam Leffler __func__, mode); 50556c4612b9SSam Leffler return 0; 50566c4612b9SSam Leffler } 50576c4612b9SSam Leffler sc->sc_rates[mode] = rt; 5058aaa70f2fSSam Leffler return (rt != NULL); 50595591b213SSam Leffler } 50605591b213SSam Leffler 50615591b213SSam Leffler static void 50625591b213SSam Leffler ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) 50635591b213SSam Leffler { 50643e50ec2cSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 50653e50ec2cSSam Leffler /* NB: on/off times from the Atheros NDIS driver, w/ permission */ 50663e50ec2cSSam Leffler static const struct { 50673e50ec2cSSam Leffler u_int rate; /* tx/rx 802.11 rate */ 50683e50ec2cSSam Leffler u_int16_t timeOn; /* LED on time (ms) */ 50693e50ec2cSSam Leffler u_int16_t timeOff; /* LED off time (ms) */ 50703e50ec2cSSam Leffler } blinkrates[] = { 50713e50ec2cSSam Leffler { 108, 40, 10 }, 50723e50ec2cSSam Leffler { 96, 44, 11 }, 50733e50ec2cSSam Leffler { 72, 50, 13 }, 50743e50ec2cSSam Leffler { 48, 57, 14 }, 50753e50ec2cSSam Leffler { 36, 67, 16 }, 50763e50ec2cSSam Leffler { 24, 80, 20 }, 50773e50ec2cSSam Leffler { 22, 100, 25 }, 50783e50ec2cSSam Leffler { 18, 133, 34 }, 50793e50ec2cSSam Leffler { 12, 160, 40 }, 50803e50ec2cSSam Leffler { 10, 200, 50 }, 50813e50ec2cSSam Leffler { 6, 240, 58 }, 50823e50ec2cSSam Leffler { 4, 267, 66 }, 50833e50ec2cSSam Leffler { 2, 400, 100 }, 50843e50ec2cSSam Leffler { 0, 500, 130 }, 5085724c193aSSam Leffler /* XXX half/quarter rates */ 50863e50ec2cSSam Leffler }; 50875591b213SSam Leffler const HAL_RATE_TABLE *rt; 50883e50ec2cSSam Leffler int i, j; 50895591b213SSam Leffler 50905591b213SSam Leffler memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); 50915591b213SSam Leffler rt = sc->sc_rates[mode]; 50925591b213SSam Leffler KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode)); 5093180f268dSSam Leffler for (i = 0; i < rt->rateCount; i++) { 5094180f268dSSam Leffler uint8_t ieeerate = rt->info[i].dot11Rate & IEEE80211_RATE_VAL; 5095180f268dSSam Leffler if (rt->info[i].phy != IEEE80211_T_HT) 5096180f268dSSam Leffler sc->sc_rixmap[ieeerate] = i; 5097180f268dSSam Leffler else 5098180f268dSSam Leffler sc->sc_rixmap[ieeerate | IEEE80211_RATE_MCS] = i; 5099180f268dSSam Leffler } 51001b1a8e41SSam Leffler memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); 510146d4d74cSSam Leffler for (i = 0; i < N(sc->sc_hwmap); i++) { 510246d4d74cSSam Leffler if (i >= rt->rateCount) { 51033e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (500 * hz) / 1000; 51043e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (130 * hz) / 1000; 510516b4851aSSam Leffler continue; 51063e50ec2cSSam Leffler } 51073e50ec2cSSam Leffler sc->sc_hwmap[i].ieeerate = 510846d4d74cSSam Leffler rt->info[i].dot11Rate & IEEE80211_RATE_VAL; 510946d4d74cSSam Leffler if (rt->info[i].phy == IEEE80211_T_HT) 511026041a14SSam Leffler sc->sc_hwmap[i].ieeerate |= IEEE80211_RATE_MCS; 5111d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; 511246d4d74cSSam Leffler if (rt->info[i].shortPreamble || 511346d4d74cSSam Leffler rt->info[i].phy == IEEE80211_T_OFDM) 5114d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags |= IEEE80211_RADIOTAP_F_SHORTPRE; 51155463c4a4SSam Leffler sc->sc_hwmap[i].rxflags = sc->sc_hwmap[i].txflags; 51163e50ec2cSSam Leffler for (j = 0; j < N(blinkrates)-1; j++) 51173e50ec2cSSam Leffler if (blinkrates[j].rate == sc->sc_hwmap[i].ieeerate) 51183e50ec2cSSam Leffler break; 51193e50ec2cSSam Leffler /* NB: this uses the last entry if the rate isn't found */ 51203e50ec2cSSam Leffler /* XXX beware of overlow */ 51213e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (blinkrates[j].timeOn * hz) / 1000; 51223e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (blinkrates[j].timeOff * hz) / 1000; 5123c42a7b7eSSam Leffler } 51245591b213SSam Leffler sc->sc_currates = rt; 51255591b213SSam Leffler sc->sc_curmode = mode; 51265591b213SSam Leffler /* 5127c42a7b7eSSam Leffler * All protection frames are transmited at 2Mb/s for 5128c42a7b7eSSam Leffler * 11g, otherwise at 1Mb/s. 51295591b213SSam Leffler */ 5130913a1ba1SSam Leffler if (mode == IEEE80211_MODE_11G) 5131ab06fdf2SSam Leffler sc->sc_protrix = ath_tx_findrix(sc, 2*2); 5132913a1ba1SSam Leffler else 5133ab06fdf2SSam Leffler sc->sc_protrix = ath_tx_findrix(sc, 2*1); 51344fa8d4efSDaniel Eischen /* NB: caller is responsible for resetting rate control state */ 51353e50ec2cSSam Leffler #undef N 51365591b213SSam Leffler } 51375591b213SSam Leffler 5138c42a7b7eSSam Leffler static void 51392e986da5SSam Leffler ath_watchdog(void *arg) 5140c42a7b7eSSam Leffler { 51412e986da5SSam Leffler struct ath_softc *sc = arg; 5142c42a7b7eSSam Leffler 51432e986da5SSam Leffler if (sc->sc_wd_timer != 0 && --sc->sc_wd_timer == 0) { 51442e986da5SSam Leffler struct ifnet *ifp = sc->sc_ifp; 5145459bc4f0SSam Leffler uint32_t hangs; 5146459bc4f0SSam Leffler 5147459bc4f0SSam Leffler if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && 5148459bc4f0SSam Leffler hangs != 0) { 5149459bc4f0SSam Leffler if_printf(ifp, "%s hang detected (0x%x)\n", 5150459bc4f0SSam Leffler hangs & 0xff ? "bb" : "mac", hangs); 5151459bc4f0SSam Leffler } else 5152c42a7b7eSSam Leffler if_printf(ifp, "device timeout\n"); 5153c42a7b7eSSam Leffler ath_reset(ifp); 5154c42a7b7eSSam Leffler ifp->if_oerrors++; 5155c42a7b7eSSam Leffler sc->sc_stats.ast_watchdog++; 5156c42a7b7eSSam Leffler } 51572e986da5SSam Leffler callout_schedule(&sc->sc_wd_ch, hz); 5158c42a7b7eSSam Leffler } 5159c42a7b7eSSam Leffler 5160a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5161c42a7b7eSSam Leffler /* 5162c42a7b7eSSam Leffler * Diagnostic interface to the HAL. This is used by various 5163c42a7b7eSSam Leffler * tools to do things like retrieve register contents for 5164c42a7b7eSSam Leffler * debugging. The mechanism is intentionally opaque so that 5165c42a7b7eSSam Leffler * it can change frequently w/o concern for compatiblity. 5166c42a7b7eSSam Leffler */ 5167c42a7b7eSSam Leffler static int 5168c42a7b7eSSam Leffler ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) 5169c42a7b7eSSam Leffler { 5170c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5171c42a7b7eSSam Leffler u_int id = ad->ad_id & ATH_DIAG_ID; 5172c42a7b7eSSam Leffler void *indata = NULL; 5173c42a7b7eSSam Leffler void *outdata = NULL; 5174c42a7b7eSSam Leffler u_int32_t insize = ad->ad_in_size; 5175c42a7b7eSSam Leffler u_int32_t outsize = ad->ad_out_size; 5176c42a7b7eSSam Leffler int error = 0; 5177c42a7b7eSSam Leffler 5178c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_IN) { 5179c42a7b7eSSam Leffler /* 5180c42a7b7eSSam Leffler * Copy in data. 5181c42a7b7eSSam Leffler */ 5182c42a7b7eSSam Leffler indata = malloc(insize, M_TEMP, M_NOWAIT); 5183c42a7b7eSSam Leffler if (indata == NULL) { 5184c42a7b7eSSam Leffler error = ENOMEM; 5185c42a7b7eSSam Leffler goto bad; 5186c42a7b7eSSam Leffler } 5187c42a7b7eSSam Leffler error = copyin(ad->ad_in_data, indata, insize); 5188c42a7b7eSSam Leffler if (error) 5189c42a7b7eSSam Leffler goto bad; 5190c42a7b7eSSam Leffler } 5191c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_DYN) { 5192c42a7b7eSSam Leffler /* 5193c42a7b7eSSam Leffler * Allocate a buffer for the results (otherwise the HAL 5194c42a7b7eSSam Leffler * returns a pointer to a buffer where we can read the 5195c42a7b7eSSam Leffler * results). Note that we depend on the HAL leaving this 5196c42a7b7eSSam Leffler * pointer for us to use below in reclaiming the buffer; 5197c42a7b7eSSam Leffler * may want to be more defensive. 5198c42a7b7eSSam Leffler */ 5199c42a7b7eSSam Leffler outdata = malloc(outsize, M_TEMP, M_NOWAIT); 5200c42a7b7eSSam Leffler if (outdata == NULL) { 5201c42a7b7eSSam Leffler error = ENOMEM; 5202c42a7b7eSSam Leffler goto bad; 5203c42a7b7eSSam Leffler } 5204c42a7b7eSSam Leffler } 5205c42a7b7eSSam Leffler if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { 5206c42a7b7eSSam Leffler if (outsize < ad->ad_out_size) 5207c42a7b7eSSam Leffler ad->ad_out_size = outsize; 5208c42a7b7eSSam Leffler if (outdata != NULL) 5209c42a7b7eSSam Leffler error = copyout(outdata, ad->ad_out_data, 5210c42a7b7eSSam Leffler ad->ad_out_size); 5211c42a7b7eSSam Leffler } else { 5212c42a7b7eSSam Leffler error = EINVAL; 5213c42a7b7eSSam Leffler } 5214c42a7b7eSSam Leffler bad: 5215c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 5216c42a7b7eSSam Leffler free(indata, M_TEMP); 5217c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 5218c42a7b7eSSam Leffler free(outdata, M_TEMP); 5219c42a7b7eSSam Leffler return error; 5220c42a7b7eSSam Leffler } 5221a585a9a1SSam Leffler #endif /* ATH_DIAGAPI */ 5222c42a7b7eSSam Leffler 5223c42a7b7eSSam Leffler static int 5224c42a7b7eSSam Leffler ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 5225c42a7b7eSSam Leffler { 5226c42a7b7eSSam Leffler #define IS_RUNNING(ifp) \ 522713f4c340SRobert Watson ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 5228c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 5229b032f27cSSam Leffler struct ieee80211com *ic = ifp->if_l2com; 5230c42a7b7eSSam Leffler struct ifreq *ifr = (struct ifreq *)data; 523184784be1SSam Leffler const HAL_RATE_TABLE *rt; 5232c42a7b7eSSam Leffler int error = 0; 5233c42a7b7eSSam Leffler 5234c42a7b7eSSam Leffler switch (cmd) { 5235c42a7b7eSSam Leffler case SIOCSIFFLAGS: 523631a8c1edSAndrew Thompson ATH_LOCK(sc); 5237c42a7b7eSSam Leffler if (IS_RUNNING(ifp)) { 5238c42a7b7eSSam Leffler /* 5239c42a7b7eSSam Leffler * To avoid rescanning another access point, 5240c42a7b7eSSam Leffler * do not call ath_init() here. Instead, 5241c42a7b7eSSam Leffler * only reflect promisc mode settings. 5242c42a7b7eSSam Leffler */ 5243c42a7b7eSSam Leffler ath_mode_init(sc); 5244c42a7b7eSSam Leffler } else if (ifp->if_flags & IFF_UP) { 5245c42a7b7eSSam Leffler /* 5246c42a7b7eSSam Leffler * Beware of being called during attach/detach 5247c42a7b7eSSam Leffler * to reset promiscuous mode. In that case we 5248c42a7b7eSSam Leffler * will still be marked UP but not RUNNING. 5249c42a7b7eSSam Leffler * However trying to re-init the interface 5250c42a7b7eSSam Leffler * is the wrong thing to do as we've already 5251c42a7b7eSSam Leffler * torn down much of our state. There's 5252c42a7b7eSSam Leffler * probably a better way to deal with this. 5253c42a7b7eSSam Leffler */ 5254b032f27cSSam Leffler if (!sc->sc_invalid) 5255fc74a9f9SBrooks Davis ath_init(sc); /* XXX lose error */ 5256d3ac945bSSam Leffler } else { 5257c42a7b7eSSam Leffler ath_stop_locked(ifp); 5258d3ac945bSSam Leffler #ifdef notyet 5259d3ac945bSSam Leffler /* XXX must wakeup in places like ath_vap_delete */ 5260d3ac945bSSam Leffler if (!sc->sc_invalid) 5261d3ac945bSSam Leffler ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); 5262d3ac945bSSam Leffler #endif 5263d3ac945bSSam Leffler } 526431a8c1edSAndrew Thompson ATH_UNLOCK(sc); 5265c42a7b7eSSam Leffler break; 5266b032f27cSSam Leffler case SIOCGIFMEDIA: 5267b032f27cSSam Leffler case SIOCSIFMEDIA: 5268b032f27cSSam Leffler error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 5269b032f27cSSam Leffler break; 5270c42a7b7eSSam Leffler case SIOCGATHSTATS: 5271c42a7b7eSSam Leffler /* NB: embed these numbers to get a consistent view */ 5272c42a7b7eSSam Leffler sc->sc_stats.ast_tx_packets = ifp->if_opackets; 5273c42a7b7eSSam Leffler sc->sc_stats.ast_rx_packets = ifp->if_ipackets; 527484784be1SSam Leffler sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi); 527584784be1SSam Leffler sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi); 5276584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 527710ad9a77SSam Leffler sc->sc_stats.ast_tdma_tsfadjp = TDMA_AVG(sc->sc_avgtsfdeltap); 527810ad9a77SSam Leffler sc->sc_stats.ast_tdma_tsfadjm = TDMA_AVG(sc->sc_avgtsfdeltam); 527910ad9a77SSam Leffler #endif 528084784be1SSam Leffler rt = sc->sc_currates; 528146d4d74cSSam Leffler sc->sc_stats.ast_tx_rate = 528246d4d74cSSam Leffler rt->info[sc->sc_txrix].dot11Rate &~ IEEE80211_RATE_BASIC; 52836aa113fdSAdrian Chadd if (rt->info[sc->sc_txrix].phy & IEEE80211_T_HT) 52846aa113fdSAdrian Chadd sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS; 5285c42a7b7eSSam Leffler return copyout(&sc->sc_stats, 5286c42a7b7eSSam Leffler ifr->ifr_data, sizeof (sc->sc_stats)); 52873fc21fedSSam Leffler case SIOCZATHSTATS: 52883fc21fedSSam Leffler error = priv_check(curthread, PRIV_DRIVER); 52893fc21fedSSam Leffler if (error == 0) 52903fc21fedSSam Leffler memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); 52913fc21fedSSam Leffler break; 5292a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5293c42a7b7eSSam Leffler case SIOCGATHDIAG: 5294c42a7b7eSSam Leffler error = ath_ioctl_diag(sc, (struct ath_diag *) ifr); 5295c42a7b7eSSam Leffler break; 5296a585a9a1SSam Leffler #endif 529731a8c1edSAndrew Thompson case SIOCGIFADDR: 5298b032f27cSSam Leffler error = ether_ioctl(ifp, cmd, data); 5299c42a7b7eSSam Leffler break; 530031a8c1edSAndrew Thompson default: 530131a8c1edSAndrew Thompson error = EINVAL; 530231a8c1edSAndrew Thompson break; 5303c42a7b7eSSam Leffler } 5304c42a7b7eSSam Leffler return error; 5305a614e076SSam Leffler #undef IS_RUNNING 5306c42a7b7eSSam Leffler } 5307c42a7b7eSSam Leffler 5308c42a7b7eSSam Leffler /* 5309c42a7b7eSSam Leffler * Announce various information on device/driver attach. 5310c42a7b7eSSam Leffler */ 5311c42a7b7eSSam Leffler static void 5312c42a7b7eSSam Leffler ath_announce(struct ath_softc *sc) 5313c42a7b7eSSam Leffler { 5314fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5315c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5316c42a7b7eSSam Leffler 5317498657cfSSam Leffler if_printf(ifp, "AR%s mac %d.%d RF%s phy %d.%d\n", 5318498657cfSSam Leffler ath_hal_mac_name(ah), ah->ah_macVersion, ah->ah_macRev, 5319498657cfSSam Leffler ath_hal_rf_name(ah), ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf); 5320c42a7b7eSSam Leffler if (bootverbose) { 5321c42a7b7eSSam Leffler int i; 5322c42a7b7eSSam Leffler for (i = 0; i <= WME_AC_VO; i++) { 5323c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[i]; 5324c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for %s traffic\n", 5325c42a7b7eSSam Leffler txq->axq_qnum, ieee80211_wme_acnames[i]); 5326c42a7b7eSSam Leffler } 5327c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for CAB traffic\n", 5328c42a7b7eSSam Leffler sc->sc_cabq->axq_qnum); 5329c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq); 5330c42a7b7eSSam Leffler } 5331e2d787faSSam Leffler if (ath_rxbuf != ATH_RXBUF) 5332e2d787faSSam Leffler if_printf(ifp, "using %u rx buffers\n", ath_rxbuf); 5333e2d787faSSam Leffler if (ath_txbuf != ATH_TXBUF) 5334e2d787faSSam Leffler if_printf(ifp, "using %u tx buffers\n", ath_txbuf); 53359ac01d39SRui Paulo if (sc->sc_mcastkey && bootverbose) 53369ac01d39SRui Paulo if_printf(ifp, "using multicast key search\n"); 5337c42a7b7eSSam Leffler } 533810ad9a77SSam Leffler 5339584f7327SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 534010ad9a77SSam Leffler static __inline uint32_t 534110ad9a77SSam Leffler ath_hal_getnexttbtt(struct ath_hal *ah) 534210ad9a77SSam Leffler { 534310ad9a77SSam Leffler #define AR_TIMER0 0x8028 534410ad9a77SSam Leffler return OS_REG_READ(ah, AR_TIMER0); 534510ad9a77SSam Leffler } 534610ad9a77SSam Leffler 534710ad9a77SSam Leffler static __inline void 534810ad9a77SSam Leffler ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) 534910ad9a77SSam Leffler { 535010ad9a77SSam Leffler /* XXX handle wrap/overflow */ 535110ad9a77SSam Leffler OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); 535210ad9a77SSam Leffler } 535310ad9a77SSam Leffler 535410ad9a77SSam Leffler static void 535510ad9a77SSam Leffler ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) 535610ad9a77SSam Leffler { 535710ad9a77SSam Leffler struct ath_hal *ah = sc->sc_ah; 535810ad9a77SSam Leffler HAL_BEACON_TIMERS bt; 535910ad9a77SSam Leffler 536010ad9a77SSam Leffler bt.bt_intval = bintval | HAL_BEACON_ENA; 536110ad9a77SSam Leffler bt.bt_nexttbtt = nexttbtt; 536210ad9a77SSam Leffler bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep; 536310ad9a77SSam Leffler bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep; 536410ad9a77SSam Leffler bt.bt_nextatim = nexttbtt+1; 536510ad9a77SSam Leffler ath_hal_beaconsettimers(ah, &bt); 536610ad9a77SSam Leffler } 536710ad9a77SSam Leffler 536810ad9a77SSam Leffler /* 536910ad9a77SSam Leffler * Calculate the beacon interval. This is periodic in the 537010ad9a77SSam Leffler * superframe for the bss. We assume each station is configured 537110ad9a77SSam Leffler * identically wrt transmit rate so the guard time we calculate 537210ad9a77SSam Leffler * above will be the same on all stations. Note we need to 537310ad9a77SSam Leffler * factor in the xmit time because the hardware will schedule 537410ad9a77SSam Leffler * a frame for transmit if the start of the frame is within 537510ad9a77SSam Leffler * the burst time. When we get hardware that properly kills 537610ad9a77SSam Leffler * frames in the PCU we can reduce/eliminate the guard time. 537710ad9a77SSam Leffler * 537810ad9a77SSam Leffler * Roundup to 1024 is so we have 1 TU buffer in the guard time 537910ad9a77SSam Leffler * to deal with the granularity of the nexttbtt timer. 11n MAC's 538010ad9a77SSam Leffler * with 1us timer granularity should allow us to reduce/eliminate 538110ad9a77SSam Leffler * this. 538210ad9a77SSam Leffler */ 538310ad9a77SSam Leffler static void 538410ad9a77SSam Leffler ath_tdma_bintvalsetup(struct ath_softc *sc, 538510ad9a77SSam Leffler const struct ieee80211_tdma_state *tdma) 538610ad9a77SSam Leffler { 538710ad9a77SSam Leffler /* copy from vap state (XXX check all vaps have same value?) */ 538810ad9a77SSam Leffler sc->sc_tdmaslotlen = tdma->tdma_slotlen; 538910ad9a77SSam Leffler 539010ad9a77SSam Leffler sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) * 539110ad9a77SSam Leffler tdma->tdma_slotcnt, 1024); 539210ad9a77SSam Leffler sc->sc_tdmabintval >>= 10; /* TSF -> TU */ 539310ad9a77SSam Leffler if (sc->sc_tdmabintval & 1) 539410ad9a77SSam Leffler sc->sc_tdmabintval++; 539510ad9a77SSam Leffler 539610ad9a77SSam Leffler if (tdma->tdma_slot == 0) { 539710ad9a77SSam Leffler /* 539810ad9a77SSam Leffler * Only slot 0 beacons; other slots respond. 539910ad9a77SSam Leffler */ 540010ad9a77SSam Leffler sc->sc_imask |= HAL_INT_SWBA; 540110ad9a77SSam Leffler sc->sc_tdmaswba = 0; /* beacon immediately */ 540210ad9a77SSam Leffler } else { 540310ad9a77SSam Leffler /* XXX all vaps must be slot 0 or slot !0 */ 540410ad9a77SSam Leffler sc->sc_imask &= ~HAL_INT_SWBA; 540510ad9a77SSam Leffler } 540610ad9a77SSam Leffler } 540710ad9a77SSam Leffler 540810ad9a77SSam Leffler /* 540910ad9a77SSam Leffler * Max 802.11 overhead. This assumes no 4-address frames and 541010ad9a77SSam Leffler * the encapsulation done by ieee80211_encap (llc). We also 541110ad9a77SSam Leffler * include potential crypto overhead. 541210ad9a77SSam Leffler */ 541310ad9a77SSam Leffler #define IEEE80211_MAXOVERHEAD \ 541410ad9a77SSam Leffler (sizeof(struct ieee80211_qosframe) \ 541510ad9a77SSam Leffler + sizeof(struct llc) \ 541610ad9a77SSam Leffler + IEEE80211_ADDR_LEN \ 541710ad9a77SSam Leffler + IEEE80211_WEP_IVLEN \ 541810ad9a77SSam Leffler + IEEE80211_WEP_KIDLEN \ 541910ad9a77SSam Leffler + IEEE80211_WEP_CRCLEN \ 542010ad9a77SSam Leffler + IEEE80211_WEP_MICLEN \ 542110ad9a77SSam Leffler + IEEE80211_CRC_LEN) 542210ad9a77SSam Leffler 542310ad9a77SSam Leffler /* 542410ad9a77SSam Leffler * Setup initially for tdma operation. Start the beacon 542510ad9a77SSam Leffler * timers and enable SWBA if we are slot 0. Otherwise 542610ad9a77SSam Leffler * we wait for slot 0 to arrive so we can sync up before 542710ad9a77SSam Leffler * starting to transmit. 542810ad9a77SSam Leffler */ 542910ad9a77SSam Leffler static void 543010ad9a77SSam Leffler ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap) 543110ad9a77SSam Leffler { 543210ad9a77SSam Leffler struct ath_hal *ah = sc->sc_ah; 543310ad9a77SSam Leffler struct ifnet *ifp = sc->sc_ifp; 543410ad9a77SSam Leffler struct ieee80211com *ic = ifp->if_l2com; 543510ad9a77SSam Leffler const struct ieee80211_txparam *tp; 543610ad9a77SSam Leffler const struct ieee80211_tdma_state *tdma = NULL; 543710ad9a77SSam Leffler int rix; 543810ad9a77SSam Leffler 543910ad9a77SSam Leffler if (vap == NULL) { 544010ad9a77SSam Leffler vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ 544110ad9a77SSam Leffler if (vap == NULL) { 544210ad9a77SSam Leffler if_printf(ifp, "%s: no vaps?\n", __func__); 544310ad9a77SSam Leffler return; 544410ad9a77SSam Leffler } 544510ad9a77SSam Leffler } 544610ad9a77SSam Leffler tp = vap->iv_bss->ni_txparms; 544710ad9a77SSam Leffler /* 544810ad9a77SSam Leffler * Calculate the guard time for each slot. This is the 544910ad9a77SSam Leffler * time to send a maximal-size frame according to the 545010ad9a77SSam Leffler * fixed/lowest transmit rate. Note that the interface 545110ad9a77SSam Leffler * mtu does not include the 802.11 overhead so we must 545210ad9a77SSam Leffler * tack that on (ath_hal_computetxtime includes the 545310ad9a77SSam Leffler * preamble and plcp in it's calculation). 545410ad9a77SSam Leffler */ 545510ad9a77SSam Leffler tdma = vap->iv_tdma; 545610ad9a77SSam Leffler if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 5457ab06fdf2SSam Leffler rix = ath_tx_findrix(sc, tp->ucastrate); 545810ad9a77SSam Leffler else 5459ab06fdf2SSam Leffler rix = ath_tx_findrix(sc, tp->mcastrate); 546010ad9a77SSam Leffler /* XXX short preamble assumed */ 546110ad9a77SSam Leffler sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates, 546210ad9a77SSam Leffler ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE); 546310ad9a77SSam Leffler 546410ad9a77SSam Leffler ath_hal_intrset(ah, 0); 546510ad9a77SSam Leffler 546610ad9a77SSam Leffler ath_beaconq_config(sc); /* setup h/w beacon q */ 54679c859a04SSam Leffler if (sc->sc_setcca) 546810ad9a77SSam Leffler ath_hal_setcca(ah, AH_FALSE); /* disable CCA */ 546910ad9a77SSam Leffler ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */ 547010ad9a77SSam Leffler ath_tdma_settimers(sc, sc->sc_tdmabintval, 547110ad9a77SSam Leffler sc->sc_tdmabintval | HAL_BEACON_RESET_TSF); 547210ad9a77SSam Leffler sc->sc_syncbeacon = 0; 547310ad9a77SSam Leffler 547410ad9a77SSam Leffler sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER; 547510ad9a77SSam Leffler sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER; 547610ad9a77SSam Leffler 547710ad9a77SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 547810ad9a77SSam Leffler 547910ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u " 548010ad9a77SSam Leffler "bsched %u guard %uus bintval %u TU dba prep %u\n", __func__, 548110ad9a77SSam Leffler tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt, 548210ad9a77SSam Leffler tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval, 548310ad9a77SSam Leffler sc->sc_tdmadbaprep); 548410ad9a77SSam Leffler } 548510ad9a77SSam Leffler 548610ad9a77SSam Leffler /* 548710ad9a77SSam Leffler * Update tdma operation. Called from the 802.11 layer 548810ad9a77SSam Leffler * when a beacon is received from the TDMA station operating 548910ad9a77SSam Leffler * in the slot immediately preceding us in the bss. Use 549010ad9a77SSam Leffler * the rx timestamp for the beacon frame to update our 549110ad9a77SSam Leffler * beacon timers so we follow their schedule. Note that 549210ad9a77SSam Leffler * by using the rx timestamp we implicitly include the 549310ad9a77SSam Leffler * propagation delay in our schedule. 549410ad9a77SSam Leffler */ 549510ad9a77SSam Leffler static void 549610ad9a77SSam Leffler ath_tdma_update(struct ieee80211_node *ni, 54972bc3ce77SSam Leffler const struct ieee80211_tdma_param *tdma, int changed) 549810ad9a77SSam Leffler { 549910ad9a77SSam Leffler #define TSF_TO_TU(_h,_l) \ 550010ad9a77SSam Leffler ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) 550110ad9a77SSam Leffler #define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) 550210ad9a77SSam Leffler struct ieee80211vap *vap = ni->ni_vap; 550310ad9a77SSam Leffler struct ieee80211com *ic = ni->ni_ic; 550410ad9a77SSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 550510ad9a77SSam Leffler struct ath_hal *ah = sc->sc_ah; 550610ad9a77SSam Leffler const HAL_RATE_TABLE *rt = sc->sc_currates; 550710ad9a77SSam Leffler u_int64_t tsf, rstamp, nextslot; 550810ad9a77SSam Leffler u_int32_t txtime, nextslottu, timer0; 550910ad9a77SSam Leffler int32_t tudelta, tsfdelta; 551010ad9a77SSam Leffler const struct ath_rx_status *rs; 551110ad9a77SSam Leffler int rix; 551210ad9a77SSam Leffler 551310ad9a77SSam Leffler sc->sc_stats.ast_tdma_update++; 551410ad9a77SSam Leffler 551510ad9a77SSam Leffler /* 551610ad9a77SSam Leffler * Check for and adopt configuration changes. 551710ad9a77SSam Leffler */ 55182bc3ce77SSam Leffler if (changed != 0) { 551910ad9a77SSam Leffler const struct ieee80211_tdma_state *ts = vap->iv_tdma; 552010ad9a77SSam Leffler 552110ad9a77SSam Leffler ath_tdma_bintvalsetup(sc, ts); 5522040972a1SSam Leffler if (changed & TDMA_UPDATE_SLOTLEN) 5523040972a1SSam Leffler ath_wme_update(ic); 552410ad9a77SSam Leffler 552510ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_TDMA, 552610ad9a77SSam Leffler "%s: adopt slot %u slotcnt %u slotlen %u us " 552710ad9a77SSam Leffler "bintval %u TU\n", __func__, 552810ad9a77SSam Leffler ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen, 552910ad9a77SSam Leffler sc->sc_tdmabintval); 553010ad9a77SSam Leffler 553110ad9a77SSam Leffler /* XXX right? */ 553210ad9a77SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 553310ad9a77SSam Leffler /* NB: beacon timers programmed below */ 553410ad9a77SSam Leffler } 553510ad9a77SSam Leffler 553610ad9a77SSam Leffler /* extend rx timestamp to 64 bits */ 55375463c4a4SSam Leffler rs = sc->sc_lastrs; 553810ad9a77SSam Leffler tsf = ath_hal_gettsf64(ah); 55395463c4a4SSam Leffler rstamp = ath_extend_tsf(rs->rs_tstamp, tsf); 554010ad9a77SSam Leffler /* 554110ad9a77SSam Leffler * The rx timestamp is set by the hardware on completing 554210ad9a77SSam Leffler * reception (at the point where the rx descriptor is DMA'd 554310ad9a77SSam Leffler * to the host). To find the start of our next slot we 554410ad9a77SSam Leffler * must adjust this time by the time required to send 554510ad9a77SSam Leffler * the packet just received. 554610ad9a77SSam Leffler */ 554710ad9a77SSam Leffler rix = rt->rateCodeToIndex[rs->rs_rate]; 554810ad9a77SSam Leffler txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix, 554910ad9a77SSam Leffler rt->info[rix].shortPreamble); 555010ad9a77SSam Leffler /* NB: << 9 is to cvt to TU and /2 */ 555110ad9a77SSam Leffler nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9); 555210ad9a77SSam Leffler nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD; 555310ad9a77SSam Leffler 555410ad9a77SSam Leffler /* 555510ad9a77SSam Leffler * TIMER0 is the h/w's idea of NextTBTT (in TU's). Convert 555610ad9a77SSam Leffler * to usecs and calculate the difference between what the 555710ad9a77SSam Leffler * other station thinks and what we have programmed. This 555810ad9a77SSam Leffler * lets us figure how to adjust our timers to match. The 555910ad9a77SSam Leffler * adjustments are done by pulling the TSF forward and possibly 556010ad9a77SSam Leffler * rewriting the beacon timers. 556110ad9a77SSam Leffler */ 556210ad9a77SSam Leffler timer0 = ath_hal_getnexttbtt(ah); 556310ad9a77SSam Leffler tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD+1)) - TU_TO_TSF(timer0)); 556410ad9a77SSam Leffler 556510ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, 556610ad9a77SSam Leffler "tsfdelta %d avg +%d/-%d\n", tsfdelta, 556710ad9a77SSam Leffler TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam)); 556810ad9a77SSam Leffler 556910ad9a77SSam Leffler if (tsfdelta < 0) { 557010ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); 557110ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta); 557210ad9a77SSam Leffler tsfdelta = -tsfdelta % 1024; 557310ad9a77SSam Leffler nextslottu++; 557410ad9a77SSam Leffler } else if (tsfdelta > 0) { 557510ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta); 557610ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); 557710ad9a77SSam Leffler tsfdelta = 1024 - (tsfdelta % 1024); 557810ad9a77SSam Leffler nextslottu++; 557910ad9a77SSam Leffler } else { 558010ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); 558110ad9a77SSam Leffler TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); 558210ad9a77SSam Leffler } 558310ad9a77SSam Leffler tudelta = nextslottu - timer0; 558410ad9a77SSam Leffler 558510ad9a77SSam Leffler /* 558610ad9a77SSam Leffler * Copy sender's timetstamp into tdma ie so they can 558710ad9a77SSam Leffler * calculate roundtrip time. We submit a beacon frame 558810ad9a77SSam Leffler * below after any timer adjustment. The frame goes out 558910ad9a77SSam Leffler * at the next TBTT so the sender can calculate the 559010ad9a77SSam Leffler * roundtrip by inspecting the tdma ie in our beacon frame. 559110ad9a77SSam Leffler * 559210ad9a77SSam Leffler * NB: This tstamp is subtlely preserved when 559310ad9a77SSam Leffler * IEEE80211_BEACON_TDMA is marked (e.g. when the 559410ad9a77SSam Leffler * slot position changes) because ieee80211_add_tdma 559510ad9a77SSam Leffler * skips over the data. 559610ad9a77SSam Leffler */ 559710ad9a77SSam Leffler memcpy(ATH_VAP(vap)->av_boff.bo_tdma + 559810ad9a77SSam Leffler __offsetof(struct ieee80211_tdma_param, tdma_tstamp), 559910ad9a77SSam Leffler &ni->ni_tstamp.data, 8); 560010ad9a77SSam Leffler #if 0 560110ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, 560210ad9a77SSam Leffler "tsf %llu nextslot %llu (%d, %d) nextslottu %u timer0 %u (%d)\n", 560310ad9a77SSam Leffler (unsigned long long) tsf, (unsigned long long) nextslot, 560410ad9a77SSam Leffler (int)(nextslot - tsf), tsfdelta, 560510ad9a77SSam Leffler nextslottu, timer0, tudelta); 560610ad9a77SSam Leffler #endif 560710ad9a77SSam Leffler /* 560810ad9a77SSam Leffler * Adjust the beacon timers only when pulling them forward 560910ad9a77SSam Leffler * or when going back by less than the beacon interval. 561010ad9a77SSam Leffler * Negative jumps larger than the beacon interval seem to 561110ad9a77SSam Leffler * cause the timers to stop and generally cause instability. 561210ad9a77SSam Leffler * This basically filters out jumps due to missed beacons. 561310ad9a77SSam Leffler */ 561410ad9a77SSam Leffler if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) { 561510ad9a77SSam Leffler ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval); 561610ad9a77SSam Leffler sc->sc_stats.ast_tdma_timers++; 561710ad9a77SSam Leffler } 561810ad9a77SSam Leffler if (tsfdelta > 0) { 561910ad9a77SSam Leffler ath_hal_adjusttsf(ah, tsfdelta); 562010ad9a77SSam Leffler sc->sc_stats.ast_tdma_tsf++; 562110ad9a77SSam Leffler } 562210ad9a77SSam Leffler ath_tdma_beacon_send(sc, vap); /* prepare response */ 562310ad9a77SSam Leffler #undef TU_TO_TSF 562410ad9a77SSam Leffler #undef TSF_TO_TU 562510ad9a77SSam Leffler } 562610ad9a77SSam Leffler 562710ad9a77SSam Leffler /* 562810ad9a77SSam Leffler * Transmit a beacon frame at SWBA. Dynamic updates 562910ad9a77SSam Leffler * to the frame contents are done as needed. 563010ad9a77SSam Leffler */ 563110ad9a77SSam Leffler static void 563210ad9a77SSam Leffler ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap) 563310ad9a77SSam Leffler { 563410ad9a77SSam Leffler struct ath_hal *ah = sc->sc_ah; 563510ad9a77SSam Leffler struct ath_buf *bf; 563610ad9a77SSam Leffler int otherant; 563710ad9a77SSam Leffler 563810ad9a77SSam Leffler /* 563910ad9a77SSam Leffler * Check if the previous beacon has gone out. If 564010ad9a77SSam Leffler * not don't try to post another, skip this period 564110ad9a77SSam Leffler * and wait for the next. Missed beacons indicate 564210ad9a77SSam Leffler * a problem and should not occur. If we miss too 564310ad9a77SSam Leffler * many consecutive beacons reset the device. 564410ad9a77SSam Leffler */ 564510ad9a77SSam Leffler if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { 564610ad9a77SSam Leffler sc->sc_bmisscount++; 564710ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 564810ad9a77SSam Leffler "%s: missed %u consecutive beacons\n", 564910ad9a77SSam Leffler __func__, sc->sc_bmisscount); 5650a32ac9d3SSam Leffler if (sc->sc_bmisscount >= ath_bstuck_threshold) 565110ad9a77SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); 565210ad9a77SSam Leffler return; 565310ad9a77SSam Leffler } 565410ad9a77SSam Leffler if (sc->sc_bmisscount != 0) { 565510ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 565610ad9a77SSam Leffler "%s: resume beacon xmit after %u misses\n", 565710ad9a77SSam Leffler __func__, sc->sc_bmisscount); 565810ad9a77SSam Leffler sc->sc_bmisscount = 0; 565910ad9a77SSam Leffler } 566010ad9a77SSam Leffler 566110ad9a77SSam Leffler /* 566210ad9a77SSam Leffler * Check recent per-antenna transmit statistics and flip 566310ad9a77SSam Leffler * the default antenna if noticeably more frames went out 566410ad9a77SSam Leffler * on the non-default antenna. 566510ad9a77SSam Leffler * XXX assumes 2 anntenae 566610ad9a77SSam Leffler */ 566710ad9a77SSam Leffler if (!sc->sc_diversity) { 566810ad9a77SSam Leffler otherant = sc->sc_defant & 1 ? 2 : 1; 566910ad9a77SSam Leffler if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) 567010ad9a77SSam Leffler ath_setdefantenna(sc, otherant); 567110ad9a77SSam Leffler sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; 567210ad9a77SSam Leffler } 567310ad9a77SSam Leffler 567410ad9a77SSam Leffler bf = ath_beacon_generate(sc, vap); 567510ad9a77SSam Leffler if (bf != NULL) { 567610ad9a77SSam Leffler /* 567710ad9a77SSam Leffler * Stop any current dma and put the new frame on the queue. 567810ad9a77SSam Leffler * This should never fail since we check above that no frames 567910ad9a77SSam Leffler * are still pending on the queue. 568010ad9a77SSam Leffler */ 568110ad9a77SSam Leffler if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { 568210ad9a77SSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 568310ad9a77SSam Leffler "%s: beacon queue %u did not stop?\n", 568410ad9a77SSam Leffler __func__, sc->sc_bhalq); 568510ad9a77SSam Leffler /* NB: the HAL still stops DMA, so proceed */ 568610ad9a77SSam Leffler } 568710ad9a77SSam Leffler ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); 568810ad9a77SSam Leffler ath_hal_txstart(ah, sc->sc_bhalq); 568910ad9a77SSam Leffler 569010ad9a77SSam Leffler sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */ 569110ad9a77SSam Leffler 569210ad9a77SSam Leffler /* 569310ad9a77SSam Leffler * Record local TSF for our last send for use 569410ad9a77SSam Leffler * in arbitrating slot collisions. 569510ad9a77SSam Leffler */ 569610ad9a77SSam Leffler vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah); 569710ad9a77SSam Leffler } 569810ad9a77SSam Leffler } 5699584f7327SSam Leffler #endif /* IEEE80211_SUPPORT_TDMA */ 5700e8dabfbeSAdrian Chadd 5701*48237774SAdrian Chadd static void 5702*48237774SAdrian Chadd ath_dfs_tasklet(void *p, int npending) 5703*48237774SAdrian Chadd { 5704*48237774SAdrian Chadd struct ath_softc *sc = (struct ath_softc *) p; 5705*48237774SAdrian Chadd struct ifnet *ifp = sc->sc_ifp; 5706*48237774SAdrian Chadd struct ieee80211com *ic = ifp->if_l2com; 5707*48237774SAdrian Chadd 5708*48237774SAdrian Chadd /* 5709*48237774SAdrian Chadd * If previous processing has found a radar event, 5710*48237774SAdrian Chadd * signal this to the net80211 layer to begin DFS 5711*48237774SAdrian Chadd * processing. 5712*48237774SAdrian Chadd */ 5713*48237774SAdrian Chadd if (ath_dfs_process_radar_event(sc, sc->sc_curchan)) { 5714*48237774SAdrian Chadd /* DFS event found, initiate channel change */ 5715*48237774SAdrian Chadd ieee80211_dfs_notify_radar(ic, sc->sc_curchan); 5716*48237774SAdrian Chadd } 5717*48237774SAdrian Chadd } 5718*48237774SAdrian Chadd 5719dba9c859SAdrian Chadd MODULE_VERSION(if_ath, 1); 5720dba9c859SAdrian Chadd MODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */ 5721