15591b213SSam Leffler /*- 2622b3fd2SSam Leffler * Copyright (c) 2002-2006 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 * 3. Neither the names of the above-listed copyright holders nor the names 165591b213SSam Leffler * of any contributors may be used to endorse or promote products derived 175591b213SSam Leffler * from this software without specific prior written permission. 185591b213SSam Leffler * 195591b213SSam Leffler * Alternatively, this software may be distributed under the terms of the 205591b213SSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 215591b213SSam Leffler * Software Foundation. 225591b213SSam Leffler * 235591b213SSam Leffler * NO WARRANTY 245591b213SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 255591b213SSam Leffler * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 265591b213SSam Leffler * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 275591b213SSam Leffler * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 285591b213SSam Leffler * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 295591b213SSam Leffler * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 305591b213SSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 315591b213SSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 325591b213SSam Leffler * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 335591b213SSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 345591b213SSam Leffler * THE POSSIBILITY OF SUCH DAMAGES. 355591b213SSam Leffler */ 365591b213SSam Leffler 375591b213SSam Leffler #include <sys/cdefs.h> 385591b213SSam Leffler __FBSDID("$FreeBSD$"); 395591b213SSam Leffler 405591b213SSam Leffler /* 415591b213SSam Leffler * Driver for the Atheros Wireless LAN controller. 425f3721d5SSam Leffler * 435f3721d5SSam Leffler * This software is derived from work of Atsushi Onoe; his contribution 445f3721d5SSam Leffler * is greatly appreciated. 455591b213SSam Leffler */ 465591b213SSam Leffler 475591b213SSam Leffler #include "opt_inet.h" 48a585a9a1SSam Leffler #include "opt_ath.h" 495591b213SSam Leffler 505591b213SSam Leffler #include <sys/param.h> 515591b213SSam Leffler #include <sys/systm.h> 525591b213SSam Leffler #include <sys/sysctl.h> 535591b213SSam Leffler #include <sys/mbuf.h> 545591b213SSam Leffler #include <sys/malloc.h> 555591b213SSam Leffler #include <sys/lock.h> 565591b213SSam Leffler #include <sys/mutex.h> 575591b213SSam Leffler #include <sys/kernel.h> 585591b213SSam Leffler #include <sys/socket.h> 595591b213SSam Leffler #include <sys/sockio.h> 605591b213SSam Leffler #include <sys/errno.h> 615591b213SSam Leffler #include <sys/callout.h> 625591b213SSam Leffler #include <sys/bus.h> 635591b213SSam Leffler #include <sys/endian.h> 640bbf5441SSam Leffler #include <sys/kthread.h> 650bbf5441SSam Leffler #include <sys/taskqueue.h> 665591b213SSam Leffler 675591b213SSam Leffler #include <machine/bus.h> 685591b213SSam Leffler 695591b213SSam Leffler #include <net/if.h> 705591b213SSam Leffler #include <net/if_dl.h> 715591b213SSam Leffler #include <net/if_media.h> 72fc74a9f9SBrooks Davis #include <net/if_types.h> 735591b213SSam Leffler #include <net/if_arp.h> 745591b213SSam Leffler #include <net/ethernet.h> 755591b213SSam Leffler #include <net/if_llc.h> 765591b213SSam Leffler 775591b213SSam Leffler #include <net80211/ieee80211_var.h> 785591b213SSam Leffler 795591b213SSam Leffler #include <net/bpf.h> 805591b213SSam Leffler 815591b213SSam Leffler #ifdef INET 825591b213SSam Leffler #include <netinet/in.h> 835591b213SSam Leffler #include <netinet/if_ether.h> 845591b213SSam Leffler #endif 855591b213SSam Leffler 865591b213SSam Leffler #include <dev/ath/if_athvar.h> 875591b213SSam Leffler #include <contrib/dev/ath/ah_desc.h> 88c42a7b7eSSam Leffler #include <contrib/dev/ath/ah_devid.h> /* XXX for softled */ 895591b213SSam Leffler 9086e07743SSam Leffler #ifdef ATH_TX99_DIAG 9186e07743SSam Leffler #include <dev/ath/ath_tx99/ath_tx99.h> 9286e07743SSam Leffler #endif 9386e07743SSam Leffler 94e8fd88a3SSam Leffler /* unaligned little endian access */ 955591b213SSam Leffler #define LE_READ_2(p) \ 965591b213SSam Leffler ((u_int16_t) \ 975591b213SSam Leffler ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8))) 985591b213SSam Leffler #define LE_READ_4(p) \ 995591b213SSam Leffler ((u_int32_t) \ 1005591b213SSam Leffler ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ 1015591b213SSam Leffler (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) 1025591b213SSam Leffler 1033e50ec2cSSam Leffler enum { 1043e50ec2cSSam Leffler ATH_LED_TX, 1053e50ec2cSSam Leffler ATH_LED_RX, 1063e50ec2cSSam Leffler ATH_LED_POLL, 1073e50ec2cSSam Leffler }; 1083e50ec2cSSam Leffler 1095591b213SSam Leffler static void ath_init(void *); 110c42a7b7eSSam Leffler static void ath_stop_locked(struct ifnet *); 1115591b213SSam Leffler static void ath_stop(struct ifnet *); 1125591b213SSam Leffler static void ath_start(struct ifnet *); 113c42a7b7eSSam Leffler static int ath_reset(struct ifnet *); 1145591b213SSam Leffler static int ath_media_change(struct ifnet *); 1155591b213SSam Leffler static void ath_watchdog(struct ifnet *); 1165591b213SSam Leffler static int ath_ioctl(struct ifnet *, u_long, caddr_t); 1175591b213SSam Leffler static void ath_fatal_proc(void *, int); 1185591b213SSam Leffler static void ath_rxorn_proc(void *, int); 1195591b213SSam Leffler static void ath_bmiss_proc(void *, int); 120c42a7b7eSSam Leffler static int ath_key_alloc(struct ieee80211com *, 121c1225b52SSam Leffler const struct ieee80211_key *, 122c1225b52SSam Leffler ieee80211_keyix *, ieee80211_keyix *); 123c42a7b7eSSam Leffler static int ath_key_delete(struct ieee80211com *, 124c42a7b7eSSam Leffler const struct ieee80211_key *); 125c42a7b7eSSam Leffler static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *, 126c42a7b7eSSam Leffler const u_int8_t mac[IEEE80211_ADDR_LEN]); 127c42a7b7eSSam Leffler static void ath_key_update_begin(struct ieee80211com *); 128c42a7b7eSSam Leffler static void ath_key_update_end(struct ieee80211com *); 1295591b213SSam Leffler static void ath_mode_init(struct ath_softc *); 130c42a7b7eSSam Leffler static void ath_setslottime(struct ath_softc *); 131c42a7b7eSSam Leffler static void ath_updateslot(struct ifnet *); 13280d2765fSSam Leffler static int ath_beaconq_setup(struct ath_hal *); 1335591b213SSam Leffler static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); 134c42a7b7eSSam Leffler static void ath_beacon_setup(struct ath_softc *, struct ath_buf *); 1355591b213SSam Leffler static void ath_beacon_proc(void *, int); 136c42a7b7eSSam Leffler static void ath_bstuck_proc(void *, int); 1375591b213SSam Leffler static void ath_beacon_free(struct ath_softc *); 1385591b213SSam Leffler static void ath_beacon_config(struct ath_softc *); 139c42a7b7eSSam Leffler static void ath_descdma_cleanup(struct ath_softc *sc, 140c42a7b7eSSam Leffler struct ath_descdma *, ath_bufhead *); 1415591b213SSam Leffler static int ath_desc_alloc(struct ath_softc *); 1425591b213SSam Leffler static void ath_desc_free(struct ath_softc *); 143c42a7b7eSSam Leffler static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *); 144c42a7b7eSSam Leffler static void ath_node_free(struct ieee80211_node *); 145c42a7b7eSSam Leffler static u_int8_t ath_node_getrssi(const struct ieee80211_node *); 1465591b213SSam Leffler static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *); 147c42a7b7eSSam Leffler static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, 148c42a7b7eSSam Leffler struct ieee80211_node *ni, 149c42a7b7eSSam Leffler int subtype, int rssi, u_int32_t rstamp); 150c42a7b7eSSam Leffler static void ath_setdefantenna(struct ath_softc *, u_int); 1515591b213SSam Leffler static void ath_rx_proc(void *, int); 152622b3fd2SSam Leffler static void ath_txq_init(struct ath_softc *sc, struct ath_txq *, int); 153c42a7b7eSSam Leffler static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype); 154c42a7b7eSSam Leffler static int ath_tx_setup(struct ath_softc *, int, int); 155c42a7b7eSSam Leffler static int ath_wme_update(struct ieee80211com *); 156c42a7b7eSSam Leffler static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *); 157c42a7b7eSSam Leffler static void ath_tx_cleanup(struct ath_softc *); 1585591b213SSam Leffler static int ath_tx_start(struct ath_softc *, struct ieee80211_node *, 1595591b213SSam Leffler struct ath_buf *, struct mbuf *); 160c42a7b7eSSam Leffler static void ath_tx_proc_q0(void *, int); 161c42a7b7eSSam Leffler static void ath_tx_proc_q0123(void *, int); 1625591b213SSam Leffler static void ath_tx_proc(void *, int); 1635591b213SSam Leffler static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *); 1645591b213SSam Leffler static void ath_draintxq(struct ath_softc *); 1655591b213SSam Leffler static void ath_stoprecv(struct ath_softc *); 1665591b213SSam Leffler static int ath_startrecv(struct ath_softc *); 167c42a7b7eSSam Leffler static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *); 1685591b213SSam Leffler static void ath_next_scan(void *); 1695591b213SSam Leffler static void ath_calibrate(void *); 17045bbf62fSSam Leffler static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int); 171e8fd88a3SSam Leffler static void ath_setup_stationkey(struct ieee80211_node *); 172e9962332SSam Leffler static void ath_newassoc(struct ieee80211_node *, int); 173aaa70f2fSSam Leffler static int ath_getchannels(struct ath_softc *, 174aaa70f2fSSam Leffler HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL); 1753e50ec2cSSam Leffler static void ath_led_event(struct ath_softc *, int); 176c42a7b7eSSam Leffler static void ath_update_txpow(struct ath_softc *); 1775591b213SSam Leffler 178c42a7b7eSSam Leffler static int ath_rate_setup(struct ath_softc *, u_int mode); 1795591b213SSam Leffler static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); 180c42a7b7eSSam Leffler 181c42a7b7eSSam Leffler static void ath_sysctlattach(struct ath_softc *); 182664443d0SSam Leffler static int ath_raw_xmit(struct ieee80211_node *, 183664443d0SSam Leffler struct mbuf *, const struct ieee80211_bpf_params *); 184c42a7b7eSSam Leffler static void ath_bpfattach(struct ath_softc *); 185c42a7b7eSSam Leffler static void ath_announce(struct ath_softc *); 1865591b213SSam Leffler 1875591b213SSam Leffler SYSCTL_DECL(_hw_ath); 1885591b213SSam Leffler 1895591b213SSam Leffler /* XXX validate sysctl values */ 1905591b213SSam Leffler static int ath_dwelltime = 200; /* 5 channels/second */ 1915591b213SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, dwell, CTLFLAG_RW, &ath_dwelltime, 1925591b213SSam Leffler 0, "channel dwell time (ms) for AP/station scanning"); 1935591b213SSam Leffler static int ath_calinterval = 30; /* calibrate every 30 secs */ 1945591b213SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval, 1955591b213SSam Leffler 0, "chip calibration interval (secs)"); 19645cabbdcSSam Leffler static int ath_outdoor = AH_TRUE; /* outdoor operation */ 197aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, outdoor, CTLFLAG_RW, &ath_outdoor, 198c42a7b7eSSam Leffler 0, "outdoor operation"); 1998c0370b7SSam Leffler TUNABLE_INT("hw.ath.outdoor", &ath_outdoor); 200c42a7b7eSSam Leffler static int ath_xchanmode = AH_TRUE; /* extended channel use */ 201aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, xchanmode, CTLFLAG_RW, &ath_xchanmode, 202c42a7b7eSSam Leffler 0, "extended channel mode"); 203c42a7b7eSSam Leffler TUNABLE_INT("hw.ath.xchanmode", &ath_xchanmode); 20445cabbdcSSam Leffler static int ath_countrycode = CTRY_DEFAULT; /* country code */ 205aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, countrycode, CTLFLAG_RW, &ath_countrycode, 20645cabbdcSSam Leffler 0, "country code"); 2078c0370b7SSam Leffler TUNABLE_INT("hw.ath.countrycode", &ath_countrycode); 20845cabbdcSSam Leffler static int ath_regdomain = 0; /* regulatory domain */ 20945cabbdcSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, regdomain, CTLFLAG_RD, &ath_regdomain, 21045cabbdcSSam Leffler 0, "regulatory domain"); 2115591b213SSam Leffler 212e2d787faSSam Leffler static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */ 213aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf, 214e2d787faSSam Leffler 0, "rx buffers allocated"); 215e2d787faSSam Leffler TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf); 216e2d787faSSam Leffler static int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */ 217aaa70f2fSSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf, 218e2d787faSSam Leffler 0, "tx buffers allocated"); 219e2d787faSSam Leffler TUNABLE_INT("hw.ath.txbuf", &ath_txbuf); 220e2d787faSSam Leffler 221a585a9a1SSam Leffler #ifdef ATH_DEBUG 222c42a7b7eSSam Leffler static int ath_debug = 0; 2235591b213SSam Leffler SYSCTL_INT(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug, 2245591b213SSam Leffler 0, "control debugging printfs"); 225f3be7956SSam Leffler TUNABLE_INT("hw.ath.debug", &ath_debug); 226e325e530SSam Leffler enum { 227e325e530SSam Leffler ATH_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ 228e325e530SSam Leffler ATH_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */ 229e325e530SSam Leffler ATH_DEBUG_RECV = 0x00000004, /* basic recv operation */ 230e325e530SSam Leffler ATH_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */ 231e325e530SSam Leffler ATH_DEBUG_RATE = 0x00000010, /* rate control */ 232e325e530SSam Leffler ATH_DEBUG_RESET = 0x00000020, /* reset processing */ 233e325e530SSam Leffler ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */ 234e325e530SSam Leffler ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */ 235e325e530SSam Leffler ATH_DEBUG_WATCHDOG = 0x00000100, /* watchdog timeout */ 236e325e530SSam Leffler ATH_DEBUG_INTR = 0x00001000, /* ISR */ 237e325e530SSam Leffler ATH_DEBUG_TX_PROC = 0x00002000, /* tx ISR proc */ 238e325e530SSam Leffler ATH_DEBUG_RX_PROC = 0x00004000, /* rx ISR proc */ 239e325e530SSam Leffler ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */ 240e325e530SSam Leffler ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */ 241c42a7b7eSSam Leffler ATH_DEBUG_KEYCACHE = 0x00020000, /* key cache management */ 242c42a7b7eSSam Leffler ATH_DEBUG_STATE = 0x00040000, /* 802.11 state transitions */ 243c42a7b7eSSam Leffler ATH_DEBUG_NODE = 0x00080000, /* node management */ 2443e50ec2cSSam Leffler ATH_DEBUG_LED = 0x00100000, /* led management */ 245bd5a9920SSam Leffler ATH_DEBUG_FF = 0x00200000, /* fast frames */ 246bd5a9920SSam Leffler ATH_DEBUG_DFS = 0x00400000, /* DFS processing */ 247c42a7b7eSSam Leffler ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */ 248e325e530SSam Leffler ATH_DEBUG_ANY = 0xffffffff 249e325e530SSam Leffler }; 250c42a7b7eSSam Leffler #define IFF_DUMPPKTS(sc, m) \ 2510a1b94c4SSam Leffler ((sc->sc_debug & (m)) || \ 252fc74a9f9SBrooks Davis (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) 253c42a7b7eSSam Leffler #define DPRINTF(sc, m, fmt, ...) do { \ 2540a1b94c4SSam Leffler if (sc->sc_debug & (m)) \ 255c42a7b7eSSam Leffler printf(fmt, __VA_ARGS__); \ 256c42a7b7eSSam Leffler } while (0) 257c42a7b7eSSam Leffler #define KEYPRINTF(sc, ix, hk, mac) do { \ 258c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_KEYCACHE) \ 2595901d2d3SSam Leffler ath_keyprint(sc, __func__, ix, hk, mac); \ 260c42a7b7eSSam Leffler } while (0) 26165f9edeeSSam Leffler static void ath_printrxbuf(const struct ath_buf *bf, u_int ix, int); 26265f9edeeSSam Leffler static void ath_printtxbuf(const struct ath_buf *bf, u_int qnum, u_int ix, int done); 2635591b213SSam Leffler #else 264c42a7b7eSSam Leffler #define IFF_DUMPPKTS(sc, m) \ 265fc74a9f9SBrooks Davis ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2)) 266d2f6ed15SSam Leffler #define DPRINTF(sc, m, fmt, ...) do { \ 267d2f6ed15SSam Leffler (void) sc; \ 268d2f6ed15SSam Leffler } while (0) 269d2f6ed15SSam Leffler #define KEYPRINTF(sc, k, ix, mac) do { \ 270d2f6ed15SSam Leffler (void) sc; \ 271d2f6ed15SSam Leffler } while (0) 2725591b213SSam Leffler #endif 2735591b213SSam Leffler 274c42a7b7eSSam Leffler MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers"); 275c42a7b7eSSam Leffler 2765591b213SSam Leffler int 2775591b213SSam Leffler ath_attach(u_int16_t devid, struct ath_softc *sc) 2785591b213SSam Leffler { 279fc74a9f9SBrooks Davis struct ifnet *ifp; 2805591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 281fc74a9f9SBrooks Davis struct ath_hal *ah = NULL; 2825591b213SSam Leffler HAL_STATUS status; 283c42a7b7eSSam Leffler int error = 0, i; 2845591b213SSam Leffler 285c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); 2865591b213SSam Leffler 287fc74a9f9SBrooks Davis ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 288fc74a9f9SBrooks Davis if (ifp == NULL) { 289fc74a9f9SBrooks Davis device_printf(sc->sc_dev, "can not if_alloc()\n"); 290fc74a9f9SBrooks Davis error = ENOSPC; 291fc74a9f9SBrooks Davis goto bad; 292fc74a9f9SBrooks Davis } 293fc74a9f9SBrooks Davis 2945591b213SSam Leffler /* set these up early for if_printf use */ 2959bf40edeSBrooks Davis if_initname(ifp, device_get_name(sc->sc_dev), 2969bf40edeSBrooks Davis device_get_unit(sc->sc_dev)); 2975591b213SSam Leffler 298f9fc583fSSam Leffler ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, &status); 2995591b213SSam Leffler if (ah == NULL) { 3005591b213SSam Leffler if_printf(ifp, "unable to attach hardware; HAL status %u\n", 3015591b213SSam Leffler status); 3025591b213SSam Leffler error = ENXIO; 3035591b213SSam Leffler goto bad; 3045591b213SSam Leffler } 30585bdc65aSSam Leffler if (ah->ah_abi != HAL_ABI_VERSION) { 306c42a7b7eSSam Leffler if_printf(ifp, "HAL ABI mismatch detected " 307c42a7b7eSSam Leffler "(HAL:0x%x != driver:0x%x)\n", 30885bdc65aSSam Leffler ah->ah_abi, HAL_ABI_VERSION); 30985bdc65aSSam Leffler error = ENXIO; 31085bdc65aSSam Leffler goto bad; 31185bdc65aSSam Leffler } 3125591b213SSam Leffler sc->sc_ah = ah; 313b58b3803SSam Leffler sc->sc_invalid = 0; /* ready to go, enable interrupt handling */ 3145591b213SSam Leffler 3155591b213SSam Leffler /* 316c42a7b7eSSam Leffler * Check if the MAC has multi-rate retry support. 317c42a7b7eSSam Leffler * We do this by trying to setup a fake extended 318c42a7b7eSSam Leffler * descriptor. MAC's that don't have support will 319c42a7b7eSSam Leffler * return false w/o doing anything. MAC's that do 320c42a7b7eSSam Leffler * support it will return true w/o doing anything. 321c42a7b7eSSam Leffler */ 322c42a7b7eSSam Leffler sc->sc_mrretry = ath_hal_setupxtxdesc(ah, NULL, 0,0, 0,0, 0,0); 323c42a7b7eSSam Leffler 324c42a7b7eSSam Leffler /* 325c42a7b7eSSam Leffler * Check if the device has hardware counters for PHY 326c42a7b7eSSam Leffler * errors. If so we need to enable the MIB interrupt 327c42a7b7eSSam Leffler * so we can act on stat triggers. 328c42a7b7eSSam Leffler */ 329c42a7b7eSSam Leffler if (ath_hal_hwphycounters(ah)) 330c42a7b7eSSam Leffler sc->sc_needmib = 1; 331c42a7b7eSSam Leffler 332c42a7b7eSSam Leffler /* 333c42a7b7eSSam Leffler * Get the hardware key cache size. 334c42a7b7eSSam Leffler */ 335c42a7b7eSSam Leffler sc->sc_keymax = ath_hal_keycachesize(ah); 336e8fd88a3SSam Leffler if (sc->sc_keymax > ATH_KEYMAX) { 337e8fd88a3SSam Leffler if_printf(ifp, "Warning, using only %u of %u key cache slots\n", 338e8fd88a3SSam Leffler ATH_KEYMAX, sc->sc_keymax); 339e8fd88a3SSam Leffler sc->sc_keymax = ATH_KEYMAX; 340c42a7b7eSSam Leffler } 341c42a7b7eSSam Leffler /* 342c42a7b7eSSam Leffler * Reset the key cache since some parts do not 343c42a7b7eSSam Leffler * reset the contents on initial power up. 344c42a7b7eSSam Leffler */ 345c42a7b7eSSam Leffler for (i = 0; i < sc->sc_keymax; i++) 346c42a7b7eSSam Leffler ath_hal_keyreset(ah, i); 347c42a7b7eSSam Leffler 348c42a7b7eSSam Leffler /* 3495591b213SSam Leffler * Collect the channel list using the default country 3505591b213SSam Leffler * code and including outdoor channels. The 802.11 layer 35145cabbdcSSam Leffler * is resposible for filtering this list based on settings 35245cabbdcSSam Leffler * like the phy mode. 3535591b213SSam Leffler */ 354aaa70f2fSSam Leffler error = ath_getchannels(sc, ath_regdomain, ath_countrycode, 355aaa70f2fSSam Leffler ath_xchanmode != 0, ath_outdoor != 0); 3565591b213SSam Leffler if (error != 0) 3575591b213SSam Leffler goto bad; 3585591b213SSam Leffler 3595591b213SSam Leffler /* 3605591b213SSam Leffler * Setup rate tables for all potential media types. 3615591b213SSam Leffler */ 3625591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11A); 3635591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11B); 3645591b213SSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11G); 365c42a7b7eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_TURBO_A); 366c42a7b7eSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_TURBO_G); 367724c193aSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_HALF); 368724c193aSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_QUARTER); 369aaa70f2fSSam Leffler 370c42a7b7eSSam Leffler /* NB: setup here so ath_rate_update is happy */ 371c42a7b7eSSam Leffler ath_setcurmode(sc, IEEE80211_MODE_11A); 3725591b213SSam Leffler 373c42a7b7eSSam Leffler /* 374c42a7b7eSSam Leffler * Allocate tx+rx descriptors and populate the lists. 375c42a7b7eSSam Leffler */ 3765591b213SSam Leffler error = ath_desc_alloc(sc); 3775591b213SSam Leffler if (error != 0) { 3785591b213SSam Leffler if_printf(ifp, "failed to allocate descriptors: %d\n", error); 3795591b213SSam Leffler goto bad; 3805591b213SSam Leffler } 381e383b240SSam Leffler callout_init(&sc->sc_scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0); 3822274d8c8SSam Leffler callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE); 383bd5a9920SSam Leffler callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE); 3845591b213SSam Leffler 385f0b2a0beSSam Leffler ATH_TXBUF_LOCK_INIT(sc); 3865591b213SSam Leffler 3870bbf5441SSam Leffler sc->sc_tq = taskqueue_create("ath_taskq", M_NOWAIT, 3880bbf5441SSam Leffler taskqueue_thread_enqueue, &sc->sc_tq); 3890bbf5441SSam Leffler taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, 3900bbf5441SSam Leffler "%s taskq", ifp->if_xname); 3910bbf5441SSam Leffler 3925591b213SSam Leffler TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, sc); 3935591b213SSam Leffler TASK_INIT(&sc->sc_rxorntask, 0, ath_rxorn_proc, sc); 3945591b213SSam Leffler TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc); 395c42a7b7eSSam Leffler TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc); 3965591b213SSam Leffler 3975591b213SSam Leffler /* 398c42a7b7eSSam Leffler * Allocate hardware transmit queues: one queue for 399c42a7b7eSSam Leffler * beacon frames and one data queue for each QoS 400c42a7b7eSSam Leffler * priority. Note that the hal handles reseting 401c42a7b7eSSam Leffler * these queues at the needed time. 402c42a7b7eSSam Leffler * 403c42a7b7eSSam Leffler * XXX PS-Poll 4045591b213SSam Leffler */ 40580d2765fSSam Leffler sc->sc_bhalq = ath_beaconq_setup(ah); 4065591b213SSam Leffler if (sc->sc_bhalq == (u_int) -1) { 4075591b213SSam Leffler if_printf(ifp, "unable to setup a beacon xmit queue!\n"); 408c42a7b7eSSam Leffler error = EIO; 409b28b4653SSam Leffler goto bad2; 4105591b213SSam Leffler } 411c42a7b7eSSam Leffler sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0); 412c42a7b7eSSam Leffler if (sc->sc_cabq == NULL) { 413c42a7b7eSSam Leffler if_printf(ifp, "unable to setup CAB xmit queue!\n"); 414c42a7b7eSSam Leffler error = EIO; 415c42a7b7eSSam Leffler goto bad2; 416c42a7b7eSSam Leffler } 4171fba0fdcSSam Leffler /* NB: s/w q, qnum used only by WITNESS */ 4181fba0fdcSSam Leffler ath_txq_init(sc, &sc->sc_mcastq, HAL_NUM_TX_QUEUES+1); 419c42a7b7eSSam Leffler /* NB: insure BK queue is the lowest priority h/w queue */ 420c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { 421c42a7b7eSSam Leffler if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", 422c42a7b7eSSam Leffler ieee80211_wme_acnames[WME_AC_BK]); 423c42a7b7eSSam Leffler error = EIO; 424c42a7b7eSSam Leffler goto bad2; 425c42a7b7eSSam Leffler } 426c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) || 427c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) || 428c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) { 429c42a7b7eSSam Leffler /* 430c42a7b7eSSam Leffler * Not enough hardware tx queues to properly do WME; 431c42a7b7eSSam Leffler * just punt and assign them all to the same h/w queue. 432c42a7b7eSSam Leffler * We could do a better job of this if, for example, 433c42a7b7eSSam Leffler * we allocate queues when we switch from station to 434c42a7b7eSSam Leffler * AP mode. 435c42a7b7eSSam Leffler */ 436c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_VI] != NULL) 437c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_VI]); 438c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != NULL) 439c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_BE]); 440c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK]; 441c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK]; 442c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK]; 443c42a7b7eSSam Leffler } 444c42a7b7eSSam Leffler 445c42a7b7eSSam Leffler /* 446c42a7b7eSSam Leffler * Special case certain configurations. Note the 447c42a7b7eSSam Leffler * CAB queue is handled by these specially so don't 448c42a7b7eSSam Leffler * include them when checking the txq setup mask. 449c42a7b7eSSam Leffler */ 450c42a7b7eSSam Leffler switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) { 451c42a7b7eSSam Leffler case 0x01: 452c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc); 453c42a7b7eSSam Leffler break; 454c42a7b7eSSam Leffler case 0x0f: 455c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc); 456c42a7b7eSSam Leffler break; 457c42a7b7eSSam Leffler default: 458c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc); 459c42a7b7eSSam Leffler break; 460c42a7b7eSSam Leffler } 461c42a7b7eSSam Leffler 462c42a7b7eSSam Leffler /* 463c42a7b7eSSam Leffler * Setup rate control. Some rate control modules 464c42a7b7eSSam Leffler * call back to change the anntena state so expose 465c42a7b7eSSam Leffler * the necessary entry points. 466c42a7b7eSSam Leffler * XXX maybe belongs in struct ath_ratectrl? 467c42a7b7eSSam Leffler */ 468c42a7b7eSSam Leffler sc->sc_setdefantenna = ath_setdefantenna; 469c42a7b7eSSam Leffler sc->sc_rc = ath_rate_attach(sc); 470c42a7b7eSSam Leffler if (sc->sc_rc == NULL) { 471c42a7b7eSSam Leffler error = EIO; 472c42a7b7eSSam Leffler goto bad2; 473c42a7b7eSSam Leffler } 474c42a7b7eSSam Leffler 4753e50ec2cSSam Leffler sc->sc_blinking = 0; 476c42a7b7eSSam Leffler sc->sc_ledstate = 1; 4773e50ec2cSSam Leffler sc->sc_ledon = 0; /* low true */ 4783e50ec2cSSam Leffler sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */ 4793e50ec2cSSam Leffler callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE); 480c42a7b7eSSam Leffler /* 481c42a7b7eSSam Leffler * Auto-enable soft led processing for IBM cards and for 482c42a7b7eSSam Leffler * 5211 minipci cards. Users can also manually enable/disable 483c42a7b7eSSam Leffler * support with a sysctl. 484c42a7b7eSSam Leffler */ 485c42a7b7eSSam Leffler sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID); 486c42a7b7eSSam Leffler if (sc->sc_softled) { 487c42a7b7eSSam Leffler ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); 4883e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); 489c42a7b7eSSam Leffler } 4905591b213SSam Leffler 4915591b213SSam Leffler ifp->if_softc = sc; 4925591b213SSam Leffler ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; 4935591b213SSam Leffler ifp->if_start = ath_start; 4945591b213SSam Leffler ifp->if_watchdog = ath_watchdog; 4955591b213SSam Leffler ifp->if_ioctl = ath_ioctl; 4965591b213SSam Leffler ifp->if_init = ath_init; 497154b8df2SMax Laier IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 498154b8df2SMax Laier ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 499154b8df2SMax Laier IFQ_SET_READY(&ifp->if_snd); 5005591b213SSam Leffler 501c42a7b7eSSam Leffler ic->ic_ifp = ifp; 502c42a7b7eSSam Leffler ic->ic_reset = ath_reset; 5035591b213SSam Leffler ic->ic_newassoc = ath_newassoc; 504c42a7b7eSSam Leffler ic->ic_updateslot = ath_updateslot; 505c42a7b7eSSam Leffler ic->ic_wme.wme_update = ath_wme_update; 5065591b213SSam Leffler /* XXX not right but it's not used anywhere important */ 5075591b213SSam Leffler ic->ic_phytype = IEEE80211_T_OFDM; 5085591b213SSam Leffler ic->ic_opmode = IEEE80211_M_STA; 509c42a7b7eSSam Leffler ic->ic_caps = 510c42a7b7eSSam Leffler IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 511fe32c3efSSam Leffler | IEEE80211_C_HOSTAP /* hostap mode */ 512fe32c3efSSam Leffler | IEEE80211_C_MONITOR /* monitor mode */ 5137a04dc27SSam Leffler | IEEE80211_C_AHDEMO /* adhoc demo mode */ 514fe32c3efSSam Leffler | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 515c42a7b7eSSam Leffler | IEEE80211_C_SHSLOT /* short slot time supported */ 516c42a7b7eSSam Leffler | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 51701e7e035SSam Leffler ; 518c42a7b7eSSam Leffler /* 519c42a7b7eSSam Leffler * Query the hal to figure out h/w crypto support. 520c42a7b7eSSam Leffler */ 521c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP)) 522c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_WEP; 523c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB)) 524c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_AES; 525c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM)) 526c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_AES_CCM; 527c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP)) 528c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_CKIP; 529c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) { 530c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TKIP; 531c42a7b7eSSam Leffler /* 532c42a7b7eSSam Leffler * Check if h/w does the MIC and/or whether the 533c42a7b7eSSam Leffler * separate key cache entries are required to 534c42a7b7eSSam Leffler * handle both tx+rx MIC keys. 535c42a7b7eSSam Leffler */ 536c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) 537c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TKIPMIC; 5385901d2d3SSam Leffler /* 5395901d2d3SSam Leffler * If the h/w supports storing tx+rx MIC keys 5405901d2d3SSam Leffler * in one cache slot automatically enable use. 5415901d2d3SSam Leffler */ 5425901d2d3SSam Leffler if (ath_hal_hastkipsplit(ah) || 5435901d2d3SSam Leffler !ath_hal_settkipsplit(ah, AH_FALSE)) 544c42a7b7eSSam Leffler sc->sc_splitmic = 1; 545c42a7b7eSSam Leffler } 546e8fd88a3SSam Leffler sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR); 547e8fd88a3SSam Leffler sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah); 548c42a7b7eSSam Leffler /* 5495901d2d3SSam Leffler * Mark key cache slots associated with global keys 5505901d2d3SSam Leffler * as in use. If we knew TKIP was not to be used we 5515901d2d3SSam Leffler * could leave the +32, +64, and +32+64 slots free. 5525901d2d3SSam Leffler */ 5535901d2d3SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) { 5545901d2d3SSam Leffler setbit(sc->sc_keymap, i); 5555901d2d3SSam Leffler setbit(sc->sc_keymap, i+64); 5565901d2d3SSam Leffler if (sc->sc_splitmic) { 5575901d2d3SSam Leffler setbit(sc->sc_keymap, i+32); 5585901d2d3SSam Leffler setbit(sc->sc_keymap, i+32+64); 5595901d2d3SSam Leffler } 5605901d2d3SSam Leffler } 5615901d2d3SSam Leffler /* 562c42a7b7eSSam Leffler * TPC support can be done either with a global cap or 563c42a7b7eSSam Leffler * per-packet support. The latter is not available on 564c42a7b7eSSam Leffler * all parts. We're a bit pedantic here as all parts 565c42a7b7eSSam Leffler * support a global cap. 566c42a7b7eSSam Leffler */ 567c59005e9SSam Leffler if (ath_hal_hastpc(ah) || ath_hal_hastxpowlimit(ah)) 568c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TXPMGT; 569c42a7b7eSSam Leffler 570c42a7b7eSSam Leffler /* 571c42a7b7eSSam Leffler * Mark WME capability only if we have sufficient 572c42a7b7eSSam Leffler * hardware queues to do proper priority scheduling. 573c42a7b7eSSam Leffler */ 574c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != sc->sc_ac2q[WME_AC_BK]) 575c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_WME; 576c42a7b7eSSam Leffler /* 577e8fd88a3SSam Leffler * Check for misc other capabilities. 578c42a7b7eSSam Leffler */ 579c42a7b7eSSam Leffler if (ath_hal_hasbursting(ah)) 580c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_BURST; 581c42a7b7eSSam Leffler 582c42a7b7eSSam Leffler /* 583c42a7b7eSSam Leffler * Indicate we need the 802.11 header padded to a 584c42a7b7eSSam Leffler * 32-bit boundary for 4-address and QoS frames. 585c42a7b7eSSam Leffler */ 586c42a7b7eSSam Leffler ic->ic_flags |= IEEE80211_F_DATAPAD; 587c42a7b7eSSam Leffler 588c42a7b7eSSam Leffler /* 589c42a7b7eSSam Leffler * Query the hal about antenna support. 590c42a7b7eSSam Leffler */ 591c42a7b7eSSam Leffler sc->sc_defant = ath_hal_getdefantenna(ah); 592c42a7b7eSSam Leffler 593c42a7b7eSSam Leffler /* 594c42a7b7eSSam Leffler * Not all chips have the VEOL support we want to 595c42a7b7eSSam Leffler * use with IBSS beacons; check here for it. 596c42a7b7eSSam Leffler */ 597c42a7b7eSSam Leffler sc->sc_hasveol = ath_hal_hasveol(ah); 5985591b213SSam Leffler 5995591b213SSam Leffler /* get mac address from hardware */ 6005591b213SSam Leffler ath_hal_getmac(ah, ic->ic_myaddr); 6015591b213SSam Leffler 6025591b213SSam Leffler /* call MI attach routine. */ 603c42a7b7eSSam Leffler ieee80211_ifattach(ic); 6047a04dc27SSam Leffler sc->sc_opmode = ic->ic_opmode; 6055591b213SSam Leffler /* override default methods */ 6065591b213SSam Leffler ic->ic_node_alloc = ath_node_alloc; 6071e774079SSam Leffler sc->sc_node_free = ic->ic_node_free; 6085591b213SSam Leffler ic->ic_node_free = ath_node_free; 609de5af704SSam Leffler ic->ic_node_getrssi = ath_node_getrssi; 610c42a7b7eSSam Leffler sc->sc_recv_mgmt = ic->ic_recv_mgmt; 611c42a7b7eSSam Leffler ic->ic_recv_mgmt = ath_recv_mgmt; 61245bbf62fSSam Leffler sc->sc_newstate = ic->ic_newstate; 61345bbf62fSSam Leffler ic->ic_newstate = ath_newstate; 614c1225b52SSam Leffler ic->ic_crypto.cs_max_keyix = sc->sc_keymax; 615c42a7b7eSSam Leffler ic->ic_crypto.cs_key_alloc = ath_key_alloc; 616c42a7b7eSSam Leffler ic->ic_crypto.cs_key_delete = ath_key_delete; 617c42a7b7eSSam Leffler ic->ic_crypto.cs_key_set = ath_key_set; 618c42a7b7eSSam Leffler ic->ic_crypto.cs_key_update_begin = ath_key_update_begin; 619c42a7b7eSSam Leffler ic->ic_crypto.cs_key_update_end = ath_key_update_end; 620664443d0SSam Leffler ic->ic_raw_xmit = ath_raw_xmit; 62145bbf62fSSam Leffler /* complete initialization */ 622c42a7b7eSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 6235591b213SSam Leffler 624c42a7b7eSSam Leffler ath_bpfattach(sc); 6254866e6c2SSam Leffler /* 6264866e6c2SSam Leffler * Setup dynamic sysctl's now that country code and 6274866e6c2SSam Leffler * regdomain are available from the hal. 6284866e6c2SSam Leffler */ 6294866e6c2SSam Leffler ath_sysctlattach(sc); 63073454c73SSam Leffler 631c42a7b7eSSam Leffler if (bootverbose) 632c42a7b7eSSam Leffler ieee80211_announce(ic); 633c42a7b7eSSam Leffler ath_announce(sc); 6345591b213SSam Leffler return 0; 635b28b4653SSam Leffler bad2: 636c42a7b7eSSam Leffler ath_tx_cleanup(sc); 637b28b4653SSam Leffler ath_desc_free(sc); 6385591b213SSam Leffler bad: 6395591b213SSam Leffler if (ah) 6405591b213SSam Leffler ath_hal_detach(ah); 641fc74a9f9SBrooks Davis if (ifp != NULL) 642fc74a9f9SBrooks Davis if_free(ifp); 6435591b213SSam Leffler sc->sc_invalid = 1; 6445591b213SSam Leffler return error; 6455591b213SSam Leffler } 6465591b213SSam Leffler 6475591b213SSam Leffler int 6485591b213SSam Leffler ath_detach(struct ath_softc *sc) 6495591b213SSam Leffler { 650fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6515591b213SSam Leffler 652c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 653c42a7b7eSSam Leffler __func__, ifp->if_flags); 6545591b213SSam Leffler 6555591b213SSam Leffler ath_stop(ifp); 65673454c73SSam Leffler bpfdetach(ifp); 657c42a7b7eSSam Leffler /* 658c42a7b7eSSam Leffler * NB: the order of these is important: 659c42a7b7eSSam Leffler * o call the 802.11 layer before detaching the hal to 660c42a7b7eSSam Leffler * insure callbacks into the driver to delete global 661c42a7b7eSSam Leffler * key cache entries can be handled 662c42a7b7eSSam Leffler * o reclaim the tx queue data structures after calling 663c42a7b7eSSam Leffler * the 802.11 layer as we'll get called back to reclaim 664c42a7b7eSSam Leffler * node state and potentially want to use them 665c42a7b7eSSam Leffler * o to cleanup the tx queues the hal is called, so detach 666c42a7b7eSSam Leffler * it last 667c42a7b7eSSam Leffler * Other than that, it's straightforward... 668c42a7b7eSSam Leffler */ 669c42a7b7eSSam Leffler ieee80211_ifdetach(&sc->sc_ic); 67086e07743SSam Leffler #ifdef ATH_TX99_DIAG 67186e07743SSam Leffler if (sc->sc_tx99 != NULL) 67286e07743SSam Leffler sc->sc_tx99->detach(sc->sc_tx99); 67386e07743SSam Leffler #endif 6740bbf5441SSam Leffler taskqueue_free(sc->sc_tq); 675c42a7b7eSSam Leffler ath_rate_detach(sc->sc_rc); 6765591b213SSam Leffler ath_desc_free(sc); 677c42a7b7eSSam Leffler ath_tx_cleanup(sc); 6785591b213SSam Leffler ath_hal_detach(sc->sc_ah); 679c4c6f08fSRuslan Ermilov if_free(ifp); 680f0b2a0beSSam Leffler 6815591b213SSam Leffler return 0; 6825591b213SSam Leffler } 6835591b213SSam Leffler 6845591b213SSam Leffler void 6855591b213SSam Leffler ath_suspend(struct ath_softc *sc) 6865591b213SSam Leffler { 687fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6885591b213SSam Leffler 689c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 690c42a7b7eSSam Leffler __func__, ifp->if_flags); 6915591b213SSam Leffler 6925591b213SSam Leffler ath_stop(ifp); 6935591b213SSam Leffler } 6945591b213SSam Leffler 6955591b213SSam Leffler void 6965591b213SSam Leffler ath_resume(struct ath_softc *sc) 6975591b213SSam Leffler { 698fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6995591b213SSam Leffler 700c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 701c42a7b7eSSam Leffler __func__, ifp->if_flags); 7025591b213SSam Leffler 7036b59f5e3SSam Leffler if (ifp->if_flags & IFF_UP) { 704fc74a9f9SBrooks Davis ath_init(sc); 70513f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 7065591b213SSam Leffler ath_start(ifp); 7075591b213SSam Leffler } 708b50c8bdeSSam Leffler if (sc->sc_softled) { 709b50c8bdeSSam Leffler ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); 710b50c8bdeSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); 711b50c8bdeSSam Leffler } 7126b59f5e3SSam Leffler } 7135591b213SSam Leffler 7145591b213SSam Leffler void 7155591b213SSam Leffler ath_shutdown(struct ath_softc *sc) 7165591b213SSam Leffler { 717fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 7185591b213SSam Leffler 719c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 720c42a7b7eSSam Leffler __func__, ifp->if_flags); 7215591b213SSam Leffler 7225591b213SSam Leffler ath_stop(ifp); 7235591b213SSam Leffler } 7245591b213SSam Leffler 725c42a7b7eSSam Leffler /* 726c42a7b7eSSam Leffler * Interrupt handler. Most of the actual processing is deferred. 727c42a7b7eSSam Leffler */ 7285591b213SSam Leffler void 7295591b213SSam Leffler ath_intr(void *arg) 7305591b213SSam Leffler { 7315591b213SSam Leffler struct ath_softc *sc = arg; 732fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 7335591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 7345591b213SSam Leffler HAL_INT status; 7355591b213SSam Leffler 7365591b213SSam Leffler if (sc->sc_invalid) { 7375591b213SSam Leffler /* 738b58b3803SSam Leffler * The hardware is not ready/present, don't touch anything. 739b58b3803SSam Leffler * Note this can happen early on if the IRQ is shared. 7405591b213SSam Leffler */ 741c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid; ignored\n", __func__); 7425591b213SSam Leffler return; 7435591b213SSam Leffler } 744fdd758d4SSam Leffler if (!ath_hal_intrpend(ah)) /* shared irq, not for us */ 745fdd758d4SSam Leffler return; 74613f4c340SRobert Watson if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & 74713f4c340SRobert Watson IFF_DRV_RUNNING))) { 748c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 749c42a7b7eSSam Leffler __func__, ifp->if_flags); 7505591b213SSam Leffler ath_hal_getisr(ah, &status); /* clear ISR */ 7515591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable further intr's */ 7525591b213SSam Leffler return; 7535591b213SSam Leffler } 754c42a7b7eSSam Leffler /* 755c42a7b7eSSam Leffler * Figure out the reason(s) for the interrupt. Note 756c42a7b7eSSam Leffler * that the hal returns a pseudo-ISR that may include 757c42a7b7eSSam Leffler * bits we haven't explicitly enabled so we mask the 758c42a7b7eSSam Leffler * value to insure we only process bits we requested. 759c42a7b7eSSam Leffler */ 7605591b213SSam Leffler ath_hal_getisr(ah, &status); /* NB: clears ISR too */ 761c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status); 762ecddff40SSam Leffler status &= sc->sc_imask; /* discard unasked for bits */ 7635591b213SSam Leffler if (status & HAL_INT_FATAL) { 7645591b213SSam Leffler sc->sc_stats.ast_hardware++; 7655591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable intr's until reset */ 76616c8acaaSSam Leffler ath_fatal_proc(sc, 0); 7675591b213SSam Leffler } else if (status & HAL_INT_RXORN) { 7685591b213SSam Leffler sc->sc_stats.ast_rxorn++; 7695591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable intr's until reset */ 7700bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxorntask); 7715591b213SSam Leffler } else { 772c42a7b7eSSam Leffler if (status & HAL_INT_SWBA) { 773c42a7b7eSSam Leffler /* 774c42a7b7eSSam Leffler * Software beacon alert--time to send a beacon. 775c42a7b7eSSam Leffler * Handle beacon transmission directly; deferring 776c42a7b7eSSam Leffler * this is too slow to meet timing constraints 777c42a7b7eSSam Leffler * under load. 778c42a7b7eSSam Leffler */ 779c42a7b7eSSam Leffler ath_beacon_proc(sc, 0); 780c42a7b7eSSam Leffler } 7815591b213SSam Leffler if (status & HAL_INT_RXEOL) { 7825591b213SSam Leffler /* 7835591b213SSam Leffler * NB: the hardware should re-read the link when 7845591b213SSam Leffler * RXE bit is written, but it doesn't work at 7855591b213SSam Leffler * least on older hardware revs. 7865591b213SSam Leffler */ 7875591b213SSam Leffler sc->sc_stats.ast_rxeol++; 7885591b213SSam Leffler sc->sc_rxlink = NULL; 7895591b213SSam Leffler } 7905591b213SSam Leffler if (status & HAL_INT_TXURN) { 7915591b213SSam Leffler sc->sc_stats.ast_txurn++; 7925591b213SSam Leffler /* bump tx trigger level */ 7935591b213SSam Leffler ath_hal_updatetxtriglevel(ah, AH_TRUE); 7945591b213SSam Leffler } 7955591b213SSam Leffler if (status & HAL_INT_RX) 7960bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 7975591b213SSam Leffler if (status & HAL_INT_TX) 7980bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask); 7995591b213SSam Leffler if (status & HAL_INT_BMISS) { 8005591b213SSam Leffler sc->sc_stats.ast_bmiss++; 8010bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bmisstask); 8025591b213SSam Leffler } 803c42a7b7eSSam Leffler if (status & HAL_INT_MIB) { 804c42a7b7eSSam Leffler sc->sc_stats.ast_mib++; 805c42a7b7eSSam Leffler /* 806c42a7b7eSSam Leffler * Disable interrupts until we service the MIB 807c42a7b7eSSam Leffler * interrupt; otherwise it will continue to fire. 808c42a7b7eSSam Leffler */ 809c42a7b7eSSam Leffler ath_hal_intrset(ah, 0); 810c42a7b7eSSam Leffler /* 811c42a7b7eSSam Leffler * Let the hal handle the event. We assume it will 812c42a7b7eSSam Leffler * clear whatever condition caused the interrupt. 813c42a7b7eSSam Leffler */ 814ffa2cab6SSam Leffler ath_hal_mibevent(ah, &sc->sc_halstats); 815c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 816c42a7b7eSSam Leffler } 8175591b213SSam Leffler } 8185591b213SSam Leffler } 8195591b213SSam Leffler 8205591b213SSam Leffler static void 8215591b213SSam Leffler ath_fatal_proc(void *arg, int pending) 8225591b213SSam Leffler { 8235591b213SSam Leffler struct ath_softc *sc = arg; 824fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 82516c8acaaSSam Leffler u_int32_t *state; 82616c8acaaSSam Leffler u_int32_t len; 8275591b213SSam Leffler 828c42a7b7eSSam Leffler if_printf(ifp, "hardware error; resetting\n"); 82916c8acaaSSam Leffler /* 83016c8acaaSSam Leffler * Fatal errors are unrecoverable. Typically these 83116c8acaaSSam Leffler * are caused by DMA errors. Collect h/w state from 83216c8acaaSSam Leffler * the hal so we can diagnose what's going on. 83316c8acaaSSam Leffler */ 83416c8acaaSSam Leffler if (ath_hal_getfatalstate(sc->sc_ah, &state, &len)) { 83516c8acaaSSam Leffler KASSERT(len >= 6*sizeof(u_int32_t), ("len %u bytes", len)); 83616c8acaaSSam Leffler if_printf(ifp, "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", 83716c8acaaSSam Leffler state[0], state[1] , state[2], state[3], 83816c8acaaSSam Leffler state[4], state[5]); 83916c8acaaSSam Leffler } 840c42a7b7eSSam Leffler ath_reset(ifp); 8415591b213SSam Leffler } 8425591b213SSam Leffler 8435591b213SSam Leffler static void 8445591b213SSam Leffler ath_rxorn_proc(void *arg, int pending) 8455591b213SSam Leffler { 8465591b213SSam Leffler struct ath_softc *sc = arg; 847fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 8485591b213SSam Leffler 849c42a7b7eSSam Leffler if_printf(ifp, "rx FIFO overrun; resetting\n"); 850c42a7b7eSSam Leffler ath_reset(ifp); 8515591b213SSam Leffler } 8525591b213SSam Leffler 8535591b213SSam Leffler static void 8545591b213SSam Leffler ath_bmiss_proc(void *arg, int pending) 8555591b213SSam Leffler { 8565591b213SSam Leffler struct ath_softc *sc = arg; 8575591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 8585591b213SSam Leffler 859c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); 8605591b213SSam Leffler KASSERT(ic->ic_opmode == IEEE80211_M_STA, 8615591b213SSam Leffler ("unexpect operating mode %u", ic->ic_opmode)); 862e585d188SSam Leffler if (ic->ic_state == IEEE80211_S_RUN) { 863d7736e13SSam Leffler u_int64_t lastrx = sc->sc_lastrx; 864d7736e13SSam Leffler u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); 865d7736e13SSam Leffler u_int bmisstimeout = 866d7736e13SSam Leffler ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024; 867d7736e13SSam Leffler 868d7736e13SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 869d7736e13SSam Leffler "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", 870d7736e13SSam Leffler __func__, (unsigned long long) tsf, 871d7736e13SSam Leffler (unsigned long long)(tsf - lastrx), 872d7736e13SSam Leffler (unsigned long long) lastrx, bmisstimeout); 873e585d188SSam Leffler /* 874d7736e13SSam Leffler * Workaround phantom bmiss interrupts by sanity-checking 875d7736e13SSam Leffler * the time of our last rx'd frame. If it is within the 876d7736e13SSam Leffler * beacon miss interval then ignore the interrupt. If it's 877d7736e13SSam Leffler * truly a bmiss we'll get another interrupt soon and that'll 878d7736e13SSam Leffler * be dispatched up for processing. 879e585d188SSam Leffler */ 880d7736e13SSam Leffler if (tsf - lastrx > bmisstimeout) { 881b5f4adb3SSam Leffler NET_LOCK_GIANT(); 882d7736e13SSam Leffler ieee80211_beacon_miss(ic); 883b5f4adb3SSam Leffler NET_UNLOCK_GIANT(); 884d7736e13SSam Leffler } else 885d7736e13SSam Leffler sc->sc_stats.ast_bmiss_phantom++; 886e585d188SSam Leffler } 8875591b213SSam Leffler } 8885591b213SSam Leffler 889724c193aSSam Leffler /* 890724c193aSSam Leffler * Convert net80211 channel to a HAL channel with the flags 891724c193aSSam Leffler * constrained to reflect the current operating mode and 892724c193aSSam Leffler * the frequency possibly mapped for GSM channels. 893724c193aSSam Leffler */ 894724c193aSSam Leffler static void 895724c193aSSam Leffler ath_mapchan(struct ieee80211com *ic, HAL_CHANNEL *hc, 896724c193aSSam Leffler const struct ieee80211_channel *chan) 8975591b213SSam Leffler { 898c42a7b7eSSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 8995591b213SSam Leffler static const u_int modeflags[] = { 9005591b213SSam Leffler 0, /* IEEE80211_MODE_AUTO */ 9015591b213SSam Leffler CHANNEL_A, /* IEEE80211_MODE_11A */ 9025591b213SSam Leffler CHANNEL_B, /* IEEE80211_MODE_11B */ 9035591b213SSam Leffler CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 904c42a7b7eSSam Leffler 0, /* IEEE80211_MODE_FH */ 905bd5a9920SSam Leffler CHANNEL_ST, /* IEEE80211_MODE_TURBO_A */ 906c42a7b7eSSam Leffler CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ 9075591b213SSam Leffler }; 908c42a7b7eSSam Leffler enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan); 909c42a7b7eSSam Leffler 910c42a7b7eSSam Leffler KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode)); 911c42a7b7eSSam Leffler KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode)); 912724c193aSSam Leffler hc->channelFlags = modeflags[mode]; 913aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) 914724c193aSSam Leffler hc->channelFlags |= CHANNEL_HALF; 915aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_QUARTER(chan)) 916724c193aSSam Leffler hc->channelFlags |= CHANNEL_QUARTER; 917724c193aSSam Leffler 918724c193aSSam Leffler hc->channel = IEEE80211_IS_CHAN_GSM(chan) ? 919724c193aSSam Leffler 2422 + (922 - chan->ic_freq) : chan->ic_freq; 920c42a7b7eSSam Leffler #undef N 9215591b213SSam Leffler } 9225591b213SSam Leffler 9235591b213SSam Leffler static void 9245591b213SSam Leffler ath_init(void *arg) 9255591b213SSam Leffler { 9265591b213SSam Leffler struct ath_softc *sc = (struct ath_softc *) arg; 9275591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 928fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 9295591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 9305591b213SSam Leffler HAL_STATUS status; 9315591b213SSam Leffler 932c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 933c42a7b7eSSam Leffler __func__, ifp->if_flags); 9345591b213SSam Leffler 935f0b2a0beSSam Leffler ATH_LOCK(sc); 9365591b213SSam Leffler /* 9375591b213SSam Leffler * Stop anything previously setup. This is safe 9385591b213SSam Leffler * whether this is the first time through or not. 9395591b213SSam Leffler */ 940c42a7b7eSSam Leffler ath_stop_locked(ifp); 9415591b213SSam Leffler 9425591b213SSam Leffler /* 9435591b213SSam Leffler * The basic interface to setting the hardware in a good 9445591b213SSam Leffler * state is ``reset''. On return the hardware is known to 9455591b213SSam Leffler * be powered up and with interrupts disabled. This must 9465591b213SSam Leffler * be followed by initialization of the appropriate bits 9475591b213SSam Leffler * and then setup of the interrupt mask. 9485591b213SSam Leffler */ 949724c193aSSam Leffler ath_mapchan(ic, &sc->sc_curchan, ic->ic_curchan); 9507a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { 9515591b213SSam Leffler if_printf(ifp, "unable to reset hardware; hal status %u\n", 9525591b213SSam Leffler status); 9535591b213SSam Leffler goto done; 9545591b213SSam Leffler } 9555591b213SSam Leffler 9565591b213SSam Leffler /* 957c42a7b7eSSam Leffler * This is needed only to setup initial state 958c42a7b7eSSam Leffler * but it's best done after a reset. 959c42a7b7eSSam Leffler */ 960c42a7b7eSSam Leffler ath_update_txpow(sc); 961c59005e9SSam Leffler /* 962c59005e9SSam Leffler * Likewise this is set during reset so update 963c59005e9SSam Leffler * state cached in the driver. 964c59005e9SSam Leffler */ 965c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 966bd5a9920SSam Leffler sc->sc_calinterval = 1; 967bd5a9920SSam Leffler sc->sc_caltries = 0; 968c42a7b7eSSam Leffler 969c42a7b7eSSam Leffler /* 9705591b213SSam Leffler * Setup the hardware after reset: the key cache 9715591b213SSam Leffler * is filled as needed and the receive engine is 9725591b213SSam Leffler * set going. Frame transmit is handled entirely 9735591b213SSam Leffler * in the frame output path; there's nothing to do 9745591b213SSam Leffler * here except setup the interrupt mask. 9755591b213SSam Leffler */ 9765591b213SSam Leffler if (ath_startrecv(sc) != 0) { 9775591b213SSam Leffler if_printf(ifp, "unable to start recv logic\n"); 9785591b213SSam Leffler goto done; 9795591b213SSam Leffler } 9805591b213SSam Leffler 9815591b213SSam Leffler /* 9825591b213SSam Leffler * Enable interrupts. 9835591b213SSam Leffler */ 9845591b213SSam Leffler sc->sc_imask = HAL_INT_RX | HAL_INT_TX 9855591b213SSam Leffler | HAL_INT_RXEOL | HAL_INT_RXORN 9865591b213SSam Leffler | HAL_INT_FATAL | HAL_INT_GLOBAL; 987c42a7b7eSSam Leffler /* 988c42a7b7eSSam Leffler * Enable MIB interrupts when there are hardware phy counters. 989c42a7b7eSSam Leffler * Note we only do this (at the moment) for station mode. 990c42a7b7eSSam Leffler */ 991c42a7b7eSSam Leffler if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) 992c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_MIB; 9935591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 9945591b213SSam Leffler 99513f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 9965591b213SSam Leffler ic->ic_state = IEEE80211_S_INIT; 9975591b213SSam Leffler 9985591b213SSam Leffler /* 9995591b213SSam Leffler * The hardware should be ready to go now so it's safe 10005591b213SSam Leffler * to kick the 802.11 state machine as it's likely to 10015591b213SSam Leffler * immediately call back to us to send mgmt frames. 10025591b213SSam Leffler */ 1003b5c99415SSam Leffler ath_chan_change(sc, ic->ic_curchan); 100486e07743SSam Leffler #ifdef ATH_TX99_DIAG 100586e07743SSam Leffler if (sc->sc_tx99 != NULL) 100686e07743SSam Leffler sc->sc_tx99->start(sc->sc_tx99); 100786e07743SSam Leffler else 100886e07743SSam Leffler #endif 1009c42a7b7eSSam Leffler if (ic->ic_opmode != IEEE80211_M_MONITOR) { 1010c42a7b7eSSam Leffler if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 101145bbf62fSSam Leffler ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1012c42a7b7eSSam Leffler } else 10136b59f5e3SSam Leffler ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 10145591b213SSam Leffler done: 1015f0b2a0beSSam Leffler ATH_UNLOCK(sc); 10165591b213SSam Leffler } 10175591b213SSam Leffler 10185591b213SSam Leffler static void 1019c42a7b7eSSam Leffler ath_stop_locked(struct ifnet *ifp) 10205591b213SSam Leffler { 10215591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 1022c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 10235591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 10245591b213SSam Leffler 1025c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", 1026c42a7b7eSSam Leffler __func__, sc->sc_invalid, ifp->if_flags); 10275591b213SSam Leffler 1028c42a7b7eSSam Leffler ATH_LOCK_ASSERT(sc); 102913f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 10305591b213SSam Leffler /* 10315591b213SSam Leffler * Shutdown the hardware and driver: 1032c42a7b7eSSam Leffler * reset 802.11 state machine 10335591b213SSam Leffler * turn off timers 1034c42a7b7eSSam Leffler * disable interrupts 1035c42a7b7eSSam Leffler * turn off the radio 10365591b213SSam Leffler * clear transmit machinery 10375591b213SSam Leffler * clear receive machinery 10385591b213SSam Leffler * drain and release tx queues 10395591b213SSam Leffler * reclaim beacon resources 10405591b213SSam Leffler * power down hardware 10415591b213SSam Leffler * 10425591b213SSam Leffler * Note that some of this work is not possible if the 10435591b213SSam Leffler * hardware is gone (invalid). 10445591b213SSam Leffler */ 104586e07743SSam Leffler #ifdef ATH_TX99_DIAG 104686e07743SSam Leffler if (sc->sc_tx99 != NULL) 104786e07743SSam Leffler sc->sc_tx99->stop(sc->sc_tx99); 104886e07743SSam Leffler #endif 1049c42a7b7eSSam Leffler ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 105013f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 10515591b213SSam Leffler ifp->if_timer = 0; 1052c42a7b7eSSam Leffler if (!sc->sc_invalid) { 10533e50ec2cSSam Leffler if (sc->sc_softled) { 10543e50ec2cSSam Leffler callout_stop(&sc->sc_ledtimer); 10553e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, 10563e50ec2cSSam Leffler !sc->sc_ledon); 10573e50ec2cSSam Leffler sc->sc_blinking = 0; 10583e50ec2cSSam Leffler } 10595591b213SSam Leffler ath_hal_intrset(ah, 0); 1060c42a7b7eSSam Leffler } 10615591b213SSam Leffler ath_draintxq(sc); 1062c42a7b7eSSam Leffler if (!sc->sc_invalid) { 10635591b213SSam Leffler ath_stoprecv(sc); 1064c42a7b7eSSam Leffler ath_hal_phydisable(ah); 1065c42a7b7eSSam Leffler } else 10665591b213SSam Leffler sc->sc_rxlink = NULL; 1067154b8df2SMax Laier IFQ_DRV_PURGE(&ifp->if_snd); 10685591b213SSam Leffler ath_beacon_free(sc); 1069c42a7b7eSSam Leffler } 1070c42a7b7eSSam Leffler } 1071c42a7b7eSSam Leffler 1072c42a7b7eSSam Leffler static void 1073c42a7b7eSSam Leffler ath_stop(struct ifnet *ifp) 1074c42a7b7eSSam Leffler { 1075c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1076c42a7b7eSSam Leffler 1077c42a7b7eSSam Leffler ATH_LOCK(sc); 1078c42a7b7eSSam Leffler ath_stop_locked(ifp); 1079c42a7b7eSSam Leffler if (!sc->sc_invalid) { 1080c42a7b7eSSam Leffler /* 1081c42a7b7eSSam Leffler * Set the chip in full sleep mode. Note that we are 1082c42a7b7eSSam Leffler * careful to do this only when bringing the interface 1083c42a7b7eSSam Leffler * completely to a stop. When the chip is in this state 1084c42a7b7eSSam Leffler * it must be carefully woken up or references to 1085c42a7b7eSSam Leffler * registers in the PCI clock domain may freeze the bus 1086c42a7b7eSSam Leffler * (and system). This varies by chip and is mostly an 1087c42a7b7eSSam Leffler * issue with newer parts that go to sleep more quickly. 1088c42a7b7eSSam Leffler */ 1089bd5a9920SSam Leffler ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); 10905591b213SSam Leffler } 1091f0b2a0beSSam Leffler ATH_UNLOCK(sc); 10925591b213SSam Leffler } 10935591b213SSam Leffler 10945591b213SSam Leffler /* 10955591b213SSam Leffler * Reset the hardware w/o losing operational state. This is 10965591b213SSam Leffler * basically a more efficient way of doing ath_stop, ath_init, 10975591b213SSam Leffler * followed by state transitions to the current 802.11 1098c42a7b7eSSam Leffler * operational state. Used to recover from various errors and 1099c42a7b7eSSam Leffler * to reset or reload hardware state. 11005591b213SSam Leffler */ 1101c42a7b7eSSam Leffler static int 1102c42a7b7eSSam Leffler ath_reset(struct ifnet *ifp) 11035591b213SSam Leffler { 1104c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 11055591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 11065591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 11075591b213SSam Leffler HAL_STATUS status; 11085591b213SSam Leffler 11095591b213SSam Leffler /* 11105591b213SSam Leffler * Convert to a HAL channel description with the flags 11115591b213SSam Leffler * constrained to reflect the current operating mode. 11125591b213SSam Leffler */ 1113724c193aSSam Leffler ath_mapchan(ic, &sc->sc_curchan, ic->ic_curchan); 11145591b213SSam Leffler 11155591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 11165591b213SSam Leffler ath_draintxq(sc); /* stop xmit side */ 11175591b213SSam Leffler ath_stoprecv(sc); /* stop recv side */ 11185591b213SSam Leffler /* NB: indicate channel change so we do a full reset */ 11197a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status)) 11205591b213SSam Leffler if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", 11215591b213SSam Leffler __func__, status); 1122c42a7b7eSSam Leffler ath_update_txpow(sc); /* update tx power state */ 1123c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 1124bd5a9920SSam Leffler sc->sc_calinterval = 1; 1125bd5a9920SSam Leffler sc->sc_caltries = 0; 1126c42a7b7eSSam Leffler /* 1127c42a7b7eSSam Leffler * We may be doing a reset in response to an ioctl 1128c42a7b7eSSam Leffler * that changes the channel so update any state that 1129c42a7b7eSSam Leffler * might change as a result. 1130c42a7b7eSSam Leffler */ 1131724c193aSSam Leffler ath_chan_change(sc, ic->ic_curchan); 1132bd5a9920SSam Leffler if (ath_startrecv(sc) != 0) /* restart recv */ 1133bd5a9920SSam Leffler if_printf(ifp, "%s: unable to start recv logic\n", __func__); 11345591b213SSam Leffler if (ic->ic_state == IEEE80211_S_RUN) 11355591b213SSam Leffler ath_beacon_config(sc); /* restart beacons */ 1136c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 1137c42a7b7eSSam Leffler 1138c42a7b7eSSam Leffler ath_start(ifp); /* restart xmit */ 1139c42a7b7eSSam Leffler return 0; 11405591b213SSam Leffler } 11415591b213SSam Leffler 11425591b213SSam Leffler static void 11435591b213SSam Leffler ath_start(struct ifnet *ifp) 11445591b213SSam Leffler { 11455591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 11465591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 11475591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 11485591b213SSam Leffler struct ieee80211_node *ni; 11495591b213SSam Leffler struct ath_buf *bf; 11505591b213SSam Leffler struct mbuf *m; 11515591b213SSam Leffler struct ieee80211_frame *wh; 1152c42a7b7eSSam Leffler struct ether_header *eh; 11535591b213SSam Leffler 115413f4c340SRobert Watson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) 11555591b213SSam Leffler return; 11565591b213SSam Leffler for (;;) { 11575591b213SSam Leffler /* 11585591b213SSam Leffler * Grab a TX buffer and associated resources. 11595591b213SSam Leffler */ 1160f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1161c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_txbuf); 1162ebecf802SSam Leffler if (bf != NULL) 1163c42a7b7eSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); 1164f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11655591b213SSam Leffler if (bf == NULL) { 1166ebecf802SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", 1167ebecf802SSam Leffler __func__); 11685591b213SSam Leffler sc->sc_stats.ast_tx_qstop++; 116913f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 11705591b213SSam Leffler break; 11715591b213SSam Leffler } 11725591b213SSam Leffler /* 11735591b213SSam Leffler * Poll the management queue for frames; they 11745591b213SSam Leffler * have priority over normal data frames. 11755591b213SSam Leffler */ 11765591b213SSam Leffler IF_DEQUEUE(&ic->ic_mgtq, m); 11775591b213SSam Leffler if (m == NULL) { 11785591b213SSam Leffler /* 11795591b213SSam Leffler * No data frames go out unless we're associated. 11805591b213SSam Leffler */ 11815591b213SSam Leffler if (ic->ic_state != IEEE80211_S_RUN) { 1182370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1183370572d9SSam Leffler "%s: discard data packet, state %s\n", 1184370572d9SSam Leffler __func__, 1185370572d9SSam Leffler ieee80211_state_name[ic->ic_state]); 11865591b213SSam Leffler sc->sc_stats.ast_tx_discard++; 1187f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1188ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1189f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11905591b213SSam Leffler break; 11915591b213SSam Leffler } 1192154b8df2SMax Laier IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ 11935591b213SSam Leffler if (m == NULL) { 1194f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1195ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1196f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11975591b213SSam Leffler break; 11985591b213SSam Leffler } 1199c42a7b7eSSam Leffler /* 1200c42a7b7eSSam Leffler * Find the node for the destination so we can do 1201c42a7b7eSSam Leffler * things like power save and fast frames aggregation. 1202c42a7b7eSSam Leffler */ 1203c42a7b7eSSam Leffler if (m->m_len < sizeof(struct ether_header) && 1204c42a7b7eSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 1205c42a7b7eSSam Leffler ic->ic_stats.is_tx_nobuf++; /* XXX */ 1206c42a7b7eSSam Leffler ni = NULL; 1207c42a7b7eSSam Leffler goto bad; 1208c42a7b7eSSam Leffler } 1209c42a7b7eSSam Leffler eh = mtod(m, struct ether_header *); 1210c42a7b7eSSam Leffler ni = ieee80211_find_txnode(ic, eh->ether_dhost); 1211c42a7b7eSSam Leffler if (ni == NULL) { 1212c42a7b7eSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 1213fe234894SSam Leffler m_freem(m); 1214c42a7b7eSSam Leffler goto bad; 1215c42a7b7eSSam Leffler } 1216c42a7b7eSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 1217c42a7b7eSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 1218c42a7b7eSSam Leffler /* 1219c42a7b7eSSam Leffler * Station in power save mode; pass the frame 1220c42a7b7eSSam Leffler * to the 802.11 layer and continue. We'll get 1221c42a7b7eSSam Leffler * the frame back when the time is right. 1222c42a7b7eSSam Leffler */ 1223c42a7b7eSSam Leffler ieee80211_pwrsave(ic, ni, m); 1224c42a7b7eSSam Leffler goto reclaim; 1225c42a7b7eSSam Leffler } 1226c42a7b7eSSam Leffler /* calculate priority so we can find the tx queue */ 1227c42a7b7eSSam Leffler if (ieee80211_classify(ic, m, ni)) { 1228c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1229c42a7b7eSSam Leffler "%s: discard, classification failure\n", 1230c42a7b7eSSam Leffler __func__); 1231fe234894SSam Leffler m_freem(m); 1232c42a7b7eSSam Leffler goto bad; 1233c42a7b7eSSam Leffler } 12345591b213SSam Leffler ifp->if_opackets++; 12355591b213SSam Leffler BPF_MTAP(ifp, m); 12365591b213SSam Leffler /* 12375591b213SSam Leffler * Encapsulate the packet in prep for transmission. 12385591b213SSam Leffler */ 1239c42a7b7eSSam Leffler m = ieee80211_encap(ic, m, ni); 12405591b213SSam Leffler if (m == NULL) { 1241370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1242c42a7b7eSSam Leffler "%s: encapsulation failure\n", 1243c42a7b7eSSam Leffler __func__); 12445591b213SSam Leffler sc->sc_stats.ast_tx_encap++; 12455591b213SSam Leffler goto bad; 12465591b213SSam Leffler } 12475591b213SSam Leffler } else { 12480a915fadSSam Leffler /* 12490a915fadSSam Leffler * Hack! The referenced node pointer is in the 12500a915fadSSam Leffler * rcvif field of the packet header. This is 12510a915fadSSam Leffler * placed there by ieee80211_mgmt_output because 12520a915fadSSam Leffler * we need to hold the reference with the frame 12530a915fadSSam Leffler * and there's no other way (other than packet 12540a915fadSSam Leffler * tags which we consider too expensive to use) 12550a915fadSSam Leffler * to pass it along. 12560a915fadSSam Leffler */ 12570a915fadSSam Leffler ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 12580a915fadSSam Leffler m->m_pkthdr.rcvif = NULL; 12590a915fadSSam Leffler 12605591b213SSam Leffler wh = mtod(m, struct ieee80211_frame *); 12615591b213SSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 12625591b213SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_RESP) { 12635591b213SSam Leffler /* fill time stamp */ 12645591b213SSam Leffler u_int64_t tsf; 12655591b213SSam Leffler u_int32_t *tstamp; 12665591b213SSam Leffler 12675591b213SSam Leffler tsf = ath_hal_gettsf64(ah); 12685591b213SSam Leffler /* XXX: adjust 100us delay to xmit */ 12695591b213SSam Leffler tsf += 100; 12705591b213SSam Leffler tstamp = (u_int32_t *)&wh[1]; 12715591b213SSam Leffler tstamp[0] = htole32(tsf & 0xffffffff); 12725591b213SSam Leffler tstamp[1] = htole32(tsf >> 32); 12735591b213SSam Leffler } 12745591b213SSam Leffler sc->sc_stats.ast_tx_mgmt++; 12755591b213SSam Leffler } 127673454c73SSam Leffler 12775591b213SSam Leffler if (ath_tx_start(sc, ni, bf, m)) { 12785591b213SSam Leffler bad: 12795591b213SSam Leffler ifp->if_oerrors++; 1280c42a7b7eSSam Leffler reclaim: 1281c42a7b7eSSam Leffler ATH_TXBUF_LOCK(sc); 1282ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1283c42a7b7eSSam Leffler ATH_TXBUF_UNLOCK(sc); 1284c42a7b7eSSam Leffler if (ni != NULL) 1285c42a7b7eSSam Leffler ieee80211_free_node(ni); 12865591b213SSam Leffler continue; 12875591b213SSam Leffler } 12885591b213SSam Leffler 12895591b213SSam Leffler sc->sc_tx_timer = 5; 12905591b213SSam Leffler ifp->if_timer = 1; 12915591b213SSam Leffler } 12925591b213SSam Leffler } 12935591b213SSam Leffler 12945591b213SSam Leffler static int 12955591b213SSam Leffler ath_media_change(struct ifnet *ifp) 12965591b213SSam Leffler { 1297c42a7b7eSSam Leffler #define IS_UP(ifp) \ 129813f4c340SRobert Watson ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 12995591b213SSam Leffler int error; 13005591b213SSam Leffler 13015591b213SSam Leffler error = ieee80211_media_change(ifp); 13025591b213SSam Leffler if (error == ENETRESET) { 13037a04dc27SSam Leffler struct ath_softc *sc = ifp->if_softc; 13047a04dc27SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 13057a04dc27SSam Leffler 13067a04dc27SSam Leffler if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 13077a04dc27SSam Leffler /* 13087a04dc27SSam Leffler * Adhoc demo mode is just ibss mode w/o beacons 13097a04dc27SSam Leffler * (mostly). The hal knows nothing about it; 13107a04dc27SSam Leffler * tell it we're operating in ibss mode. 13117a04dc27SSam Leffler */ 13127a04dc27SSam Leffler sc->sc_opmode = HAL_M_IBSS; 13137a04dc27SSam Leffler } else 13147a04dc27SSam Leffler sc->sc_opmode = ic->ic_opmode; 1315c42a7b7eSSam Leffler if (IS_UP(ifp)) 1316fc74a9f9SBrooks Davis ath_init(ifp->if_softc); /* XXX lose error */ 13175591b213SSam Leffler error = 0; 13185591b213SSam Leffler } 13195591b213SSam Leffler return error; 1320c42a7b7eSSam Leffler #undef IS_UP 13215591b213SSam Leffler } 13225591b213SSam Leffler 1323a585a9a1SSam Leffler #ifdef ATH_DEBUG 1324c42a7b7eSSam Leffler static void 13255901d2d3SSam Leffler ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix, 1326c42a7b7eSSam Leffler const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) 13275591b213SSam Leffler { 1328c42a7b7eSSam Leffler static const char *ciphers[] = { 1329c42a7b7eSSam Leffler "WEP", 1330c42a7b7eSSam Leffler "AES-OCB", 1331c42a7b7eSSam Leffler "AES-CCM", 1332c42a7b7eSSam Leffler "CKIP", 1333c42a7b7eSSam Leffler "TKIP", 1334c42a7b7eSSam Leffler "CLR", 1335c42a7b7eSSam Leffler }; 1336c42a7b7eSSam Leffler int i, n; 13375591b213SSam Leffler 1338c42a7b7eSSam Leffler printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]); 1339c42a7b7eSSam Leffler for (i = 0, n = hk->kv_len; i < n; i++) 1340c42a7b7eSSam Leffler printf("%02x", hk->kv_val[i]); 1341c42a7b7eSSam Leffler printf(" mac %s", ether_sprintf(mac)); 1342c42a7b7eSSam Leffler if (hk->kv_type == HAL_CIPHER_TKIP) { 13435901d2d3SSam Leffler printf(" %s ", sc->sc_splitmic ? "mic" : "rxmic"); 1344c42a7b7eSSam Leffler for (i = 0; i < sizeof(hk->kv_mic); i++) 1345c42a7b7eSSam Leffler printf("%02x", hk->kv_mic[i]); 13465901d2d3SSam Leffler #if HAL_ABI_VERSION > 0x06052200 13475901d2d3SSam Leffler if (!sc->sc_splitmic) { 13485901d2d3SSam Leffler printf(" txmic "); 13495901d2d3SSam Leffler for (i = 0; i < sizeof(hk->kv_txmic); i++) 13505901d2d3SSam Leffler printf("%02x", hk->kv_txmic[i]); 13515901d2d3SSam Leffler } 13525901d2d3SSam Leffler #endif 13532075afbaSSam Leffler } 1354c42a7b7eSSam Leffler printf("\n"); 1355c42a7b7eSSam Leffler } 1356c42a7b7eSSam Leffler #endif 1357c42a7b7eSSam Leffler 13585591b213SSam Leffler /* 1359c42a7b7eSSam Leffler * Set a TKIP key into the hardware. This handles the 1360c42a7b7eSSam Leffler * potential distribution of key state to multiple key 1361c42a7b7eSSam Leffler * cache slots for TKIP. 13625591b213SSam Leffler */ 1363c42a7b7eSSam Leffler static int 1364c42a7b7eSSam Leffler ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k, 1365c42a7b7eSSam Leffler HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) 1366c42a7b7eSSam Leffler { 1367c42a7b7eSSam Leffler #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) 1368c42a7b7eSSam Leffler static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; 13698cec0ab9SSam Leffler struct ath_hal *ah = sc->sc_ah; 13708cec0ab9SSam Leffler 1371c42a7b7eSSam Leffler KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP, 1372c42a7b7eSSam Leffler ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher)); 1373c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { 13745901d2d3SSam Leffler if (sc->sc_splitmic) { 1375c42a7b7eSSam Leffler /* 1376c1225b52SSam Leffler * TX key goes at first index, RX key at the rx index. 1377c42a7b7eSSam Leffler * The hal handles the MIC keys at index+64. 1378c42a7b7eSSam Leffler */ 1379c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); 1380c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); 1381c42a7b7eSSam Leffler if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid)) 1382c42a7b7eSSam Leffler return 0; 1383c42a7b7eSSam Leffler 1384c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); 1385c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix+32, hk, mac); 1386c42a7b7eSSam Leffler /* XXX delete tx key on failure? */ 1387c42a7b7eSSam Leffler return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac); 13885901d2d3SSam Leffler } else { 13895901d2d3SSam Leffler /* 13905901d2d3SSam Leffler * Room for both TX+RX MIC keys in one key cache 13915901d2d3SSam Leffler * slot, just set key at the first index; the hal 13925901d2d3SSam Leffler * will handle the reset. 13935901d2d3SSam Leffler */ 13945901d2d3SSam Leffler memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); 13955901d2d3SSam Leffler #if HAL_ABI_VERSION > 0x06052200 13965901d2d3SSam Leffler memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic)); 13975901d2d3SSam Leffler #endif 13985901d2d3SSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, mac); 13995901d2d3SSam Leffler return ath_hal_keyset(ah, k->wk_keyix, hk, mac); 14005901d2d3SSam Leffler } 1401c42a7b7eSSam Leffler } else if (k->wk_flags & IEEE80211_KEY_XR) { 1402c42a7b7eSSam Leffler /* 1403c42a7b7eSSam Leffler * TX/RX key goes at first index. 1404c42a7b7eSSam Leffler * The hal handles the MIC keys are index+64. 1405c42a7b7eSSam Leffler */ 1406c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ? 1407c42a7b7eSSam Leffler k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic)); 1408e8fd88a3SSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, mac); 1409e8fd88a3SSam Leffler return ath_hal_keyset(ah, k->wk_keyix, hk, mac); 1410c42a7b7eSSam Leffler } 1411c42a7b7eSSam Leffler return 0; 1412c42a7b7eSSam Leffler #undef IEEE80211_KEY_XR 1413c42a7b7eSSam Leffler } 1414c42a7b7eSSam Leffler 1415c42a7b7eSSam Leffler /* 1416c42a7b7eSSam Leffler * Set a net80211 key into the hardware. This handles the 1417c42a7b7eSSam Leffler * potential distribution of key state to multiple key 1418c42a7b7eSSam Leffler * cache slots for TKIP with hardware MIC support. 1419c42a7b7eSSam Leffler */ 1420c42a7b7eSSam Leffler static int 1421c42a7b7eSSam Leffler ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, 1422e8fd88a3SSam Leffler const u_int8_t mac0[IEEE80211_ADDR_LEN], 1423e8fd88a3SSam Leffler struct ieee80211_node *bss) 1424c42a7b7eSSam Leffler { 1425c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1426c42a7b7eSSam Leffler static const u_int8_t ciphermap[] = { 1427c42a7b7eSSam Leffler HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ 1428c42a7b7eSSam Leffler HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ 1429c42a7b7eSSam Leffler HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ 1430c42a7b7eSSam Leffler HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ 1431c42a7b7eSSam Leffler (u_int8_t) -1, /* 4 is not allocated */ 1432c42a7b7eSSam Leffler HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ 1433c42a7b7eSSam Leffler HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ 1434c42a7b7eSSam Leffler }; 1435c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1436c42a7b7eSSam Leffler const struct ieee80211_cipher *cip = k->wk_cipher; 1437e8fd88a3SSam Leffler u_int8_t gmac[IEEE80211_ADDR_LEN]; 1438e8fd88a3SSam Leffler const u_int8_t *mac; 1439c42a7b7eSSam Leffler HAL_KEYVAL hk; 1440c42a7b7eSSam Leffler 1441c42a7b7eSSam Leffler memset(&hk, 0, sizeof(hk)); 1442c42a7b7eSSam Leffler /* 1443c42a7b7eSSam Leffler * Software crypto uses a "clear key" so non-crypto 1444c42a7b7eSSam Leffler * state kept in the key cache are maintained and 1445c42a7b7eSSam Leffler * so that rx frames have an entry to match. 1446c42a7b7eSSam Leffler */ 1447c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 1448c42a7b7eSSam Leffler KASSERT(cip->ic_cipher < N(ciphermap), 1449c42a7b7eSSam Leffler ("invalid cipher type %u", cip->ic_cipher)); 1450c42a7b7eSSam Leffler hk.kv_type = ciphermap[cip->ic_cipher]; 1451c42a7b7eSSam Leffler hk.kv_len = k->wk_keylen; 1452c42a7b7eSSam Leffler memcpy(hk.kv_val, k->wk_key, k->wk_keylen); 14538cec0ab9SSam Leffler } else 1454c42a7b7eSSam Leffler hk.kv_type = HAL_CIPHER_CLR; 1455c42a7b7eSSam Leffler 1456e8fd88a3SSam Leffler if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) { 1457e8fd88a3SSam Leffler /* 1458e8fd88a3SSam Leffler * Group keys on hardware that supports multicast frame 1459e8fd88a3SSam Leffler * key search use a mac that is the sender's address with 1460e8fd88a3SSam Leffler * the high bit set instead of the app-specified address. 1461e8fd88a3SSam Leffler */ 1462e8fd88a3SSam Leffler IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr); 1463e8fd88a3SSam Leffler gmac[0] |= 0x80; 1464e8fd88a3SSam Leffler mac = gmac; 1465e8fd88a3SSam Leffler } else 1466e8fd88a3SSam Leffler mac = mac0; 1467e8fd88a3SSam Leffler 1468c42a7b7eSSam Leffler if (hk.kv_type == HAL_CIPHER_TKIP && 14695901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 1470c42a7b7eSSam Leffler return ath_keyset_tkip(sc, k, &hk, mac); 1471c42a7b7eSSam Leffler } else { 1472c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix, &hk, mac); 1473c42a7b7eSSam Leffler return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); 14748cec0ab9SSam Leffler } 1475c42a7b7eSSam Leffler #undef N 14765591b213SSam Leffler } 14775591b213SSam Leffler 14785591b213SSam Leffler /* 1479c42a7b7eSSam Leffler * Allocate tx/rx key slots for TKIP. We allocate two slots for 1480c42a7b7eSSam Leffler * each key, one for decrypt/encrypt and the other for the MIC. 1481c42a7b7eSSam Leffler */ 1482c42a7b7eSSam Leffler static u_int16_t 1483c1225b52SSam Leffler key_alloc_2pair(struct ath_softc *sc, 1484c1225b52SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 1485c42a7b7eSSam Leffler { 1486c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1487c42a7b7eSSam Leffler u_int i, keyix; 1488c42a7b7eSSam Leffler 1489c42a7b7eSSam Leffler KASSERT(sc->sc_splitmic, ("key cache !split")); 1490c42a7b7eSSam Leffler /* XXX could optimize */ 1491c42a7b7eSSam Leffler for (i = 0; i < N(sc->sc_keymap)/4; i++) { 1492c42a7b7eSSam Leffler u_int8_t b = sc->sc_keymap[i]; 1493c42a7b7eSSam Leffler if (b != 0xff) { 1494c42a7b7eSSam Leffler /* 1495c42a7b7eSSam Leffler * One or more slots in this byte are free. 1496c42a7b7eSSam Leffler */ 1497c42a7b7eSSam Leffler keyix = i*NBBY; 1498c42a7b7eSSam Leffler while (b & 1) { 1499c42a7b7eSSam Leffler again: 1500c42a7b7eSSam Leffler keyix++; 1501c42a7b7eSSam Leffler b >>= 1; 1502c42a7b7eSSam Leffler } 1503c42a7b7eSSam Leffler /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ 1504c42a7b7eSSam Leffler if (isset(sc->sc_keymap, keyix+32) || 1505c42a7b7eSSam Leffler isset(sc->sc_keymap, keyix+64) || 1506c42a7b7eSSam Leffler isset(sc->sc_keymap, keyix+32+64)) { 1507c42a7b7eSSam Leffler /* full pair unavailable */ 1508c42a7b7eSSam Leffler /* XXX statistic */ 1509c42a7b7eSSam Leffler if (keyix == (i+1)*NBBY) { 1510c42a7b7eSSam Leffler /* no slots were appropriate, advance */ 1511c42a7b7eSSam Leffler continue; 1512c42a7b7eSSam Leffler } 1513c42a7b7eSSam Leffler goto again; 1514c42a7b7eSSam Leffler } 1515c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix); 1516c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+64); 1517c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+32); 1518c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+32+64); 1519c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 1520c42a7b7eSSam Leffler "%s: key pair %u,%u %u,%u\n", 1521c42a7b7eSSam Leffler __func__, keyix, keyix+64, 1522c42a7b7eSSam Leffler keyix+32, keyix+32+64); 1523c1225b52SSam Leffler *txkeyix = keyix; 1524c1225b52SSam Leffler *rxkeyix = keyix+32; 1525c1225b52SSam Leffler return 1; 1526c42a7b7eSSam Leffler } 1527c42a7b7eSSam Leffler } 1528c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); 1529c1225b52SSam Leffler return 0; 1530c42a7b7eSSam Leffler #undef N 1531c42a7b7eSSam Leffler } 1532c42a7b7eSSam Leffler 1533c42a7b7eSSam Leffler /* 15345901d2d3SSam Leffler * Allocate tx/rx key slots for TKIP. We allocate two slots for 15355901d2d3SSam Leffler * each key, one for decrypt/encrypt and the other for the MIC. 15365901d2d3SSam Leffler */ 15375901d2d3SSam Leffler static u_int16_t 15385901d2d3SSam Leffler key_alloc_pair(struct ath_softc *sc, 15395901d2d3SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 15405901d2d3SSam Leffler { 15415901d2d3SSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 15425901d2d3SSam Leffler u_int i, keyix; 15435901d2d3SSam Leffler 15445901d2d3SSam Leffler KASSERT(!sc->sc_splitmic, ("key cache split")); 15455901d2d3SSam Leffler /* XXX could optimize */ 15465901d2d3SSam Leffler for (i = 0; i < N(sc->sc_keymap)/4; i++) { 15475901d2d3SSam Leffler u_int8_t b = sc->sc_keymap[i]; 15485901d2d3SSam Leffler if (b != 0xff) { 15495901d2d3SSam Leffler /* 15505901d2d3SSam Leffler * One or more slots in this byte are free. 15515901d2d3SSam Leffler */ 15525901d2d3SSam Leffler keyix = i*NBBY; 15535901d2d3SSam Leffler while (b & 1) { 15545901d2d3SSam Leffler again: 15555901d2d3SSam Leffler keyix++; 15565901d2d3SSam Leffler b >>= 1; 15575901d2d3SSam Leffler } 15585901d2d3SSam Leffler if (isset(sc->sc_keymap, keyix+64)) { 15595901d2d3SSam Leffler /* full pair unavailable */ 15605901d2d3SSam Leffler /* XXX statistic */ 15615901d2d3SSam Leffler if (keyix == (i+1)*NBBY) { 15625901d2d3SSam Leffler /* no slots were appropriate, advance */ 15635901d2d3SSam Leffler continue; 15645901d2d3SSam Leffler } 15655901d2d3SSam Leffler goto again; 15665901d2d3SSam Leffler } 15675901d2d3SSam Leffler setbit(sc->sc_keymap, keyix); 15685901d2d3SSam Leffler setbit(sc->sc_keymap, keyix+64); 15695901d2d3SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 15705901d2d3SSam Leffler "%s: key pair %u,%u\n", 15715901d2d3SSam Leffler __func__, keyix, keyix+64); 15725901d2d3SSam Leffler *txkeyix = *rxkeyix = keyix; 15735901d2d3SSam Leffler return 1; 15745901d2d3SSam Leffler } 15755901d2d3SSam Leffler } 15765901d2d3SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); 15775901d2d3SSam Leffler return 0; 15785901d2d3SSam Leffler #undef N 15795901d2d3SSam Leffler } 15805901d2d3SSam Leffler 15815901d2d3SSam Leffler /* 1582c42a7b7eSSam Leffler * Allocate a single key cache slot. 1583c42a7b7eSSam Leffler */ 1584c1225b52SSam Leffler static int 1585c1225b52SSam Leffler key_alloc_single(struct ath_softc *sc, 1586c1225b52SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 1587c42a7b7eSSam Leffler { 1588c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1589c42a7b7eSSam Leffler u_int i, keyix; 1590c42a7b7eSSam Leffler 1591c42a7b7eSSam Leffler /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ 1592c42a7b7eSSam Leffler for (i = 0; i < N(sc->sc_keymap); i++) { 1593c42a7b7eSSam Leffler u_int8_t b = sc->sc_keymap[i]; 1594c42a7b7eSSam Leffler if (b != 0xff) { 1595c42a7b7eSSam Leffler /* 1596c42a7b7eSSam Leffler * One or more slots are free. 1597c42a7b7eSSam Leffler */ 1598c42a7b7eSSam Leffler keyix = i*NBBY; 1599c42a7b7eSSam Leffler while (b & 1) 1600c42a7b7eSSam Leffler keyix++, b >>= 1; 1601c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix); 1602c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n", 1603c42a7b7eSSam Leffler __func__, keyix); 1604c1225b52SSam Leffler *txkeyix = *rxkeyix = keyix; 1605c1225b52SSam Leffler return 1; 1606c42a7b7eSSam Leffler } 1607c42a7b7eSSam Leffler } 1608c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__); 1609c1225b52SSam Leffler return 0; 1610c42a7b7eSSam Leffler #undef N 1611c42a7b7eSSam Leffler } 1612c42a7b7eSSam Leffler 1613c42a7b7eSSam Leffler /* 1614c42a7b7eSSam Leffler * Allocate one or more key cache slots for a uniacst key. The 1615c42a7b7eSSam Leffler * key itself is needed only to identify the cipher. For hardware 1616c42a7b7eSSam Leffler * TKIP with split cipher+MIC keys we allocate two key cache slot 1617c42a7b7eSSam Leffler * pairs so that we can setup separate TX and RX MIC keys. Note 1618c42a7b7eSSam Leffler * that the MIC key for a TKIP key at slot i is assumed by the 1619c42a7b7eSSam Leffler * hardware to be at slot i+64. This limits TKIP keys to the first 1620c42a7b7eSSam Leffler * 64 entries. 1621c42a7b7eSSam Leffler */ 1622c42a7b7eSSam Leffler static int 1623c1225b52SSam Leffler ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k, 1624c1225b52SSam Leffler ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 1625c42a7b7eSSam Leffler { 1626c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1627c42a7b7eSSam Leffler 1628c42a7b7eSSam Leffler /* 16298ca623d7SSam Leffler * Group key allocation must be handled specially for 16308ca623d7SSam Leffler * parts that do not support multicast key cache search 16318ca623d7SSam Leffler * functionality. For those parts the key id must match 16328ca623d7SSam Leffler * the h/w key index so lookups find the right key. On 16338ca623d7SSam Leffler * parts w/ the key search facility we install the sender's 16348ca623d7SSam Leffler * mac address (with the high bit set) and let the hardware 16358ca623d7SSam Leffler * find the key w/o using the key id. This is preferred as 16368ca623d7SSam Leffler * it permits us to support multiple users for adhoc and/or 16378ca623d7SSam Leffler * multi-station operation. 16388ca623d7SSam Leffler */ 16398ca623d7SSam Leffler if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) { 16408ca623d7SSam Leffler if (!(&ic->ic_nw_keys[0] <= k && 16418ca623d7SSam Leffler k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) { 16428ca623d7SSam Leffler /* should not happen */ 16438ca623d7SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 16448ca623d7SSam Leffler "%s: bogus group key\n", __func__); 1645c1225b52SSam Leffler return 0; 16468ca623d7SSam Leffler } 16478ca623d7SSam Leffler /* 16488ca623d7SSam Leffler * XXX we pre-allocate the global keys so 16498ca623d7SSam Leffler * have no way to check if they've already been allocated. 16508ca623d7SSam Leffler */ 1651c1225b52SSam Leffler *keyix = *rxkeyix = k - ic->ic_nw_keys; 1652c1225b52SSam Leffler return 1; 16538ca623d7SSam Leffler } 16548ca623d7SSam Leffler 16558ca623d7SSam Leffler /* 1656c42a7b7eSSam Leffler * We allocate two pair for TKIP when using the h/w to do 1657c42a7b7eSSam Leffler * the MIC. For everything else, including software crypto, 1658c42a7b7eSSam Leffler * we allocate a single entry. Note that s/w crypto requires 1659c42a7b7eSSam Leffler * a pass-through slot on the 5211 and 5212. The 5210 does 1660c42a7b7eSSam Leffler * not support pass-through cache entries and we map all 1661c42a7b7eSSam Leffler * those requests to slot 0. 1662c42a7b7eSSam Leffler */ 1663c42a7b7eSSam Leffler if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 1664c1225b52SSam Leffler return key_alloc_single(sc, keyix, rxkeyix); 1665c42a7b7eSSam Leffler } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP && 16665901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 16675901d2d3SSam Leffler if (sc->sc_splitmic) 1668c1225b52SSam Leffler return key_alloc_2pair(sc, keyix, rxkeyix); 16695901d2d3SSam Leffler else 16705901d2d3SSam Leffler return key_alloc_pair(sc, keyix, rxkeyix); 1671c42a7b7eSSam Leffler } else { 1672c1225b52SSam Leffler return key_alloc_single(sc, keyix, rxkeyix); 1673c42a7b7eSSam Leffler } 1674c42a7b7eSSam Leffler } 1675c42a7b7eSSam Leffler 1676c42a7b7eSSam Leffler /* 1677c42a7b7eSSam Leffler * Delete an entry in the key cache allocated by ath_key_alloc. 1678c42a7b7eSSam Leffler */ 1679c42a7b7eSSam Leffler static int 1680c42a7b7eSSam Leffler ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) 1681c42a7b7eSSam Leffler { 1682c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1683c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1684c42a7b7eSSam Leffler const struct ieee80211_cipher *cip = k->wk_cipher; 1685c42a7b7eSSam Leffler u_int keyix = k->wk_keyix; 1686c42a7b7eSSam Leffler 1687c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); 1688c42a7b7eSSam Leffler 1689c42a7b7eSSam Leffler ath_hal_keyreset(ah, keyix); 1690c42a7b7eSSam Leffler /* 1691c42a7b7eSSam Leffler * Handle split tx/rx keying required for TKIP with h/w MIC. 1692c42a7b7eSSam Leffler */ 1693c42a7b7eSSam Leffler if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 1694c1225b52SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) 1695c42a7b7eSSam Leffler ath_hal_keyreset(ah, keyix+32); /* RX key */ 1696c42a7b7eSSam Leffler if (keyix >= IEEE80211_WEP_NKID) { 1697c42a7b7eSSam Leffler /* 1698c42a7b7eSSam Leffler * Don't touch keymap entries for global keys so 1699c42a7b7eSSam Leffler * they are never considered for dynamic allocation. 1700c42a7b7eSSam Leffler */ 1701c42a7b7eSSam Leffler clrbit(sc->sc_keymap, keyix); 1702c42a7b7eSSam Leffler if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 17035901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 1704c42a7b7eSSam Leffler clrbit(sc->sc_keymap, keyix+64); /* TX key MIC */ 17055901d2d3SSam Leffler if (sc->sc_splitmic) { 17065901d2d3SSam Leffler /* +32 for RX key, +32+64 for RX key MIC */ 17075901d2d3SSam Leffler clrbit(sc->sc_keymap, keyix+32); 17085901d2d3SSam Leffler clrbit(sc->sc_keymap, keyix+32+64); 17095901d2d3SSam Leffler } 1710c42a7b7eSSam Leffler } 1711c42a7b7eSSam Leffler } 1712c42a7b7eSSam Leffler return 1; 1713c42a7b7eSSam Leffler } 1714c42a7b7eSSam Leffler 1715c42a7b7eSSam Leffler /* 1716c42a7b7eSSam Leffler * Set the key cache contents for the specified key. Key cache 1717c42a7b7eSSam Leffler * slot(s) must already have been allocated by ath_key_alloc. 1718c42a7b7eSSam Leffler */ 1719c42a7b7eSSam Leffler static int 1720c42a7b7eSSam Leffler ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, 1721c42a7b7eSSam Leffler const u_int8_t mac[IEEE80211_ADDR_LEN]) 1722c42a7b7eSSam Leffler { 1723c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1724c42a7b7eSSam Leffler 1725e8fd88a3SSam Leffler return ath_keyset(sc, k, mac, ic->ic_bss); 1726c42a7b7eSSam Leffler } 1727c42a7b7eSSam Leffler 1728c42a7b7eSSam Leffler /* 1729c42a7b7eSSam Leffler * Block/unblock tx+rx processing while a key change is done. 1730c42a7b7eSSam Leffler * We assume the caller serializes key management operations 1731c42a7b7eSSam Leffler * so we only need to worry about synchronization with other 1732c42a7b7eSSam Leffler * uses that originate in the driver. 1733c42a7b7eSSam Leffler */ 1734c42a7b7eSSam Leffler static void 1735c42a7b7eSSam Leffler ath_key_update_begin(struct ieee80211com *ic) 1736c42a7b7eSSam Leffler { 1737c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 1738c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1739c42a7b7eSSam Leffler 1740c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1741c42a7b7eSSam Leffler #if 0 1742c42a7b7eSSam Leffler tasklet_disable(&sc->sc_rxtq); 1743c42a7b7eSSam Leffler #endif 1744c42a7b7eSSam Leffler IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */ 1745c42a7b7eSSam Leffler } 1746c42a7b7eSSam Leffler 1747c42a7b7eSSam Leffler static void 1748c42a7b7eSSam Leffler ath_key_update_end(struct ieee80211com *ic) 1749c42a7b7eSSam Leffler { 1750c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 1751c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1752c42a7b7eSSam Leffler 1753c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1754c42a7b7eSSam Leffler IF_UNLOCK(&ifp->if_snd); 1755c42a7b7eSSam Leffler #if 0 1756c42a7b7eSSam Leffler tasklet_enable(&sc->sc_rxtq); 1757c42a7b7eSSam Leffler #endif 1758c42a7b7eSSam Leffler } 17595591b213SSam Leffler 17604bc0e754SSam Leffler /* 17614bc0e754SSam Leffler * Calculate the receive filter according to the 17624bc0e754SSam Leffler * operating mode and state: 17634bc0e754SSam Leffler * 17644bc0e754SSam Leffler * o always accept unicast, broadcast, and multicast traffic 1765c42a7b7eSSam Leffler * o maintain current state of phy error reception (the hal 1766c42a7b7eSSam Leffler * may enable phy error frames for noise immunity work) 17674bc0e754SSam Leffler * o probe request frames are accepted only when operating in 17684bc0e754SSam Leffler * hostap, adhoc, or monitor modes 17694bc0e754SSam Leffler * o enable promiscuous mode according to the interface state 17704bc0e754SSam Leffler * o accept beacons: 17714bc0e754SSam Leffler * - when operating in adhoc mode so the 802.11 layer creates 17724bc0e754SSam Leffler * node table entries for peers, 17734bc0e754SSam Leffler * - when operating in station mode for collecting rssi data when 17744bc0e754SSam Leffler * the station is otherwise quiet, or 17754bc0e754SSam Leffler * - when scanning 17766f48c956SSam Leffler * o accept control frames: 17776f48c956SSam Leffler * - when in monitor mode 17784bc0e754SSam Leffler */ 17794bc0e754SSam Leffler static u_int32_t 1780c42a7b7eSSam Leffler ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state) 17814bc0e754SSam Leffler { 1782bd5a9920SSam Leffler #define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR) 17834bc0e754SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 17844bc0e754SSam Leffler struct ath_hal *ah = sc->sc_ah; 1785fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 17864bc0e754SSam Leffler u_int32_t rfilt; 17874bc0e754SSam Leffler 1788bd5a9920SSam Leffler rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) 17894bc0e754SSam Leffler | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 17904bc0e754SSam Leffler if (ic->ic_opmode != IEEE80211_M_STA) 17914bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROBEREQ; 17924bc0e754SSam Leffler if (ic->ic_opmode != IEEE80211_M_HOSTAP && 17934bc0e754SSam Leffler (ifp->if_flags & IFF_PROMISC)) 17944bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROM; 17954bc0e754SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA || 17964bc0e754SSam Leffler ic->ic_opmode == IEEE80211_M_IBSS || 1797c42a7b7eSSam Leffler state == IEEE80211_S_SCAN) 17984bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_BEACON; 17996f48c956SSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) 18006f48c956SSam Leffler rfilt |= HAL_RX_FILTER_CONTROL; 18014bc0e754SSam Leffler return rfilt; 1802bd5a9920SSam Leffler #undef RX_FILTER_PRESERVE 18034bc0e754SSam Leffler } 18044bc0e754SSam Leffler 18055591b213SSam Leffler static void 18065591b213SSam Leffler ath_mode_init(struct ath_softc *sc) 18075591b213SSam Leffler { 18085591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 18095591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 1810fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 18115591b213SSam Leffler u_int32_t rfilt, mfilt[2], val; 18125591b213SSam Leffler u_int8_t pos; 18135591b213SSam Leffler struct ifmultiaddr *ifma; 18145591b213SSam Leffler 18154bc0e754SSam Leffler /* configure rx filter */ 1816c42a7b7eSSam Leffler rfilt = ath_calcrxfilter(sc, ic->ic_state); 18174bc0e754SSam Leffler ath_hal_setrxfilter(ah, rfilt); 18184bc0e754SSam Leffler 18195591b213SSam Leffler /* configure operational mode */ 1820c42a7b7eSSam Leffler ath_hal_setopmode(ah); 1821c42a7b7eSSam Leffler 1822c42a7b7eSSam Leffler /* 1823c42a7b7eSSam Leffler * Handle any link-level address change. Note that we only 1824c42a7b7eSSam Leffler * need to force ic_myaddr; any other addresses are handled 1825c42a7b7eSSam Leffler * as a byproduct of the ifnet code marking the interface 1826c42a7b7eSSam Leffler * down then up. 1827c42a7b7eSSam Leffler * 1828c42a7b7eSSam Leffler * XXX should get from lladdr instead of arpcom but that's more work 1829c42a7b7eSSam Leffler */ 18304a0d6638SRuslan Ermilov IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 1831c42a7b7eSSam Leffler ath_hal_setmac(ah, ic->ic_myaddr); 18325591b213SSam Leffler 18335591b213SSam Leffler /* calculate and install multicast filter */ 18345591b213SSam Leffler if ((ifp->if_flags & IFF_ALLMULTI) == 0) { 18355591b213SSam Leffler mfilt[0] = mfilt[1] = 0; 183613b203d0SRobert Watson IF_ADDR_LOCK(ifp); 18375591b213SSam Leffler TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 18385591b213SSam Leffler caddr_t dl; 18395591b213SSam Leffler 18405591b213SSam Leffler /* calculate XOR of eight 6bit values */ 18415591b213SSam Leffler dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 18425591b213SSam Leffler val = LE_READ_4(dl + 0); 18435591b213SSam Leffler pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 18445591b213SSam Leffler val = LE_READ_4(dl + 3); 18455591b213SSam Leffler pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 18465591b213SSam Leffler pos &= 0x3f; 18475591b213SSam Leffler mfilt[pos / 32] |= (1 << (pos % 32)); 18485591b213SSam Leffler } 184913b203d0SRobert Watson IF_ADDR_UNLOCK(ifp); 18505591b213SSam Leffler } else { 18515591b213SSam Leffler mfilt[0] = mfilt[1] = ~0; 18525591b213SSam Leffler } 18535591b213SSam Leffler ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]); 1854c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, MC filter %08x:%08x\n", 1855c42a7b7eSSam Leffler __func__, rfilt, mfilt[0], mfilt[1]); 18565591b213SSam Leffler } 18575591b213SSam Leffler 1858c42a7b7eSSam Leffler /* 1859c42a7b7eSSam Leffler * Set the slot time based on the current setting. 1860c42a7b7eSSam Leffler */ 1861c42a7b7eSSam Leffler static void 1862c42a7b7eSSam Leffler ath_setslottime(struct ath_softc *sc) 1863c42a7b7eSSam Leffler { 1864c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 1865c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1866aaa70f2fSSam Leffler u_int usec; 1867c42a7b7eSSam Leffler 1868aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) 1869aaa70f2fSSam Leffler usec = 13; 1870aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) 1871aaa70f2fSSam Leffler usec = 21; 1872724c193aSSam Leffler else if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) { 1873724c193aSSam Leffler /* honor short/long slot time only in 11g */ 1874724c193aSSam Leffler /* XXX shouldn't honor on pure g or turbo g channel */ 1875724c193aSSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 1876aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_9; 1877aaa70f2fSSam Leffler else 1878aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_20; 1879724c193aSSam Leffler } else 1880724c193aSSam Leffler usec = HAL_SLOT_TIME_9; 1881aaa70f2fSSam Leffler 1882aaa70f2fSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 1883aaa70f2fSSam Leffler "%s: chan %u MHz flags 0x%x %s slot, %u usec\n", 1884aaa70f2fSSam Leffler __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags, 1885aaa70f2fSSam Leffler ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec); 1886aaa70f2fSSam Leffler 1887aaa70f2fSSam Leffler ath_hal_setslottime(ah, usec); 1888c42a7b7eSSam Leffler sc->sc_updateslot = OK; 1889c42a7b7eSSam Leffler } 1890c42a7b7eSSam Leffler 1891c42a7b7eSSam Leffler /* 1892c42a7b7eSSam Leffler * Callback from the 802.11 layer to update the 1893c42a7b7eSSam Leffler * slot time based on the current setting. 1894c42a7b7eSSam Leffler */ 1895c42a7b7eSSam Leffler static void 1896c42a7b7eSSam Leffler ath_updateslot(struct ifnet *ifp) 1897c42a7b7eSSam Leffler { 1898c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1899c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 1900c42a7b7eSSam Leffler 1901c42a7b7eSSam Leffler /* 1902c42a7b7eSSam Leffler * When not coordinating the BSS, change the hardware 1903c42a7b7eSSam Leffler * immediately. For other operation we defer the change 1904c42a7b7eSSam Leffler * until beacon updates have propagated to the stations. 1905c42a7b7eSSam Leffler */ 1906c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) 1907c42a7b7eSSam Leffler sc->sc_updateslot = UPDATE; 1908c42a7b7eSSam Leffler else 1909c42a7b7eSSam Leffler ath_setslottime(sc); 1910c42a7b7eSSam Leffler } 1911c42a7b7eSSam Leffler 1912c42a7b7eSSam Leffler /* 191380d2765fSSam Leffler * Setup a h/w transmit queue for beacons. 191480d2765fSSam Leffler */ 191580d2765fSSam Leffler static int 191680d2765fSSam Leffler ath_beaconq_setup(struct ath_hal *ah) 191780d2765fSSam Leffler { 191880d2765fSSam Leffler HAL_TXQ_INFO qi; 191980d2765fSSam Leffler 192080d2765fSSam Leffler memset(&qi, 0, sizeof(qi)); 192180d2765fSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 192280d2765fSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 192380d2765fSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 19240f2e86fbSSam Leffler /* NB: for dynamic turbo, don't enable any other interrupts */ 1925bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; 192680d2765fSSam Leffler return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi); 192780d2765fSSam Leffler } 192880d2765fSSam Leffler 192980d2765fSSam Leffler /* 19300f2e86fbSSam Leffler * Setup the transmit queue parameters for the beacon queue. 19310f2e86fbSSam Leffler */ 19320f2e86fbSSam Leffler static int 19330f2e86fbSSam Leffler ath_beaconq_config(struct ath_softc *sc) 19340f2e86fbSSam Leffler { 19350f2e86fbSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) 19360f2e86fbSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 19370f2e86fbSSam Leffler struct ath_hal *ah = sc->sc_ah; 19380f2e86fbSSam Leffler HAL_TXQ_INFO qi; 19390f2e86fbSSam Leffler 19400f2e86fbSSam Leffler ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi); 19410f2e86fbSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 19420f2e86fbSSam Leffler /* 19430f2e86fbSSam Leffler * Always burst out beacon and CAB traffic. 19440f2e86fbSSam Leffler */ 19450f2e86fbSSam Leffler qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; 19460f2e86fbSSam Leffler qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT; 19470f2e86fbSSam Leffler qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT; 19480f2e86fbSSam Leffler } else { 19490f2e86fbSSam Leffler struct wmeParams *wmep = 19500f2e86fbSSam Leffler &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE]; 19510f2e86fbSSam Leffler /* 19520f2e86fbSSam Leffler * Adhoc mode; important thing is to use 2x cwmin. 19530f2e86fbSSam Leffler */ 19540f2e86fbSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 19550f2e86fbSSam Leffler qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 19560f2e86fbSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 19570f2e86fbSSam Leffler } 19580f2e86fbSSam Leffler 19590f2e86fbSSam Leffler if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) { 19600f2e86fbSSam Leffler device_printf(sc->sc_dev, "unable to update parameters for " 19610f2e86fbSSam Leffler "beacon hardware queue!\n"); 19620f2e86fbSSam Leffler return 0; 19630f2e86fbSSam Leffler } else { 19640f2e86fbSSam Leffler ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ 19650f2e86fbSSam Leffler return 1; 19660f2e86fbSSam Leffler } 19670f2e86fbSSam Leffler #undef ATH_EXPONENT_TO_VALUE 19680f2e86fbSSam Leffler } 19690f2e86fbSSam Leffler 19700f2e86fbSSam Leffler /* 1971c42a7b7eSSam Leffler * Allocate and setup an initial beacon frame. 1972c42a7b7eSSam Leffler */ 19735591b213SSam Leffler static int 19745591b213SSam Leffler ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) 19755591b213SSam Leffler { 1976c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 19775591b213SSam Leffler struct ath_buf *bf; 19785591b213SSam Leffler struct mbuf *m; 1979c42a7b7eSSam Leffler int error; 19805591b213SSam Leffler 1981c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_bbuf); 1982c42a7b7eSSam Leffler if (bf == NULL) { 1983c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: no dma buffers\n", __func__); 1984c42a7b7eSSam Leffler sc->sc_stats.ast_be_nombuf++; /* XXX */ 1985c42a7b7eSSam Leffler return ENOMEM; /* XXX */ 1986c42a7b7eSSam Leffler } 19875591b213SSam Leffler /* 19885591b213SSam Leffler * NB: the beacon data buffer must be 32-bit aligned; 19895591b213SSam Leffler * we assume the mbuf routines will return us something 19905591b213SSam Leffler * with this alignment (perhaps should assert). 19915591b213SSam Leffler */ 1992c42a7b7eSSam Leffler m = ieee80211_beacon_alloc(ic, ni, &sc->sc_boff); 19935591b213SSam Leffler if (m == NULL) { 1994c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: cannot get mbuf\n", 1995c42a7b7eSSam Leffler __func__); 19965591b213SSam Leffler sc->sc_stats.ast_be_nombuf++; 19975591b213SSam Leffler return ENOMEM; 19985591b213SSam Leffler } 1999f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2000f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 20015591b213SSam Leffler BUS_DMA_NOWAIT); 2002c42a7b7eSSam Leffler if (error == 0) { 2003c42a7b7eSSam Leffler bf->bf_m = m; 2004f818612bSSam Leffler bf->bf_node = ieee80211_ref_node(ni); 2005c42a7b7eSSam Leffler } else { 20065591b213SSam Leffler m_freem(m); 2007c42a7b7eSSam Leffler } 20085591b213SSam Leffler return error; 20095591b213SSam Leffler } 2010c42a7b7eSSam Leffler 2011c42a7b7eSSam Leffler /* 2012c42a7b7eSSam Leffler * Setup the beacon frame for transmit. 2013c42a7b7eSSam Leffler */ 2014c42a7b7eSSam Leffler static void 2015c42a7b7eSSam Leffler ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) 2016c42a7b7eSSam Leffler { 2017c42a7b7eSSam Leffler #define USE_SHPREAMBLE(_ic) \ 2018c42a7b7eSSam Leffler (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 2019c42a7b7eSSam Leffler == IEEE80211_F_SHPREAMBLE) 2020c42a7b7eSSam Leffler struct ieee80211_node *ni = bf->bf_node; 2021c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2022c42a7b7eSSam Leffler struct mbuf *m = bf->bf_m; 2023c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2024c42a7b7eSSam Leffler struct ath_desc *ds; 2025c42a7b7eSSam Leffler int flags, antenna; 202655f63772SSam Leffler const HAL_RATE_TABLE *rt; 202755f63772SSam Leffler u_int8_t rix, rate; 2028c42a7b7eSSam Leffler 20294a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n", 2030c42a7b7eSSam Leffler __func__, m, m->m_len); 20315591b213SSam Leffler 20325591b213SSam Leffler /* setup descriptors */ 20335591b213SSam Leffler ds = bf->bf_desc; 20345591b213SSam Leffler 2035c42a7b7eSSam Leffler flags = HAL_TXDESC_NOACK; 2036c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) { 2037c42a7b7eSSam Leffler ds->ds_link = bf->bf_daddr; /* self-linked */ 2038c42a7b7eSSam Leffler flags |= HAL_TXDESC_VEOL; 2039c42a7b7eSSam Leffler /* 2040c42a7b7eSSam Leffler * Let hardware handle antenna switching. 2041c42a7b7eSSam Leffler */ 20424866e6c2SSam Leffler antenna = sc->sc_txantenna; 2043c42a7b7eSSam Leffler } else { 20445591b213SSam Leffler ds->ds_link = 0; 2045c42a7b7eSSam Leffler /* 2046c42a7b7eSSam Leffler * Switch antenna every 4 beacons. 2047c42a7b7eSSam Leffler * XXX assumes two antenna 2048c42a7b7eSSam Leffler */ 2049df4d04afSSam Leffler antenna = sc->sc_txantenna != 0 ? sc->sc_txantenna 2050df4d04afSSam Leffler : (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1); 2051c42a7b7eSSam Leffler } 2052c42a7b7eSSam Leffler 2053c42a7b7eSSam Leffler KASSERT(bf->bf_nseg == 1, 2054c42a7b7eSSam Leffler ("multi-segment beacon frame; nseg %u", bf->bf_nseg)); 20555591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 20565591b213SSam Leffler /* 20575591b213SSam Leffler * Calculate rate code. 20585591b213SSam Leffler * XXX everything at min xmit rate 20595591b213SSam Leffler */ 206055f63772SSam Leffler rix = sc->sc_minrateix; 206155f63772SSam Leffler rt = sc->sc_currates; 206255f63772SSam Leffler rate = rt->info[rix].rateCode; 2063c42a7b7eSSam Leffler if (USE_SHPREAMBLE(ic)) 206455f63772SSam Leffler rate |= rt->info[rix].shortPreamble; 20655591b213SSam Leffler ath_hal_setuptxdesc(ah, ds 2066c42a7b7eSSam Leffler , m->m_len + IEEE80211_CRC_LEN /* frame length */ 20675591b213SSam Leffler , sizeof(struct ieee80211_frame)/* header length */ 20685591b213SSam Leffler , HAL_PKT_TYPE_BEACON /* Atheros packet type */ 2069c42a7b7eSSam Leffler , ni->ni_txpower /* txpower XXX */ 20705591b213SSam Leffler , rate, 1 /* series 0 rate/tries */ 20715591b213SSam Leffler , HAL_TXKEYIX_INVALID /* no encryption */ 2072c42a7b7eSSam Leffler , antenna /* antenna mode */ 2073c42a7b7eSSam Leffler , flags /* no ack, veol for beacons */ 20745591b213SSam Leffler , 0 /* rts/cts rate */ 20755591b213SSam Leffler , 0 /* rts/cts duration */ 20765591b213SSam Leffler ); 20775591b213SSam Leffler /* NB: beacon's BufLen must be a multiple of 4 bytes */ 20785591b213SSam Leffler ath_hal_filltxdesc(ah, ds 2079c42a7b7eSSam Leffler , roundup(m->m_len, 4) /* buffer length */ 20805591b213SSam Leffler , AH_TRUE /* first segment */ 20815591b213SSam Leffler , AH_TRUE /* last segment */ 2082c42a7b7eSSam Leffler , ds /* first descriptor */ 20835591b213SSam Leffler ); 2084c42a7b7eSSam Leffler #undef USE_SHPREAMBLE 20855591b213SSam Leffler } 20865591b213SSam Leffler 2087c42a7b7eSSam Leffler /* 2088622b3fd2SSam Leffler * Append the contents of src to dst; both queues 2089622b3fd2SSam Leffler * are assumed to be locked. 2090622b3fd2SSam Leffler */ 2091622b3fd2SSam Leffler static void 2092622b3fd2SSam Leffler ath_txqmove(struct ath_txq *dst, struct ath_txq *src) 2093622b3fd2SSam Leffler { 2094622b3fd2SSam Leffler STAILQ_CONCAT(&dst->axq_q, &src->axq_q); 2095622b3fd2SSam Leffler dst->axq_link = src->axq_link; 2096622b3fd2SSam Leffler src->axq_link = NULL; 2097622b3fd2SSam Leffler dst->axq_depth += src->axq_depth; 2098622b3fd2SSam Leffler src->axq_depth = 0; 2099622b3fd2SSam Leffler } 2100622b3fd2SSam Leffler 2101622b3fd2SSam Leffler /* 2102c42a7b7eSSam Leffler * Transmit a beacon frame at SWBA. Dynamic updates to the 2103c42a7b7eSSam Leffler * frame contents are done as needed and the slot time is 2104c42a7b7eSSam Leffler * also adjusted based on current state. 2105c42a7b7eSSam Leffler */ 21065591b213SSam Leffler static void 21075591b213SSam Leffler ath_beacon_proc(void *arg, int pending) 21085591b213SSam Leffler { 21095591b213SSam Leffler struct ath_softc *sc = arg; 2110c42a7b7eSSam Leffler struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); 2111c42a7b7eSSam Leffler struct ieee80211_node *ni = bf->bf_node; 2112c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 21135591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 2114622b3fd2SSam Leffler struct ath_txq *cabq = sc->sc_cabq; 2115c42a7b7eSSam Leffler struct mbuf *m; 2116622b3fd2SSam Leffler int ncabq, nmcastq, error, otherant; 21175591b213SSam Leffler 2118c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n", 2119c42a7b7eSSam Leffler __func__, pending); 2120c42a7b7eSSam Leffler 21210a915fadSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA || 2122c42a7b7eSSam Leffler ic->ic_opmode == IEEE80211_M_MONITOR || 21230a915fadSSam Leffler bf == NULL || bf->bf_m == NULL) { 2124c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: ic_flags=%x bf=%p bf_m=%p\n", 2125c42a7b7eSSam Leffler __func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL); 21265591b213SSam Leffler return; 21275591b213SSam Leffler } 2128c42a7b7eSSam Leffler /* 2129c42a7b7eSSam Leffler * Check if the previous beacon has gone out. If 2130c66c48cbSSam Leffler * not don't try to post another, skip this period 2131c66c48cbSSam Leffler * and wait for the next. Missed beacons indicate 2132c66c48cbSSam Leffler * a problem and should not occur. If we miss too 2133c66c48cbSSam Leffler * many consecutive beacons reset the device. 2134c42a7b7eSSam Leffler */ 2135c42a7b7eSSam Leffler if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { 2136c42a7b7eSSam Leffler sc->sc_bmisscount++; 21374a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2138c42a7b7eSSam Leffler "%s: missed %u consecutive beacons\n", 2139c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2140c42a7b7eSSam Leffler if (sc->sc_bmisscount > 3) /* NB: 3 is a guess */ 21410bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); 2142c42a7b7eSSam Leffler return; 2143c42a7b7eSSam Leffler } 2144c42a7b7eSSam Leffler if (sc->sc_bmisscount != 0) { 2145c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2146c42a7b7eSSam Leffler "%s: resume beacon xmit after %u misses\n", 2147c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2148c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 2149c42a7b7eSSam Leffler } 2150c42a7b7eSSam Leffler 2151c42a7b7eSSam Leffler /* 2152c42a7b7eSSam Leffler * Update dynamic beacon contents. If this returns 2153c42a7b7eSSam Leffler * non-zero then we need to remap the memory because 2154c42a7b7eSSam Leffler * the beacon frame changed size (probably because 2155c42a7b7eSSam Leffler * of the TIM bitmap). 2156c42a7b7eSSam Leffler */ 2157c42a7b7eSSam Leffler m = bf->bf_m; 2158622b3fd2SSam Leffler nmcastq = sc->sc_mcastq.axq_depth; 2159622b3fd2SSam Leffler ncabq = ath_hal_numtxpending(ah, cabq->axq_qnum); 2160622b3fd2SSam Leffler if (ieee80211_beacon_update(ic, bf->bf_node, &sc->sc_boff, m, ncabq+nmcastq)) { 2161c42a7b7eSSam Leffler /* XXX too conservative? */ 2162c42a7b7eSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2163f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2164f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 2165c42a7b7eSSam Leffler BUS_DMA_NOWAIT); 2166c42a7b7eSSam Leffler if (error != 0) { 2167c42a7b7eSSam Leffler if_printf(ic->ic_ifp, 2168f9e6219bSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 2169c42a7b7eSSam Leffler __func__, error); 2170c42a7b7eSSam Leffler return; 2171c42a7b7eSSam Leffler } 2172c42a7b7eSSam Leffler } 2173622b3fd2SSam Leffler if (ncabq && (sc->sc_boff.bo_tim[4] & 1)) { 2174622b3fd2SSam Leffler /* 2175622b3fd2SSam Leffler * CABQ traffic from the previous DTIM is still pending. 2176622b3fd2SSam Leffler * This is ok for now but when there are multiple vap's 2177622b3fd2SSam Leffler * and we are using staggered beacons we'll want to drain 2178622b3fd2SSam Leffler * the cabq before loading frames for the different vap. 2179622b3fd2SSam Leffler */ 2180622b3fd2SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2181622b3fd2SSam Leffler "%s: cabq did not drain, mcastq %u cabq %u/%u\n", 2182622b3fd2SSam Leffler __func__, nmcastq, ncabq, cabq->axq_depth); 2183622b3fd2SSam Leffler sc->sc_stats.ast_cabq_busy++; 2184622b3fd2SSam Leffler } 2185c42a7b7eSSam Leffler 2186c42a7b7eSSam Leffler /* 2187c42a7b7eSSam Leffler * Handle slot time change when a non-ERP station joins/leaves 2188c42a7b7eSSam Leffler * an 11g network. The 802.11 layer notifies us via callback, 2189c42a7b7eSSam Leffler * we mark updateslot, then wait one beacon before effecting 2190c42a7b7eSSam Leffler * the change. This gives associated stations at least one 2191c42a7b7eSSam Leffler * beacon interval to note the state change. 2192c42a7b7eSSam Leffler */ 2193c42a7b7eSSam Leffler /* XXX locking */ 2194c42a7b7eSSam Leffler if (sc->sc_updateslot == UPDATE) 2195c42a7b7eSSam Leffler sc->sc_updateslot = COMMIT; /* commit next beacon */ 2196c42a7b7eSSam Leffler else if (sc->sc_updateslot == COMMIT) 2197c42a7b7eSSam Leffler ath_setslottime(sc); /* commit change to h/w */ 2198c42a7b7eSSam Leffler 2199c42a7b7eSSam Leffler /* 2200c42a7b7eSSam Leffler * Check recent per-antenna transmit statistics and flip 2201c42a7b7eSSam Leffler * the default antenna if noticeably more frames went out 2202c42a7b7eSSam Leffler * on the non-default antenna. 2203c42a7b7eSSam Leffler * XXX assumes 2 anntenae 2204c42a7b7eSSam Leffler */ 2205c42a7b7eSSam Leffler otherant = sc->sc_defant & 1 ? 2 : 1; 2206c42a7b7eSSam Leffler if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) 2207c42a7b7eSSam Leffler ath_setdefantenna(sc, otherant); 2208c42a7b7eSSam Leffler sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; 2209c42a7b7eSSam Leffler 2210c42a7b7eSSam Leffler /* 2211c42a7b7eSSam Leffler * Construct tx descriptor. 2212c42a7b7eSSam Leffler */ 2213c42a7b7eSSam Leffler ath_beacon_setup(sc, bf); 2214c42a7b7eSSam Leffler 2215c42a7b7eSSam Leffler /* 2216c42a7b7eSSam Leffler * Stop any current dma and put the new frame on the queue. 2217c42a7b7eSSam Leffler * This should never fail since we check above that no frames 2218c42a7b7eSSam Leffler * are still pending on the queue. 2219c42a7b7eSSam Leffler */ 22205591b213SSam Leffler if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { 2221c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2222c42a7b7eSSam Leffler "%s: beacon queue %u did not stop?\n", 2223c42a7b7eSSam Leffler __func__, sc->sc_bhalq); 22245591b213SSam Leffler } 22255591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 22265591b213SSam Leffler 2227c42a7b7eSSam Leffler /* 2228c42a7b7eSSam Leffler * Enable the CAB queue before the beacon queue to 2229c42a7b7eSSam Leffler * insure cab frames are triggered by this beacon. 2230c42a7b7eSSam Leffler */ 2231f3af83f7SSam Leffler if (sc->sc_boff.bo_tim_len && (sc->sc_boff.bo_tim[4] & 1)) { 2232f3af83f7SSam Leffler /* NB: only at DTIM */ 2233622b3fd2SSam Leffler ATH_TXQ_LOCK(cabq); 2234622b3fd2SSam Leffler ATH_TXQ_LOCK(&sc->sc_mcastq); 2235622b3fd2SSam Leffler if (nmcastq) { 2236622b3fd2SSam Leffler struct ath_buf *bfm; 2237622b3fd2SSam Leffler 2238622b3fd2SSam Leffler /* 2239622b3fd2SSam Leffler * Move frames from the s/w mcast q to the h/w cab q. 2240622b3fd2SSam Leffler */ 2241622b3fd2SSam Leffler bfm = STAILQ_FIRST(&sc->sc_mcastq.axq_q); 2242622b3fd2SSam Leffler if (cabq->axq_link != NULL) { 2243622b3fd2SSam Leffler *cabq->axq_link = bfm->bf_daddr; 2244622b3fd2SSam Leffler } else 2245622b3fd2SSam Leffler ath_hal_puttxbuf(ah, cabq->axq_qnum, 2246622b3fd2SSam Leffler bfm->bf_daddr); 2247622b3fd2SSam Leffler ath_txqmove(cabq, &sc->sc_mcastq); 2248622b3fd2SSam Leffler 2249622b3fd2SSam Leffler sc->sc_stats.ast_cabq_xmit += nmcastq; 2250622b3fd2SSam Leffler } 2251622b3fd2SSam Leffler /* NB: gated by beacon so safe to start here */ 2252622b3fd2SSam Leffler ath_hal_txstart(ah, cabq->axq_qnum); 2253622b3fd2SSam Leffler ATH_TXQ_UNLOCK(cabq); 2254622b3fd2SSam Leffler ATH_TXQ_UNLOCK(&sc->sc_mcastq); 2255622b3fd2SSam Leffler } 22565591b213SSam Leffler ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); 22575591b213SSam Leffler ath_hal_txstart(ah, sc->sc_bhalq); 2258c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, 2259c42a7b7eSSam Leffler "%s: TXDP[%u] = %p (%p)\n", __func__, 2260c42a7b7eSSam Leffler sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc); 2261c42a7b7eSSam Leffler 2262c42a7b7eSSam Leffler sc->sc_stats.ast_be_xmit++; 22635591b213SSam Leffler } 22645591b213SSam Leffler 2265c42a7b7eSSam Leffler /* 2266c42a7b7eSSam Leffler * Reset the hardware after detecting beacons have stopped. 2267c42a7b7eSSam Leffler */ 2268c42a7b7eSSam Leffler static void 2269c42a7b7eSSam Leffler ath_bstuck_proc(void *arg, int pending) 2270c42a7b7eSSam Leffler { 2271c42a7b7eSSam Leffler struct ath_softc *sc = arg; 2272fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2273c42a7b7eSSam Leffler 2274c42a7b7eSSam Leffler if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n", 2275c42a7b7eSSam Leffler sc->sc_bmisscount); 2276c42a7b7eSSam Leffler ath_reset(ifp); 2277c42a7b7eSSam Leffler } 2278c42a7b7eSSam Leffler 2279c42a7b7eSSam Leffler /* 2280c42a7b7eSSam Leffler * Reclaim beacon resources. 2281c42a7b7eSSam Leffler */ 22825591b213SSam Leffler static void 22835591b213SSam Leffler ath_beacon_free(struct ath_softc *sc) 22845591b213SSam Leffler { 2285c42a7b7eSSam Leffler struct ath_buf *bf; 22865591b213SSam Leffler 2287f818612bSSam Leffler STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { 22885591b213SSam Leffler if (bf->bf_m != NULL) { 22895591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 22905591b213SSam Leffler m_freem(bf->bf_m); 22915591b213SSam Leffler bf->bf_m = NULL; 2292f818612bSSam Leffler } 2293f818612bSSam Leffler if (bf->bf_node != NULL) { 2294f818612bSSam Leffler ieee80211_free_node(bf->bf_node); 22955591b213SSam Leffler bf->bf_node = NULL; 22965591b213SSam Leffler } 22975591b213SSam Leffler } 2298f818612bSSam Leffler } 22995591b213SSam Leffler 23005591b213SSam Leffler /* 23015591b213SSam Leffler * Configure the beacon and sleep timers. 23025591b213SSam Leffler * 23035591b213SSam Leffler * When operating as an AP this resets the TSF and sets 23045591b213SSam Leffler * up the hardware to notify us when we need to issue beacons. 23055591b213SSam Leffler * 23065591b213SSam Leffler * When operating in station mode this sets up the beacon 23075591b213SSam Leffler * timers according to the timestamp of the last received 23085591b213SSam Leffler * beacon and the current TSF, configures PCF and DTIM 23095591b213SSam Leffler * handling, programs the sleep registers so the hardware 23105591b213SSam Leffler * will wakeup in time to receive beacons, and configures 23115591b213SSam Leffler * the beacon miss handling so we'll receive a BMISS 23125591b213SSam Leffler * interrupt when we stop seeing beacons from the AP 23135591b213SSam Leffler * we've associated with. 23145591b213SSam Leffler */ 23155591b213SSam Leffler static void 23165591b213SSam Leffler ath_beacon_config(struct ath_softc *sc) 23175591b213SSam Leffler { 231880d939bfSSam Leffler #define TSF_TO_TU(_h,_l) \ 231980d939bfSSam Leffler ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) 232080d939bfSSam Leffler #define FUDGE 2 23215591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 23225591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 23235591b213SSam Leffler struct ieee80211_node *ni = ic->ic_bss; 232480d939bfSSam Leffler u_int32_t nexttbtt, intval, tsftu; 232580d939bfSSam Leffler u_int64_t tsf; 23265591b213SSam Leffler 23278371372bSSam Leffler /* extract tstamp from last beacon and convert to TU */ 23288371372bSSam Leffler nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), 23298371372bSSam Leffler LE_READ_4(ni->ni_tstamp.data)); 23308371372bSSam Leffler /* NB: the beacon interval is kept internally in TU's */ 23314bacf7c1SSam Leffler intval = ni->ni_intval & HAL_BEACON_PERIOD; 2332a6c992f4SSam Leffler if (nexttbtt == 0) /* e.g. for ap mode */ 2333a6c992f4SSam Leffler nexttbtt = intval; 2334a6c992f4SSam Leffler else if (intval) /* NB: can be 0 for monitor mode */ 2335a6c992f4SSam Leffler nexttbtt = roundup(nexttbtt, intval); 2336a6c992f4SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", 2337a6c992f4SSam Leffler __func__, nexttbtt, intval, ni->ni_intval); 23386b59f5e3SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) { 23395591b213SSam Leffler HAL_BEACON_STATE bs; 23408371372bSSam Leffler int dtimperiod, dtimcount; 23418371372bSSam Leffler int cfpperiod, cfpcount; 23425591b213SSam Leffler 23438371372bSSam Leffler /* 23448371372bSSam Leffler * Setup dtim and cfp parameters according to 23458371372bSSam Leffler * last beacon we received (which may be none). 23468371372bSSam Leffler */ 23478371372bSSam Leffler dtimperiod = ni->ni_dtim_period; 23488371372bSSam Leffler if (dtimperiod <= 0) /* NB: 0 if not known */ 23498371372bSSam Leffler dtimperiod = 1; 23508371372bSSam Leffler dtimcount = ni->ni_dtim_count; 23518371372bSSam Leffler if (dtimcount >= dtimperiod) /* NB: sanity check */ 23528371372bSSam Leffler dtimcount = 0; /* XXX? */ 23538371372bSSam Leffler cfpperiod = 1; /* NB: no PCF support yet */ 23548371372bSSam Leffler cfpcount = 0; 23558371372bSSam Leffler /* 23568371372bSSam Leffler * Pull nexttbtt forward to reflect the current 23578371372bSSam Leffler * TSF and calculate dtim+cfp state for the result. 23588371372bSSam Leffler */ 23598371372bSSam Leffler tsf = ath_hal_gettsf64(ah); 236080d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 23618371372bSSam Leffler do { 23628371372bSSam Leffler nexttbtt += intval; 23638371372bSSam Leffler if (--dtimcount < 0) { 23648371372bSSam Leffler dtimcount = dtimperiod - 1; 23658371372bSSam Leffler if (--cfpcount < 0) 23668371372bSSam Leffler cfpcount = cfpperiod - 1; 23678371372bSSam Leffler } 23688371372bSSam Leffler } while (nexttbtt < tsftu); 23695591b213SSam Leffler memset(&bs, 0, sizeof(bs)); 2370a6c992f4SSam Leffler bs.bs_intval = intval; 23715591b213SSam Leffler bs.bs_nexttbtt = nexttbtt; 23728371372bSSam Leffler bs.bs_dtimperiod = dtimperiod*intval; 23738371372bSSam Leffler bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 23748371372bSSam Leffler bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 23758371372bSSam Leffler bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 23768371372bSSam Leffler bs.bs_cfpmaxduration = 0; 23778371372bSSam Leffler #if 0 23785591b213SSam Leffler /* 2379c42a7b7eSSam Leffler * The 802.11 layer records the offset to the DTIM 2380c42a7b7eSSam Leffler * bitmap while receiving beacons; use it here to 2381c42a7b7eSSam Leffler * enable h/w detection of our AID being marked in 2382c42a7b7eSSam Leffler * the bitmap vector (to indicate frames for us are 2383c42a7b7eSSam Leffler * pending at the AP). 23848371372bSSam Leffler * XXX do DTIM handling in s/w to WAR old h/w bugs 23858371372bSSam Leffler * XXX enable based on h/w rev for newer chips 2386c42a7b7eSSam Leffler */ 2387c42a7b7eSSam Leffler bs.bs_timoffset = ni->ni_timoff; 23888371372bSSam Leffler #endif 2389c42a7b7eSSam Leffler /* 23905591b213SSam Leffler * Calculate the number of consecutive beacons to miss 23915591b213SSam Leffler * before taking a BMISS interrupt. The configuration 23925591b213SSam Leffler * is specified in ms, so we need to convert that to 23935591b213SSam Leffler * TU's and then calculate based on the beacon interval. 23945591b213SSam Leffler * Note that we clamp the result to at most 10 beacons. 23955591b213SSam Leffler */ 2396b9919097SSam Leffler bs.bs_bmissthreshold = ic->ic_bmissthreshold; 23975591b213SSam Leffler if (bs.bs_bmissthreshold > 10) 23985591b213SSam Leffler bs.bs_bmissthreshold = 10; 23995591b213SSam Leffler else if (bs.bs_bmissthreshold <= 0) 24005591b213SSam Leffler bs.bs_bmissthreshold = 1; 24015591b213SSam Leffler 24025591b213SSam Leffler /* 24035591b213SSam Leffler * Calculate sleep duration. The configuration is 24045591b213SSam Leffler * given in ms. We insure a multiple of the beacon 24055591b213SSam Leffler * period is used. Also, if the sleep duration is 24065591b213SSam Leffler * greater than the DTIM period then it makes senses 24075591b213SSam Leffler * to make it a multiple of that. 24085591b213SSam Leffler * 24095591b213SSam Leffler * XXX fixed at 100ms 24105591b213SSam Leffler */ 24114bacf7c1SSam Leffler bs.bs_sleepduration = 24124bacf7c1SSam Leffler roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval); 24135591b213SSam Leffler if (bs.bs_sleepduration > bs.bs_dtimperiod) 24145591b213SSam Leffler bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 24155591b213SSam Leffler 2416c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 24178371372bSSam 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" 24185591b213SSam Leffler , __func__ 24198371372bSSam Leffler , tsf, tsftu 24205591b213SSam Leffler , bs.bs_intval 24215591b213SSam Leffler , bs.bs_nexttbtt 24225591b213SSam Leffler , bs.bs_dtimperiod 24235591b213SSam Leffler , bs.bs_nextdtim 24245591b213SSam Leffler , bs.bs_bmissthreshold 24255591b213SSam Leffler , bs.bs_sleepduration 2426c42a7b7eSSam Leffler , bs.bs_cfpperiod 2427c42a7b7eSSam Leffler , bs.bs_cfpmaxduration 2428c42a7b7eSSam Leffler , bs.bs_cfpnext 2429c42a7b7eSSam Leffler , bs.bs_timoffset 2430c42a7b7eSSam Leffler ); 24315591b213SSam Leffler ath_hal_intrset(ah, 0); 2432c42a7b7eSSam Leffler ath_hal_beacontimers(ah, &bs); 24335591b213SSam Leffler sc->sc_imask |= HAL_INT_BMISS; 24345591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 24355591b213SSam Leffler } else { 24365591b213SSam Leffler ath_hal_intrset(ah, 0); 2437a6c992f4SSam Leffler if (nexttbtt == intval) 2438c42a7b7eSSam Leffler intval |= HAL_BEACON_RESET_TSF; 2439c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS) { 2440c42a7b7eSSam Leffler /* 2441c42a7b7eSSam Leffler * In IBSS mode enable the beacon timers but only 2442c42a7b7eSSam Leffler * enable SWBA interrupts if we need to manually 2443c42a7b7eSSam Leffler * prepare beacon frames. Otherwise we use a 2444c42a7b7eSSam Leffler * self-linked tx descriptor and let the hardware 2445c42a7b7eSSam Leffler * deal with things. 2446c42a7b7eSSam Leffler */ 2447c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 2448c42a7b7eSSam Leffler if (!sc->sc_hasveol) 2449c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_SWBA; 245080d939bfSSam Leffler if ((intval & HAL_BEACON_RESET_TSF) == 0) { 245180d939bfSSam Leffler /* 245280d939bfSSam Leffler * Pull nexttbtt forward to reflect 245380d939bfSSam Leffler * the current TSF. 245480d939bfSSam Leffler */ 245580d939bfSSam Leffler tsf = ath_hal_gettsf64(ah); 245680d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 245780d939bfSSam Leffler do { 245880d939bfSSam Leffler nexttbtt += intval; 245980d939bfSSam Leffler } while (nexttbtt < tsftu); 246080d939bfSSam Leffler } 24610f2e86fbSSam Leffler ath_beaconq_config(sc); 2462c42a7b7eSSam Leffler } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 2463c42a7b7eSSam Leffler /* 2464c42a7b7eSSam Leffler * In AP mode we enable the beacon timers and 2465c42a7b7eSSam Leffler * SWBA interrupts to prepare beacon frames. 2466c42a7b7eSSam Leffler */ 2467c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 24685591b213SSam Leffler sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */ 24690f2e86fbSSam Leffler ath_beaconq_config(sc); 2470c42a7b7eSSam Leffler } 2471c42a7b7eSSam Leffler ath_hal_beaconinit(ah, nexttbtt, intval); 2472c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 24735591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 2474c42a7b7eSSam Leffler /* 2475c42a7b7eSSam Leffler * When using a self-linked beacon descriptor in 2476c42a7b7eSSam Leffler * ibss mode load it once here. 2477c42a7b7eSSam Leffler */ 2478c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) 2479c42a7b7eSSam Leffler ath_beacon_proc(sc, 0); 24805591b213SSam Leffler } 248180d939bfSSam Leffler sc->sc_syncbeacon = 0; 248280d939bfSSam Leffler #undef FUDGE 24838371372bSSam Leffler #undef TSF_TO_TU 24845591b213SSam Leffler } 24855591b213SSam Leffler 24865591b213SSam Leffler static void 24875591b213SSam Leffler ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 24885591b213SSam Leffler { 24895591b213SSam Leffler bus_addr_t *paddr = (bus_addr_t*) arg; 2490d77367bfSSam Leffler KASSERT(error == 0, ("error %u on bus_dma callback", error)); 24915591b213SSam Leffler *paddr = segs->ds_addr; 24925591b213SSam Leffler } 24935591b213SSam Leffler 24945591b213SSam Leffler static int 2495c42a7b7eSSam Leffler ath_descdma_setup(struct ath_softc *sc, 2496c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head, 2497c42a7b7eSSam Leffler const char *name, int nbuf, int ndesc) 2498c42a7b7eSSam Leffler { 2499c42a7b7eSSam Leffler #define DS2PHYS(_dd, _ds) \ 2500c42a7b7eSSam Leffler ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) 2501fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2502c42a7b7eSSam Leffler struct ath_desc *ds; 2503c42a7b7eSSam Leffler struct ath_buf *bf; 2504c42a7b7eSSam Leffler int i, bsize, error; 2505c42a7b7eSSam Leffler 2506c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n", 2507c42a7b7eSSam Leffler __func__, name, nbuf, ndesc); 2508c42a7b7eSSam Leffler 2509c42a7b7eSSam Leffler dd->dd_name = name; 2510c42a7b7eSSam Leffler dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; 2511c42a7b7eSSam Leffler 2512c42a7b7eSSam Leffler /* 2513c42a7b7eSSam Leffler * Setup DMA descriptor area. 2514c42a7b7eSSam Leffler */ 2515c2175ff5SMarius Strobl error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */ 2516c42a7b7eSSam Leffler PAGE_SIZE, 0, /* alignment, bounds */ 2517c42a7b7eSSam Leffler BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 2518c42a7b7eSSam Leffler BUS_SPACE_MAXADDR, /* highaddr */ 2519c42a7b7eSSam Leffler NULL, NULL, /* filter, filterarg */ 2520c42a7b7eSSam Leffler dd->dd_desc_len, /* maxsize */ 2521c42a7b7eSSam Leffler 1, /* nsegments */ 25226ccb8ea7SSam Leffler dd->dd_desc_len, /* maxsegsize */ 2523c42a7b7eSSam Leffler BUS_DMA_ALLOCNOW, /* flags */ 2524c42a7b7eSSam Leffler NULL, /* lockfunc */ 2525c42a7b7eSSam Leffler NULL, /* lockarg */ 2526c42a7b7eSSam Leffler &dd->dd_dmat); 2527c42a7b7eSSam Leffler if (error != 0) { 2528c42a7b7eSSam Leffler if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); 2529c42a7b7eSSam Leffler return error; 2530c42a7b7eSSam Leffler } 2531c42a7b7eSSam Leffler 2532c42a7b7eSSam Leffler /* allocate descriptors */ 2533c42a7b7eSSam Leffler error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap); 2534c42a7b7eSSam Leffler if (error != 0) { 2535c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s descriptors, " 2536c42a7b7eSSam Leffler "error %u\n", dd->dd_name, error); 2537c42a7b7eSSam Leffler goto fail0; 2538c42a7b7eSSam Leffler } 2539c42a7b7eSSam Leffler 2540c42a7b7eSSam Leffler error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc, 25410553a01fSSam Leffler BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 25420553a01fSSam Leffler &dd->dd_dmamap); 2543c42a7b7eSSam Leffler if (error != 0) { 2544c42a7b7eSSam Leffler if_printf(ifp, "unable to alloc memory for %u %s descriptors, " 2545c42a7b7eSSam Leffler "error %u\n", nbuf * ndesc, dd->dd_name, error); 2546c42a7b7eSSam Leffler goto fail1; 2547c42a7b7eSSam Leffler } 2548c42a7b7eSSam Leffler 2549c42a7b7eSSam Leffler error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap, 2550c42a7b7eSSam Leffler dd->dd_desc, dd->dd_desc_len, 2551c42a7b7eSSam Leffler ath_load_cb, &dd->dd_desc_paddr, 2552c42a7b7eSSam Leffler BUS_DMA_NOWAIT); 2553c42a7b7eSSam Leffler if (error != 0) { 2554c42a7b7eSSam Leffler if_printf(ifp, "unable to map %s descriptors, error %u\n", 2555c42a7b7eSSam Leffler dd->dd_name, error); 2556c42a7b7eSSam Leffler goto fail2; 2557c42a7b7eSSam Leffler } 2558c42a7b7eSSam Leffler 2559c42a7b7eSSam Leffler ds = dd->dd_desc; 2560c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n", 2561c42a7b7eSSam Leffler __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len, 2562c42a7b7eSSam Leffler (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len); 2563c42a7b7eSSam Leffler 2564ebecf802SSam Leffler /* allocate rx buffers */ 2565c42a7b7eSSam Leffler bsize = sizeof(struct ath_buf) * nbuf; 2566c42a7b7eSSam Leffler bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO); 2567c42a7b7eSSam Leffler if (bf == NULL) { 2568c42a7b7eSSam Leffler if_printf(ifp, "malloc of %s buffers failed, size %u\n", 2569c42a7b7eSSam Leffler dd->dd_name, bsize); 2570c42a7b7eSSam Leffler goto fail3; 2571c42a7b7eSSam Leffler } 2572c42a7b7eSSam Leffler dd->dd_bufptr = bf; 2573c42a7b7eSSam Leffler 2574c42a7b7eSSam Leffler STAILQ_INIT(head); 2575c42a7b7eSSam Leffler for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { 2576c42a7b7eSSam Leffler bf->bf_desc = ds; 2577c42a7b7eSSam Leffler bf->bf_daddr = DS2PHYS(dd, ds); 2578c42a7b7eSSam Leffler error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, 2579c42a7b7eSSam Leffler &bf->bf_dmamap); 2580c42a7b7eSSam Leffler if (error != 0) { 2581c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s " 2582c42a7b7eSSam Leffler "buffer %u, error %u\n", dd->dd_name, i, error); 2583c42a7b7eSSam Leffler ath_descdma_cleanup(sc, dd, head); 2584c42a7b7eSSam Leffler return error; 2585c42a7b7eSSam Leffler } 2586c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(head, bf, bf_list); 2587c42a7b7eSSam Leffler } 2588c42a7b7eSSam Leffler return 0; 2589c42a7b7eSSam Leffler fail3: 2590c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 2591c42a7b7eSSam Leffler fail2: 2592c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 2593c42a7b7eSSam Leffler fail1: 2594c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 2595c42a7b7eSSam Leffler fail0: 2596c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 2597c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 2598c42a7b7eSSam Leffler return error; 2599c42a7b7eSSam Leffler #undef DS2PHYS 2600c42a7b7eSSam Leffler } 2601c42a7b7eSSam Leffler 2602c42a7b7eSSam Leffler static void 2603c42a7b7eSSam Leffler ath_descdma_cleanup(struct ath_softc *sc, 2604c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head) 2605c42a7b7eSSam Leffler { 2606c42a7b7eSSam Leffler struct ath_buf *bf; 2607c42a7b7eSSam Leffler struct ieee80211_node *ni; 2608c42a7b7eSSam Leffler 2609c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 2610c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 2611c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 2612c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 2613c42a7b7eSSam Leffler 2614c42a7b7eSSam Leffler STAILQ_FOREACH(bf, head, bf_list) { 2615c42a7b7eSSam Leffler if (bf->bf_m) { 2616c42a7b7eSSam Leffler m_freem(bf->bf_m); 2617c42a7b7eSSam Leffler bf->bf_m = NULL; 2618c42a7b7eSSam Leffler } 2619c42a7b7eSSam Leffler if (bf->bf_dmamap != NULL) { 2620c42a7b7eSSam Leffler bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap); 2621c42a7b7eSSam Leffler bf->bf_dmamap = NULL; 2622c42a7b7eSSam Leffler } 2623c42a7b7eSSam Leffler ni = bf->bf_node; 2624c42a7b7eSSam Leffler bf->bf_node = NULL; 2625c42a7b7eSSam Leffler if (ni != NULL) { 2626c42a7b7eSSam Leffler /* 2627c42a7b7eSSam Leffler * Reclaim node reference. 2628c42a7b7eSSam Leffler */ 2629c42a7b7eSSam Leffler ieee80211_free_node(ni); 2630c42a7b7eSSam Leffler } 2631c42a7b7eSSam Leffler } 2632c42a7b7eSSam Leffler 2633c42a7b7eSSam Leffler STAILQ_INIT(head); 2634c42a7b7eSSam Leffler free(dd->dd_bufptr, M_ATHDEV); 2635c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 2636c42a7b7eSSam Leffler } 2637c42a7b7eSSam Leffler 2638c42a7b7eSSam Leffler static int 26395591b213SSam Leffler ath_desc_alloc(struct ath_softc *sc) 26405591b213SSam Leffler { 2641c42a7b7eSSam Leffler int error; 26425591b213SSam Leffler 2643c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, 2644e2d787faSSam Leffler "rx", ath_rxbuf, 1); 26455591b213SSam Leffler if (error != 0) 26465591b213SSam Leffler return error; 26475591b213SSam Leffler 2648c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, 2649e2d787faSSam Leffler "tx", ath_txbuf, ATH_TXDESC); 2650c42a7b7eSSam Leffler if (error != 0) { 2651c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 26525591b213SSam Leffler return error; 2653c42a7b7eSSam Leffler } 2654c42a7b7eSSam Leffler 2655c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, 2656c42a7b7eSSam Leffler "beacon", 1, 1); 2657c42a7b7eSSam Leffler if (error != 0) { 2658c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 2659c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 2660c42a7b7eSSam Leffler return error; 2661c42a7b7eSSam Leffler } 26625591b213SSam Leffler return 0; 26635591b213SSam Leffler } 26645591b213SSam Leffler 26655591b213SSam Leffler static void 26665591b213SSam Leffler ath_desc_free(struct ath_softc *sc) 26675591b213SSam Leffler { 26685591b213SSam Leffler 2669c42a7b7eSSam Leffler if (sc->sc_bdma.dd_desc_len != 0) 2670c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); 2671c42a7b7eSSam Leffler if (sc->sc_txdma.dd_desc_len != 0) 2672c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 2673c42a7b7eSSam Leffler if (sc->sc_rxdma.dd_desc_len != 0) 2674c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 26755591b213SSam Leffler } 26765591b213SSam Leffler 26775591b213SSam Leffler static struct ieee80211_node * 2678c42a7b7eSSam Leffler ath_node_alloc(struct ieee80211_node_table *nt) 26795591b213SSam Leffler { 2680c42a7b7eSSam Leffler struct ieee80211com *ic = nt->nt_ic; 2681c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 2682c42a7b7eSSam Leffler const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; 2683c42a7b7eSSam Leffler struct ath_node *an; 2684c42a7b7eSSam Leffler 2685c42a7b7eSSam Leffler an = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO); 2686c42a7b7eSSam Leffler if (an == NULL) { 2687c42a7b7eSSam Leffler /* XXX stat+msg */ 2688de5af704SSam Leffler return NULL; 26895591b213SSam Leffler } 2690c42a7b7eSSam Leffler an->an_avgrssi = ATH_RSSI_DUMMY_MARKER; 2691c42a7b7eSSam Leffler ath_rate_node_init(sc, an); 26925591b213SSam Leffler 2693c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); 2694c42a7b7eSSam Leffler return &an->an_node; 2695c42a7b7eSSam Leffler } 2696c42a7b7eSSam Leffler 26975591b213SSam Leffler static void 2698c42a7b7eSSam Leffler ath_node_free(struct ieee80211_node *ni) 26995591b213SSam Leffler { 2700c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2701c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 27021e774079SSam Leffler 2703c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: ni %p\n", __func__, ni); 2704c42a7b7eSSam Leffler 2705c42a7b7eSSam Leffler ath_rate_node_cleanup(sc, ATH_NODE(ni)); 2706c42a7b7eSSam Leffler sc->sc_node_free(ni); 27075591b213SSam Leffler } 27085591b213SSam Leffler 2709de5af704SSam Leffler static u_int8_t 2710c42a7b7eSSam Leffler ath_node_getrssi(const struct ieee80211_node *ni) 2711de5af704SSam Leffler { 2712c42a7b7eSSam Leffler #define HAL_EP_RND(x, mul) \ 2713c42a7b7eSSam Leffler ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) 2714c42a7b7eSSam Leffler u_int32_t avgrssi = ATH_NODE_CONST(ni)->an_avgrssi; 2715c42a7b7eSSam Leffler int32_t rssi; 2716de5af704SSam Leffler 2717de5af704SSam Leffler /* 2718c42a7b7eSSam Leffler * When only one frame is received there will be no state in 2719c42a7b7eSSam Leffler * avgrssi so fallback on the value recorded by the 802.11 layer. 2720de5af704SSam Leffler */ 2721c42a7b7eSSam Leffler if (avgrssi != ATH_RSSI_DUMMY_MARKER) 2722c42a7b7eSSam Leffler rssi = HAL_EP_RND(avgrssi, HAL_RSSI_EP_MULTIPLIER); 2723de5af704SSam Leffler else 2724c42a7b7eSSam Leffler rssi = ni->ni_rssi; 2725c42a7b7eSSam Leffler return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 2726c42a7b7eSSam Leffler #undef HAL_EP_RND 2727de5af704SSam Leffler } 2728de5af704SSam Leffler 27295591b213SSam Leffler static int 27305591b213SSam Leffler ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) 27315591b213SSam Leffler { 27325591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 27335591b213SSam Leffler int error; 27345591b213SSam Leffler struct mbuf *m; 27355591b213SSam Leffler struct ath_desc *ds; 27365591b213SSam Leffler 27375591b213SSam Leffler m = bf->bf_m; 27385591b213SSam Leffler if (m == NULL) { 27395591b213SSam Leffler /* 27405591b213SSam Leffler * NB: by assigning a page to the rx dma buffer we 27415591b213SSam Leffler * implicitly satisfy the Atheros requirement that 27425591b213SSam Leffler * this buffer be cache-line-aligned and sized to be 27435591b213SSam Leffler * multiple of the cache line size. Not doing this 27445591b213SSam Leffler * causes weird stuff to happen (for the 5210 at least). 27455591b213SSam Leffler */ 27465591b213SSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 27475591b213SSam Leffler if (m == NULL) { 2748c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2749c42a7b7eSSam Leffler "%s: no mbuf/cluster\n", __func__); 27505591b213SSam Leffler sc->sc_stats.ast_rx_nombuf++; 27515591b213SSam Leffler return ENOMEM; 27525591b213SSam Leffler } 27535591b213SSam Leffler m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 27545591b213SSam Leffler 2755f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, 2756c42a7b7eSSam Leffler bf->bf_dmamap, m, 2757f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 27585591b213SSam Leffler BUS_DMA_NOWAIT); 27595591b213SSam Leffler if (error != 0) { 2760c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2761f9e6219bSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed; error %d\n", 2762c42a7b7eSSam Leffler __func__, error); 27635591b213SSam Leffler sc->sc_stats.ast_rx_busdma++; 2764b2792ff6SSam Leffler m_freem(m); 27655591b213SSam Leffler return error; 27665591b213SSam Leffler } 2767d77367bfSSam Leffler KASSERT(bf->bf_nseg == 1, 2768d77367bfSSam Leffler ("multi-segment packet; nseg %u", bf->bf_nseg)); 2769b2792ff6SSam Leffler bf->bf_m = m; 27705591b213SSam Leffler } 27715591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD); 27725591b213SSam Leffler 277304e22a02SSam Leffler /* 277404e22a02SSam Leffler * Setup descriptors. For receive we always terminate 277504e22a02SSam Leffler * the descriptor list with a self-linked entry so we'll 277604e22a02SSam Leffler * not get overrun under high load (as can happen with a 2777c42a7b7eSSam Leffler * 5212 when ANI processing enables PHY error frames). 277804e22a02SSam Leffler * 277904e22a02SSam Leffler * To insure the last descriptor is self-linked we create 278004e22a02SSam Leffler * each descriptor as self-linked and add it to the end. As 278104e22a02SSam Leffler * each additional descriptor is added the previous self-linked 278204e22a02SSam Leffler * entry is ``fixed'' naturally. This should be safe even 278304e22a02SSam Leffler * if DMA is happening. When processing RX interrupts we 278404e22a02SSam Leffler * never remove/process the last, self-linked, entry on the 278504e22a02SSam Leffler * descriptor list. This insures the hardware always has 278604e22a02SSam Leffler * someplace to write a new frame. 278704e22a02SSam Leffler */ 27885591b213SSam Leffler ds = bf->bf_desc; 278904e22a02SSam Leffler ds->ds_link = bf->bf_daddr; /* link to self */ 27905591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 27915591b213SSam Leffler ath_hal_setuprxdesc(ah, ds 27925591b213SSam Leffler , m->m_len /* buffer size */ 27935591b213SSam Leffler , 0 27945591b213SSam Leffler ); 27955591b213SSam Leffler 27965591b213SSam Leffler if (sc->sc_rxlink != NULL) 27975591b213SSam Leffler *sc->sc_rxlink = bf->bf_daddr; 27985591b213SSam Leffler sc->sc_rxlink = &ds->ds_link; 27995591b213SSam Leffler return 0; 28005591b213SSam Leffler } 28015591b213SSam Leffler 2802c42a7b7eSSam Leffler /* 280303ed599aSSam Leffler * Extend 15-bit time stamp from rx descriptor to 28047b0c77ecSSam Leffler * a full 64-bit TSF using the specified TSF. 280503ed599aSSam Leffler */ 280603ed599aSSam Leffler static __inline u_int64_t 28077b0c77ecSSam Leffler ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf) 280803ed599aSSam Leffler { 280903ed599aSSam Leffler if ((tsf & 0x7fff) < rstamp) 281003ed599aSSam Leffler tsf -= 0x8000; 281103ed599aSSam Leffler return ((tsf &~ 0x7fff) | rstamp); 281203ed599aSSam Leffler } 281303ed599aSSam Leffler 281403ed599aSSam Leffler /* 2815c42a7b7eSSam Leffler * Intercept management frames to collect beacon rssi data 2816c42a7b7eSSam Leffler * and to do ibss merges. 2817c42a7b7eSSam Leffler */ 2818c42a7b7eSSam Leffler static void 2819c42a7b7eSSam Leffler ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, 2820c42a7b7eSSam Leffler struct ieee80211_node *ni, 2821c42a7b7eSSam Leffler int subtype, int rssi, u_int32_t rstamp) 2822c42a7b7eSSam Leffler { 2823c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 2824c42a7b7eSSam Leffler 2825c42a7b7eSSam Leffler /* 2826c42a7b7eSSam Leffler * Call up first so subsequent work can use information 2827c42a7b7eSSam Leffler * potentially stored in the node (e.g. for ibss merge). 2828c42a7b7eSSam Leffler */ 2829c42a7b7eSSam Leffler sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, rstamp); 2830c42a7b7eSSam Leffler switch (subtype) { 2831c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_BEACON: 2832c42a7b7eSSam Leffler /* update rssi statistics for use by the hal */ 2833ffa2cab6SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); 283480d939bfSSam Leffler if (sc->sc_syncbeacon && 283580d939bfSSam Leffler ni == ic->ic_bss && ic->ic_state == IEEE80211_S_RUN) { 283680d939bfSSam Leffler /* 283780d939bfSSam Leffler * Resync beacon timers using the tsf of the beacon 283880d939bfSSam Leffler * frame we just received. 283980d939bfSSam Leffler */ 284080d939bfSSam Leffler ath_beacon_config(sc); 284180d939bfSSam Leffler } 2842c42a7b7eSSam Leffler /* fall thru... */ 2843c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 2844c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && 2845c42a7b7eSSam Leffler ic->ic_state == IEEE80211_S_RUN) { 28467b0c77ecSSam Leffler u_int64_t tsf = ath_extend_tsf(rstamp, 28477b0c77ecSSam Leffler ath_hal_gettsf64(sc->sc_ah)); 2848c42a7b7eSSam Leffler /* 2849c42a7b7eSSam Leffler * Handle ibss merge as needed; check the tsf on the 2850c42a7b7eSSam Leffler * frame before attempting the merge. The 802.11 spec 2851c42a7b7eSSam Leffler * says the station should change it's bssid to match 2852c42a7b7eSSam Leffler * the oldest station with the same ssid, where oldest 2853f818612bSSam Leffler * is determined by the tsf. Note that hardware 2854f818612bSSam Leffler * reconfiguration happens through callback to 285503ed599aSSam Leffler * ath_newstate as the state machine will go from 285603ed599aSSam Leffler * RUN -> RUN when this happens. 2857c42a7b7eSSam Leffler */ 285803ed599aSSam Leffler if (le64toh(ni->ni_tstamp.tsf) >= tsf) { 285903ed599aSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 286033d7d80cSTai-hwa Liang "ibss merge, rstamp %u tsf %ju " 286133d7d80cSTai-hwa Liang "tstamp %ju\n", rstamp, (uintmax_t)tsf, 286233d7d80cSTai-hwa Liang (uintmax_t)ni->ni_tstamp.tsf); 2863641b4d0bSSam Leffler (void) ieee80211_ibss_merge(ni); 2864c42a7b7eSSam Leffler } 286503ed599aSSam Leffler } 2866c42a7b7eSSam Leffler break; 2867c42a7b7eSSam Leffler } 2868c42a7b7eSSam Leffler } 2869c42a7b7eSSam Leffler 2870c42a7b7eSSam Leffler /* 2871c42a7b7eSSam Leffler * Set the default antenna. 2872c42a7b7eSSam Leffler */ 2873c42a7b7eSSam Leffler static void 2874c42a7b7eSSam Leffler ath_setdefantenna(struct ath_softc *sc, u_int antenna) 2875c42a7b7eSSam Leffler { 2876c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2877c42a7b7eSSam Leffler 2878c42a7b7eSSam Leffler /* XXX block beacon interrupts */ 2879c42a7b7eSSam Leffler ath_hal_setdefantenna(ah, antenna); 2880c42a7b7eSSam Leffler if (sc->sc_defant != antenna) 2881c42a7b7eSSam Leffler sc->sc_stats.ast_ant_defswitch++; 2882c42a7b7eSSam Leffler sc->sc_defant = antenna; 2883c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 2884c42a7b7eSSam Leffler } 2885c42a7b7eSSam Leffler 28867b0c77ecSSam Leffler static int 28877b0c77ecSSam Leffler ath_rx_tap(struct ath_softc *sc, struct mbuf *m, 288865f9edeeSSam Leffler const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) 28897b0c77ecSSam Leffler { 28907b0c77ecSSam Leffler u_int8_t rix; 28917b0c77ecSSam Leffler 28927b0c77ecSSam Leffler KASSERT(sc->sc_drvbpf != NULL, ("no tap")); 28937b0c77ecSSam Leffler 28947b0c77ecSSam Leffler /* 28957b0c77ecSSam Leffler * Discard anything shorter than an ack or cts. 28967b0c77ecSSam Leffler */ 28977b0c77ecSSam Leffler if (m->m_pkthdr.len < IEEE80211_ACK_LEN) { 28987b0c77ecSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, "%s: runt packet %d\n", 28997b0c77ecSSam Leffler __func__, m->m_pkthdr.len); 29007b0c77ecSSam Leffler sc->sc_stats.ast_rx_tooshort++; 29017b0c77ecSSam Leffler return 0; 29027b0c77ecSSam Leffler } 290365f9edeeSSam Leffler sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf)); 290465f9edeeSSam Leffler rix = rs->rs_rate; 29057b0c77ecSSam Leffler sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; 290665f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 29077b0c77ecSSam Leffler sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; 29087b0c77ecSSam Leffler /* XXX propagate other error flags from descriptor */ 29097b0c77ecSSam Leffler sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; 291065f9edeeSSam Leffler sc->sc_rx_th.wr_antsignal = rs->rs_rssi + nf; 29117b0c77ecSSam Leffler sc->sc_rx_th.wr_antnoise = nf; 291265f9edeeSSam Leffler sc->sc_rx_th.wr_antenna = rs->rs_antenna; 29137b0c77ecSSam Leffler 29147b0c77ecSSam Leffler bpf_mtap2(sc->sc_drvbpf, &sc->sc_rx_th, sc->sc_rx_th_len, m); 29157b0c77ecSSam Leffler 29167b0c77ecSSam Leffler return 1; 29177b0c77ecSSam Leffler } 29187b0c77ecSSam Leffler 29195591b213SSam Leffler static void 29205591b213SSam Leffler ath_rx_proc(void *arg, int npending) 29215591b213SSam Leffler { 29228cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 2923c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 2924c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 29255591b213SSam Leffler struct ath_softc *sc = arg; 29265591b213SSam Leffler struct ath_buf *bf; 2927d1d0cf62SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 2928fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 29295591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 29305591b213SSam Leffler struct ath_desc *ds; 293165f9edeeSSam Leffler struct ath_rx_status *rs; 29325591b213SSam Leffler struct mbuf *m; 29330a915fadSSam Leffler struct ieee80211_node *ni; 2934de5af704SSam Leffler struct ath_node *an; 2935d7736e13SSam Leffler int len, type, ngood; 29365591b213SSam Leffler u_int phyerr; 29375591b213SSam Leffler HAL_STATUS status; 29387b0c77ecSSam Leffler int16_t nf; 29397b0c77ecSSam Leffler u_int64_t tsf; 29405591b213SSam Leffler 2941b5f4adb3SSam Leffler NET_LOCK_GIANT(); /* XXX */ 2942b5f4adb3SSam Leffler 2943c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); 2944d7736e13SSam Leffler ngood = 0; 29457b0c77ecSSam Leffler nf = ath_hal_getchannoise(ah, &sc->sc_curchan); 29467b0c77ecSSam Leffler tsf = ath_hal_gettsf64(ah); 29475591b213SSam Leffler do { 2948c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 29495591b213SSam Leffler if (bf == NULL) { /* NB: shouldn't happen */ 2950c42a7b7eSSam Leffler if_printf(ifp, "%s: no buffer!\n", __func__); 29515591b213SSam Leffler break; 29525591b213SSam Leffler } 2953b2792ff6SSam Leffler m = bf->bf_m; 2954b2792ff6SSam Leffler if (m == NULL) { /* NB: shouldn't happen */ 2955b2792ff6SSam Leffler /* 2956b2792ff6SSam Leffler * If mbuf allocation failed previously there 2957b2792ff6SSam Leffler * will be no mbuf; try again to re-populate it. 2958b2792ff6SSam Leffler */ 2959b2792ff6SSam Leffler /* XXX make debug msg */ 2960b2792ff6SSam Leffler if_printf(ifp, "%s: no mbuf!\n", __func__); 2961b2792ff6SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 2962b2792ff6SSam Leffler goto rx_next; 2963b2792ff6SSam Leffler } 296404e22a02SSam Leffler ds = bf->bf_desc; 296504e22a02SSam Leffler if (ds->ds_link == bf->bf_daddr) { 296604e22a02SSam Leffler /* NB: never process the self-linked entry at the end */ 296704e22a02SSam Leffler break; 296804e22a02SSam Leffler } 29698cec0ab9SSam Leffler /* XXX sync descriptor memory */ 29708cec0ab9SSam Leffler /* 29718cec0ab9SSam Leffler * Must provide the virtual address of the current 29728cec0ab9SSam Leffler * descriptor, the physical address, and the virtual 29738cec0ab9SSam Leffler * address of the next descriptor in the h/w chain. 29748cec0ab9SSam Leffler * This allows the HAL to look ahead to see if the 29758cec0ab9SSam Leffler * hardware is done with a descriptor by checking the 29768cec0ab9SSam Leffler * done bit in the following descriptor and the address 29778cec0ab9SSam Leffler * of the current descriptor the DMA engine is working 29788cec0ab9SSam Leffler * on. All this is necessary because of our use of 29798cec0ab9SSam Leffler * a self-linked list to avoid rx overruns. 29808cec0ab9SSam Leffler */ 298165f9edeeSSam Leffler rs = &bf->bf_status.ds_rxstat; 29828cec0ab9SSam Leffler status = ath_hal_rxprocdesc(ah, ds, 298365f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 2984a585a9a1SSam Leffler #ifdef ATH_DEBUG 2985c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_RECV_DESC) 29867a4c5ed9SSam Leffler ath_printrxbuf(bf, 0, status == HAL_OK); 29875591b213SSam Leffler #endif 29885591b213SSam Leffler if (status == HAL_EINPROGRESS) 29895591b213SSam Leffler break; 2990c42a7b7eSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 299165f9edeeSSam Leffler if (rs->rs_more) { 2992c42a7b7eSSam Leffler /* 2993c42a7b7eSSam Leffler * Frame spans multiple descriptors; this 2994c42a7b7eSSam Leffler * cannot happen yet as we don't support 2995c42a7b7eSSam Leffler * jumbograms. If not in monitor mode, 2996c42a7b7eSSam Leffler * discard the frame. 2997c42a7b7eSSam Leffler */ 2998c42a7b7eSSam Leffler if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2999c42a7b7eSSam Leffler sc->sc_stats.ast_rx_toobig++; 3000c42a7b7eSSam Leffler goto rx_next; 3001c42a7b7eSSam Leffler } 3002c42a7b7eSSam Leffler /* fall thru for monitor mode handling... */ 300365f9edeeSSam Leffler } else if (rs->rs_status != 0) { 300465f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 30055591b213SSam Leffler sc->sc_stats.ast_rx_crcerr++; 300665f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_FIFO) 30075591b213SSam Leffler sc->sc_stats.ast_rx_fifoerr++; 300865f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_PHY) { 30095591b213SSam Leffler sc->sc_stats.ast_rx_phyerr++; 301065f9edeeSSam Leffler phyerr = rs->rs_phyerr & 0x1f; 30115591b213SSam Leffler sc->sc_stats.ast_rx_phy[phyerr]++; 3012c42a7b7eSSam Leffler goto rx_next; 3013c42a7b7eSSam Leffler } 301465f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_DECRYPT) { 301585643802SSam Leffler /* 3016c42a7b7eSSam Leffler * Decrypt error. If the error occurred 3017c42a7b7eSSam Leffler * because there was no hardware key, then 3018c42a7b7eSSam Leffler * let the frame through so the upper layers 3019c42a7b7eSSam Leffler * can process it. This is necessary for 5210 3020c42a7b7eSSam Leffler * parts which have no way to setup a ``clear'' 3021c42a7b7eSSam Leffler * key cache entry. 3022c42a7b7eSSam Leffler * 3023c42a7b7eSSam Leffler * XXX do key cache faulting 302485643802SSam Leffler */ 302565f9edeeSSam Leffler if (rs->rs_keyix == HAL_RXKEYIX_INVALID) 3026c42a7b7eSSam Leffler goto rx_accept; 3027c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badcrypt++; 30285591b213SSam Leffler } 302965f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_MIC) { 3030c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badmic++; 3031c42a7b7eSSam Leffler /* 3032c42a7b7eSSam Leffler * Do minimal work required to hand off 3033c42a7b7eSSam Leffler * the 802.11 header for notifcation. 3034c42a7b7eSSam Leffler */ 3035c42a7b7eSSam Leffler /* XXX frag's and qos frames */ 303665f9edeeSSam Leffler len = rs->rs_datalen; 3037c42a7b7eSSam Leffler if (len >= sizeof (struct ieee80211_frame)) { 3038c42a7b7eSSam Leffler bus_dmamap_sync(sc->sc_dmat, 3039c42a7b7eSSam Leffler bf->bf_dmamap, 3040c42a7b7eSSam Leffler BUS_DMASYNC_POSTREAD); 3041c42a7b7eSSam Leffler ieee80211_notify_michael_failure(ic, 3042c42a7b7eSSam Leffler mtod(m, struct ieee80211_frame *), 30430ab4040aSSam Leffler sc->sc_splitmic ? 304465f9edeeSSam Leffler rs->rs_keyix-32 : rs->rs_keyix 30450ab4040aSSam Leffler ); 3046c42a7b7eSSam Leffler } 3047c42a7b7eSSam Leffler } 3048c42a7b7eSSam Leffler ifp->if_ierrors++; 3049c42a7b7eSSam Leffler /* 30507b0c77ecSSam Leffler * When a tap is present pass error frames 30517b0c77ecSSam Leffler * that have been requested. By default we 30527b0c77ecSSam Leffler * pass decrypt+mic errors but others may be 30537b0c77ecSSam Leffler * interesting (e.g. crc). 3054c42a7b7eSSam Leffler */ 305516d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf) && 305665f9edeeSSam Leffler (rs->rs_status & sc->sc_monpass)) { 30577b0c77ecSSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 30587b0c77ecSSam Leffler BUS_DMASYNC_POSTREAD); 30597b0c77ecSSam Leffler /* NB: bpf needs the mbuf length setup */ 306065f9edeeSSam Leffler len = rs->rs_datalen; 30617b0c77ecSSam Leffler m->m_pkthdr.len = m->m_len = len; 306265f9edeeSSam Leffler (void) ath_rx_tap(sc, m, rs, tsf, nf); 30637b0c77ecSSam Leffler } 30647b0c77ecSSam Leffler /* XXX pass MIC errors up for s/w reclaculation */ 30655591b213SSam Leffler goto rx_next; 30665591b213SSam Leffler } 3067c42a7b7eSSam Leffler rx_accept: 3068c42a7b7eSSam Leffler /* 3069c42a7b7eSSam Leffler * Sync and unmap the frame. At this point we're 3070c42a7b7eSSam Leffler * committed to passing the mbuf somewhere so clear 3071c66c48cbSSam Leffler * bf_m; this means a new mbuf must be allocated 3072c42a7b7eSSam Leffler * when the rx descriptor is setup again to receive 3073c42a7b7eSSam Leffler * another frame. 3074c42a7b7eSSam Leffler */ 30755591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 30765591b213SSam Leffler BUS_DMASYNC_POSTREAD); 30775591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 30785591b213SSam Leffler bf->bf_m = NULL; 3079c42a7b7eSSam Leffler 30805591b213SSam Leffler m->m_pkthdr.rcvif = ifp; 308165f9edeeSSam Leffler len = rs->rs_datalen; 30825591b213SSam Leffler m->m_pkthdr.len = m->m_len = len; 308373454c73SSam Leffler 308465f9edeeSSam Leffler sc->sc_stats.ast_ant_rx[rs->rs_antenna]++; 3085c42a7b7eSSam Leffler 308616d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf) && 308765f9edeeSSam Leffler !ath_rx_tap(sc, m, rs, tsf, nf)) { 30887b0c77ecSSam Leffler m_freem(m); /* XXX reclaim */ 3089c42a7b7eSSam Leffler goto rx_next; 3090c42a7b7eSSam Leffler } 30910a915fadSSam Leffler 30925591b213SSam Leffler /* 3093c42a7b7eSSam Leffler * From this point on we assume the frame is at least 3094c42a7b7eSSam Leffler * as large as ieee80211_frame_min; verify that. 30955591b213SSam Leffler */ 3096c42a7b7eSSam Leffler if (len < IEEE80211_MIN_LEN) { 3097c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, "%s: short packet %d\n", 3098c42a7b7eSSam Leffler __func__, len); 3099c42a7b7eSSam Leffler sc->sc_stats.ast_rx_tooshort++; 3100c42a7b7eSSam Leffler m_freem(m); 3101c42a7b7eSSam Leffler goto rx_next; 31025591b213SSam Leffler } 31030a915fadSSam Leffler 3104c42a7b7eSSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) { 3105c42a7b7eSSam Leffler ieee80211_dump_pkt(mtod(m, caddr_t), len, 310665f9edeeSSam Leffler sc->sc_hwmap[rs->rs_rate].ieeerate, 310765f9edeeSSam Leffler rs->rs_rssi); 3108c42a7b7eSSam Leffler } 3109c42a7b7eSSam Leffler 3110c42a7b7eSSam Leffler m_adj(m, -IEEE80211_CRC_LEN); 3111de5af704SSam Leffler 3112de5af704SSam Leffler /* 3113c42a7b7eSSam Leffler * Locate the node for sender, track state, and then 3114c42a7b7eSSam Leffler * pass the (referenced) node up to the 802.11 layer 3115c42a7b7eSSam Leffler * for its use. 3116c42a7b7eSSam Leffler */ 3117c1225b52SSam Leffler ni = ieee80211_find_rxnode_withkey(ic, 3118c1225b52SSam Leffler mtod(m, const struct ieee80211_frame_min *), 311965f9edeeSSam Leffler rs->rs_keyix == HAL_RXKEYIX_INVALID ? 312065f9edeeSSam Leffler IEEE80211_KEYIX_NONE : rs->rs_keyix); 3121c42a7b7eSSam Leffler /* 3122c42a7b7eSSam Leffler * Track rx rssi and do any rx antenna management. 3123de5af704SSam Leffler */ 3124de5af704SSam Leffler an = ATH_NODE(ni); 312565f9edeeSSam Leffler ATH_RSSI_LPF(an->an_avgrssi, rs->rs_rssi); 312665f9edeeSSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi); 3127e8fd88a3SSam Leffler /* 3128e8fd88a3SSam Leffler * Send frame up for processing. 3129e8fd88a3SSam Leffler */ 313065f9edeeSSam Leffler type = ieee80211_input(ic, m, ni, rs->rs_rssi, rs->rs_tstamp); 3131e8fd88a3SSam Leffler ieee80211_free_node(ni); 3132c42a7b7eSSam Leffler if (sc->sc_diversity) { 3133c42a7b7eSSam Leffler /* 3134c42a7b7eSSam Leffler * When using fast diversity, change the default rx 3135c42a7b7eSSam Leffler * antenna if diversity chooses the other antenna 3 3136c42a7b7eSSam Leffler * times in a row. 3137c42a7b7eSSam Leffler */ 313865f9edeeSSam Leffler if (sc->sc_defant != rs->rs_antenna) { 3139c42a7b7eSSam Leffler if (++sc->sc_rxotherant >= 3) 314065f9edeeSSam Leffler ath_setdefantenna(sc, rs->rs_antenna); 3141c42a7b7eSSam Leffler } else 3142c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 3143c42a7b7eSSam Leffler } 31443e50ec2cSSam Leffler if (sc->sc_softled) { 31453e50ec2cSSam Leffler /* 31463e50ec2cSSam Leffler * Blink for any data frame. Otherwise do a 31473e50ec2cSSam Leffler * heartbeat-style blink when idle. The latter 31483e50ec2cSSam Leffler * is mainly for station mode where we depend on 31493e50ec2cSSam Leffler * periodic beacon frames to trigger the poll event. 31503e50ec2cSSam Leffler */ 315131640eb7SSam Leffler if (type == IEEE80211_FC0_TYPE_DATA) { 315265f9edeeSSam Leffler sc->sc_rxrate = rs->rs_rate; 31533e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_RX); 31543e50ec2cSSam Leffler } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) 31553e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_POLL); 31563e50ec2cSSam Leffler } 3157d7736e13SSam Leffler /* 3158d7736e13SSam Leffler * Arrange to update the last rx timestamp only for 3159d7736e13SSam Leffler * frames from our ap when operating in station mode. 3160d7736e13SSam Leffler * This assumes the rx key is always setup when associated. 3161d7736e13SSam Leffler */ 3162d7736e13SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA && 316365f9edeeSSam Leffler rs->rs_keyix != HAL_RXKEYIX_INVALID) 3164d7736e13SSam Leffler ngood++; 31655591b213SSam Leffler rx_next: 3166c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 31675591b213SSam Leffler } while (ath_rxbuf_init(sc, bf) == 0); 31685591b213SSam Leffler 3169c42a7b7eSSam Leffler /* rx signal state monitoring */ 3170bd5a9920SSam Leffler ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan); 3171d7736e13SSam Leffler if (ngood) 3172d7736e13SSam Leffler sc->sc_lastrx = tsf; 3173b5f4adb3SSam Leffler 3174cd196bb2SSam Leffler /* NB: may want to check mgtq too */ 3175cd196bb2SSam Leffler if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && 3176cd196bb2SSam Leffler !IFQ_IS_EMPTY(&ifp->if_snd)) 3177cd196bb2SSam Leffler ath_start(ifp); 3178cd196bb2SSam Leffler 3179b5f4adb3SSam Leffler NET_UNLOCK_GIANT(); /* XXX */ 31808cec0ab9SSam Leffler #undef PA2DESC 31815591b213SSam Leffler } 31825591b213SSam Leffler 3183622b3fd2SSam Leffler static void 3184622b3fd2SSam Leffler ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum) 3185622b3fd2SSam Leffler { 3186622b3fd2SSam Leffler txq->axq_qnum = qnum; 3187622b3fd2SSam Leffler txq->axq_depth = 0; 3188622b3fd2SSam Leffler txq->axq_intrcnt = 0; 3189622b3fd2SSam Leffler txq->axq_link = NULL; 3190622b3fd2SSam Leffler STAILQ_INIT(&txq->axq_q); 3191622b3fd2SSam Leffler ATH_TXQ_LOCK_INIT(sc, txq); 3192622b3fd2SSam Leffler } 3193622b3fd2SSam Leffler 31945591b213SSam Leffler /* 3195c42a7b7eSSam Leffler * Setup a h/w transmit queue. 31965591b213SSam Leffler */ 3197c42a7b7eSSam Leffler static struct ath_txq * 3198c42a7b7eSSam Leffler ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) 3199c42a7b7eSSam Leffler { 3200c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3201c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3202c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3203c42a7b7eSSam Leffler int qnum; 3204c42a7b7eSSam Leffler 3205c42a7b7eSSam Leffler memset(&qi, 0, sizeof(qi)); 3206c42a7b7eSSam Leffler qi.tqi_subtype = subtype; 3207c42a7b7eSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 3208c42a7b7eSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 3209c42a7b7eSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 3210c42a7b7eSSam Leffler /* 3211c42a7b7eSSam Leffler * Enable interrupts only for EOL and DESC conditions. 3212c42a7b7eSSam Leffler * We mark tx descriptors to receive a DESC interrupt 3213c42a7b7eSSam Leffler * when a tx queue gets deep; otherwise waiting for the 3214c42a7b7eSSam Leffler * EOL to reap descriptors. Note that this is done to 3215c42a7b7eSSam Leffler * reduce interrupt load and this only defers reaping 3216c42a7b7eSSam Leffler * descriptors, never transmitting frames. Aside from 3217c42a7b7eSSam Leffler * reducing interrupts this also permits more concurrency. 3218c42a7b7eSSam Leffler * The only potential downside is if the tx queue backs 3219c42a7b7eSSam Leffler * up in which case the top half of the kernel may backup 3220c42a7b7eSSam Leffler * due to a lack of tx descriptors. 3221c42a7b7eSSam Leffler */ 3222bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; 3223c42a7b7eSSam Leffler qnum = ath_hal_setuptxqueue(ah, qtype, &qi); 3224c42a7b7eSSam Leffler if (qnum == -1) { 3225c42a7b7eSSam Leffler /* 3226c42a7b7eSSam Leffler * NB: don't print a message, this happens 3227a614e076SSam Leffler * normally on parts with too few tx queues 3228c42a7b7eSSam Leffler */ 3229c42a7b7eSSam Leffler return NULL; 3230c42a7b7eSSam Leffler } 3231c42a7b7eSSam Leffler if (qnum >= N(sc->sc_txq)) { 32326891c875SPeter Wemm device_printf(sc->sc_dev, 32336891c875SPeter Wemm "hal qnum %u out of range, max %zu!\n", 3234c42a7b7eSSam Leffler qnum, N(sc->sc_txq)); 3235c42a7b7eSSam Leffler ath_hal_releasetxqueue(ah, qnum); 3236c42a7b7eSSam Leffler return NULL; 3237c42a7b7eSSam Leffler } 3238c42a7b7eSSam Leffler if (!ATH_TXQ_SETUP(sc, qnum)) { 3239622b3fd2SSam Leffler ath_txq_init(sc, &sc->sc_txq[qnum], qnum); 3240c42a7b7eSSam Leffler sc->sc_txqsetup |= 1<<qnum; 3241c42a7b7eSSam Leffler } 3242c42a7b7eSSam Leffler return &sc->sc_txq[qnum]; 3243c42a7b7eSSam Leffler #undef N 3244c42a7b7eSSam Leffler } 3245c42a7b7eSSam Leffler 3246c42a7b7eSSam Leffler /* 3247c42a7b7eSSam Leffler * Setup a hardware data transmit queue for the specified 3248c42a7b7eSSam Leffler * access control. The hal may not support all requested 3249c42a7b7eSSam Leffler * queues in which case it will return a reference to a 3250c42a7b7eSSam Leffler * previously setup queue. We record the mapping from ac's 3251c42a7b7eSSam Leffler * to h/w queues for use by ath_tx_start and also track 3252c42a7b7eSSam Leffler * the set of h/w queues being used to optimize work in the 3253c42a7b7eSSam Leffler * transmit interrupt handler and related routines. 3254c42a7b7eSSam Leffler */ 3255c42a7b7eSSam Leffler static int 3256c42a7b7eSSam Leffler ath_tx_setup(struct ath_softc *sc, int ac, int haltype) 3257c42a7b7eSSam Leffler { 3258c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3259c42a7b7eSSam Leffler struct ath_txq *txq; 3260c42a7b7eSSam Leffler 3261c42a7b7eSSam Leffler if (ac >= N(sc->sc_ac2q)) { 32626891c875SPeter Wemm device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n", 3263c42a7b7eSSam Leffler ac, N(sc->sc_ac2q)); 3264c42a7b7eSSam Leffler return 0; 3265c42a7b7eSSam Leffler } 3266c42a7b7eSSam Leffler txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype); 3267c42a7b7eSSam Leffler if (txq != NULL) { 3268c42a7b7eSSam Leffler sc->sc_ac2q[ac] = txq; 3269c42a7b7eSSam Leffler return 1; 3270c42a7b7eSSam Leffler } else 3271c42a7b7eSSam Leffler return 0; 3272c42a7b7eSSam Leffler #undef N 3273c42a7b7eSSam Leffler } 3274c42a7b7eSSam Leffler 3275c42a7b7eSSam Leffler /* 3276c42a7b7eSSam Leffler * Update WME parameters for a transmit queue. 3277c42a7b7eSSam Leffler */ 3278c42a7b7eSSam Leffler static int 3279c42a7b7eSSam Leffler ath_txq_update(struct ath_softc *sc, int ac) 3280c42a7b7eSSam Leffler { 3281c42a7b7eSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1) 3282c42a7b7eSSam Leffler #define ATH_TXOP_TO_US(v) (v<<5) 3283c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 3284c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[ac]; 3285c42a7b7eSSam Leffler struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; 3286c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3287c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3288c42a7b7eSSam Leffler 3289c42a7b7eSSam Leffler ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi); 3290c42a7b7eSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 3291c42a7b7eSSam Leffler qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 3292c42a7b7eSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 3293c42a7b7eSSam Leffler qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit); 3294c42a7b7eSSam Leffler 3295c42a7b7eSSam Leffler if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) { 3296c42a7b7eSSam Leffler device_printf(sc->sc_dev, "unable to update hardware queue " 3297c42a7b7eSSam Leffler "parameters for %s traffic!\n", 3298c42a7b7eSSam Leffler ieee80211_wme_acnames[ac]); 3299c42a7b7eSSam Leffler return 0; 3300c42a7b7eSSam Leffler } else { 3301c42a7b7eSSam Leffler ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */ 3302c42a7b7eSSam Leffler return 1; 3303c42a7b7eSSam Leffler } 3304c42a7b7eSSam Leffler #undef ATH_TXOP_TO_US 3305c42a7b7eSSam Leffler #undef ATH_EXPONENT_TO_VALUE 3306c42a7b7eSSam Leffler } 3307c42a7b7eSSam Leffler 3308c42a7b7eSSam Leffler /* 3309c42a7b7eSSam Leffler * Callback from the 802.11 layer to update WME parameters. 3310c42a7b7eSSam Leffler */ 3311c42a7b7eSSam Leffler static int 3312c42a7b7eSSam Leffler ath_wme_update(struct ieee80211com *ic) 3313c42a7b7eSSam Leffler { 3314c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 3315c42a7b7eSSam Leffler 3316c42a7b7eSSam Leffler return !ath_txq_update(sc, WME_AC_BE) || 3317c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_BK) || 3318c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VI) || 3319c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VO) ? EIO : 0; 3320c42a7b7eSSam Leffler } 3321c42a7b7eSSam Leffler 3322c42a7b7eSSam Leffler /* 3323c42a7b7eSSam Leffler * Reclaim resources for a setup queue. 3324c42a7b7eSSam Leffler */ 3325c42a7b7eSSam Leffler static void 3326c42a7b7eSSam Leffler ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) 3327c42a7b7eSSam Leffler { 3328c42a7b7eSSam Leffler 3329c42a7b7eSSam Leffler ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum); 3330c42a7b7eSSam Leffler ATH_TXQ_LOCK_DESTROY(txq); 3331c42a7b7eSSam Leffler sc->sc_txqsetup &= ~(1<<txq->axq_qnum); 3332c42a7b7eSSam Leffler } 3333c42a7b7eSSam Leffler 3334c42a7b7eSSam Leffler /* 3335c42a7b7eSSam Leffler * Reclaim all tx queue resources. 3336c42a7b7eSSam Leffler */ 3337c42a7b7eSSam Leffler static void 3338c42a7b7eSSam Leffler ath_tx_cleanup(struct ath_softc *sc) 3339c42a7b7eSSam Leffler { 3340c42a7b7eSSam Leffler int i; 3341c42a7b7eSSam Leffler 3342c42a7b7eSSam Leffler ATH_TXBUF_LOCK_DESTROY(sc); 3343c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 3344c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 3345c42a7b7eSSam Leffler ath_tx_cleanupq(sc, &sc->sc_txq[i]); 3346622b3fd2SSam Leffler ATH_TXQ_LOCK_DESTROY(&sc->sc_mcastq); 3347c42a7b7eSSam Leffler } 33485591b213SSam Leffler 334999d258fdSSam Leffler /* 335099d258fdSSam Leffler * Defragment an mbuf chain, returning at most maxfrags separate 335199d258fdSSam Leffler * mbufs+clusters. If this is not possible NULL is returned and 3352a7073e8bSSam Leffler * the original mbuf chain is left in it's present (potentially 3353a7073e8bSSam Leffler * modified) state. We use two techniques: collapsing consecutive 3354a7073e8bSSam Leffler * mbufs and replacing consecutive mbufs by a cluster. 335599d258fdSSam Leffler */ 335699d258fdSSam Leffler static struct mbuf * 335799d258fdSSam Leffler ath_defrag(struct mbuf *m0, int how, int maxfrags) 335899d258fdSSam Leffler { 335999d258fdSSam Leffler struct mbuf *m, *n, *n2, **prev; 336099d258fdSSam Leffler u_int curfrags; 336199d258fdSSam Leffler 336299d258fdSSam Leffler /* 336399d258fdSSam Leffler * Calculate the current number of frags. 336499d258fdSSam Leffler */ 336599d258fdSSam Leffler curfrags = 0; 336699d258fdSSam Leffler for (m = m0; m != NULL; m = m->m_next) 336799d258fdSSam Leffler curfrags++; 336899d258fdSSam Leffler /* 336999d258fdSSam Leffler * First, try to collapse mbufs. Note that we always collapse 337099d258fdSSam Leffler * towards the front so we don't need to deal with moving the 337199d258fdSSam Leffler * pkthdr. This may be suboptimal if the first mbuf has much 337299d258fdSSam Leffler * less data than the following. 337399d258fdSSam Leffler */ 337499d258fdSSam Leffler m = m0; 337599d258fdSSam Leffler again: 337699d258fdSSam Leffler for (;;) { 337799d258fdSSam Leffler n = m->m_next; 337899d258fdSSam Leffler if (n == NULL) 337999d258fdSSam Leffler break; 3380019b9669SSam Leffler if ((m->m_flags & M_RDONLY) == 0 && 3381019b9669SSam Leffler n->m_len < M_TRAILINGSPACE(m)) { 338299d258fdSSam Leffler bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, 338399d258fdSSam Leffler n->m_len); 338499d258fdSSam Leffler m->m_len += n->m_len; 338599d258fdSSam Leffler m->m_next = n->m_next; 338699d258fdSSam Leffler m_free(n); 338799d258fdSSam Leffler if (--curfrags <= maxfrags) 338899d258fdSSam Leffler return m0; 338999d258fdSSam Leffler } else 339099d258fdSSam Leffler m = n; 339199d258fdSSam Leffler } 339299d258fdSSam Leffler KASSERT(maxfrags > 1, 339399d258fdSSam Leffler ("maxfrags %u, but normal collapse failed", maxfrags)); 339499d258fdSSam Leffler /* 339599d258fdSSam Leffler * Collapse consecutive mbufs to a cluster. 339699d258fdSSam Leffler */ 339799d258fdSSam Leffler prev = &m0->m_next; /* NB: not the first mbuf */ 339899d258fdSSam Leffler while ((n = *prev) != NULL) { 339999d258fdSSam Leffler if ((n2 = n->m_next) != NULL && 340099d258fdSSam Leffler n->m_len + n2->m_len < MCLBYTES) { 340199d258fdSSam Leffler m = m_getcl(how, MT_DATA, 0); 340299d258fdSSam Leffler if (m == NULL) 340399d258fdSSam Leffler goto bad; 340499d258fdSSam Leffler bcopy(mtod(n, void *), mtod(m, void *), n->m_len); 340599d258fdSSam Leffler bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, 340699d258fdSSam Leffler n2->m_len); 340799d258fdSSam Leffler m->m_len = n->m_len + n2->m_len; 340899d258fdSSam Leffler m->m_next = n2->m_next; 340999d258fdSSam Leffler *prev = m; 341099d258fdSSam Leffler m_free(n); 341199d258fdSSam Leffler m_free(n2); 341299d258fdSSam Leffler if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ 341399d258fdSSam Leffler return m0; 341499d258fdSSam Leffler /* 341599d258fdSSam Leffler * Still not there, try the normal collapse 341699d258fdSSam Leffler * again before we allocate another cluster. 341799d258fdSSam Leffler */ 341899d258fdSSam Leffler goto again; 341999d258fdSSam Leffler } 342099d258fdSSam Leffler prev = &n->m_next; 342199d258fdSSam Leffler } 342299d258fdSSam Leffler /* 342399d258fdSSam Leffler * No place where we can collapse to a cluster; punt. 342499d258fdSSam Leffler * This can occur if, for example, you request 2 frags 342599d258fdSSam Leffler * but the packet requires that both be clusters (we 342699d258fdSSam Leffler * never reallocate the first mbuf to avoid moving the 342799d258fdSSam Leffler * packet header). 342899d258fdSSam Leffler */ 342999d258fdSSam Leffler bad: 343099d258fdSSam Leffler return NULL; 343199d258fdSSam Leffler } 343299d258fdSSam Leffler 34338b5341deSSam Leffler /* 34348b5341deSSam Leffler * Return h/w rate index for an IEEE rate (w/o basic rate bit). 34358b5341deSSam Leffler */ 34368b5341deSSam Leffler static int 34378b5341deSSam Leffler ath_tx_findrix(const HAL_RATE_TABLE *rt, int rate) 34388b5341deSSam Leffler { 34398b5341deSSam Leffler int i; 34408b5341deSSam Leffler 34418b5341deSSam Leffler for (i = 0; i < rt->rateCount; i++) 34428b5341deSSam Leffler if ((rt->info[i].dot11Rate & IEEE80211_RATE_VAL) == rate) 34438b5341deSSam Leffler return i; 34448b5341deSSam Leffler return 0; /* NB: lowest rate */ 34458b5341deSSam Leffler } 34468b5341deSSam Leffler 34475591b213SSam Leffler static int 3448664443d0SSam Leffler ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0) 3449664443d0SSam Leffler { 3450664443d0SSam Leffler struct mbuf *m; 3451664443d0SSam Leffler int error; 3452664443d0SSam Leffler 3453664443d0SSam Leffler /* 3454664443d0SSam Leffler * Load the DMA map so any coalescing is done. This 3455664443d0SSam Leffler * also calculates the number of descriptors we need. 3456664443d0SSam Leffler */ 3457664443d0SSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 3458664443d0SSam Leffler bf->bf_segs, &bf->bf_nseg, 3459664443d0SSam Leffler BUS_DMA_NOWAIT); 3460664443d0SSam Leffler if (error == EFBIG) { 3461664443d0SSam Leffler /* XXX packet requires too many descriptors */ 3462664443d0SSam Leffler bf->bf_nseg = ATH_TXDESC+1; 3463664443d0SSam Leffler } else if (error != 0) { 3464664443d0SSam Leffler sc->sc_stats.ast_tx_busdma++; 3465664443d0SSam Leffler m_freem(m0); 3466664443d0SSam Leffler return error; 3467664443d0SSam Leffler } 3468664443d0SSam Leffler /* 3469664443d0SSam Leffler * Discard null packets and check for packets that 3470664443d0SSam Leffler * require too many TX descriptors. We try to convert 3471664443d0SSam Leffler * the latter to a cluster. 3472664443d0SSam Leffler */ 3473664443d0SSam Leffler if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */ 3474664443d0SSam Leffler sc->sc_stats.ast_tx_linear++; 3475664443d0SSam Leffler m = ath_defrag(m0, M_DONTWAIT, ATH_TXDESC); 3476664443d0SSam Leffler if (m == NULL) { 3477664443d0SSam Leffler m_freem(m0); 3478664443d0SSam Leffler sc->sc_stats.ast_tx_nombuf++; 3479664443d0SSam Leffler return ENOMEM; 3480664443d0SSam Leffler } 3481664443d0SSam Leffler m0 = m; 3482664443d0SSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 3483664443d0SSam Leffler bf->bf_segs, &bf->bf_nseg, 3484664443d0SSam Leffler BUS_DMA_NOWAIT); 3485664443d0SSam Leffler if (error != 0) { 3486664443d0SSam Leffler sc->sc_stats.ast_tx_busdma++; 3487664443d0SSam Leffler m_freem(m0); 3488664443d0SSam Leffler return error; 3489664443d0SSam Leffler } 3490664443d0SSam Leffler KASSERT(bf->bf_nseg <= ATH_TXDESC, 3491664443d0SSam Leffler ("too many segments after defrag; nseg %u", bf->bf_nseg)); 3492664443d0SSam Leffler } else if (bf->bf_nseg == 0) { /* null packet, discard */ 3493664443d0SSam Leffler sc->sc_stats.ast_tx_nodata++; 3494664443d0SSam Leffler m_freem(m0); 3495664443d0SSam Leffler return EIO; 3496664443d0SSam Leffler } 3497664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n", 3498664443d0SSam Leffler __func__, m0, m0->m_pkthdr.len); 3499664443d0SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 3500664443d0SSam Leffler bf->bf_m = m0; 3501664443d0SSam Leffler 3502664443d0SSam Leffler return 0; 3503664443d0SSam Leffler } 3504664443d0SSam Leffler 3505664443d0SSam Leffler static void 3506664443d0SSam Leffler ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) 3507664443d0SSam Leffler { 3508664443d0SSam Leffler struct ath_hal *ah = sc->sc_ah; 3509664443d0SSam Leffler struct ath_desc *ds, *ds0; 3510664443d0SSam Leffler int i; 3511664443d0SSam Leffler 3512664443d0SSam Leffler /* 3513664443d0SSam Leffler * Fillin the remainder of the descriptor info. 3514664443d0SSam Leffler */ 3515664443d0SSam Leffler ds0 = ds = bf->bf_desc; 3516664443d0SSam Leffler for (i = 0; i < bf->bf_nseg; i++, ds++) { 3517664443d0SSam Leffler ds->ds_data = bf->bf_segs[i].ds_addr; 3518664443d0SSam Leffler if (i == bf->bf_nseg - 1) 3519664443d0SSam Leffler ds->ds_link = 0; 3520664443d0SSam Leffler else 3521664443d0SSam Leffler ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1); 3522664443d0SSam Leffler ath_hal_filltxdesc(ah, ds 3523664443d0SSam Leffler , bf->bf_segs[i].ds_len /* segment length */ 3524664443d0SSam Leffler , i == 0 /* first segment */ 3525664443d0SSam Leffler , i == bf->bf_nseg - 1 /* last segment */ 3526664443d0SSam Leffler , ds0 /* first descriptor */ 3527664443d0SSam Leffler ); 3528664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3529664443d0SSam Leffler "%s: %d: %08x %08x %08x %08x %08x %08x\n", 3530664443d0SSam Leffler __func__, i, ds->ds_link, ds->ds_data, 3531664443d0SSam Leffler ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]); 3532664443d0SSam Leffler } 3533664443d0SSam Leffler /* 3534664443d0SSam Leffler * Insert the frame on the outbound list and pass it on 3535664443d0SSam Leffler * to the hardware. Multicast frames buffered for power 3536664443d0SSam Leffler * save stations and transmit from the CAB queue are stored 3537664443d0SSam Leffler * on a s/w only queue and loaded on to the CAB queue in 3538664443d0SSam Leffler * the SWBA handler since frames only go out on DTIM and 3539664443d0SSam Leffler * to avoid possible races. 3540664443d0SSam Leffler */ 3541664443d0SSam Leffler ATH_TXQ_LOCK(txq); 3542664443d0SSam Leffler ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 3543664443d0SSam Leffler if (txq != &sc->sc_mcastq) { 3544664443d0SSam Leffler if (txq->axq_link == NULL) { 3545664443d0SSam Leffler ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 3546664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3547664443d0SSam Leffler "%s: TXDP[%u] = %p (%p) depth %d\n", __func__, 3548664443d0SSam Leffler txq->axq_qnum, (caddr_t)bf->bf_daddr, bf->bf_desc, 3549664443d0SSam Leffler txq->axq_depth); 3550664443d0SSam Leffler } else { 3551664443d0SSam Leffler *txq->axq_link = bf->bf_daddr; 3552664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3553664443d0SSam Leffler "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, 3554664443d0SSam Leffler txq->axq_qnum, txq->axq_link, 3555664443d0SSam Leffler (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); 3556664443d0SSam Leffler } 3557664443d0SSam Leffler txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 3558664443d0SSam Leffler ath_hal_txstart(ah, txq->axq_qnum); 3559664443d0SSam Leffler } else { 3560664443d0SSam Leffler if (txq->axq_link != NULL) 3561664443d0SSam Leffler *txq->axq_link = bf->bf_daddr; 3562664443d0SSam Leffler txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 3563664443d0SSam Leffler } 3564664443d0SSam Leffler ATH_TXQ_UNLOCK(txq); 3565664443d0SSam Leffler } 3566664443d0SSam Leffler 3567664443d0SSam Leffler static int 35685591b213SSam Leffler ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, 35695591b213SSam Leffler struct mbuf *m0) 35705591b213SSam Leffler { 35715591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 35725591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 3573fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 3574c4c3cb46SSam Leffler const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; 3575664443d0SSam Leffler int error, iswep, ismcast, ismrr; 3576be613480SSam Leffler int keyix, hdrlen, pktlen, try0; 3577c42a7b7eSSam Leffler u_int8_t rix, txrate, ctsrate; 3578c42a7b7eSSam Leffler u_int8_t cix = 0xff; /* NB: silence compiler */ 3579664443d0SSam Leffler struct ath_desc *ds; 3580c42a7b7eSSam Leffler struct ath_txq *txq; 35815591b213SSam Leffler struct ieee80211_frame *wh; 3582c42a7b7eSSam Leffler u_int subtype, flags, ctsduration; 35835591b213SSam Leffler HAL_PKT_TYPE atype; 35845591b213SSam Leffler const HAL_RATE_TABLE *rt; 35855591b213SSam Leffler HAL_BOOL shortPreamble; 35865591b213SSam Leffler struct ath_node *an; 3587c4c3cb46SSam Leffler u_int pri; 35885591b213SSam Leffler 35895591b213SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 35905591b213SSam Leffler iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; 3591c42a7b7eSSam Leffler ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 3592c42a7b7eSSam Leffler hdrlen = ieee80211_anyhdrsize(wh); 3593c42a7b7eSSam Leffler /* 3594a614e076SSam Leffler * Packet length must not include any 3595a614e076SSam Leffler * pad bytes; deduct them here. 3596c42a7b7eSSam Leffler */ 3597c42a7b7eSSam Leffler pktlen = m0->m_pkthdr.len - (hdrlen & 3); 35985591b213SSam Leffler 35995591b213SSam Leffler if (iswep) { 3600c42a7b7eSSam Leffler const struct ieee80211_cipher *cip; 3601c42a7b7eSSam Leffler struct ieee80211_key *k; 3602c42a7b7eSSam Leffler 3603c42a7b7eSSam Leffler /* 3604c42a7b7eSSam Leffler * Construct the 802.11 header+trailer for an encrypted 3605c42a7b7eSSam Leffler * frame. The only reason this can fail is because of an 3606c42a7b7eSSam Leffler * unknown or unsupported cipher/key type. 3607c42a7b7eSSam Leffler */ 3608c42a7b7eSSam Leffler k = ieee80211_crypto_encap(ic, ni, m0); 3609c42a7b7eSSam Leffler if (k == NULL) { 3610c42a7b7eSSam Leffler /* 3611c42a7b7eSSam Leffler * This can happen when the key is yanked after the 3612c42a7b7eSSam Leffler * frame was queued. Just discard the frame; the 3613c42a7b7eSSam Leffler * 802.11 layer counts failures and provides 3614c42a7b7eSSam Leffler * debugging/diagnostics. 3615c42a7b7eSSam Leffler */ 36160c97ab96SSam Leffler m_freem(m0); 3617c42a7b7eSSam Leffler return EIO; 36185591b213SSam Leffler } 3619c42a7b7eSSam Leffler /* 3620c42a7b7eSSam Leffler * Adjust the packet + header lengths for the crypto 3621c42a7b7eSSam Leffler * additions and calculate the h/w key index. When 3622c42a7b7eSSam Leffler * a s/w mic is done the frame will have had any mic 3623f9748b9dSSam Leffler * added to it prior to entry so m0->m_pkthdr.len above will 3624c42a7b7eSSam Leffler * account for it. Otherwise we need to add it to the 3625c42a7b7eSSam Leffler * packet length. 3626c42a7b7eSSam Leffler */ 3627c42a7b7eSSam Leffler cip = k->wk_cipher; 3628c42a7b7eSSam Leffler hdrlen += cip->ic_header; 3629c42a7b7eSSam Leffler pktlen += cip->ic_header + cip->ic_trailer; 3630c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0) 3631c42a7b7eSSam Leffler pktlen += cip->ic_miclen; 3632c42a7b7eSSam Leffler keyix = k->wk_keyix; 3633c42a7b7eSSam Leffler 3634c42a7b7eSSam Leffler /* packet header may have moved, reset our local pointer */ 3635167ecdcaSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 3636e8fd88a3SSam Leffler } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { 3637e8fd88a3SSam Leffler /* 3638e8fd88a3SSam Leffler * Use station key cache slot, if assigned. 3639e8fd88a3SSam Leffler */ 3640e8fd88a3SSam Leffler keyix = ni->ni_ucastkey.wk_keyix; 3641e8fd88a3SSam Leffler if (keyix == IEEE80211_KEYIX_NONE) 3642e8fd88a3SSam Leffler keyix = HAL_TXKEYIX_INVALID; 3643c42a7b7eSSam Leffler } else 3644c42a7b7eSSam Leffler keyix = HAL_TXKEYIX_INVALID; 3645c42a7b7eSSam Leffler 36465591b213SSam Leffler pktlen += IEEE80211_CRC_LEN; 36475591b213SSam Leffler 36485591b213SSam Leffler /* 36495591b213SSam Leffler * Load the DMA map so any coalescing is done. This 36505591b213SSam Leffler * also calculates the number of descriptors we need. 36515591b213SSam Leffler */ 3652664443d0SSam Leffler error = ath_tx_dmasetup(sc, bf, m0); 365305680ab6SSam Leffler if (error != 0) 365405680ab6SSam Leffler return error; 36550a915fadSSam Leffler bf->bf_node = ni; /* NB: held reference */ 3656664443d0SSam Leffler m0 = bf->bf_m; /* NB: may have changed */ 3657664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 36585591b213SSam Leffler 36595591b213SSam Leffler /* setup descriptors */ 36605591b213SSam Leffler ds = bf->bf_desc; 36615591b213SSam Leffler rt = sc->sc_currates; 36625591b213SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 36635591b213SSam Leffler 36645591b213SSam Leffler /* 3665c42a7b7eSSam Leffler * NB: the 802.11 layer marks whether or not we should 3666c42a7b7eSSam Leffler * use short preamble based on the current mode and 3667c42a7b7eSSam Leffler * negotiated parameters. 36685591b213SSam Leffler */ 3669c42a7b7eSSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 3670c42a7b7eSSam Leffler (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { 3671c42a7b7eSSam Leffler shortPreamble = AH_TRUE; 3672c42a7b7eSSam Leffler sc->sc_stats.ast_tx_shortpre++; 3673c42a7b7eSSam Leffler } else { 3674c42a7b7eSSam Leffler shortPreamble = AH_FALSE; 3675c42a7b7eSSam Leffler } 3676c42a7b7eSSam Leffler 3677c42a7b7eSSam Leffler an = ATH_NODE(ni); 3678c42a7b7eSSam Leffler flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 3679be613480SSam Leffler ismrr = 0; /* default no multi-rate retry*/ 3680c42a7b7eSSam Leffler /* 3681c42a7b7eSSam Leffler * Calculate Atheros packet type from IEEE80211 packet header, 3682c42a7b7eSSam Leffler * setup for rate calculations, and select h/w transmit queue. 3683c42a7b7eSSam Leffler */ 36845591b213SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 36855591b213SSam Leffler case IEEE80211_FC0_TYPE_MGT: 36865591b213SSam Leffler subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 36875591b213SSam Leffler if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) 36885591b213SSam Leffler atype = HAL_PKT_TYPE_BEACON; 36895591b213SSam Leffler else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 36905591b213SSam Leffler atype = HAL_PKT_TYPE_PROBE_RESP; 36915591b213SSam Leffler else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) 36925591b213SSam Leffler atype = HAL_PKT_TYPE_ATIM; 3693c42a7b7eSSam Leffler else 3694c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_NORMAL; /* XXX */ 369555f63772SSam Leffler rix = sc->sc_minrateix; 369655f63772SSam Leffler txrate = rt->info[rix].rateCode; 3697c42a7b7eSSam Leffler if (shortPreamble) 369855f63772SSam Leffler txrate |= rt->info[rix].shortPreamble; 3699be613480SSam Leffler try0 = ATH_TXMGTTRY; 3700c42a7b7eSSam Leffler /* NB: force all management frames to highest queue */ 3701c42a7b7eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 3702c42a7b7eSSam Leffler /* NB: force all management frames to highest queue */ 3703c4c3cb46SSam Leffler pri = WME_AC_VO; 3704c42a7b7eSSam Leffler } else 3705c4c3cb46SSam Leffler pri = WME_AC_BE; 3706c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 37075591b213SSam Leffler break; 37085591b213SSam Leffler case IEEE80211_FC0_TYPE_CTL: 3709c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ 371055f63772SSam Leffler rix = sc->sc_minrateix; 371155f63772SSam Leffler txrate = rt->info[rix].rateCode; 3712c42a7b7eSSam Leffler if (shortPreamble) 371355f63772SSam Leffler txrate |= rt->info[rix].shortPreamble; 3714be613480SSam Leffler try0 = ATH_TXMGTTRY; 3715c42a7b7eSSam Leffler /* NB: force all ctl frames to highest queue */ 3716c42a7b7eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 3717c42a7b7eSSam Leffler /* NB: force all ctl frames to highest queue */ 3718c4c3cb46SSam Leffler pri = WME_AC_VO; 3719c42a7b7eSSam Leffler } else 3720c4c3cb46SSam Leffler pri = WME_AC_BE; 3721c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 3722c42a7b7eSSam Leffler break; 3723c42a7b7eSSam Leffler case IEEE80211_FC0_TYPE_DATA: 3724c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_NORMAL; /* default */ 3725c42a7b7eSSam Leffler /* 37268b5341deSSam Leffler * Data frames: multicast frames go out at a fixed rate, 37278b5341deSSam Leffler * otherwise consult the rate control module for the 37288b5341deSSam Leffler * rate to use. 3729c42a7b7eSSam Leffler */ 37308b5341deSSam Leffler if (ismcast) { 37318b5341deSSam Leffler /* 37328b5341deSSam Leffler * Check mcast rate setting in case it's changed. 37338b5341deSSam Leffler * XXX move out of fastpath 37348b5341deSSam Leffler */ 37358b5341deSSam Leffler if (ic->ic_mcast_rate != sc->sc_mcastrate) { 37368b5341deSSam Leffler sc->sc_mcastrix = 37378b5341deSSam Leffler ath_tx_findrix(rt, ic->ic_mcast_rate); 37388b5341deSSam Leffler sc->sc_mcastrate = ic->ic_mcast_rate; 37398b5341deSSam Leffler } 37408b5341deSSam Leffler rix = sc->sc_mcastrix; 37418b5341deSSam Leffler txrate = rt->info[rix].rateCode; 37428b5341deSSam Leffler if (shortPreamble) 37438b5341deSSam Leffler txrate |= rt->info[rix].shortPreamble; 37448b5341deSSam Leffler try0 = 1; 37458b5341deSSam Leffler } else { 3746c42a7b7eSSam Leffler ath_rate_findrate(sc, an, shortPreamble, pktlen, 3747c42a7b7eSSam Leffler &rix, &try0, &txrate); 37483e50ec2cSSam Leffler sc->sc_txrate = txrate; /* for LED blinking */ 3749be613480SSam Leffler if (try0 != ATH_TXMAXTRY) 3750be613480SSam Leffler ismrr = 1; 37518b5341deSSam Leffler } 3752c4c3cb46SSam Leffler pri = M_WME_GETAC(m0); 3753f9748b9dSSam Leffler if (cap->cap_wmeParams[pri].wmep_noackPolicy) 3754c42a7b7eSSam Leffler flags |= HAL_TXDESC_NOACK; 37555591b213SSam Leffler break; 37565591b213SSam Leffler default: 3757c42a7b7eSSam Leffler if_printf(ifp, "bogus frame type 0x%x (%s)\n", 3758c42a7b7eSSam Leffler wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); 3759c42a7b7eSSam Leffler /* XXX statistic */ 37605591b213SSam Leffler m_freem(m0); 37615591b213SSam Leffler return EIO; 37625591b213SSam Leffler } 3763c4c3cb46SSam Leffler txq = sc->sc_ac2q[pri]; 3764c42a7b7eSSam Leffler 37655591b213SSam Leffler /* 3766c42a7b7eSSam Leffler * When servicing one or more stations in power-save mode 3767622b3fd2SSam Leffler * (or) if there is some mcast data waiting on the mcast 3768622b3fd2SSam Leffler * queue (to prevent out of order delivery) multicast 3769622b3fd2SSam Leffler * frames must be buffered until after the beacon. 37705591b213SSam Leffler */ 3771622b3fd2SSam Leffler if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth)) { 3772622b3fd2SSam Leffler txq = &sc->sc_mcastq; 3773c42a7b7eSSam Leffler /* XXX? more bit in 802.11 frame header */ 37745591b213SSam Leffler } 37755591b213SSam Leffler 37765591b213SSam Leffler /* 37775591b213SSam Leffler * Calculate miscellaneous flags. 37785591b213SSam Leffler */ 3779c42a7b7eSSam Leffler if (ismcast) { 37805591b213SSam Leffler flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ 37815591b213SSam Leffler } else if (pktlen > ic->ic_rtsthreshold) { 37825591b213SSam Leffler flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */ 3783c42a7b7eSSam Leffler cix = rt->info[rix].controlRate; 37845591b213SSam Leffler sc->sc_stats.ast_tx_rts++; 37855591b213SSam Leffler } 3786f9748b9dSSam Leffler if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */ 3787f9748b9dSSam Leffler sc->sc_stats.ast_tx_noack++; 37885591b213SSam Leffler 37895591b213SSam Leffler /* 3790c42a7b7eSSam Leffler * If 802.11g protection is enabled, determine whether 3791c42a7b7eSSam Leffler * to use RTS/CTS or just CTS. Note that this is only 3792c42a7b7eSSam Leffler * done for OFDM unicast frames. 3793c42a7b7eSSam Leffler */ 3794c42a7b7eSSam Leffler if ((ic->ic_flags & IEEE80211_F_USEPROT) && 3795c42a7b7eSSam Leffler rt->info[rix].phy == IEEE80211_T_OFDM && 3796c42a7b7eSSam Leffler (flags & HAL_TXDESC_NOACK) == 0) { 3797c42a7b7eSSam Leffler /* XXX fragments must use CCK rates w/ protection */ 3798c42a7b7eSSam Leffler if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 3799c42a7b7eSSam Leffler flags |= HAL_TXDESC_RTSENA; 3800c42a7b7eSSam Leffler else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 3801c42a7b7eSSam Leffler flags |= HAL_TXDESC_CTSENA; 3802c42a7b7eSSam Leffler cix = rt->info[sc->sc_protrix].controlRate; 3803c42a7b7eSSam Leffler sc->sc_stats.ast_tx_protect++; 3804c42a7b7eSSam Leffler } 3805c42a7b7eSSam Leffler 3806c42a7b7eSSam Leffler /* 3807f6aa038bSSam Leffler * Calculate duration. This logically belongs in the 802.11 3808f6aa038bSSam Leffler * layer but it lacks sufficient information to calculate it. 3809f6aa038bSSam Leffler */ 3810f6aa038bSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0 && 3811f6aa038bSSam Leffler (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) { 3812f6aa038bSSam Leffler u_int16_t dur; 3813f6aa038bSSam Leffler /* 3814f6aa038bSSam Leffler * XXX not right with fragmentation. 3815f6aa038bSSam Leffler */ 3816c42a7b7eSSam Leffler if (shortPreamble) 3817c42a7b7eSSam Leffler dur = rt->info[rix].spAckDuration; 3818c42a7b7eSSam Leffler else 3819c42a7b7eSSam Leffler dur = rt->info[rix].lpAckDuration; 3820c42a7b7eSSam Leffler *(u_int16_t *)wh->i_dur = htole16(dur); 3821f6aa038bSSam Leffler } 3822f6aa038bSSam Leffler 3823f6aa038bSSam Leffler /* 38245591b213SSam Leffler * Calculate RTS/CTS rate and duration if needed. 38255591b213SSam Leffler */ 38265591b213SSam Leffler ctsduration = 0; 38275591b213SSam Leffler if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { 38285591b213SSam Leffler /* 38295591b213SSam Leffler * CTS transmit rate is derived from the transmit rate 38305591b213SSam Leffler * by looking in the h/w rate table. We must also factor 38315591b213SSam Leffler * in whether or not a short preamble is to be used. 38325591b213SSam Leffler */ 3833c42a7b7eSSam Leffler /* NB: cix is set above where RTS/CTS is enabled */ 3834c42a7b7eSSam Leffler KASSERT(cix != 0xff, ("cix not setup")); 38355591b213SSam Leffler ctsrate = rt->info[cix].rateCode; 38365591b213SSam Leffler /* 3837c42a7b7eSSam Leffler * Compute the transmit duration based on the frame 3838c42a7b7eSSam Leffler * size and the size of an ACK frame. We call into the 3839c42a7b7eSSam Leffler * HAL to do the computation since it depends on the 3840c42a7b7eSSam Leffler * characteristics of the actual PHY being used. 3841c42a7b7eSSam Leffler * 3842c42a7b7eSSam Leffler * NB: CTS is assumed the same size as an ACK so we can 3843c42a7b7eSSam Leffler * use the precalculated ACK durations. 38445591b213SSam Leffler */ 3845c42a7b7eSSam Leffler if (shortPreamble) { 3846c42a7b7eSSam Leffler ctsrate |= rt->info[cix].shortPreamble; 3847c42a7b7eSSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 3848c42a7b7eSSam Leffler ctsduration += rt->info[cix].spAckDuration; 38495591b213SSam Leffler ctsduration += ath_hal_computetxtime(ah, 3850c42a7b7eSSam Leffler rt, pktlen, rix, AH_TRUE); 3851c42a7b7eSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 38526ee571b2SSam Leffler ctsduration += rt->info[rix].spAckDuration; 3853c42a7b7eSSam Leffler } else { 3854c42a7b7eSSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 3855c42a7b7eSSam Leffler ctsduration += rt->info[cix].lpAckDuration; 3856c42a7b7eSSam Leffler ctsduration += ath_hal_computetxtime(ah, 3857c42a7b7eSSam Leffler rt, pktlen, rix, AH_FALSE); 3858c42a7b7eSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 38596ee571b2SSam Leffler ctsduration += rt->info[rix].lpAckDuration; 38605591b213SSam Leffler } 3861c42a7b7eSSam Leffler /* 3862c42a7b7eSSam Leffler * Must disable multi-rate retry when using RTS/CTS. 3863c42a7b7eSSam Leffler */ 3864be613480SSam Leffler ismrr = 0; 3865be613480SSam Leffler try0 = ATH_TXMGTTRY; /* XXX */ 38665591b213SSam Leffler } else 38675591b213SSam Leffler ctsrate = 0; 38685591b213SSam Leffler 3869c42a7b7eSSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 3870c42a7b7eSSam Leffler ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len, 38713e50ec2cSSam Leffler sc->sc_hwmap[txrate].ieeerate, -1); 38725591b213SSam Leffler 3873ff046a6cSSam Leffler if (bpf_peers_present(ic->ic_rawbpf)) 3874eb2cdcb1SSam Leffler bpf_mtap(ic->ic_rawbpf, m0); 387516d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf)) { 38767b0c77ecSSam Leffler u_int64_t tsf = ath_hal_gettsf64(ah); 38777b0c77ecSSam Leffler 38787b0c77ecSSam Leffler sc->sc_tx_th.wt_tsf = htole64(tsf); 3879d3be6f5bSSam Leffler sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags; 3880eb2cdcb1SSam Leffler if (iswep) 3881eb2cdcb1SSam Leffler sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 38823e50ec2cSSam Leffler sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate; 3883c42a7b7eSSam Leffler sc->sc_tx_th.wt_txpower = ni->ni_txpower; 3884c42a7b7eSSam Leffler sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 3885eb2cdcb1SSam Leffler 3886eb2cdcb1SSam Leffler bpf_mtap2(sc->sc_drvbpf, 38872f1ad18bSSam Leffler &sc->sc_tx_th, sc->sc_tx_th_len, m0); 3888eb2cdcb1SSam Leffler } 3889eb2cdcb1SSam Leffler 38905591b213SSam Leffler /* 3891c42a7b7eSSam Leffler * Determine if a tx interrupt should be generated for 3892c42a7b7eSSam Leffler * this descriptor. We take a tx interrupt to reap 3893c42a7b7eSSam Leffler * descriptors when the h/w hits an EOL condition or 3894c42a7b7eSSam Leffler * when the descriptor is specifically marked to generate 3895c42a7b7eSSam Leffler * an interrupt. We periodically mark descriptors in this 3896c42a7b7eSSam Leffler * way to insure timely replenishing of the supply needed 3897c42a7b7eSSam Leffler * for sending frames. Defering interrupts reduces system 3898c42a7b7eSSam Leffler * load and potentially allows more concurrent work to be 3899c42a7b7eSSam Leffler * done but if done to aggressively can cause senders to 3900c42a7b7eSSam Leffler * backup. 3901c42a7b7eSSam Leffler * 3902c42a7b7eSSam Leffler * NB: use >= to deal with sc_txintrperiod changing 3903c42a7b7eSSam Leffler * dynamically through sysctl. 3904c42a7b7eSSam Leffler */ 3905c42a7b7eSSam Leffler if (flags & HAL_TXDESC_INTREQ) { 3906c42a7b7eSSam Leffler txq->axq_intrcnt = 0; 3907c42a7b7eSSam Leffler } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) { 3908c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; 3909c42a7b7eSSam Leffler txq->axq_intrcnt = 0; 3910c42a7b7eSSam Leffler } 3911c42a7b7eSSam Leffler 3912c42a7b7eSSam Leffler /* 39135591b213SSam Leffler * Formulate first tx descriptor with tx controls. 39145591b213SSam Leffler */ 39155591b213SSam Leffler /* XXX check return value? */ 39165591b213SSam Leffler ath_hal_setuptxdesc(ah, ds 39175591b213SSam Leffler , pktlen /* packet length */ 39185591b213SSam Leffler , hdrlen /* header length */ 39195591b213SSam Leffler , atype /* Atheros packet type */ 3920c42a7b7eSSam Leffler , ni->ni_txpower /* txpower */ 3921c42a7b7eSSam Leffler , txrate, try0 /* series 0 rate/tries */ 3922c42a7b7eSSam Leffler , keyix /* key cache index */ 3923c42a7b7eSSam Leffler , sc->sc_txantenna /* antenna mode */ 39245591b213SSam Leffler , flags /* flags */ 39255591b213SSam Leffler , ctsrate /* rts/cts rate */ 39265591b213SSam Leffler , ctsduration /* rts/cts duration */ 39275591b213SSam Leffler ); 3928ebecf802SSam Leffler bf->bf_flags = flags; 3929c42a7b7eSSam Leffler /* 3930c42a7b7eSSam Leffler * Setup the multi-rate retry state only when we're 3931c42a7b7eSSam Leffler * going to use it. This assumes ath_hal_setuptxdesc 3932c42a7b7eSSam Leffler * initializes the descriptors (so we don't have to) 3933c42a7b7eSSam Leffler * when the hardware supports multi-rate retry and 3934c42a7b7eSSam Leffler * we don't use it. 3935c42a7b7eSSam Leffler */ 3936be613480SSam Leffler if (ismrr) 3937c42a7b7eSSam Leffler ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix); 3938c42a7b7eSSam Leffler 3939664443d0SSam Leffler ath_tx_handoff(sc, txq, bf); 39405591b213SSam Leffler return 0; 39415591b213SSam Leffler } 39425591b213SSam Leffler 3943c42a7b7eSSam 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; 39500a915fadSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 3951ebecf802SSam Leffler struct ath_buf *bf; 3952c4c3cb46SSam Leffler struct ath_desc *ds, *ds0; 395365f9edeeSSam Leffler struct ath_tx_status *ts; 39545591b213SSam Leffler struct ieee80211_node *ni; 39555591b213SSam Leffler struct ath_node *an; 3956d7736e13SSam Leffler int sr, lr, pri, nacked; 39575591b213SSam Leffler HAL_STATUS status; 39585591b213SSam Leffler 3959c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n", 3960c42a7b7eSSam Leffler __func__, txq->axq_qnum, 3961c42a7b7eSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum), 3962c42a7b7eSSam Leffler txq->axq_link); 3963d7736e13SSam Leffler nacked = 0; 39645591b213SSam Leffler for (;;) { 3965c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 3966c42a7b7eSSam Leffler txq->axq_intrcnt = 0; /* reset periodic desc intr count */ 3967c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 39685591b213SSam Leffler if (bf == NULL) { 3969c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39705591b213SSam Leffler break; 39715591b213SSam Leffler } 3972c4c3cb46SSam Leffler ds0 = &bf->bf_desc[0]; 39735591b213SSam Leffler ds = &bf->bf_desc[bf->bf_nseg - 1]; 397465f9edeeSSam Leffler ts = &bf->bf_status.ds_txstat; 397565f9edeeSSam Leffler status = ath_hal_txprocdesc(ah, ds, ts); 3976a585a9a1SSam Leffler #ifdef ATH_DEBUG 3977c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 39787a4c5ed9SSam Leffler ath_printtxbuf(bf, txq->axq_qnum, 0, status == HAL_OK); 39795591b213SSam Leffler #endif 39805591b213SSam Leffler if (status == HAL_EINPROGRESS) { 3981c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39825591b213SSam Leffler break; 39835591b213SSam Leffler } 3984c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 3985ebecf802SSam Leffler if (txq->axq_depth == 0) 39861539af1eSSam Leffler txq->axq_link = NULL; 3987c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39885591b213SSam Leffler 39895591b213SSam Leffler ni = bf->bf_node; 39905591b213SSam Leffler if (ni != NULL) { 3991c42a7b7eSSam Leffler an = ATH_NODE(ni); 399265f9edeeSSam Leffler if (ts->ts_status == 0) { 399365f9edeeSSam Leffler u_int8_t txant = ts->ts_antenna; 3994c42a7b7eSSam Leffler sc->sc_stats.ast_ant_tx[txant]++; 3995c42a7b7eSSam Leffler sc->sc_ant_tx[txant]++; 399665f9edeeSSam Leffler if (ts->ts_rate & HAL_TXSTAT_ALTRATE) 3997c42a7b7eSSam Leffler sc->sc_stats.ast_tx_altrate++; 399865f9edeeSSam Leffler sc->sc_stats.ast_tx_rssi = ts->ts_rssi; 3999ffa2cab6SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, 400065f9edeeSSam Leffler ts->ts_rssi); 4001c42a7b7eSSam Leffler pri = M_WME_GETAC(bf->bf_m); 4002c42a7b7eSSam Leffler if (pri >= WME_AC_VO) 4003c42a7b7eSSam Leffler ic->ic_wme.wme_hipri_traffic++; 4004c42a7b7eSSam Leffler ni->ni_inact = ni->ni_inact_reload; 40055591b213SSam Leffler } else { 400665f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_XRETRY) 40075591b213SSam Leffler sc->sc_stats.ast_tx_xretries++; 400865f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FIFO) 40095591b213SSam Leffler sc->sc_stats.ast_tx_fifoerr++; 401065f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FILT) 40115591b213SSam Leffler sc->sc_stats.ast_tx_filtered++; 40125591b213SSam Leffler } 401365f9edeeSSam Leffler sr = ts->ts_shortretry; 401465f9edeeSSam Leffler lr = ts->ts_longretry; 40155591b213SSam Leffler sc->sc_stats.ast_tx_shortretry += sr; 40165591b213SSam Leffler sc->sc_stats.ast_tx_longretry += lr; 4017c42a7b7eSSam Leffler /* 4018c42a7b7eSSam Leffler * Hand the descriptor to the rate control algorithm. 4019c42a7b7eSSam Leffler */ 402065f9edeeSSam Leffler if ((ts->ts_status & HAL_TXERR_FILT) == 0 && 4021ebecf802SSam Leffler (bf->bf_flags & HAL_TXDESC_NOACK) == 0) { 4022d7736e13SSam Leffler /* 4023d7736e13SSam Leffler * If frame was ack'd update the last rx time 4024d7736e13SSam Leffler * used to workaround phantom bmiss interrupts. 4025d7736e13SSam Leffler */ 402665f9edeeSSam Leffler if (ts->ts_status == 0) 4027d7736e13SSam Leffler nacked++; 402865f9edeeSSam Leffler ath_rate_tx_complete(sc, an, bf); 4029d7736e13SSam Leffler } 40300a915fadSSam Leffler /* 40310a915fadSSam Leffler * Reclaim reference to node. 40320a915fadSSam Leffler * 40330a915fadSSam Leffler * NB: the node may be reclaimed here if, for example 40340a915fadSSam Leffler * this is a DEAUTH message that was sent and the 40350a915fadSSam Leffler * node was timed out due to inactivity. 40360a915fadSSam Leffler */ 4037c42a7b7eSSam Leffler ieee80211_free_node(ni); 40385591b213SSam Leffler } 40395591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 40405591b213SSam Leffler BUS_DMASYNC_POSTWRITE); 40415591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 40425591b213SSam Leffler m_freem(bf->bf_m); 40435591b213SSam Leffler bf->bf_m = NULL; 40445591b213SSam Leffler bf->bf_node = NULL; 40455591b213SSam Leffler 4046f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 4047c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4048f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 40495591b213SSam Leffler } 4050d7736e13SSam Leffler return nacked; 4051d7736e13SSam Leffler } 4052d7736e13SSam Leffler 4053d7736e13SSam Leffler static __inline int 4054d7736e13SSam Leffler txqactive(struct ath_hal *ah, int qnum) 4055d7736e13SSam Leffler { 4056e2815d69SSam Leffler u_int32_t txqs = 1<<qnum; 4057e2815d69SSam Leffler ath_hal_gettxintrtxqs(ah, &txqs); 40589760f8aeSSam Leffler return (txqs & (1<<qnum)); 4059c42a7b7eSSam Leffler } 4060c42a7b7eSSam Leffler 4061c42a7b7eSSam Leffler /* 4062c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4063c42a7b7eSSam Leffler * for a single hardware transmit queue (e.g. 5210 and 5211). 4064c42a7b7eSSam Leffler */ 4065c42a7b7eSSam Leffler static void 4066c42a7b7eSSam Leffler ath_tx_proc_q0(void *arg, int npending) 4067c42a7b7eSSam Leffler { 4068c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4069fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4070c42a7b7eSSam Leffler 4071d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0])) 4072d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4073d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4074d7736e13SSam Leffler ath_tx_processq(sc, sc->sc_cabq); 407513f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 40765591b213SSam Leffler sc->sc_tx_timer = 0; 40775591b213SSam Leffler 40783e50ec2cSSam Leffler if (sc->sc_softled) 40793e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 40803e50ec2cSSam Leffler 40815591b213SSam Leffler ath_start(ifp); 40825591b213SSam Leffler } 40835591b213SSam Leffler 40845591b213SSam Leffler /* 4085c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4086c42a7b7eSSam Leffler * for four hardware queues, 0-3 (e.g. 5212 w/ WME support). 40875591b213SSam Leffler */ 40885591b213SSam Leffler static void 4089c42a7b7eSSam Leffler ath_tx_proc_q0123(void *arg, int npending) 4090c42a7b7eSSam Leffler { 4091c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4092fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4093d7736e13SSam Leffler int nacked; 4094c42a7b7eSSam Leffler 4095c42a7b7eSSam Leffler /* 4096c42a7b7eSSam Leffler * Process each active queue. 4097c42a7b7eSSam Leffler */ 4098d7736e13SSam Leffler nacked = 0; 4099d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0)) 4100d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[0]); 4101d7736e13SSam Leffler if (txqactive(sc->sc_ah, 1)) 4102d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[1]); 4103d7736e13SSam Leffler if (txqactive(sc->sc_ah, 2)) 4104d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[2]); 4105d7736e13SSam Leffler if (txqactive(sc->sc_ah, 3)) 4106d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[3]); 4107d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4108c42a7b7eSSam Leffler ath_tx_processq(sc, sc->sc_cabq); 4109d7736e13SSam Leffler if (nacked) 4110d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4111c42a7b7eSSam Leffler 411213f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4113c42a7b7eSSam Leffler sc->sc_tx_timer = 0; 4114c42a7b7eSSam Leffler 41153e50ec2cSSam Leffler if (sc->sc_softled) 41163e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 41173e50ec2cSSam Leffler 4118c42a7b7eSSam Leffler ath_start(ifp); 4119c42a7b7eSSam Leffler } 4120c42a7b7eSSam Leffler 4121c42a7b7eSSam Leffler /* 4122c42a7b7eSSam Leffler * Deferred processing of transmit interrupt. 4123c42a7b7eSSam Leffler */ 4124c42a7b7eSSam Leffler static void 4125c42a7b7eSSam Leffler ath_tx_proc(void *arg, int npending) 4126c42a7b7eSSam Leffler { 4127c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4128fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4129d7736e13SSam Leffler int i, nacked; 4130c42a7b7eSSam Leffler 4131c42a7b7eSSam Leffler /* 4132c42a7b7eSSam Leffler * Process each active queue. 4133c42a7b7eSSam Leffler */ 4134d7736e13SSam Leffler nacked = 0; 4135c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4136d7736e13SSam Leffler if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i)) 4137d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[i]); 4138d7736e13SSam Leffler if (nacked) 4139d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4140c42a7b7eSSam Leffler 414113f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4142c42a7b7eSSam Leffler sc->sc_tx_timer = 0; 4143c42a7b7eSSam Leffler 41443e50ec2cSSam Leffler if (sc->sc_softled) 41453e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 41463e50ec2cSSam Leffler 4147c42a7b7eSSam Leffler ath_start(ifp); 4148c42a7b7eSSam Leffler } 4149c42a7b7eSSam Leffler 4150c42a7b7eSSam Leffler static void 4151c42a7b7eSSam Leffler ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) 41525591b213SSam Leffler { 4153a585a9a1SSam Leffler #ifdef ATH_DEBUG 41545591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4155d2f6ed15SSam Leffler #endif 415623428eafSSam Leffler struct ieee80211_node *ni; 41575591b213SSam Leffler struct ath_buf *bf; 41587a4c5ed9SSam Leffler u_int ix; 41595591b213SSam Leffler 4160c42a7b7eSSam Leffler /* 4161c42a7b7eSSam Leffler * NB: this assumes output has been stopped and 4162ebecf802SSam Leffler * we do not need to block ath_tx_tasklet 4163c42a7b7eSSam Leffler */ 41647a4c5ed9SSam Leffler for (ix = 0;; ix++) { 4165c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 4166c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 41675591b213SSam Leffler if (bf == NULL) { 4168ebecf802SSam Leffler txq->axq_link = NULL; 4169c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 41705591b213SSam Leffler break; 41715591b213SSam Leffler } 4172c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 4173c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 4174a585a9a1SSam Leffler #ifdef ATH_DEBUG 41754a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 41767a4c5ed9SSam Leffler ath_printtxbuf(bf, txq->axq_qnum, ix, 417765f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 417865f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 41794a3ac3fcSSam Leffler ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t), 41804a3ac3fcSSam Leffler bf->bf_m->m_len, 0, -1); 41814a3ac3fcSSam Leffler } 4182a585a9a1SSam Leffler #endif /* ATH_DEBUG */ 41835591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 41845591b213SSam Leffler m_freem(bf->bf_m); 41855591b213SSam Leffler bf->bf_m = NULL; 418623428eafSSam Leffler ni = bf->bf_node; 41875591b213SSam Leffler bf->bf_node = NULL; 4188c42a7b7eSSam Leffler if (ni != NULL) { 418923428eafSSam Leffler /* 419023428eafSSam Leffler * Reclaim node reference. 419123428eafSSam Leffler */ 4192c42a7b7eSSam Leffler ieee80211_free_node(ni); 419323428eafSSam Leffler } 4194f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 4195c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4196f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 41975591b213SSam Leffler } 4198c42a7b7eSSam Leffler } 4199c42a7b7eSSam Leffler 4200c42a7b7eSSam Leffler static void 4201c42a7b7eSSam Leffler ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) 4202c42a7b7eSSam Leffler { 4203c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4204c42a7b7eSSam Leffler 4205c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 4206c42a7b7eSSam Leffler __func__, txq->axq_qnum, 42076891c875SPeter Wemm (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, txq->axq_qnum), 42086891c875SPeter Wemm txq->axq_link); 42094a3ac3fcSSam Leffler (void) ath_hal_stoptxdma(ah, txq->axq_qnum); 4210c42a7b7eSSam Leffler } 4211c42a7b7eSSam Leffler 4212c42a7b7eSSam Leffler /* 4213c42a7b7eSSam Leffler * Drain the transmit queues and reclaim resources. 4214c42a7b7eSSam Leffler */ 4215c42a7b7eSSam Leffler static void 4216c42a7b7eSSam Leffler ath_draintxq(struct ath_softc *sc) 4217c42a7b7eSSam Leffler { 4218c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4219fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4220c42a7b7eSSam Leffler int i; 4221c42a7b7eSSam Leffler 4222c42a7b7eSSam Leffler /* XXX return value */ 4223c42a7b7eSSam Leffler if (!sc->sc_invalid) { 4224c42a7b7eSSam Leffler /* don't touch the hardware if marked invalid */ 42254a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 42264a3ac3fcSSam Leffler __func__, sc->sc_bhalq, 42274a3ac3fcSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq), 42284a3ac3fcSSam Leffler NULL); 4229c42a7b7eSSam Leffler (void) ath_hal_stoptxdma(ah, sc->sc_bhalq); 4230c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4231c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4232c42a7b7eSSam Leffler ath_tx_stopdma(sc, &sc->sc_txq[i]); 4233c42a7b7eSSam Leffler } 4234c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4235c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4236c42a7b7eSSam Leffler ath_tx_draintxq(sc, &sc->sc_txq[i]); 4237622b3fd2SSam Leffler ath_tx_draintxq(sc, &sc->sc_mcastq); 42384a3ac3fcSSam Leffler #ifdef ATH_DEBUG 42394a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 42404a3ac3fcSSam Leffler struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); 42414a3ac3fcSSam Leffler if (bf != NULL && bf->bf_m != NULL) { 42424a3ac3fcSSam Leffler ath_printtxbuf(bf, sc->sc_bhalq, 0, 424365f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 424465f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 42454a3ac3fcSSam Leffler ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t), 42464a3ac3fcSSam Leffler bf->bf_m->m_len, 0, -1); 42474a3ac3fcSSam Leffler } 42484a3ac3fcSSam Leffler } 42494a3ac3fcSSam Leffler #endif /* ATH_DEBUG */ 425013f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 42515591b213SSam Leffler sc->sc_tx_timer = 0; 42525591b213SSam Leffler } 42535591b213SSam Leffler 42545591b213SSam Leffler /* 42555591b213SSam Leffler * Disable the receive h/w in preparation for a reset. 42565591b213SSam Leffler */ 42575591b213SSam Leffler static void 42585591b213SSam Leffler ath_stoprecv(struct ath_softc *sc) 42595591b213SSam Leffler { 42608cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 4261c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 4262c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 42635591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 42645591b213SSam Leffler 42655591b213SSam Leffler ath_hal_stoppcurecv(ah); /* disable PCU */ 42665591b213SSam Leffler ath_hal_setrxfilter(ah, 0); /* clear recv filter */ 42675591b213SSam Leffler ath_hal_stopdmarecv(ah); /* disable DMA engine */ 4268c42a7b7eSSam Leffler DELAY(3000); /* 3ms is long enough for 1 frame */ 4269a585a9a1SSam Leffler #ifdef ATH_DEBUG 4270c42a7b7eSSam Leffler if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) { 42715591b213SSam Leffler struct ath_buf *bf; 42727a4c5ed9SSam Leffler u_int ix; 42735591b213SSam Leffler 4274e325e530SSam Leffler printf("%s: rx queue %p, link %p\n", __func__, 427530310634SPeter Wemm (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); 42767a4c5ed9SSam Leffler ix = 0; 4277c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 42788cec0ab9SSam Leffler struct ath_desc *ds = bf->bf_desc; 427965f9edeeSSam Leffler struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; 4280c42a7b7eSSam Leffler HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, 428165f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 4282c42a7b7eSSam Leffler if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL)) 42837a4c5ed9SSam Leffler ath_printrxbuf(bf, ix, status == HAL_OK); 42847a4c5ed9SSam Leffler ix++; 42855591b213SSam Leffler } 42865591b213SSam Leffler } 42875591b213SSam Leffler #endif 42885591b213SSam Leffler sc->sc_rxlink = NULL; /* just in case */ 42898cec0ab9SSam Leffler #undef PA2DESC 42905591b213SSam Leffler } 42915591b213SSam Leffler 42925591b213SSam Leffler /* 42935591b213SSam Leffler * Enable the receive h/w following a reset. 42945591b213SSam Leffler */ 42955591b213SSam Leffler static int 42965591b213SSam Leffler ath_startrecv(struct ath_softc *sc) 42975591b213SSam Leffler { 42985591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 42995591b213SSam Leffler struct ath_buf *bf; 43005591b213SSam Leffler 43015591b213SSam Leffler sc->sc_rxlink = NULL; 4302c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 43035591b213SSam Leffler int error = ath_rxbuf_init(sc, bf); 43045591b213SSam Leffler if (error != 0) { 4305c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, 4306c42a7b7eSSam Leffler "%s: ath_rxbuf_init failed %d\n", 4307c42a7b7eSSam Leffler __func__, error); 43085591b213SSam Leffler return error; 43095591b213SSam Leffler } 43105591b213SSam Leffler } 43115591b213SSam Leffler 4312c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 43135591b213SSam Leffler ath_hal_putrxbuf(ah, bf->bf_daddr); 43145591b213SSam Leffler ath_hal_rxena(ah); /* enable recv descriptors */ 43155591b213SSam Leffler ath_mode_init(sc); /* set filters, etc. */ 43165591b213SSam Leffler ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ 43175591b213SSam Leffler return 0; 43185591b213SSam Leffler } 43195591b213SSam Leffler 43205591b213SSam Leffler /* 4321c42a7b7eSSam Leffler * Update internal state after a channel change. 4322c42a7b7eSSam Leffler */ 4323c42a7b7eSSam Leffler static void 4324c42a7b7eSSam Leffler ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan) 4325c42a7b7eSSam Leffler { 4326c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4327c42a7b7eSSam Leffler enum ieee80211_phymode mode; 432816b4851aSSam Leffler u_int16_t flags; 4329c42a7b7eSSam Leffler 4330c42a7b7eSSam Leffler /* 4331c42a7b7eSSam Leffler * Change channels and update the h/w rate map 4332c42a7b7eSSam Leffler * if we're switching; e.g. 11a to 11b/g. 4333c42a7b7eSSam Leffler */ 4334aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) 4335724c193aSSam Leffler mode = IEEE80211_MODE_HALF; 4336aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(chan)) 4337724c193aSSam Leffler mode = IEEE80211_MODE_QUARTER; 4338724c193aSSam Leffler else 4339724c193aSSam Leffler mode = ieee80211_chan2mode(ic, chan); 4340c42a7b7eSSam Leffler if (mode != sc->sc_curmode) 4341c42a7b7eSSam Leffler ath_setcurmode(sc, mode); 4342c42a7b7eSSam Leffler /* 434316b4851aSSam Leffler * Update BPF state. NB: ethereal et. al. don't handle 434416b4851aSSam Leffler * merged flags well so pick a unique mode for their use. 4345c42a7b7eSSam Leffler */ 434616b4851aSSam Leffler if (IEEE80211_IS_CHAN_A(chan)) 434716b4851aSSam Leffler flags = IEEE80211_CHAN_A; 434816b4851aSSam Leffler /* XXX 11g schizophrenia */ 4349aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_ANYG(chan)) 435016b4851aSSam Leffler flags = IEEE80211_CHAN_G; 435116b4851aSSam Leffler else 435216b4851aSSam Leffler flags = IEEE80211_CHAN_B; 435316b4851aSSam Leffler if (IEEE80211_IS_CHAN_T(chan)) 435416b4851aSSam Leffler flags |= IEEE80211_CHAN_TURBO; 4355724c193aSSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) 4356724c193aSSam Leffler flags |= IEEE80211_CHAN_HALF; 4357724c193aSSam Leffler if (IEEE80211_IS_CHAN_QUARTER(chan)) 4358724c193aSSam Leffler flags |= IEEE80211_CHAN_QUARTER; 4359c42a7b7eSSam Leffler sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq = 4360c42a7b7eSSam Leffler htole16(chan->ic_freq); 4361c42a7b7eSSam Leffler sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = 436216b4851aSSam Leffler htole16(flags); 4363c42a7b7eSSam Leffler } 4364c42a7b7eSSam Leffler 4365c42a7b7eSSam Leffler /* 4366bd5a9920SSam Leffler * Poll for a channel clear indication; this is required 4367bd5a9920SSam Leffler * for channels requiring DFS and not previously visited 4368bd5a9920SSam Leffler * and/or with a recent radar detection. 4369bd5a9920SSam Leffler */ 4370bd5a9920SSam Leffler static void 4371bd5a9920SSam Leffler ath_dfswait(void *arg) 4372bd5a9920SSam Leffler { 4373bd5a9920SSam Leffler struct ath_softc *sc = arg; 4374bd5a9920SSam Leffler struct ath_hal *ah = sc->sc_ah; 4375bd5a9920SSam Leffler HAL_CHANNEL hchan; 4376bd5a9920SSam Leffler 4377bd5a9920SSam Leffler ath_hal_radar_wait(ah, &hchan); 4378bd5a9920SSam Leffler DPRINTF(sc, ATH_DEBUG_DFS, "%s: radar_wait %u/%x/%x\n", 4379bd5a9920SSam Leffler __func__, hchan.channel, hchan.channelFlags, hchan.privFlags); 4380bd5a9920SSam Leffler 4381bd5a9920SSam Leffler if (hchan.privFlags & CHANNEL_INTERFERENCE) { 4382bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4383bd5a9920SSam Leffler "channel %u/0x%x/0x%x has interference\n", 4384bd5a9920SSam Leffler hchan.channel, hchan.channelFlags, hchan.privFlags); 4385bd5a9920SSam Leffler return; 4386bd5a9920SSam Leffler } 4387bd5a9920SSam Leffler if ((hchan.privFlags & CHANNEL_DFS) == 0) { 4388bd5a9920SSam Leffler /* XXX should not happen */ 4389bd5a9920SSam Leffler return; 4390bd5a9920SSam Leffler } 4391bd5a9920SSam Leffler if (hchan.privFlags & CHANNEL_DFS_CLEAR) { 4392bd5a9920SSam Leffler sc->sc_curchan.privFlags |= CHANNEL_DFS_CLEAR; 4393bd5a9920SSam Leffler sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4394bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4395bd5a9920SSam Leffler "channel %u/0x%x/0x%x marked clear\n", 4396bd5a9920SSam Leffler hchan.channel, hchan.channelFlags, hchan.privFlags); 4397bd5a9920SSam Leffler } else 4398bd5a9920SSam Leffler callout_reset(&sc->sc_dfs_ch, 2 * hz, ath_dfswait, sc); 4399bd5a9920SSam Leffler } 4400bd5a9920SSam Leffler 4401bd5a9920SSam Leffler /* 44025591b213SSam Leffler * Set/change channels. If the channel is really being changed, 4403c42a7b7eSSam Leffler * it's done by reseting the chip. To accomplish this we must 44045591b213SSam Leffler * first cleanup any pending DMA, then restart stuff after a la 44055591b213SSam Leffler * ath_init. 44065591b213SSam Leffler */ 44075591b213SSam Leffler static int 44085591b213SSam Leffler ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) 44095591b213SSam Leffler { 44105591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 44115591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 44125591b213SSam Leffler HAL_CHANNEL hchan; 4413c42a7b7eSSam Leffler 4414c42a7b7eSSam Leffler /* 4415c42a7b7eSSam Leffler * Convert to a HAL channel description with 4416c42a7b7eSSam Leffler * the flags constrained to reflect the current 4417c42a7b7eSSam Leffler * operating mode. 4418c42a7b7eSSam Leffler */ 4419724c193aSSam Leffler ath_mapchan(ic, &hchan, chan); 4420c42a7b7eSSam Leffler 4421370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 4422370572d9SSam Leffler "%s: %u (%u MHz, hal flags 0x%x) -> %u (%u MHz, hal flags 0x%x)\n", 4423c42a7b7eSSam Leffler __func__, 4424bd5a9920SSam Leffler ath_hal_mhz2ieee(ah, sc->sc_curchan.channel, 4425c42a7b7eSSam Leffler sc->sc_curchan.channelFlags), 4426370572d9SSam Leffler sc->sc_curchan.channel, sc->sc_curchan.channelFlags, 4427bd5a9920SSam Leffler ath_hal_mhz2ieee(ah, hchan.channel, hchan.channelFlags), 4428370572d9SSam Leffler hchan.channel, hchan.channelFlags); 4429c42a7b7eSSam Leffler if (hchan.channel != sc->sc_curchan.channel || 4430c42a7b7eSSam Leffler hchan.channelFlags != sc->sc_curchan.channelFlags) { 4431c42a7b7eSSam Leffler HAL_STATUS status; 44325591b213SSam Leffler 44335591b213SSam Leffler /* 44345591b213SSam Leffler * To switch channels clear any pending DMA operations; 44355591b213SSam Leffler * wait long enough for the RX fifo to drain, reset the 44365591b213SSam Leffler * hardware at the new frequency, and then re-enable 44375591b213SSam Leffler * the relevant bits of the h/w. 44385591b213SSam Leffler */ 44395591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 44405591b213SSam Leffler ath_draintxq(sc); /* clear pending tx frames */ 44415591b213SSam Leffler ath_stoprecv(sc); /* turn off frame recv */ 44427a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)) { 4443370572d9SSam Leffler if_printf(ic->ic_ifp, "%s: unable to reset " 4444370572d9SSam Leffler "channel %u (%u Mhz, flags 0x%x hal flags 0x%x)\n", 4445370572d9SSam Leffler __func__, ieee80211_chan2ieee(ic, chan), 4446370572d9SSam Leffler chan->ic_freq, chan->ic_flags, hchan.channelFlags); 44475591b213SSam Leffler return EIO; 44485591b213SSam Leffler } 4449c42a7b7eSSam Leffler sc->sc_curchan = hchan; 4450c42a7b7eSSam Leffler ath_update_txpow(sc); /* update tx power state */ 4451c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 4452bd5a9920SSam Leffler sc->sc_calinterval = 1; 4453bd5a9920SSam Leffler sc->sc_caltries = 0; 4454c42a7b7eSSam Leffler 44555591b213SSam Leffler /* 44565591b213SSam Leffler * Re-enable rx framework. 44575591b213SSam Leffler */ 44585591b213SSam Leffler if (ath_startrecv(sc) != 0) { 4459c42a7b7eSSam Leffler if_printf(ic->ic_ifp, 4460370572d9SSam Leffler "%s: unable to restart recv logic\n", __func__); 44615591b213SSam Leffler return EIO; 44625591b213SSam Leffler } 44635591b213SSam Leffler 44645591b213SSam Leffler /* 44655591b213SSam Leffler * Change channels and update the h/w rate map 44665591b213SSam Leffler * if we're switching; e.g. 11a to 11b/g. 44675591b213SSam Leffler */ 44685591b213SSam Leffler ic->ic_ibss_chan = chan; 4469c42a7b7eSSam Leffler ath_chan_change(sc, chan); 44700a915fadSSam Leffler 44710a915fadSSam Leffler /* 4472bd5a9920SSam Leffler * Handle DFS required waiting period to determine 4473bd5a9920SSam Leffler * if channel is clear of radar traffic. 4474bd5a9920SSam Leffler */ 4475bd5a9920SSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 4476bd5a9920SSam Leffler #define DFS_AND_NOT_CLEAR(_c) \ 4477bd5a9920SSam Leffler (((_c)->privFlags & (CHANNEL_DFS | CHANNEL_DFS_CLEAR)) == CHANNEL_DFS) 4478bd5a9920SSam Leffler if (DFS_AND_NOT_CLEAR(&sc->sc_curchan)) { 4479bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4480bd5a9920SSam Leffler "wait for DFS clear channel signal\n"); 4481bd5a9920SSam Leffler /* XXX stop sndq */ 4482bd5a9920SSam Leffler sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 4483bd5a9920SSam Leffler callout_reset(&sc->sc_dfs_ch, 4484bd5a9920SSam Leffler 2 * hz, ath_dfswait, sc); 4485bd5a9920SSam Leffler } else 4486bd5a9920SSam Leffler callout_stop(&sc->sc_dfs_ch); 4487bd5a9920SSam Leffler #undef DFS_NOT_CLEAR 4488bd5a9920SSam Leffler } 4489bd5a9920SSam Leffler 4490bd5a9920SSam Leffler /* 44910a915fadSSam Leffler * Re-enable interrupts. 44920a915fadSSam Leffler */ 44930a915fadSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 44945591b213SSam Leffler } 44955591b213SSam Leffler return 0; 44965591b213SSam Leffler } 44975591b213SSam Leffler 44985591b213SSam Leffler static void 44995591b213SSam Leffler ath_next_scan(void *arg) 45005591b213SSam Leffler { 45015591b213SSam Leffler struct ath_softc *sc = arg; 45025591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 45035591b213SSam Leffler 45045591b213SSam Leffler if (ic->ic_state == IEEE80211_S_SCAN) 4505c42a7b7eSSam Leffler ieee80211_next_scan(ic); 45065591b213SSam Leffler } 45075591b213SSam Leffler 45085591b213SSam Leffler /* 45095591b213SSam Leffler * Periodically recalibrate the PHY to account 45105591b213SSam Leffler * for temperature/environment changes. 45115591b213SSam Leffler */ 45125591b213SSam Leffler static void 45135591b213SSam Leffler ath_calibrate(void *arg) 45145591b213SSam Leffler { 45155591b213SSam Leffler struct ath_softc *sc = arg; 45165591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4517bd5a9920SSam Leffler HAL_BOOL iqCalDone; 45185591b213SSam Leffler 45195591b213SSam Leffler sc->sc_stats.ast_per_cal++; 45205591b213SSam Leffler 45215591b213SSam Leffler if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { 45225591b213SSam Leffler /* 45235591b213SSam Leffler * Rfgain is out of bounds, reset the chip 45245591b213SSam Leffler * to load new gain values. 45255591b213SSam Leffler */ 4526370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 4527370572d9SSam Leffler "%s: rfgain change\n", __func__); 45285591b213SSam Leffler sc->sc_stats.ast_per_rfgain++; 4529fc74a9f9SBrooks Davis ath_reset(sc->sc_ifp); 45305591b213SSam Leffler } 4531bd5a9920SSam Leffler if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) { 4532c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 4533c42a7b7eSSam Leffler "%s: calibration of channel %u failed\n", 4534c42a7b7eSSam Leffler __func__, sc->sc_curchan.channel); 45355591b213SSam Leffler sc->sc_stats.ast_per_calfail++; 45365591b213SSam Leffler } 45377b0c77ecSSam Leffler /* 45387b0c77ecSSam Leffler * Calibrate noise floor data again in case of change. 45397b0c77ecSSam Leffler */ 45407b0c77ecSSam Leffler ath_hal_process_noisefloor(ah); 4541bd5a9920SSam Leffler /* 4542bd5a9920SSam Leffler * Poll more frequently when the IQ calibration is in 4543bd5a9920SSam Leffler * progress to speedup loading the final settings. 4544bd5a9920SSam Leffler * We temper this aggressive polling with an exponential 4545bd5a9920SSam Leffler * back off after 4 tries up to ath_calinterval. 4546bd5a9920SSam Leffler */ 4547bd5a9920SSam Leffler if (iqCalDone || sc->sc_calinterval >= ath_calinterval) { 4548bd5a9920SSam Leffler sc->sc_caltries = 0; 4549bd5a9920SSam Leffler sc->sc_calinterval = ath_calinterval; 4550bd5a9920SSam Leffler } else if (sc->sc_caltries > 4) { 4551bd5a9920SSam Leffler sc->sc_caltries = 0; 4552bd5a9920SSam Leffler sc->sc_calinterval <<= 1; 4553bd5a9920SSam Leffler if (sc->sc_calinterval > ath_calinterval) 4554bd5a9920SSam Leffler sc->sc_calinterval = ath_calinterval; 4555bd5a9920SSam Leffler } 4556bd5a9920SSam Leffler KASSERT(0 < sc->sc_calinterval && sc->sc_calinterval <= ath_calinterval, 4557bd5a9920SSam Leffler ("bad calibration interval %u", sc->sc_calinterval)); 4558bd5a9920SSam Leffler 4559bd5a9920SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 4560bd5a9920SSam Leffler "%s: next +%u (%siqCalDone tries %u)\n", __func__, 4561bd5a9920SSam Leffler sc->sc_calinterval, iqCalDone ? "" : "!", sc->sc_caltries); 4562bd5a9920SSam Leffler sc->sc_caltries++; 4563bd5a9920SSam Leffler callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, 4564bd5a9920SSam Leffler ath_calibrate, sc); 45655591b213SSam Leffler } 45665591b213SSam Leffler 45675591b213SSam Leffler static int 456845bbf62fSSam Leffler ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 45695591b213SSam Leffler { 4570c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 457145bbf62fSSam Leffler struct ath_softc *sc = ifp->if_softc; 457245bbf62fSSam Leffler struct ath_hal *ah = sc->sc_ah; 45735591b213SSam Leffler struct ieee80211_node *ni; 45745591b213SSam Leffler int i, error; 45758cec0ab9SSam Leffler const u_int8_t *bssid; 45765591b213SSam Leffler u_int32_t rfilt; 45775591b213SSam Leffler static const HAL_LED_STATE leds[] = { 45785591b213SSam Leffler HAL_LED_INIT, /* IEEE80211_S_INIT */ 45795591b213SSam Leffler HAL_LED_SCAN, /* IEEE80211_S_SCAN */ 45805591b213SSam Leffler HAL_LED_AUTH, /* IEEE80211_S_AUTH */ 45815591b213SSam Leffler HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */ 45825591b213SSam Leffler HAL_LED_RUN, /* IEEE80211_S_RUN */ 45835591b213SSam Leffler }; 45845591b213SSam Leffler 4585c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__, 458645bbf62fSSam Leffler ieee80211_state_name[ic->ic_state], 4587c42a7b7eSSam Leffler ieee80211_state_name[nstate]); 45885591b213SSam Leffler 4589c42a7b7eSSam Leffler callout_stop(&sc->sc_scan_ch); 4590c42a7b7eSSam Leffler callout_stop(&sc->sc_cal_ch); 4591bd5a9920SSam Leffler callout_stop(&sc->sc_dfs_ch); 45925591b213SSam Leffler ath_hal_setledstate(ah, leds[nstate]); /* set LED */ 45935591b213SSam Leffler 45945591b213SSam Leffler if (nstate == IEEE80211_S_INIT) { 45955591b213SSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 45964c24deacSSam Leffler /* 45974c24deacSSam Leffler * NB: disable interrupts so we don't rx frames. 45984c24deacSSam Leffler */ 4599e8fd88a3SSam Leffler ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL); 4600c42a7b7eSSam Leffler /* 4601c42a7b7eSSam Leffler * Notify the rate control algorithm. 4602c42a7b7eSSam Leffler */ 4603c42a7b7eSSam Leffler ath_rate_newstate(sc, nstate); 4604c42a7b7eSSam Leffler goto done; 46055591b213SSam Leffler } 46065591b213SSam Leffler ni = ic->ic_bss; 4607b5c99415SSam Leffler error = ath_chan_set(sc, ic->ic_curchan); 46085591b213SSam Leffler if (error != 0) 46095591b213SSam Leffler goto bad; 4610c42a7b7eSSam Leffler rfilt = ath_calcrxfilter(sc, nstate); 4611c42a7b7eSSam Leffler if (nstate == IEEE80211_S_SCAN) 46125591b213SSam Leffler bssid = ifp->if_broadcastaddr; 4613c42a7b7eSSam Leffler else 46145591b213SSam Leffler bssid = ni->ni_bssid; 46155591b213SSam Leffler ath_hal_setrxfilter(ah, rfilt); 4616c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s\n", 4617c42a7b7eSSam Leffler __func__, rfilt, ether_sprintf(bssid)); 46185591b213SSam Leffler 46195591b213SSam Leffler if (nstate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA) 46205591b213SSam Leffler ath_hal_setassocid(ah, bssid, ni->ni_associd); 46215591b213SSam Leffler else 46225591b213SSam Leffler ath_hal_setassocid(ah, bssid, 0); 4623c42a7b7eSSam Leffler if (ic->ic_flags & IEEE80211_F_PRIVACY) { 46245591b213SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) 46255591b213SSam Leffler if (ath_hal_keyisvalid(ah, i)) 46265591b213SSam Leffler ath_hal_keysetmac(ah, i, bssid); 46275591b213SSam Leffler } 46285591b213SSam Leffler 4629c42a7b7eSSam Leffler /* 4630c42a7b7eSSam Leffler * Notify the rate control algorithm so rates 4631c42a7b7eSSam Leffler * are setup should ath_beacon_alloc be called. 4632c42a7b7eSSam Leffler */ 4633c42a7b7eSSam Leffler ath_rate_newstate(sc, nstate); 4634c42a7b7eSSam Leffler 4635c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) { 4636c42a7b7eSSam Leffler /* nothing to do */; 4637c42a7b7eSSam Leffler } else if (nstate == IEEE80211_S_RUN) { 4638c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 4639c42a7b7eSSam Leffler "%s(RUN): ic_flags=0x%08x iv=%d bssid=%s " 46405591b213SSam Leffler "capinfo=0x%04x chan=%d\n" 46415591b213SSam Leffler , __func__ 46425591b213SSam Leffler , ic->ic_flags 46435591b213SSam Leffler , ni->ni_intval 46445591b213SSam Leffler , ether_sprintf(ni->ni_bssid) 46455591b213SSam Leffler , ni->ni_capinfo 4646b5c99415SSam Leffler , ieee80211_chan2ieee(ic, ic->ic_curchan)); 46475591b213SSam Leffler 4648e8fd88a3SSam Leffler switch (ic->ic_opmode) { 4649e8fd88a3SSam Leffler case IEEE80211_M_HOSTAP: 4650e8fd88a3SSam Leffler case IEEE80211_M_IBSS: 46515591b213SSam Leffler /* 4652e8fd88a3SSam Leffler * Allocate and setup the beacon frame. 4653e8fd88a3SSam Leffler * 4654f818612bSSam Leffler * Stop any previous beacon DMA. This may be 4655f818612bSSam Leffler * necessary, for example, when an ibss merge 4656f818612bSSam Leffler * causes reconfiguration; there will be a state 4657f818612bSSam Leffler * transition from RUN->RUN that means we may 4658f818612bSSam Leffler * be called with beacon transmission active. 4659f818612bSSam Leffler */ 4660f818612bSSam Leffler ath_hal_stoptxdma(ah, sc->sc_bhalq); 4661f818612bSSam Leffler ath_beacon_free(sc); 46625591b213SSam Leffler error = ath_beacon_alloc(sc, ni); 46635591b213SSam Leffler if (error != 0) 46645591b213SSam Leffler goto bad; 46657a04dc27SSam Leffler /* 466680d939bfSSam Leffler * If joining an adhoc network defer beacon timer 466780d939bfSSam Leffler * configuration to the next beacon frame so we 466880d939bfSSam Leffler * have a current TSF to use. Otherwise we're 466980d939bfSSam Leffler * starting an ibss/bss so there's no need to delay. 46707a04dc27SSam Leffler */ 467180d939bfSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && 467280d939bfSSam Leffler ic->ic_bss->ni_tstamp.tsf != 0) 467380d939bfSSam Leffler sc->sc_syncbeacon = 1; 467480d939bfSSam Leffler else 46757a04dc27SSam Leffler ath_beacon_config(sc); 4676e8fd88a3SSam Leffler break; 4677e8fd88a3SSam Leffler case IEEE80211_M_STA: 4678e8fd88a3SSam Leffler /* 4679e8fd88a3SSam Leffler * Allocate a key cache slot to the station. 4680e8fd88a3SSam Leffler */ 4681e8fd88a3SSam Leffler if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && 4682e8fd88a3SSam Leffler sc->sc_hasclrkey && 4683e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE) 4684e8fd88a3SSam Leffler ath_setup_stationkey(ni); 46857a04dc27SSam Leffler /* 468680d939bfSSam Leffler * Defer beacon timer configuration to the next 468780d939bfSSam Leffler * beacon frame so we have a current TSF to use 468880d939bfSSam Leffler * (any TSF collected when scanning is likely old). 46897a04dc27SSam Leffler */ 469080d939bfSSam Leffler sc->sc_syncbeacon = 1; 4691e8fd88a3SSam Leffler break; 4692e8fd88a3SSam Leffler default: 4693e8fd88a3SSam Leffler break; 46945591b213SSam Leffler } 46955591b213SSam Leffler 46965591b213SSam Leffler /* 46977b0c77ecSSam Leffler * Let the hal process statistics collected during a 46987b0c77ecSSam Leffler * scan so it can provide calibrated noise floor data. 46997b0c77ecSSam Leffler */ 47007b0c77ecSSam Leffler ath_hal_process_noisefloor(ah); 47017b0c77ecSSam Leffler /* 4702ffa2cab6SSam Leffler * Reset rssi stats; maybe not the best place... 4703ffa2cab6SSam Leffler */ 4704ffa2cab6SSam Leffler sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; 4705ffa2cab6SSam Leffler sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; 4706ffa2cab6SSam Leffler sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; 47075591b213SSam Leffler } else { 4708c42a7b7eSSam Leffler ath_hal_intrset(ah, 4709c42a7b7eSSam Leffler sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); 47105591b213SSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 47115591b213SSam Leffler } 4712c42a7b7eSSam Leffler done: 471345bbf62fSSam Leffler /* 471445bbf62fSSam Leffler * Invoke the parent method to complete the work. 471545bbf62fSSam Leffler */ 4716c42a7b7eSSam Leffler error = sc->sc_newstate(ic, nstate, arg); 4717c42a7b7eSSam Leffler /* 4718c42a7b7eSSam Leffler * Finally, start any timers. 4719c42a7b7eSSam Leffler */ 4720c42a7b7eSSam Leffler if (nstate == IEEE80211_S_RUN) { 4721c42a7b7eSSam Leffler /* start periodic recalibration timer */ 4722bd5a9920SSam Leffler callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, 4723c42a7b7eSSam Leffler ath_calibrate, sc); 4724c42a7b7eSSam Leffler } else if (nstate == IEEE80211_S_SCAN) { 4725c42a7b7eSSam Leffler /* start ap/neighbor scan timer */ 4726c42a7b7eSSam Leffler callout_reset(&sc->sc_scan_ch, (ath_dwelltime * hz) / 1000, 4727c42a7b7eSSam Leffler ath_next_scan, sc); 4728c42a7b7eSSam Leffler } 47295591b213SSam Leffler bad: 47305591b213SSam Leffler return error; 47315591b213SSam Leffler } 47325591b213SSam Leffler 47335591b213SSam Leffler /* 4734e8fd88a3SSam Leffler * Allocate a key cache slot to the station so we can 4735e8fd88a3SSam Leffler * setup a mapping from key index to node. The key cache 4736e8fd88a3SSam Leffler * slot is needed for managing antenna state and for 4737e8fd88a3SSam Leffler * compression when stations do not use crypto. We do 4738e8fd88a3SSam Leffler * it uniliaterally here; if crypto is employed this slot 4739e8fd88a3SSam Leffler * will be reassigned. 4740e8fd88a3SSam Leffler */ 4741e8fd88a3SSam Leffler static void 4742e8fd88a3SSam Leffler ath_setup_stationkey(struct ieee80211_node *ni) 4743e8fd88a3SSam Leffler { 4744e8fd88a3SSam Leffler struct ieee80211com *ic = ni->ni_ic; 4745e8fd88a3SSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 4746c1225b52SSam Leffler ieee80211_keyix keyix, rxkeyix; 4747e8fd88a3SSam Leffler 4748c1225b52SSam Leffler if (!ath_key_alloc(ic, &ni->ni_ucastkey, &keyix, &rxkeyix)) { 4749e8fd88a3SSam Leffler /* 4750e8fd88a3SSam Leffler * Key cache is full; we'll fall back to doing 4751e8fd88a3SSam Leffler * the more expensive lookup in software. Note 4752e8fd88a3SSam Leffler * this also means no h/w compression. 4753e8fd88a3SSam Leffler */ 4754e8fd88a3SSam Leffler /* XXX msg+statistic */ 4755e8fd88a3SSam Leffler } else { 4756c1225b52SSam Leffler /* XXX locking? */ 4757e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix = keyix; 4758c1225b52SSam Leffler ni->ni_ucastkey.wk_rxkeyix = rxkeyix; 4759e8fd88a3SSam Leffler /* NB: this will create a pass-thru key entry */ 4760e8fd88a3SSam Leffler ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, ic->ic_bss); 4761e8fd88a3SSam Leffler } 4762e8fd88a3SSam Leffler } 4763e8fd88a3SSam Leffler 4764e8fd88a3SSam Leffler /* 47655591b213SSam Leffler * Setup driver-specific state for a newly associated node. 47665591b213SSam Leffler * Note that we're called also on a re-associate, the isnew 47675591b213SSam Leffler * param tells us if this is the first time or not. 47685591b213SSam Leffler */ 47695591b213SSam Leffler static void 4770e9962332SSam Leffler ath_newassoc(struct ieee80211_node *ni, int isnew) 47715591b213SSam Leffler { 4772e9962332SSam Leffler struct ieee80211com *ic = ni->ni_ic; 4773c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 47745591b213SSam Leffler 4775c42a7b7eSSam Leffler ath_rate_newassoc(sc, ATH_NODE(ni), isnew); 4776e8fd88a3SSam Leffler if (isnew && 4777e8fd88a3SSam Leffler (ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey) { 4778e8fd88a3SSam Leffler KASSERT(ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE, 4779e8fd88a3SSam Leffler ("new assoc with a unicast key already setup (keyix %u)", 4780e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix)); 4781e8fd88a3SSam Leffler ath_setup_stationkey(ni); 4782e8fd88a3SSam Leffler } 47835591b213SSam Leffler } 47845591b213SSam Leffler 47855591b213SSam Leffler static int 4786aaa70f2fSSam Leffler ath_getchannels(struct ath_softc *sc, 4787aaa70f2fSSam Leffler HAL_REG_DOMAIN rd, HAL_CTRY_CODE cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) 47885591b213SSam Leffler { 4789aaa70f2fSSam Leffler #define COMPAT \ 4790aaa70f2fSSam Leffler (CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE|CHANNEL_HALF|CHANNEL_QUARTER) 4791ae2734b6SSam Leffler #define IS_CHAN_PUBLIC_SAFETY(_c) \ 4792ae2734b6SSam Leffler (((_c)->channelFlags & CHANNEL_5GHZ) && \ 4793ae2734b6SSam Leffler ((_c)->channel > 4940 && (_c)->channel < 4990)) 47945591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4795fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 47965591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 47975591b213SSam Leffler HAL_CHANNEL *chans; 47985591b213SSam Leffler int i, ix, nchan; 4799aaa70f2fSSam Leffler u_int32_t regdomain; 48005591b213SSam Leffler 48015591b213SSam Leffler chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL), 48025591b213SSam Leffler M_TEMP, M_NOWAIT); 48035591b213SSam Leffler if (chans == NULL) { 48045591b213SSam Leffler if_printf(ifp, "unable to allocate channel table\n"); 48055591b213SSam Leffler return ENOMEM; 48065591b213SSam Leffler } 48075591b213SSam Leffler if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, 4808aaa70f2fSSam Leffler NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) { 4809ee7d6840SSam Leffler (void) ath_hal_getregdomain(ah, ®domain); 4810c42a7b7eSSam Leffler if_printf(ifp, "unable to collect channel list from hal; " 4811aaa70f2fSSam Leffler "regdomain likely %u country code %u\n", regdomain, cc); 48125591b213SSam Leffler free(chans, M_TEMP); 48135591b213SSam Leffler return EINVAL; 48145591b213SSam Leffler } 48155591b213SSam Leffler 48165591b213SSam Leffler /* 48175591b213SSam Leffler * Convert HAL channels to ieee80211 ones and insert 48185591b213SSam Leffler * them in the table according to their channel number. 48195591b213SSam Leffler */ 4820aaa70f2fSSam Leffler memset(ic->ic_channels, 0, sizeof(ic->ic_channels)); 48215591b213SSam Leffler for (i = 0; i < nchan; i++) { 48225591b213SSam Leffler HAL_CHANNEL *c = &chans[i]; 4823bd5a9920SSam Leffler u_int16_t flags; 4824bd5a9920SSam Leffler 4825ae2734b6SSam Leffler /* 4826ae2734b6SSam Leffler * XXX we're not ready to handle the ieee number mapping 4827ae2734b6SSam Leffler * for public safety channels as they overlap with any 4828aaa70f2fSSam Leffler * 2GHz channels; for now use a non-public safety 4829aaa70f2fSSam Leffler * numbering that is non-overlapping. 4830ae2734b6SSam Leffler */ 4831bd5a9920SSam Leffler ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags); 4832aaa70f2fSSam Leffler if (IS_CHAN_PUBLIC_SAFETY(c)) 4833aaa70f2fSSam Leffler ix += 37; /* XXX */ 48345591b213SSam Leffler if (ix > IEEE80211_CHAN_MAX) { 4835bd5a9920SSam Leffler if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n", 48365591b213SSam Leffler ix, c->channel, c->channelFlags); 48375591b213SSam Leffler continue; 48385591b213SSam Leffler } 4839bd5a9920SSam Leffler if (ix < 0) { 4840bd5a9920SSam Leffler /* XXX can't handle stuff <2400 right now */ 4841bd5a9920SSam Leffler if (bootverbose) 4842bd5a9920SSam Leffler if_printf(ifp, "hal channel %d (%u/%x) " 4843bd5a9920SSam Leffler "cannot be handled; ignored\n", 4844bd5a9920SSam Leffler ix, c->channel, c->channelFlags); 4845bd5a9920SSam Leffler continue; 4846bd5a9920SSam Leffler } 4847724c193aSSam Leffler if (bootverbose) 4848724c193aSSam Leffler if_printf(ifp, "hal channel %u/%x -> %u\n", 4849724c193aSSam Leffler c->channel, c->channelFlags, ix); 4850bd5a9920SSam Leffler /* 4851bd5a9920SSam Leffler * Calculate net80211 flags; most are compatible 4852bd5a9920SSam Leffler * but some need massaging. Note the static turbo 4853bd5a9920SSam Leffler * conversion can be removed once net80211 is updated 4854bd5a9920SSam Leffler * to understand static vs. dynamic turbo. 4855bd5a9920SSam Leffler */ 4856bd5a9920SSam Leffler flags = c->channelFlags & COMPAT; 4857bd5a9920SSam Leffler if (c->channelFlags & CHANNEL_STURBO) 4858bd5a9920SSam Leffler flags |= IEEE80211_CHAN_TURBO; 4859724c193aSSam Leffler if (ath_hal_isgsmsku(ah)) { 4860724c193aSSam Leffler /* remap to true frequencies */ 4861724c193aSSam Leffler c->channel = 922 + (2422 - c->channel); 4862724c193aSSam Leffler flags |= IEEE80211_CHAN_GSM; 4863724c193aSSam Leffler ix = ieee80211_mhz2ieee(c->channel, flags); 4864724c193aSSam Leffler } 48655591b213SSam Leffler if (ic->ic_channels[ix].ic_freq == 0) { 48665591b213SSam Leffler ic->ic_channels[ix].ic_freq = c->channel; 4867bd5a9920SSam Leffler ic->ic_channels[ix].ic_flags = flags; 48685591b213SSam Leffler } else { 48695591b213SSam Leffler /* channels overlap; e.g. 11g and 11b */ 4870bd5a9920SSam Leffler ic->ic_channels[ix].ic_flags |= flags; 48715591b213SSam Leffler } 48725591b213SSam Leffler } 48735591b213SSam Leffler free(chans, M_TEMP); 4874ee7d6840SSam Leffler (void) ath_hal_getregdomain(ah, &sc->sc_regdomain); 4875aaa70f2fSSam Leffler ath_hal_getcountrycode(ah, &sc->sc_countrycode); 4876aaa70f2fSSam Leffler sc->sc_xchanmode = xchanmode; 4877aaa70f2fSSam Leffler sc->sc_outdoor = outdoor; 48785591b213SSam Leffler return 0; 4879ae2734b6SSam Leffler #undef IS_CHAN_PUBLIC_SAFETY 4880bd5a9920SSam Leffler #undef COMPAT 48815591b213SSam Leffler } 48825591b213SSam Leffler 4883c42a7b7eSSam Leffler static void 48843e50ec2cSSam Leffler ath_led_done(void *arg) 4885c42a7b7eSSam Leffler { 48863e50ec2cSSam Leffler struct ath_softc *sc = arg; 48873e50ec2cSSam Leffler 48883e50ec2cSSam Leffler sc->sc_blinking = 0; 48893e50ec2cSSam Leffler } 4890c42a7b7eSSam Leffler 4891c42a7b7eSSam Leffler /* 48923e50ec2cSSam Leffler * Turn the LED off: flip the pin and then set a timer so no 48933e50ec2cSSam Leffler * update will happen for the specified duration. 4894c42a7b7eSSam Leffler */ 48953e50ec2cSSam Leffler static void 48963e50ec2cSSam Leffler ath_led_off(void *arg) 48973e50ec2cSSam Leffler { 48983e50ec2cSSam Leffler struct ath_softc *sc = arg; 48993e50ec2cSSam Leffler 49003e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); 49013e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc); 4902c42a7b7eSSam Leffler } 49033e50ec2cSSam Leffler 49043e50ec2cSSam Leffler /* 49053e50ec2cSSam Leffler * Blink the LED according to the specified on/off times. 49063e50ec2cSSam Leffler */ 49073e50ec2cSSam Leffler static void 49083e50ec2cSSam Leffler ath_led_blink(struct ath_softc *sc, int on, int off) 49093e50ec2cSSam Leffler { 49103e50ec2cSSam Leffler DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off); 49113e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon); 49123e50ec2cSSam Leffler sc->sc_blinking = 1; 49133e50ec2cSSam Leffler sc->sc_ledoff = off; 49143e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc); 49153e50ec2cSSam Leffler } 49163e50ec2cSSam Leffler 49173e50ec2cSSam Leffler static void 49183e50ec2cSSam Leffler ath_led_event(struct ath_softc *sc, int event) 49193e50ec2cSSam Leffler { 49203e50ec2cSSam Leffler 49213e50ec2cSSam Leffler sc->sc_ledevent = ticks; /* time of last event */ 49223e50ec2cSSam Leffler if (sc->sc_blinking) /* don't interrupt active blink */ 49233e50ec2cSSam Leffler return; 49243e50ec2cSSam Leffler switch (event) { 49253e50ec2cSSam Leffler case ATH_LED_POLL: 49263e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[0].ledon, 49273e50ec2cSSam Leffler sc->sc_hwmap[0].ledoff); 49283e50ec2cSSam Leffler break; 49293e50ec2cSSam Leffler case ATH_LED_TX: 49303e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[sc->sc_txrate].ledon, 49313e50ec2cSSam Leffler sc->sc_hwmap[sc->sc_txrate].ledoff); 49323e50ec2cSSam Leffler break; 49333e50ec2cSSam Leffler case ATH_LED_RX: 49343e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[sc->sc_rxrate].ledon, 49353e50ec2cSSam Leffler sc->sc_hwmap[sc->sc_rxrate].ledoff); 49363e50ec2cSSam Leffler break; 4937c42a7b7eSSam Leffler } 4938c42a7b7eSSam Leffler } 4939c42a7b7eSSam Leffler 4940c42a7b7eSSam Leffler static void 4941c42a7b7eSSam Leffler ath_update_txpow(struct ath_softc *sc) 4942c42a7b7eSSam Leffler { 4943c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4944c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4945c42a7b7eSSam Leffler u_int32_t txpow; 4946c42a7b7eSSam Leffler 4947c42a7b7eSSam Leffler if (sc->sc_curtxpow != ic->ic_txpowlimit) { 4948c42a7b7eSSam Leffler ath_hal_settxpowlimit(ah, ic->ic_txpowlimit); 4949c42a7b7eSSam Leffler /* read back in case value is clamped */ 4950ee7d6840SSam Leffler if (ath_hal_gettxpowlimit(ah, &txpow)) 4951c42a7b7eSSam Leffler ic->ic_txpowlimit = sc->sc_curtxpow = txpow; 4952c42a7b7eSSam Leffler } 4953c42a7b7eSSam Leffler /* 4954c42a7b7eSSam Leffler * Fetch max tx power level for status requests. 4955c42a7b7eSSam Leffler */ 4956ee7d6840SSam Leffler if (ath_hal_getmaxtxpow(sc->sc_ah, &txpow)) 4957c42a7b7eSSam Leffler ic->ic_bss->ni_txpower = txpow; 4958c42a7b7eSSam Leffler } 4959c42a7b7eSSam Leffler 49606c4612b9SSam Leffler static int 49616c4612b9SSam Leffler ath_rate_setup(struct ath_softc *sc, u_int mode) 49626c4612b9SSam Leffler { 49636c4612b9SSam Leffler struct ath_hal *ah = sc->sc_ah; 49646c4612b9SSam Leffler const HAL_RATE_TABLE *rt; 49656c4612b9SSam Leffler 49666c4612b9SSam Leffler switch (mode) { 49676c4612b9SSam Leffler case IEEE80211_MODE_11A: 49686c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A); 49696c4612b9SSam Leffler break; 4970724c193aSSam Leffler case IEEE80211_MODE_HALF: 4971aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE); 4972aaa70f2fSSam Leffler break; 4973724c193aSSam Leffler case IEEE80211_MODE_QUARTER: 4974aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE); 4975aaa70f2fSSam Leffler break; 49766c4612b9SSam Leffler case IEEE80211_MODE_11B: 49776c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11B); 49786c4612b9SSam Leffler break; 49796c4612b9SSam Leffler case IEEE80211_MODE_11G: 49806c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11G); 49816c4612b9SSam Leffler break; 49826c4612b9SSam Leffler case IEEE80211_MODE_TURBO_A: 49836c4612b9SSam Leffler /* XXX until static/dynamic turbo is fixed */ 49846c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_TURBO); 49856c4612b9SSam Leffler break; 49866c4612b9SSam Leffler case IEEE80211_MODE_TURBO_G: 49876c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_108G); 49886c4612b9SSam Leffler break; 49896c4612b9SSam Leffler default: 49906c4612b9SSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid mode %u\n", 49916c4612b9SSam Leffler __func__, mode); 49926c4612b9SSam Leffler return 0; 49936c4612b9SSam Leffler } 49946c4612b9SSam Leffler sc->sc_rates[mode] = rt; 4995aaa70f2fSSam Leffler return (rt != NULL); 49965591b213SSam Leffler } 49975591b213SSam Leffler 49985591b213SSam Leffler static void 49995591b213SSam Leffler ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) 50005591b213SSam Leffler { 50013e50ec2cSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 50023e50ec2cSSam Leffler /* NB: on/off times from the Atheros NDIS driver, w/ permission */ 50033e50ec2cSSam Leffler static const struct { 50043e50ec2cSSam Leffler u_int rate; /* tx/rx 802.11 rate */ 50053e50ec2cSSam Leffler u_int16_t timeOn; /* LED on time (ms) */ 50063e50ec2cSSam Leffler u_int16_t timeOff; /* LED off time (ms) */ 50073e50ec2cSSam Leffler } blinkrates[] = { 50083e50ec2cSSam Leffler { 108, 40, 10 }, 50093e50ec2cSSam Leffler { 96, 44, 11 }, 50103e50ec2cSSam Leffler { 72, 50, 13 }, 50113e50ec2cSSam Leffler { 48, 57, 14 }, 50123e50ec2cSSam Leffler { 36, 67, 16 }, 50133e50ec2cSSam Leffler { 24, 80, 20 }, 50143e50ec2cSSam Leffler { 22, 100, 25 }, 50153e50ec2cSSam Leffler { 18, 133, 34 }, 50163e50ec2cSSam Leffler { 12, 160, 40 }, 50173e50ec2cSSam Leffler { 10, 200, 50 }, 50183e50ec2cSSam Leffler { 6, 240, 58 }, 50193e50ec2cSSam Leffler { 4, 267, 66 }, 50203e50ec2cSSam Leffler { 2, 400, 100 }, 50213e50ec2cSSam Leffler { 0, 500, 130 }, 5022724c193aSSam Leffler /* XXX half/quarter rates */ 50233e50ec2cSSam Leffler }; 50245591b213SSam Leffler const HAL_RATE_TABLE *rt; 50253e50ec2cSSam Leffler int i, j; 50265591b213SSam Leffler 50275591b213SSam Leffler memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); 50285591b213SSam Leffler rt = sc->sc_rates[mode]; 50295591b213SSam Leffler KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode)); 50305591b213SSam Leffler for (i = 0; i < rt->rateCount; i++) 50315591b213SSam Leffler sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; 50321b1a8e41SSam Leffler memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); 5033c42a7b7eSSam Leffler for (i = 0; i < 32; i++) { 5034c42a7b7eSSam Leffler u_int8_t ix = rt->rateCodeToIndex[i]; 50353e50ec2cSSam Leffler if (ix == 0xff) { 50363e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (500 * hz) / 1000; 50373e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (130 * hz) / 1000; 503816b4851aSSam Leffler continue; 50393e50ec2cSSam Leffler } 50403e50ec2cSSam Leffler sc->sc_hwmap[i].ieeerate = 50413e50ec2cSSam Leffler rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; 5042d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; 504316b4851aSSam Leffler if (rt->info[ix].shortPreamble || 504416b4851aSSam Leffler rt->info[ix].phy == IEEE80211_T_OFDM) 5045d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags |= IEEE80211_RADIOTAP_F_SHORTPRE; 5046d3be6f5bSSam Leffler /* NB: receive frames include FCS */ 5047d3be6f5bSSam Leffler sc->sc_hwmap[i].rxflags = sc->sc_hwmap[i].txflags | 5048d3be6f5bSSam Leffler IEEE80211_RADIOTAP_F_FCS; 50493e50ec2cSSam Leffler /* setup blink rate table to avoid per-packet lookup */ 50503e50ec2cSSam Leffler for (j = 0; j < N(blinkrates)-1; j++) 50513e50ec2cSSam Leffler if (blinkrates[j].rate == sc->sc_hwmap[i].ieeerate) 50523e50ec2cSSam Leffler break; 50533e50ec2cSSam Leffler /* NB: this uses the last entry if the rate isn't found */ 50543e50ec2cSSam Leffler /* XXX beware of overlow */ 50553e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (blinkrates[j].timeOn * hz) / 1000; 50563e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (blinkrates[j].timeOff * hz) / 1000; 5057c42a7b7eSSam Leffler } 50585591b213SSam Leffler sc->sc_currates = rt; 50595591b213SSam Leffler sc->sc_curmode = mode; 50605591b213SSam Leffler /* 5061c42a7b7eSSam Leffler * All protection frames are transmited at 2Mb/s for 5062c42a7b7eSSam Leffler * 11g, otherwise at 1Mb/s. 50635591b213SSam Leffler */ 5064913a1ba1SSam Leffler if (mode == IEEE80211_MODE_11G) 5065913a1ba1SSam Leffler sc->sc_protrix = ath_tx_findrix(rt, 2*2); 5066913a1ba1SSam Leffler else 5067913a1ba1SSam Leffler sc->sc_protrix = ath_tx_findrix(rt, 2*1); 506855f63772SSam Leffler /* rate index used to send management frames */ 506955f63772SSam Leffler sc->sc_minrateix = 0; 50708b5341deSSam Leffler /* 50718b5341deSSam Leffler * Setup multicast rate state. 50728b5341deSSam Leffler */ 50738b5341deSSam Leffler /* XXX layering violation */ 50748b5341deSSam Leffler sc->sc_mcastrix = ath_tx_findrix(rt, sc->sc_ic.ic_mcast_rate); 50758b5341deSSam Leffler sc->sc_mcastrate = sc->sc_ic.ic_mcast_rate; 5076c42a7b7eSSam Leffler /* NB: caller is responsible for reseting rate control state */ 50773e50ec2cSSam Leffler #undef N 50785591b213SSam Leffler } 50795591b213SSam Leffler 5080a585a9a1SSam Leffler #ifdef ATH_DEBUG 50815591b213SSam Leffler static void 508265f9edeeSSam Leffler ath_printrxbuf(const struct ath_buf *bf, u_int ix, int done) 50835591b213SSam Leffler { 508465f9edeeSSam Leffler const struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; 508565f9edeeSSam Leffler const struct ath_desc *ds; 50865591b213SSam Leffler int i; 50875591b213SSam Leffler 50885591b213SSam Leffler for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { 50897a4c5ed9SSam Leffler printf("R[%2u] (DS.V:%p DS.P:%p) L:%08x D:%08x%s\n" 50907a4c5ed9SSam Leffler " %08x %08x %08x %08x\n", 509165f9edeeSSam Leffler ix, ds, (const struct ath_desc *)bf->bf_daddr + i, 50925591b213SSam Leffler ds->ds_link, ds->ds_data, 509365f9edeeSSam Leffler !done ? "" : (rs->rs_status == 0) ? " *" : " !", 50945591b213SSam Leffler ds->ds_ctl0, ds->ds_ctl1, 50957a4c5ed9SSam Leffler ds->ds_hw[0], ds->ds_hw[1]); 50965591b213SSam Leffler } 50975591b213SSam Leffler } 50985591b213SSam Leffler 50995591b213SSam Leffler static void 510065f9edeeSSam Leffler ath_printtxbuf(const struct ath_buf *bf, u_int qnum, u_int ix, int done) 51015591b213SSam Leffler { 510265f9edeeSSam Leffler const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; 510365f9edeeSSam Leffler const struct ath_desc *ds; 51045591b213SSam Leffler int i; 51055591b213SSam Leffler 51067a4c5ed9SSam Leffler printf("Q%u[%3u]", qnum, ix); 51075591b213SSam Leffler for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { 5108ebecf802SSam Leffler printf(" (DS.V:%p DS.P:%p) L:%08x D:%08x F:04%x%s\n" 51097a4c5ed9SSam Leffler " %08x %08x %08x %08x %08x %08x\n", 511065f9edeeSSam Leffler ds, (const struct ath_desc *)bf->bf_daddr + i, 5111ebecf802SSam Leffler ds->ds_link, ds->ds_data, bf->bf_flags, 511265f9edeeSSam Leffler !done ? "" : (ts->ts_status == 0) ? " *" : " !", 51135591b213SSam Leffler ds->ds_ctl0, ds->ds_ctl1, 51147a4c5ed9SSam Leffler ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3]); 51155591b213SSam Leffler } 51165591b213SSam Leffler } 5117a585a9a1SSam Leffler #endif /* ATH_DEBUG */ 5118c42a7b7eSSam Leffler 5119c42a7b7eSSam Leffler static void 5120c42a7b7eSSam Leffler ath_watchdog(struct ifnet *ifp) 5121c42a7b7eSSam Leffler { 5122c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 5123c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5124c42a7b7eSSam Leffler 5125c42a7b7eSSam Leffler ifp->if_timer = 0; 512613f4c340SRobert Watson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) 5127c42a7b7eSSam Leffler return; 5128c42a7b7eSSam Leffler if (sc->sc_tx_timer) { 5129c42a7b7eSSam Leffler if (--sc->sc_tx_timer == 0) { 5130c42a7b7eSSam Leffler if_printf(ifp, "device timeout\n"); 5131c42a7b7eSSam Leffler ath_reset(ifp); 5132c42a7b7eSSam Leffler ifp->if_oerrors++; 5133c42a7b7eSSam Leffler sc->sc_stats.ast_watchdog++; 5134c42a7b7eSSam Leffler } else 5135c42a7b7eSSam Leffler ifp->if_timer = 1; 5136c42a7b7eSSam Leffler } 5137c42a7b7eSSam Leffler ieee80211_watchdog(ic); 5138c42a7b7eSSam Leffler } 5139c42a7b7eSSam Leffler 5140a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5141c42a7b7eSSam Leffler /* 5142c42a7b7eSSam Leffler * Diagnostic interface to the HAL. This is used by various 5143c42a7b7eSSam Leffler * tools to do things like retrieve register contents for 5144c42a7b7eSSam Leffler * debugging. The mechanism is intentionally opaque so that 5145c42a7b7eSSam Leffler * it can change frequently w/o concern for compatiblity. 5146c42a7b7eSSam Leffler */ 5147c42a7b7eSSam Leffler static int 5148c42a7b7eSSam Leffler ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) 5149c42a7b7eSSam Leffler { 5150c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5151c42a7b7eSSam Leffler u_int id = ad->ad_id & ATH_DIAG_ID; 5152c42a7b7eSSam Leffler void *indata = NULL; 5153c42a7b7eSSam Leffler void *outdata = NULL; 5154c42a7b7eSSam Leffler u_int32_t insize = ad->ad_in_size; 5155c42a7b7eSSam Leffler u_int32_t outsize = ad->ad_out_size; 5156c42a7b7eSSam Leffler int error = 0; 5157c42a7b7eSSam Leffler 5158c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_IN) { 5159c42a7b7eSSam Leffler /* 5160c42a7b7eSSam Leffler * Copy in data. 5161c42a7b7eSSam Leffler */ 5162c42a7b7eSSam Leffler indata = malloc(insize, M_TEMP, M_NOWAIT); 5163c42a7b7eSSam Leffler if (indata == NULL) { 5164c42a7b7eSSam Leffler error = ENOMEM; 5165c42a7b7eSSam Leffler goto bad; 5166c42a7b7eSSam Leffler } 5167c42a7b7eSSam Leffler error = copyin(ad->ad_in_data, indata, insize); 5168c42a7b7eSSam Leffler if (error) 5169c42a7b7eSSam Leffler goto bad; 5170c42a7b7eSSam Leffler } 5171c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_DYN) { 5172c42a7b7eSSam Leffler /* 5173c42a7b7eSSam Leffler * Allocate a buffer for the results (otherwise the HAL 5174c42a7b7eSSam Leffler * returns a pointer to a buffer where we can read the 5175c42a7b7eSSam Leffler * results). Note that we depend on the HAL leaving this 5176c42a7b7eSSam Leffler * pointer for us to use below in reclaiming the buffer; 5177c42a7b7eSSam Leffler * may want to be more defensive. 5178c42a7b7eSSam Leffler */ 5179c42a7b7eSSam Leffler outdata = malloc(outsize, M_TEMP, M_NOWAIT); 5180c42a7b7eSSam Leffler if (outdata == NULL) { 5181c42a7b7eSSam Leffler error = ENOMEM; 5182c42a7b7eSSam Leffler goto bad; 5183c42a7b7eSSam Leffler } 5184c42a7b7eSSam Leffler } 5185c42a7b7eSSam Leffler if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { 5186c42a7b7eSSam Leffler if (outsize < ad->ad_out_size) 5187c42a7b7eSSam Leffler ad->ad_out_size = outsize; 5188c42a7b7eSSam Leffler if (outdata != NULL) 5189c42a7b7eSSam Leffler error = copyout(outdata, ad->ad_out_data, 5190c42a7b7eSSam Leffler ad->ad_out_size); 5191c42a7b7eSSam Leffler } else { 5192c42a7b7eSSam Leffler error = EINVAL; 5193c42a7b7eSSam Leffler } 5194c42a7b7eSSam Leffler bad: 5195c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 5196c42a7b7eSSam Leffler free(indata, M_TEMP); 5197c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 5198c42a7b7eSSam Leffler free(outdata, M_TEMP); 5199c42a7b7eSSam Leffler return error; 5200c42a7b7eSSam Leffler } 5201a585a9a1SSam Leffler #endif /* ATH_DIAGAPI */ 5202c42a7b7eSSam Leffler 5203c42a7b7eSSam Leffler static int 5204c42a7b7eSSam Leffler ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 5205c42a7b7eSSam Leffler { 5206c42a7b7eSSam Leffler #define IS_RUNNING(ifp) \ 520713f4c340SRobert Watson ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 5208c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 5209c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5210c42a7b7eSSam Leffler struct ifreq *ifr = (struct ifreq *)data; 5211c42a7b7eSSam Leffler int error = 0; 5212c42a7b7eSSam Leffler 5213c42a7b7eSSam Leffler ATH_LOCK(sc); 5214c42a7b7eSSam Leffler switch (cmd) { 5215c42a7b7eSSam Leffler case SIOCSIFFLAGS: 5216c42a7b7eSSam Leffler if (IS_RUNNING(ifp)) { 5217c42a7b7eSSam Leffler /* 5218c42a7b7eSSam Leffler * To avoid rescanning another access point, 5219c42a7b7eSSam Leffler * do not call ath_init() here. Instead, 5220c42a7b7eSSam Leffler * only reflect promisc mode settings. 5221c42a7b7eSSam Leffler */ 5222c42a7b7eSSam Leffler ath_mode_init(sc); 5223c42a7b7eSSam Leffler } else if (ifp->if_flags & IFF_UP) { 5224c42a7b7eSSam Leffler /* 5225c42a7b7eSSam Leffler * Beware of being called during attach/detach 5226c42a7b7eSSam Leffler * to reset promiscuous mode. In that case we 5227c42a7b7eSSam Leffler * will still be marked UP but not RUNNING. 5228c42a7b7eSSam Leffler * However trying to re-init the interface 5229c42a7b7eSSam Leffler * is the wrong thing to do as we've already 5230c42a7b7eSSam Leffler * torn down much of our state. There's 5231c42a7b7eSSam Leffler * probably a better way to deal with this. 5232c42a7b7eSSam Leffler */ 5233c42a7b7eSSam Leffler if (!sc->sc_invalid && ic->ic_bss != NULL) 5234fc74a9f9SBrooks Davis ath_init(sc); /* XXX lose error */ 5235c42a7b7eSSam Leffler } else 5236c42a7b7eSSam Leffler ath_stop_locked(ifp); 5237c42a7b7eSSam Leffler break; 5238c42a7b7eSSam Leffler case SIOCADDMULTI: 5239c42a7b7eSSam Leffler case SIOCDELMULTI: 5240c42a7b7eSSam Leffler /* 5241c42a7b7eSSam Leffler * The upper layer has already installed/removed 5242c42a7b7eSSam Leffler * the multicast address(es), just recalculate the 5243c42a7b7eSSam Leffler * multicast filter for the card. 5244c42a7b7eSSam Leffler */ 524513f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 5246c42a7b7eSSam Leffler ath_mode_init(sc); 5247c42a7b7eSSam Leffler break; 5248c42a7b7eSSam Leffler case SIOCGATHSTATS: 5249c42a7b7eSSam Leffler /* NB: embed these numbers to get a consistent view */ 5250c42a7b7eSSam Leffler sc->sc_stats.ast_tx_packets = ifp->if_opackets; 5251c42a7b7eSSam Leffler sc->sc_stats.ast_rx_packets = ifp->if_ipackets; 5252c42a7b7eSSam Leffler sc->sc_stats.ast_rx_rssi = ieee80211_getrssi(ic); 52536bf62dd1SSam Leffler sc->sc_stats.ast_rx_noise = 52546bf62dd1SSam Leffler ath_hal_getchannoise(sc->sc_ah, &sc->sc_curchan); 52556bf62dd1SSam Leffler sc->sc_stats.ast_tx_rate = sc->sc_hwmap[sc->sc_txrate].ieeerate; 5256c42a7b7eSSam Leffler ATH_UNLOCK(sc); 5257c42a7b7eSSam Leffler /* 5258c42a7b7eSSam Leffler * NB: Drop the softc lock in case of a page fault; 5259c42a7b7eSSam Leffler * we'll accept any potential inconsisentcy in the 5260c42a7b7eSSam Leffler * statistics. The alternative is to copy the data 5261c42a7b7eSSam Leffler * to a local structure. 5262c42a7b7eSSam Leffler */ 5263c42a7b7eSSam Leffler return copyout(&sc->sc_stats, 5264c42a7b7eSSam Leffler ifr->ifr_data, sizeof (sc->sc_stats)); 5265a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5266c42a7b7eSSam Leffler case SIOCGATHDIAG: 52671d89d44fSSam Leffler ATH_UNLOCK(sc); 5268c42a7b7eSSam Leffler error = ath_ioctl_diag(sc, (struct ath_diag *) ifr); 52691d89d44fSSam Leffler ATH_LOCK(sc); 5270c42a7b7eSSam Leffler break; 5271a585a9a1SSam Leffler #endif 5272c42a7b7eSSam Leffler default: 5273c42a7b7eSSam Leffler error = ieee80211_ioctl(ic, cmd, data); 5274c42a7b7eSSam Leffler if (error == ENETRESET) { 5275c42a7b7eSSam Leffler if (IS_RUNNING(ifp) && 5276c42a7b7eSSam Leffler ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 5277fc74a9f9SBrooks Davis ath_init(sc); /* XXX lose error */ 5278c42a7b7eSSam Leffler error = 0; 5279c42a7b7eSSam Leffler } 5280c42a7b7eSSam Leffler if (error == ERESTART) 5281c42a7b7eSSam Leffler error = IS_RUNNING(ifp) ? ath_reset(ifp) : 0; 5282c42a7b7eSSam Leffler break; 5283c42a7b7eSSam Leffler } 5284c42a7b7eSSam Leffler ATH_UNLOCK(sc); 5285c42a7b7eSSam Leffler return error; 5286a614e076SSam Leffler #undef IS_RUNNING 5287c42a7b7eSSam Leffler } 5288c42a7b7eSSam Leffler 5289c42a7b7eSSam Leffler static int 5290c42a7b7eSSam Leffler ath_sysctl_slottime(SYSCTL_HANDLER_ARGS) 5291c42a7b7eSSam Leffler { 5292c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5293c42a7b7eSSam Leffler u_int slottime = ath_hal_getslottime(sc->sc_ah); 5294c42a7b7eSSam Leffler int error; 5295c42a7b7eSSam Leffler 5296c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &slottime, 0, req); 5297c42a7b7eSSam Leffler if (error || !req->newptr) 5298c42a7b7eSSam Leffler return error; 5299c42a7b7eSSam Leffler return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; 5300c42a7b7eSSam Leffler } 5301c42a7b7eSSam Leffler 5302c42a7b7eSSam Leffler static int 5303c42a7b7eSSam Leffler ath_sysctl_acktimeout(SYSCTL_HANDLER_ARGS) 5304c42a7b7eSSam Leffler { 5305c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5306c42a7b7eSSam Leffler u_int acktimeout = ath_hal_getacktimeout(sc->sc_ah); 5307c42a7b7eSSam Leffler int error; 5308c42a7b7eSSam Leffler 5309c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &acktimeout, 0, req); 5310c42a7b7eSSam Leffler if (error || !req->newptr) 5311c42a7b7eSSam Leffler return error; 5312c42a7b7eSSam Leffler return !ath_hal_setacktimeout(sc->sc_ah, acktimeout) ? EINVAL : 0; 5313c42a7b7eSSam Leffler } 5314c42a7b7eSSam Leffler 5315c42a7b7eSSam Leffler static int 5316c42a7b7eSSam Leffler ath_sysctl_ctstimeout(SYSCTL_HANDLER_ARGS) 5317c42a7b7eSSam Leffler { 5318c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5319c42a7b7eSSam Leffler u_int ctstimeout = ath_hal_getctstimeout(sc->sc_ah); 5320c42a7b7eSSam Leffler int error; 5321c42a7b7eSSam Leffler 5322c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &ctstimeout, 0, req); 5323c42a7b7eSSam Leffler if (error || !req->newptr) 5324c42a7b7eSSam Leffler return error; 5325c42a7b7eSSam Leffler return !ath_hal_setctstimeout(sc->sc_ah, ctstimeout) ? EINVAL : 0; 5326c42a7b7eSSam Leffler } 5327c42a7b7eSSam Leffler 5328c42a7b7eSSam Leffler static int 5329c42a7b7eSSam Leffler ath_sysctl_softled(SYSCTL_HANDLER_ARGS) 5330c42a7b7eSSam Leffler { 5331c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5332c42a7b7eSSam Leffler int softled = sc->sc_softled; 5333c42a7b7eSSam Leffler int error; 5334c42a7b7eSSam Leffler 5335c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &softled, 0, req); 5336c42a7b7eSSam Leffler if (error || !req->newptr) 5337c42a7b7eSSam Leffler return error; 53383e50ec2cSSam Leffler softled = (softled != 0); 5339c42a7b7eSSam Leffler if (softled != sc->sc_softled) { 53403e50ec2cSSam Leffler if (softled) { 53413e50ec2cSSam Leffler /* NB: handle any sc_ledpin change */ 5342c42a7b7eSSam Leffler ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); 53433e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, 53443e50ec2cSSam Leffler !sc->sc_ledon); 53453e50ec2cSSam Leffler } 5346c42a7b7eSSam Leffler sc->sc_softled = softled; 5347c42a7b7eSSam Leffler } 5348c42a7b7eSSam Leffler return 0; 5349c42a7b7eSSam Leffler } 5350c42a7b7eSSam Leffler 5351c42a7b7eSSam Leffler static int 5352b298baf2SSam Leffler ath_sysctl_ledpin(SYSCTL_HANDLER_ARGS) 5353b298baf2SSam Leffler { 5354b298baf2SSam Leffler struct ath_softc *sc = arg1; 5355b298baf2SSam Leffler int ledpin = sc->sc_ledpin; 5356b298baf2SSam Leffler int error; 5357b298baf2SSam Leffler 5358b298baf2SSam Leffler error = sysctl_handle_int(oidp, &ledpin, 0, req); 5359b298baf2SSam Leffler if (error || !req->newptr) 5360b298baf2SSam Leffler return error; 5361b298baf2SSam Leffler if (ledpin != sc->sc_ledpin) { 5362b298baf2SSam Leffler sc->sc_ledpin = ledpin; 5363b298baf2SSam Leffler if (sc->sc_softled) { 5364b298baf2SSam Leffler ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); 5365b298baf2SSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, 5366b298baf2SSam Leffler !sc->sc_ledon); 5367b298baf2SSam Leffler } 5368b298baf2SSam Leffler } 5369b298baf2SSam Leffler return 0; 5370b298baf2SSam Leffler } 5371b298baf2SSam Leffler 5372b298baf2SSam Leffler static int 53738debcae4SSam Leffler ath_sysctl_txantenna(SYSCTL_HANDLER_ARGS) 53748debcae4SSam Leffler { 53758debcae4SSam Leffler struct ath_softc *sc = arg1; 53768debcae4SSam Leffler u_int txantenna = ath_hal_getantennaswitch(sc->sc_ah); 53778debcae4SSam Leffler int error; 53788debcae4SSam Leffler 53798debcae4SSam Leffler error = sysctl_handle_int(oidp, &txantenna, 0, req); 53808debcae4SSam Leffler if (!error && req->newptr) { 53818debcae4SSam Leffler /* XXX assumes 2 antenna ports */ 53828debcae4SSam Leffler if (txantenna < HAL_ANT_VARIABLE || txantenna > HAL_ANT_FIXED_B) 53838debcae4SSam Leffler return EINVAL; 53848debcae4SSam Leffler ath_hal_setantennaswitch(sc->sc_ah, txantenna); 53858debcae4SSam Leffler /* 53868debcae4SSam Leffler * NB: with the switch locked this isn't meaningful, 53878debcae4SSam Leffler * but set it anyway so things like radiotap get 53888debcae4SSam Leffler * consistent info in their data. 53898debcae4SSam Leffler */ 53908debcae4SSam Leffler sc->sc_txantenna = txantenna; 53918debcae4SSam Leffler } 53928debcae4SSam Leffler return error; 53938debcae4SSam Leffler } 53948debcae4SSam Leffler 53958debcae4SSam Leffler static int 5396c42a7b7eSSam Leffler ath_sysctl_rxantenna(SYSCTL_HANDLER_ARGS) 5397c42a7b7eSSam Leffler { 5398c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5399c42a7b7eSSam Leffler u_int defantenna = ath_hal_getdefantenna(sc->sc_ah); 5400c42a7b7eSSam Leffler int error; 5401c42a7b7eSSam Leffler 5402c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &defantenna, 0, req); 5403c42a7b7eSSam Leffler if (!error && req->newptr) 5404c42a7b7eSSam Leffler ath_hal_setdefantenna(sc->sc_ah, defantenna); 5405c42a7b7eSSam Leffler return error; 5406c42a7b7eSSam Leffler } 5407c42a7b7eSSam Leffler 5408c42a7b7eSSam Leffler static int 5409c42a7b7eSSam Leffler ath_sysctl_diversity(SYSCTL_HANDLER_ARGS) 5410c42a7b7eSSam Leffler { 5411c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5412c59005e9SSam Leffler u_int diversity = ath_hal_getdiversity(sc->sc_ah); 5413c42a7b7eSSam Leffler int error; 5414c42a7b7eSSam Leffler 5415c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &diversity, 0, req); 5416c42a7b7eSSam Leffler if (error || !req->newptr) 5417c42a7b7eSSam Leffler return error; 5418c59005e9SSam Leffler if (!ath_hal_setdiversity(sc->sc_ah, diversity)) 5419c59005e9SSam Leffler return EINVAL; 5420c42a7b7eSSam Leffler sc->sc_diversity = diversity; 5421c59005e9SSam Leffler return 0; 5422c42a7b7eSSam Leffler } 5423c42a7b7eSSam Leffler 5424c42a7b7eSSam Leffler static int 5425c42a7b7eSSam Leffler ath_sysctl_diag(SYSCTL_HANDLER_ARGS) 5426c42a7b7eSSam Leffler { 5427c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5428c42a7b7eSSam Leffler u_int32_t diag; 5429c42a7b7eSSam Leffler int error; 5430c42a7b7eSSam Leffler 5431c42a7b7eSSam Leffler if (!ath_hal_getdiag(sc->sc_ah, &diag)) 5432c42a7b7eSSam Leffler return EINVAL; 5433c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &diag, 0, req); 5434c42a7b7eSSam Leffler if (error || !req->newptr) 5435c42a7b7eSSam Leffler return error; 5436c42a7b7eSSam Leffler return !ath_hal_setdiag(sc->sc_ah, diag) ? EINVAL : 0; 5437c42a7b7eSSam Leffler } 5438c42a7b7eSSam Leffler 5439c42a7b7eSSam Leffler static int 5440c42a7b7eSSam Leffler ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) 5441c42a7b7eSSam Leffler { 5442c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5443fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5444c42a7b7eSSam Leffler u_int32_t scale; 5445c42a7b7eSSam Leffler int error; 5446c42a7b7eSSam Leffler 5447ee7d6840SSam Leffler (void) ath_hal_gettpscale(sc->sc_ah, &scale); 5448c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &scale, 0, req); 5449c42a7b7eSSam Leffler if (error || !req->newptr) 5450c42a7b7eSSam Leffler return error; 545116d84e01SSam Leffler return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : 545216d84e01SSam Leffler (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0; 5453c42a7b7eSSam Leffler } 5454c42a7b7eSSam Leffler 5455c42a7b7eSSam Leffler static int 5456c42a7b7eSSam Leffler ath_sysctl_tpc(SYSCTL_HANDLER_ARGS) 5457c42a7b7eSSam Leffler { 5458c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5459c42a7b7eSSam Leffler u_int tpc = ath_hal_gettpc(sc->sc_ah); 5460c42a7b7eSSam Leffler int error; 5461c42a7b7eSSam Leffler 5462c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &tpc, 0, req); 5463c42a7b7eSSam Leffler if (error || !req->newptr) 5464c42a7b7eSSam Leffler return error; 5465c42a7b7eSSam Leffler return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0; 5466c42a7b7eSSam Leffler } 5467c42a7b7eSSam Leffler 546817f3f177SSam Leffler static int 5469bd5a9920SSam Leffler ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) 5470bd5a9920SSam Leffler { 5471bd5a9920SSam Leffler struct ath_softc *sc = arg1; 547216d84e01SSam Leffler struct ifnet *ifp = sc->sc_ifp; 5473bd5a9920SSam Leffler struct ath_hal *ah = sc->sc_ah; 5474bd5a9920SSam Leffler u_int rfkill = ath_hal_getrfkill(ah); 5475bd5a9920SSam Leffler int error; 5476bd5a9920SSam Leffler 5477bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &rfkill, 0, req); 5478bd5a9920SSam Leffler if (error || !req->newptr) 5479bd5a9920SSam Leffler return error; 5480bd5a9920SSam Leffler if (rfkill == ath_hal_getrfkill(ah)) /* unchanged */ 5481bd5a9920SSam Leffler return 0; 548216d84e01SSam Leffler if (!ath_hal_setrfkill(ah, rfkill)) 5483bd5a9920SSam Leffler return EINVAL; 548416d84e01SSam Leffler return (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0; 5485bd5a9920SSam Leffler } 5486bd5a9920SSam Leffler 5487bd5a9920SSam Leffler static int 5488bd5a9920SSam Leffler ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS) 5489bd5a9920SSam Leffler { 5490bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5491bd5a9920SSam Leffler u_int rfsilent; 5492bd5a9920SSam Leffler int error; 5493bd5a9920SSam Leffler 5494ee7d6840SSam Leffler (void) ath_hal_getrfsilent(sc->sc_ah, &rfsilent); 5495bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &rfsilent, 0, req); 5496bd5a9920SSam Leffler if (error || !req->newptr) 5497bd5a9920SSam Leffler return error; 5498bd5a9920SSam Leffler if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent)) 5499bd5a9920SSam Leffler return EINVAL; 5500bd5a9920SSam Leffler sc->sc_rfsilentpin = rfsilent & 0x1c; 5501bd5a9920SSam Leffler sc->sc_rfsilentpol = (rfsilent & 0x2) != 0; 5502bd5a9920SSam Leffler return 0; 5503bd5a9920SSam Leffler } 5504bd5a9920SSam Leffler 5505bd5a9920SSam Leffler static int 5506aaa70f2fSSam Leffler ath_sysctl_countrycode(SYSCTL_HANDLER_ARGS) 5507aaa70f2fSSam Leffler { 5508aaa70f2fSSam Leffler struct ath_softc *sc = arg1; 5509aaa70f2fSSam Leffler u_int32_t cc = sc->sc_countrycode; 5510aaa70f2fSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5511aaa70f2fSSam Leffler int error; 5512aaa70f2fSSam Leffler 5513aaa70f2fSSam Leffler error = sysctl_handle_int(oidp, &cc, 0, req); 5514aaa70f2fSSam Leffler if (error || !req->newptr) 5515aaa70f2fSSam Leffler return error; 5516aaa70f2fSSam Leffler error = ath_getchannels(sc, sc->sc_regdomain, cc, 5517aaa70f2fSSam Leffler sc->sc_outdoor, sc->sc_xchanmode); 5518aaa70f2fSSam Leffler if (error != 0) 5519aaa70f2fSSam Leffler return error; 5520aaa70f2fSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 5521aaa70f2fSSam Leffler /* setcurmode? */ 5522aaa70f2fSSam Leffler return 0; 5523aaa70f2fSSam Leffler } 5524aaa70f2fSSam Leffler 5525aaa70f2fSSam Leffler static int 552617f3f177SSam Leffler ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS) 552717f3f177SSam Leffler { 552817f3f177SSam Leffler struct ath_softc *sc = arg1; 5529aaa70f2fSSam Leffler u_int32_t rd = sc->sc_regdomain; 5530aaa70f2fSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 553117f3f177SSam Leffler int error; 553217f3f177SSam Leffler 553317f3f177SSam Leffler error = sysctl_handle_int(oidp, &rd, 0, req); 553417f3f177SSam Leffler if (error || !req->newptr) 553517f3f177SSam Leffler return error; 5536aaa70f2fSSam Leffler if (!ath_hal_setregdomain(sc->sc_ah, rd)) 5537aaa70f2fSSam Leffler return EINVAL; 5538aaa70f2fSSam Leffler error = ath_getchannels(sc, rd, sc->sc_countrycode, 5539aaa70f2fSSam Leffler sc->sc_outdoor, sc->sc_xchanmode); 5540aaa70f2fSSam Leffler if (error != 0) 5541aaa70f2fSSam Leffler return error; 5542aaa70f2fSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 5543aaa70f2fSSam Leffler /* setcurmode? */ 5544aaa70f2fSSam Leffler return 0; 554517f3f177SSam Leffler } 554617f3f177SSam Leffler 5547bd5a9920SSam Leffler static int 5548bd5a9920SSam Leffler ath_sysctl_tpack(SYSCTL_HANDLER_ARGS) 5549bd5a9920SSam Leffler { 5550bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5551bd5a9920SSam Leffler u_int32_t tpack; 5552bd5a9920SSam Leffler int error; 5553bd5a9920SSam Leffler 5554ee7d6840SSam Leffler (void) ath_hal_gettpack(sc->sc_ah, &tpack); 5555bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &tpack, 0, req); 5556bd5a9920SSam Leffler if (error || !req->newptr) 5557bd5a9920SSam Leffler return error; 5558bd5a9920SSam Leffler return !ath_hal_settpack(sc->sc_ah, tpack) ? EINVAL : 0; 5559bd5a9920SSam Leffler } 5560bd5a9920SSam Leffler 5561bd5a9920SSam Leffler static int 5562bd5a9920SSam Leffler ath_sysctl_tpcts(SYSCTL_HANDLER_ARGS) 5563bd5a9920SSam Leffler { 5564bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5565bd5a9920SSam Leffler u_int32_t tpcts; 5566bd5a9920SSam Leffler int error; 5567bd5a9920SSam Leffler 5568ee7d6840SSam Leffler (void) ath_hal_gettpcts(sc->sc_ah, &tpcts); 5569bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &tpcts, 0, req); 5570bd5a9920SSam Leffler if (error || !req->newptr) 5571bd5a9920SSam Leffler return error; 5572bd5a9920SSam Leffler return !ath_hal_settpcts(sc->sc_ah, tpcts) ? EINVAL : 0; 5573bd5a9920SSam Leffler } 5574bd5a9920SSam Leffler 5575c42a7b7eSSam Leffler static void 5576c42a7b7eSSam Leffler ath_sysctlattach(struct ath_softc *sc) 5577c42a7b7eSSam Leffler { 5578c42a7b7eSSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 5579c42a7b7eSSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 5580c59005e9SSam Leffler struct ath_hal *ah = sc->sc_ah; 5581c42a7b7eSSam Leffler 5582aaa70f2fSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5583aaa70f2fSSam Leffler "countrycode", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5584aaa70f2fSSam Leffler ath_sysctl_countrycode, "I", "country code"); 558517f3f177SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 558617f3f177SSam Leffler "regdomain", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 558717f3f177SSam Leffler ath_sysctl_regdomain, "I", "EEPROM regdomain code"); 5588a585a9a1SSam Leffler #ifdef ATH_DEBUG 5589c42a7b7eSSam Leffler sc->sc_debug = ath_debug; 5590c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5591c42a7b7eSSam Leffler "debug", CTLFLAG_RW, &sc->sc_debug, 0, 5592c42a7b7eSSam Leffler "control debugging printfs"); 5593d2f6ed15SSam Leffler #endif 5594c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5595c42a7b7eSSam Leffler "slottime", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5596c42a7b7eSSam Leffler ath_sysctl_slottime, "I", "802.11 slot time (us)"); 5597c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5598c42a7b7eSSam Leffler "acktimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5599c42a7b7eSSam Leffler ath_sysctl_acktimeout, "I", "802.11 ACK timeout (us)"); 5600c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5601c42a7b7eSSam Leffler "ctstimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5602c42a7b7eSSam Leffler ath_sysctl_ctstimeout, "I", "802.11 CTS timeout (us)"); 5603c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5604c42a7b7eSSam Leffler "softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5605c42a7b7eSSam Leffler ath_sysctl_softled, "I", "enable/disable software LED support"); 5606b298baf2SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5607b298baf2SSam Leffler "ledpin", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5608b298baf2SSam Leffler ath_sysctl_ledpin, "I", "GPIO pin connected to LED"); 5609c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 56103e50ec2cSSam Leffler "ledon", CTLFLAG_RW, &sc->sc_ledon, 0, 56113e50ec2cSSam Leffler "setting to turn LED on"); 56123e50ec2cSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 56133e50ec2cSSam Leffler "ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0, 56143e50ec2cSSam Leffler "idle time for inactivity LED (ticks)"); 56158debcae4SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 56168debcae4SSam Leffler "txantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 56178debcae4SSam Leffler ath_sysctl_txantenna, "I", "antenna switch"); 5618c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5619c42a7b7eSSam Leffler "rxantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5620c42a7b7eSSam Leffler ath_sysctl_rxantenna, "I", "default/rx antenna"); 5621c59005e9SSam Leffler if (ath_hal_hasdiversity(ah)) 5622c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5623c42a7b7eSSam Leffler "diversity", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5624c42a7b7eSSam Leffler ath_sysctl_diversity, "I", "antenna diversity"); 5625c42a7b7eSSam Leffler sc->sc_txintrperiod = ATH_TXINTR_PERIOD; 5626c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5627c42a7b7eSSam Leffler "txintrperiod", CTLFLAG_RW, &sc->sc_txintrperiod, 0, 5628c42a7b7eSSam Leffler "tx descriptor batching"); 5629c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5630c42a7b7eSSam Leffler "diag", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5631c42a7b7eSSam Leffler ath_sysctl_diag, "I", "h/w diagnostic control"); 5632c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5633c42a7b7eSSam Leffler "tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5634c42a7b7eSSam Leffler ath_sysctl_tpscale, "I", "tx power scaling"); 5635bd5a9920SSam Leffler if (ath_hal_hastpc(ah)) { 5636c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5637c42a7b7eSSam Leffler "tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5638c42a7b7eSSam Leffler ath_sysctl_tpc, "I", "enable/disable per-packet TPC"); 5639bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5640bd5a9920SSam Leffler "tpack", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5641bd5a9920SSam Leffler ath_sysctl_tpack, "I", "tx power for ack frames"); 5642bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5643bd5a9920SSam Leffler "tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5644bd5a9920SSam Leffler ath_sysctl_tpcts, "I", "tx power for cts frames"); 5645bd5a9920SSam Leffler } 5646bd5a9920SSam Leffler if (ath_hal_hasrfsilent(ah)) { 5647bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5648bd5a9920SSam Leffler "rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5649bd5a9920SSam Leffler ath_sysctl_rfsilent, "I", "h/w RF silent config"); 5650bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5651bd5a9920SSam Leffler "rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5652bd5a9920SSam Leffler ath_sysctl_rfkill, "I", "enable/disable RF kill switch"); 5653bd5a9920SSam Leffler } 56547b0c77ecSSam Leffler sc->sc_monpass = HAL_RXERR_DECRYPT | HAL_RXERR_MIC; 56557b0c77ecSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 56567b0c77ecSSam Leffler "monpass", CTLFLAG_RW, &sc->sc_monpass, 0, 56577b0c77ecSSam Leffler "mask of error frames to pass when monitoring"); 5658c42a7b7eSSam Leffler } 5659c42a7b7eSSam Leffler 5660c42a7b7eSSam Leffler static void 5661c42a7b7eSSam Leffler ath_bpfattach(struct ath_softc *sc) 5662c42a7b7eSSam Leffler { 5663fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5664c42a7b7eSSam Leffler 5665c42a7b7eSSam Leffler bpfattach2(ifp, DLT_IEEE802_11_RADIO, 5666c42a7b7eSSam Leffler sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th), 5667c42a7b7eSSam Leffler &sc->sc_drvbpf); 5668c42a7b7eSSam Leffler /* 5669c42a7b7eSSam Leffler * Initialize constant fields. 5670c42a7b7eSSam Leffler * XXX make header lengths a multiple of 32-bits so subsequent 5671c42a7b7eSSam Leffler * headers are properly aligned; this is a kludge to keep 5672c42a7b7eSSam Leffler * certain applications happy. 5673c42a7b7eSSam Leffler * 5674c42a7b7eSSam Leffler * NB: the channel is setup each time we transition to the 5675c42a7b7eSSam Leffler * RUN state to avoid filling it in for each frame. 5676c42a7b7eSSam Leffler */ 5677c42a7b7eSSam Leffler sc->sc_tx_th_len = roundup(sizeof(sc->sc_tx_th), sizeof(u_int32_t)); 5678c42a7b7eSSam Leffler sc->sc_tx_th.wt_ihdr.it_len = htole16(sc->sc_tx_th_len); 5679c42a7b7eSSam Leffler sc->sc_tx_th.wt_ihdr.it_present = htole32(ATH_TX_RADIOTAP_PRESENT); 5680c42a7b7eSSam Leffler 5681d3be6f5bSSam Leffler sc->sc_rx_th_len = roundup(sizeof(sc->sc_rx_th), sizeof(u_int32_t)); 5682d3be6f5bSSam Leffler sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_th_len); 5683c42a7b7eSSam Leffler sc->sc_rx_th.wr_ihdr.it_present = htole32(ATH_RX_RADIOTAP_PRESENT); 5684c42a7b7eSSam Leffler } 5685c42a7b7eSSam Leffler 5686664443d0SSam Leffler static int 5687664443d0SSam Leffler ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, 5688664443d0SSam Leffler struct ath_buf *bf, struct mbuf *m0, 5689664443d0SSam Leffler const struct ieee80211_bpf_params *params) 5690664443d0SSam Leffler { 5691664443d0SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5692664443d0SSam Leffler struct ath_hal *ah = sc->sc_ah; 5693664443d0SSam Leffler int error, ismcast, ismrr; 5694664443d0SSam Leffler int hdrlen, pktlen, try0, txantenna; 5695664443d0SSam Leffler u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3; 5696664443d0SSam Leffler struct ath_txq *txq; 5697664443d0SSam Leffler struct ieee80211_frame *wh; 5698664443d0SSam Leffler u_int flags, ctsduration; 5699664443d0SSam Leffler HAL_PKT_TYPE atype; 5700664443d0SSam Leffler const HAL_RATE_TABLE *rt; 5701664443d0SSam Leffler struct ath_desc *ds; 5702664443d0SSam Leffler u_int pri; 5703664443d0SSam Leffler 5704664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 5705664443d0SSam Leffler ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 5706664443d0SSam Leffler hdrlen = ieee80211_anyhdrsize(wh); 5707664443d0SSam Leffler /* 5708664443d0SSam Leffler * Packet length must not include any 5709664443d0SSam Leffler * pad bytes; deduct them here. 5710664443d0SSam Leffler */ 5711664443d0SSam Leffler /* XXX honor IEEE80211_BPF_DATAPAD */ 5712664443d0SSam Leffler pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN; 5713664443d0SSam Leffler 5714664443d0SSam Leffler error = ath_tx_dmasetup(sc, bf, m0); 5715664443d0SSam Leffler if (error != 0) 5716664443d0SSam Leffler return error; 5717664443d0SSam Leffler m0 = bf->bf_m; /* NB: may have changed */ 5718664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 5719664443d0SSam Leffler bf->bf_node = ni; /* NB: held reference */ 5720664443d0SSam Leffler 5721664443d0SSam Leffler flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 5722664443d0SSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 5723664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_RTS) 5724664443d0SSam Leffler flags |= HAL_TXDESC_RTSENA; 5725664443d0SSam Leffler else if (params->ibp_flags & IEEE80211_BPF_CTS) 5726664443d0SSam Leffler flags |= HAL_TXDESC_CTSENA; 5727664443d0SSam Leffler /* XXX leave ismcast to injector? */ 5728664443d0SSam Leffler if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast) 5729664443d0SSam Leffler flags |= HAL_TXDESC_NOACK; 5730664443d0SSam Leffler 5731664443d0SSam Leffler rt = sc->sc_currates; 5732664443d0SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 5733664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate0); 5734664443d0SSam Leffler txrate = rt->info[rix].rateCode; 5735664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5736664443d0SSam Leffler txrate |= rt->info[rix].shortPreamble; 57376bf62dd1SSam Leffler sc->sc_txrate = txrate; 5738664443d0SSam Leffler try0 = params->ibp_try0; 5739664443d0SSam Leffler ismrr = (params->ibp_try1 != 0); 5740664443d0SSam Leffler txantenna = params->ibp_pri >> 2; 5741664443d0SSam Leffler if (txantenna == 0) /* XXX? */ 5742664443d0SSam Leffler txantenna = sc->sc_txantenna; 5743664443d0SSam Leffler ctsduration = 0; 5744664443d0SSam Leffler if (flags & (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) { 5745664443d0SSam Leffler cix = ath_tx_findrix(rt, params->ibp_ctsrate); 5746664443d0SSam Leffler ctsrate = rt->info[cix].rateCode; 5747664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) { 5748664443d0SSam Leffler ctsrate |= rt->info[cix].shortPreamble; 5749664443d0SSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 5750664443d0SSam Leffler ctsduration += rt->info[cix].spAckDuration; 5751664443d0SSam Leffler ctsduration += ath_hal_computetxtime(ah, 5752664443d0SSam Leffler rt, pktlen, rix, AH_TRUE); 5753664443d0SSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 5754664443d0SSam Leffler ctsduration += rt->info[rix].spAckDuration; 5755664443d0SSam Leffler } else { 5756664443d0SSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 5757664443d0SSam Leffler ctsduration += rt->info[cix].lpAckDuration; 5758664443d0SSam Leffler ctsduration += ath_hal_computetxtime(ah, 5759664443d0SSam Leffler rt, pktlen, rix, AH_FALSE); 5760664443d0SSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 5761664443d0SSam Leffler ctsduration += rt->info[rix].lpAckDuration; 5762664443d0SSam Leffler } 5763664443d0SSam Leffler ismrr = 0; /* XXX */ 5764664443d0SSam Leffler } else 5765664443d0SSam Leffler ctsrate = 0; 5766664443d0SSam Leffler pri = params->ibp_pri & 3; 5767664443d0SSam Leffler /* 5768664443d0SSam Leffler * NB: we mark all packets as type PSPOLL so the h/w won't 5769664443d0SSam Leffler * set the sequence number, duration, etc. 5770664443d0SSam Leffler */ 5771664443d0SSam Leffler atype = HAL_PKT_TYPE_PSPOLL; 5772664443d0SSam Leffler 5773664443d0SSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 5774664443d0SSam Leffler ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len, 5775664443d0SSam Leffler sc->sc_hwmap[txrate].ieeerate, -1); 5776664443d0SSam Leffler 5777664443d0SSam Leffler if (bpf_peers_present(ic->ic_rawbpf)) 5778664443d0SSam Leffler bpf_mtap(ic->ic_rawbpf, m0); 5779664443d0SSam Leffler if (bpf_peers_present(sc->sc_drvbpf)) { 5780664443d0SSam Leffler u_int64_t tsf = ath_hal_gettsf64(ah); 5781664443d0SSam Leffler 5782664443d0SSam Leffler sc->sc_tx_th.wt_tsf = htole64(tsf); 5783664443d0SSam Leffler sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags; 5784664443d0SSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) 5785664443d0SSam Leffler sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 5786664443d0SSam Leffler sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate; 5787664443d0SSam Leffler sc->sc_tx_th.wt_txpower = ni->ni_txpower; 5788664443d0SSam Leffler sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 5789664443d0SSam Leffler 5790664443d0SSam Leffler bpf_mtap2(sc->sc_drvbpf, 5791664443d0SSam Leffler &sc->sc_tx_th, sc->sc_tx_th_len, m0); 5792664443d0SSam Leffler } 5793664443d0SSam Leffler 5794664443d0SSam Leffler /* 5795664443d0SSam Leffler * Formulate first tx descriptor with tx controls. 5796664443d0SSam Leffler */ 5797664443d0SSam Leffler ds = bf->bf_desc; 5798664443d0SSam Leffler /* XXX check return value? */ 5799664443d0SSam Leffler ath_hal_setuptxdesc(ah, ds 5800664443d0SSam Leffler , pktlen /* packet length */ 5801664443d0SSam Leffler , hdrlen /* header length */ 5802664443d0SSam Leffler , atype /* Atheros packet type */ 5803664443d0SSam Leffler , params->ibp_power /* txpower */ 5804664443d0SSam Leffler , txrate, try0 /* series 0 rate/tries */ 5805664443d0SSam Leffler , HAL_TXKEYIX_INVALID /* key cache index */ 5806664443d0SSam Leffler , txantenna /* antenna mode */ 5807664443d0SSam Leffler , flags /* flags */ 5808664443d0SSam Leffler , ctsrate /* rts/cts rate */ 5809664443d0SSam Leffler , ctsduration /* rts/cts duration */ 5810664443d0SSam Leffler ); 5811664443d0SSam Leffler bf->bf_flags = flags; 5812664443d0SSam Leffler 5813664443d0SSam Leffler if (ismrr) { 5814664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate1); 5815664443d0SSam Leffler rate1 = rt->info[rix].rateCode; 5816664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5817664443d0SSam Leffler rate1 |= rt->info[rix].shortPreamble; 5818664443d0SSam Leffler if (params->ibp_try2) { 5819664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate2); 5820664443d0SSam Leffler rate2 = rt->info[rix].rateCode; 5821664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5822664443d0SSam Leffler rate2 |= rt->info[rix].shortPreamble; 5823664443d0SSam Leffler } else 5824664443d0SSam Leffler rate2 = 0; 5825664443d0SSam Leffler if (params->ibp_try3) { 5826664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate3); 5827664443d0SSam Leffler rate3 = rt->info[rix].rateCode; 5828664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5829664443d0SSam Leffler rate3 |= rt->info[rix].shortPreamble; 5830664443d0SSam Leffler } else 5831664443d0SSam Leffler rate3 = 0; 5832664443d0SSam Leffler ath_hal_setupxtxdesc(ah, ds 5833664443d0SSam Leffler , rate1, params->ibp_try1 /* series 1 */ 5834664443d0SSam Leffler , rate2, params->ibp_try2 /* series 2 */ 5835664443d0SSam Leffler , rate3, params->ibp_try3 /* series 3 */ 5836664443d0SSam Leffler ); 5837664443d0SSam Leffler } 5838664443d0SSam Leffler 5839664443d0SSam Leffler /* 5840664443d0SSam Leffler * When servicing one or more stations in power-save mode 5841664443d0SSam Leffler * (or) if there is some mcast data waiting on the mcast 5842664443d0SSam Leffler * queue (to prevent out of order delivery) multicast 5843664443d0SSam Leffler * frames must be buffered until after the beacon. 5844664443d0SSam Leffler */ 5845664443d0SSam Leffler txq = sc->sc_ac2q[pri]; 5846664443d0SSam Leffler if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth)) 5847664443d0SSam Leffler txq = &sc->sc_mcastq; 5848664443d0SSam Leffler ath_tx_handoff(sc, txq, bf); 5849664443d0SSam Leffler return 0; 5850664443d0SSam Leffler } 5851664443d0SSam Leffler 5852664443d0SSam Leffler static int 5853664443d0SSam Leffler ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 5854664443d0SSam Leffler const struct ieee80211_bpf_params *params) 5855664443d0SSam Leffler { 5856664443d0SSam Leffler struct ieee80211com *ic = ni->ni_ic; 5857664443d0SSam Leffler struct ifnet *ifp = ic->ic_ifp; 5858664443d0SSam Leffler struct ath_softc *sc = ifp->if_softc; 5859664443d0SSam Leffler struct ath_buf *bf; 5860664443d0SSam Leffler 5861664443d0SSam Leffler if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { 5862b03cfe23SSepherosa Ziehau ieee80211_free_node(ni); 5863664443d0SSam Leffler m_freem(m); 5864664443d0SSam Leffler return ENETDOWN; 5865664443d0SSam Leffler } 5866664443d0SSam Leffler /* 5867664443d0SSam Leffler * Grab a TX buffer and associated resources. 5868664443d0SSam Leffler */ 5869664443d0SSam Leffler ATH_TXBUF_LOCK(sc); 5870664443d0SSam Leffler bf = STAILQ_FIRST(&sc->sc_txbuf); 5871664443d0SSam Leffler if (bf != NULL) 5872664443d0SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); 5873664443d0SSam Leffler ATH_TXBUF_UNLOCK(sc); 5874664443d0SSam Leffler if (bf == NULL) { 5875664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", 5876664443d0SSam Leffler __func__); 5877664443d0SSam Leffler sc->sc_stats.ast_tx_qstop++; 5878664443d0SSam Leffler ifp->if_drv_flags |= IFF_DRV_OACTIVE; 5879b03cfe23SSepherosa Ziehau ieee80211_free_node(ni); 5880664443d0SSam Leffler m_freem(m); 5881664443d0SSam Leffler return ENOBUFS; 5882664443d0SSam Leffler } 5883664443d0SSam Leffler 5884664443d0SSam Leffler ifp->if_opackets++; 5885664443d0SSam Leffler sc->sc_stats.ast_tx_raw++; 5886664443d0SSam Leffler 5887664443d0SSam Leffler if (params == NULL) { 5888664443d0SSam Leffler /* 5889664443d0SSam Leffler * Legacy path; interpret frame contents to decide 5890664443d0SSam Leffler * precisely how to send the frame. 5891664443d0SSam Leffler */ 5892664443d0SSam Leffler if (ath_tx_start(sc, ni, bf, m)) 5893664443d0SSam Leffler goto bad; 5894664443d0SSam Leffler } else { 5895664443d0SSam Leffler /* 5896664443d0SSam Leffler * Caller supplied explicit parameters to use in 5897664443d0SSam Leffler * sending the frame. 5898664443d0SSam Leffler */ 5899664443d0SSam Leffler if (ath_tx_raw_start(sc, ni, bf, m, params)) 5900664443d0SSam Leffler goto bad; 5901664443d0SSam Leffler } 5902664443d0SSam Leffler sc->sc_tx_timer = 5; 5903664443d0SSam Leffler ifp->if_timer = 1; 5904664443d0SSam Leffler 5905664443d0SSam Leffler return 0; 5906664443d0SSam Leffler bad: 5907664443d0SSam Leffler ifp->if_oerrors++; 5908664443d0SSam Leffler ATH_TXBUF_LOCK(sc); 5909664443d0SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 5910664443d0SSam Leffler ATH_TXBUF_UNLOCK(sc); 5911664443d0SSam Leffler ieee80211_free_node(ni); 5912664443d0SSam Leffler return EIO; /* XXX */ 5913664443d0SSam Leffler } 5914664443d0SSam Leffler 5915c42a7b7eSSam Leffler /* 5916c42a7b7eSSam Leffler * Announce various information on device/driver attach. 5917c42a7b7eSSam Leffler */ 5918c42a7b7eSSam Leffler static void 5919c42a7b7eSSam Leffler ath_announce(struct ath_softc *sc) 5920c42a7b7eSSam Leffler { 5921c42a7b7eSSam Leffler #define HAL_MODE_DUALBAND (HAL_MODE_11A|HAL_MODE_11B) 5922fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5923c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5924c42a7b7eSSam Leffler u_int modes, cc; 5925c42a7b7eSSam Leffler 5926c42a7b7eSSam Leffler if_printf(ifp, "mac %d.%d phy %d.%d", 5927c42a7b7eSSam Leffler ah->ah_macVersion, ah->ah_macRev, 5928c42a7b7eSSam Leffler ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf); 5929c42a7b7eSSam Leffler /* 5930c42a7b7eSSam Leffler * Print radio revision(s). We check the wireless modes 5931c42a7b7eSSam Leffler * to avoid falsely printing revs for inoperable parts. 5932c42a7b7eSSam Leffler * Dual-band radio revs are returned in the 5Ghz rev number. 5933c42a7b7eSSam Leffler */ 5934c42a7b7eSSam Leffler ath_hal_getcountrycode(ah, &cc); 5935c42a7b7eSSam Leffler modes = ath_hal_getwirelessmodes(ah, cc); 5936c42a7b7eSSam Leffler if ((modes & HAL_MODE_DUALBAND) == HAL_MODE_DUALBAND) { 5937c42a7b7eSSam Leffler if (ah->ah_analog5GhzRev && ah->ah_analog2GhzRev) 5938c42a7b7eSSam Leffler printf(" 5ghz radio %d.%d 2ghz radio %d.%d", 5939c42a7b7eSSam Leffler ah->ah_analog5GhzRev >> 4, 5940c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf, 5941c42a7b7eSSam Leffler ah->ah_analog2GhzRev >> 4, 5942c42a7b7eSSam Leffler ah->ah_analog2GhzRev & 0xf); 5943c42a7b7eSSam Leffler else 5944c42a7b7eSSam Leffler printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4, 5945c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf); 5946c42a7b7eSSam Leffler } else 5947c42a7b7eSSam Leffler printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4, 5948c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf); 5949c42a7b7eSSam Leffler printf("\n"); 5950c42a7b7eSSam Leffler if (bootverbose) { 5951c42a7b7eSSam Leffler int i; 5952c42a7b7eSSam Leffler for (i = 0; i <= WME_AC_VO; i++) { 5953c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[i]; 5954c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for %s traffic\n", 5955c42a7b7eSSam Leffler txq->axq_qnum, ieee80211_wme_acnames[i]); 5956c42a7b7eSSam Leffler } 5957c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for CAB traffic\n", 5958c42a7b7eSSam Leffler sc->sc_cabq->axq_qnum); 5959c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq); 5960c42a7b7eSSam Leffler } 5961e2d787faSSam Leffler if (ath_rxbuf != ATH_RXBUF) 5962e2d787faSSam Leffler if_printf(ifp, "using %u rx buffers\n", ath_rxbuf); 5963e2d787faSSam Leffler if (ath_txbuf != ATH_TXBUF) 5964e2d787faSSam Leffler if_printf(ifp, "using %u tx buffers\n", ath_txbuf); 5965c42a7b7eSSam Leffler #undef HAL_MODE_DUALBAND 5966c42a7b7eSSam Leffler } 5967