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); 367aaa70f2fSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11A_HALF); 368aaa70f2fSSam Leffler ath_rate_setup(sc, IEEE80211_MODE_11A_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 } 417622b3fd2SSam Leffler ath_txq_init(sc, &sc->sc_mcastq, -1); /* NB: s/w q, qnum not used */ 418c42a7b7eSSam Leffler /* NB: insure BK queue is the lowest priority h/w queue */ 419c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { 420c42a7b7eSSam Leffler if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", 421c42a7b7eSSam Leffler ieee80211_wme_acnames[WME_AC_BK]); 422c42a7b7eSSam Leffler error = EIO; 423c42a7b7eSSam Leffler goto bad2; 424c42a7b7eSSam Leffler } 425c42a7b7eSSam Leffler if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) || 426c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) || 427c42a7b7eSSam Leffler !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) { 428c42a7b7eSSam Leffler /* 429c42a7b7eSSam Leffler * Not enough hardware tx queues to properly do WME; 430c42a7b7eSSam Leffler * just punt and assign them all to the same h/w queue. 431c42a7b7eSSam Leffler * We could do a better job of this if, for example, 432c42a7b7eSSam Leffler * we allocate queues when we switch from station to 433c42a7b7eSSam Leffler * AP mode. 434c42a7b7eSSam Leffler */ 435c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_VI] != NULL) 436c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_VI]); 437c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != NULL) 438c42a7b7eSSam Leffler ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_BE]); 439c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK]; 440c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK]; 441c42a7b7eSSam Leffler sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK]; 442c42a7b7eSSam Leffler } 443c42a7b7eSSam Leffler 444c42a7b7eSSam Leffler /* 445c42a7b7eSSam Leffler * Special case certain configurations. Note the 446c42a7b7eSSam Leffler * CAB queue is handled by these specially so don't 447c42a7b7eSSam Leffler * include them when checking the txq setup mask. 448c42a7b7eSSam Leffler */ 449c42a7b7eSSam Leffler switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) { 450c42a7b7eSSam Leffler case 0x01: 451c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc); 452c42a7b7eSSam Leffler break; 453c42a7b7eSSam Leffler case 0x0f: 454c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc); 455c42a7b7eSSam Leffler break; 456c42a7b7eSSam Leffler default: 457c42a7b7eSSam Leffler TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc); 458c42a7b7eSSam Leffler break; 459c42a7b7eSSam Leffler } 460c42a7b7eSSam Leffler 461c42a7b7eSSam Leffler /* 462c42a7b7eSSam Leffler * Setup rate control. Some rate control modules 463c42a7b7eSSam Leffler * call back to change the anntena state so expose 464c42a7b7eSSam Leffler * the necessary entry points. 465c42a7b7eSSam Leffler * XXX maybe belongs in struct ath_ratectrl? 466c42a7b7eSSam Leffler */ 467c42a7b7eSSam Leffler sc->sc_setdefantenna = ath_setdefantenna; 468c42a7b7eSSam Leffler sc->sc_rc = ath_rate_attach(sc); 469c42a7b7eSSam Leffler if (sc->sc_rc == NULL) { 470c42a7b7eSSam Leffler error = EIO; 471c42a7b7eSSam Leffler goto bad2; 472c42a7b7eSSam Leffler } 473c42a7b7eSSam Leffler 4743e50ec2cSSam Leffler sc->sc_blinking = 0; 475c42a7b7eSSam Leffler sc->sc_ledstate = 1; 4763e50ec2cSSam Leffler sc->sc_ledon = 0; /* low true */ 4773e50ec2cSSam Leffler sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */ 4783e50ec2cSSam Leffler callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE); 479c42a7b7eSSam Leffler /* 480c42a7b7eSSam Leffler * Auto-enable soft led processing for IBM cards and for 481c42a7b7eSSam Leffler * 5211 minipci cards. Users can also manually enable/disable 482c42a7b7eSSam Leffler * support with a sysctl. 483c42a7b7eSSam Leffler */ 484c42a7b7eSSam Leffler sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID); 485c42a7b7eSSam Leffler if (sc->sc_softled) { 486c42a7b7eSSam Leffler ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); 4873e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); 488c42a7b7eSSam Leffler } 4895591b213SSam Leffler 4905591b213SSam Leffler ifp->if_softc = sc; 4915591b213SSam Leffler ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; 4925591b213SSam Leffler ifp->if_start = ath_start; 4935591b213SSam Leffler ifp->if_watchdog = ath_watchdog; 4945591b213SSam Leffler ifp->if_ioctl = ath_ioctl; 4955591b213SSam Leffler ifp->if_init = ath_init; 496154b8df2SMax Laier IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 497154b8df2SMax Laier ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 498154b8df2SMax Laier IFQ_SET_READY(&ifp->if_snd); 4995591b213SSam Leffler 500c42a7b7eSSam Leffler ic->ic_ifp = ifp; 501c42a7b7eSSam Leffler ic->ic_reset = ath_reset; 5025591b213SSam Leffler ic->ic_newassoc = ath_newassoc; 503c42a7b7eSSam Leffler ic->ic_updateslot = ath_updateslot; 504c42a7b7eSSam Leffler ic->ic_wme.wme_update = ath_wme_update; 5055591b213SSam Leffler /* XXX not right but it's not used anywhere important */ 5065591b213SSam Leffler ic->ic_phytype = IEEE80211_T_OFDM; 5075591b213SSam Leffler ic->ic_opmode = IEEE80211_M_STA; 508c42a7b7eSSam Leffler ic->ic_caps = 509c42a7b7eSSam Leffler IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 510fe32c3efSSam Leffler | IEEE80211_C_HOSTAP /* hostap mode */ 511fe32c3efSSam Leffler | IEEE80211_C_MONITOR /* monitor mode */ 5127a04dc27SSam Leffler | IEEE80211_C_AHDEMO /* adhoc demo mode */ 513fe32c3efSSam Leffler | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 514c42a7b7eSSam Leffler | IEEE80211_C_SHSLOT /* short slot time supported */ 515c42a7b7eSSam Leffler | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 51601e7e035SSam Leffler ; 517c42a7b7eSSam Leffler /* 518c42a7b7eSSam Leffler * Query the hal to figure out h/w crypto support. 519c42a7b7eSSam Leffler */ 520c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP)) 521c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_WEP; 522c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB)) 523c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_AES; 524c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM)) 525c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_AES_CCM; 526c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP)) 527c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_CKIP; 528c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) { 529c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TKIP; 530c42a7b7eSSam Leffler /* 531c42a7b7eSSam Leffler * Check if h/w does the MIC and/or whether the 532c42a7b7eSSam Leffler * separate key cache entries are required to 533c42a7b7eSSam Leffler * handle both tx+rx MIC keys. 534c42a7b7eSSam Leffler */ 535c42a7b7eSSam Leffler if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) 536c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TKIPMIC; 5375901d2d3SSam Leffler /* 5385901d2d3SSam Leffler * If the h/w supports storing tx+rx MIC keys 5395901d2d3SSam Leffler * in one cache slot automatically enable use. 5405901d2d3SSam Leffler */ 5415901d2d3SSam Leffler if (ath_hal_hastkipsplit(ah) || 5425901d2d3SSam Leffler !ath_hal_settkipsplit(ah, AH_FALSE)) 543c42a7b7eSSam Leffler sc->sc_splitmic = 1; 544c42a7b7eSSam Leffler } 545e8fd88a3SSam Leffler sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR); 546e8fd88a3SSam Leffler sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah); 547c42a7b7eSSam Leffler /* 5485901d2d3SSam Leffler * Mark key cache slots associated with global keys 5495901d2d3SSam Leffler * as in use. If we knew TKIP was not to be used we 5505901d2d3SSam Leffler * could leave the +32, +64, and +32+64 slots free. 5515901d2d3SSam Leffler */ 5525901d2d3SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) { 5535901d2d3SSam Leffler setbit(sc->sc_keymap, i); 5545901d2d3SSam Leffler setbit(sc->sc_keymap, i+64); 5555901d2d3SSam Leffler if (sc->sc_splitmic) { 5565901d2d3SSam Leffler setbit(sc->sc_keymap, i+32); 5575901d2d3SSam Leffler setbit(sc->sc_keymap, i+32+64); 5585901d2d3SSam Leffler } 5595901d2d3SSam Leffler } 5605901d2d3SSam Leffler /* 561c42a7b7eSSam Leffler * TPC support can be done either with a global cap or 562c42a7b7eSSam Leffler * per-packet support. The latter is not available on 563c42a7b7eSSam Leffler * all parts. We're a bit pedantic here as all parts 564c42a7b7eSSam Leffler * support a global cap. 565c42a7b7eSSam Leffler */ 566c59005e9SSam Leffler if (ath_hal_hastpc(ah) || ath_hal_hastxpowlimit(ah)) 567c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_TXPMGT; 568c42a7b7eSSam Leffler 569c42a7b7eSSam Leffler /* 570c42a7b7eSSam Leffler * Mark WME capability only if we have sufficient 571c42a7b7eSSam Leffler * hardware queues to do proper priority scheduling. 572c42a7b7eSSam Leffler */ 573c42a7b7eSSam Leffler if (sc->sc_ac2q[WME_AC_BE] != sc->sc_ac2q[WME_AC_BK]) 574c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_WME; 575c42a7b7eSSam Leffler /* 576e8fd88a3SSam Leffler * Check for misc other capabilities. 577c42a7b7eSSam Leffler */ 578c42a7b7eSSam Leffler if (ath_hal_hasbursting(ah)) 579c42a7b7eSSam Leffler ic->ic_caps |= IEEE80211_C_BURST; 580c42a7b7eSSam Leffler 581c42a7b7eSSam Leffler /* 582c42a7b7eSSam Leffler * Indicate we need the 802.11 header padded to a 583c42a7b7eSSam Leffler * 32-bit boundary for 4-address and QoS frames. 584c42a7b7eSSam Leffler */ 585c42a7b7eSSam Leffler ic->ic_flags |= IEEE80211_F_DATAPAD; 586c42a7b7eSSam Leffler 587c42a7b7eSSam Leffler /* 588c42a7b7eSSam Leffler * Query the hal about antenna support. 589c42a7b7eSSam Leffler */ 590c42a7b7eSSam Leffler sc->sc_defant = ath_hal_getdefantenna(ah); 591c42a7b7eSSam Leffler 592c42a7b7eSSam Leffler /* 593c42a7b7eSSam Leffler * Not all chips have the VEOL support we want to 594c42a7b7eSSam Leffler * use with IBSS beacons; check here for it. 595c42a7b7eSSam Leffler */ 596c42a7b7eSSam Leffler sc->sc_hasveol = ath_hal_hasveol(ah); 5975591b213SSam Leffler 5985591b213SSam Leffler /* get mac address from hardware */ 5995591b213SSam Leffler ath_hal_getmac(ah, ic->ic_myaddr); 6005591b213SSam Leffler 6015591b213SSam Leffler /* call MI attach routine. */ 602c42a7b7eSSam Leffler ieee80211_ifattach(ic); 6037a04dc27SSam Leffler sc->sc_opmode = ic->ic_opmode; 6045591b213SSam Leffler /* override default methods */ 6055591b213SSam Leffler ic->ic_node_alloc = ath_node_alloc; 6061e774079SSam Leffler sc->sc_node_free = ic->ic_node_free; 6075591b213SSam Leffler ic->ic_node_free = ath_node_free; 608de5af704SSam Leffler ic->ic_node_getrssi = ath_node_getrssi; 609c42a7b7eSSam Leffler sc->sc_recv_mgmt = ic->ic_recv_mgmt; 610c42a7b7eSSam Leffler ic->ic_recv_mgmt = ath_recv_mgmt; 61145bbf62fSSam Leffler sc->sc_newstate = ic->ic_newstate; 61245bbf62fSSam Leffler ic->ic_newstate = ath_newstate; 613c1225b52SSam Leffler ic->ic_crypto.cs_max_keyix = sc->sc_keymax; 614c42a7b7eSSam Leffler ic->ic_crypto.cs_key_alloc = ath_key_alloc; 615c42a7b7eSSam Leffler ic->ic_crypto.cs_key_delete = ath_key_delete; 616c42a7b7eSSam Leffler ic->ic_crypto.cs_key_set = ath_key_set; 617c42a7b7eSSam Leffler ic->ic_crypto.cs_key_update_begin = ath_key_update_begin; 618c42a7b7eSSam Leffler ic->ic_crypto.cs_key_update_end = ath_key_update_end; 619664443d0SSam Leffler ic->ic_raw_xmit = ath_raw_xmit; 62045bbf62fSSam Leffler /* complete initialization */ 621c42a7b7eSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 6225591b213SSam Leffler 623c42a7b7eSSam Leffler ath_bpfattach(sc); 6244866e6c2SSam Leffler /* 6254866e6c2SSam Leffler * Setup dynamic sysctl's now that country code and 6264866e6c2SSam Leffler * regdomain are available from the hal. 6274866e6c2SSam Leffler */ 6284866e6c2SSam Leffler ath_sysctlattach(sc); 62973454c73SSam Leffler 630c42a7b7eSSam Leffler if (bootverbose) 631c42a7b7eSSam Leffler ieee80211_announce(ic); 632c42a7b7eSSam Leffler ath_announce(sc); 6335591b213SSam Leffler return 0; 634b28b4653SSam Leffler bad2: 635c42a7b7eSSam Leffler ath_tx_cleanup(sc); 636b28b4653SSam Leffler ath_desc_free(sc); 6375591b213SSam Leffler bad: 6385591b213SSam Leffler if (ah) 6395591b213SSam Leffler ath_hal_detach(ah); 640fc74a9f9SBrooks Davis if (ifp != NULL) 641fc74a9f9SBrooks Davis if_free(ifp); 6425591b213SSam Leffler sc->sc_invalid = 1; 6435591b213SSam Leffler return error; 6445591b213SSam Leffler } 6455591b213SSam Leffler 6465591b213SSam Leffler int 6475591b213SSam Leffler ath_detach(struct ath_softc *sc) 6485591b213SSam Leffler { 649fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6505591b213SSam Leffler 651c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 652c42a7b7eSSam Leffler __func__, ifp->if_flags); 6535591b213SSam Leffler 6545591b213SSam Leffler ath_stop(ifp); 65573454c73SSam Leffler bpfdetach(ifp); 656c42a7b7eSSam Leffler /* 657c42a7b7eSSam Leffler * NB: the order of these is important: 658c42a7b7eSSam Leffler * o call the 802.11 layer before detaching the hal to 659c42a7b7eSSam Leffler * insure callbacks into the driver to delete global 660c42a7b7eSSam Leffler * key cache entries can be handled 661c42a7b7eSSam Leffler * o reclaim the tx queue data structures after calling 662c42a7b7eSSam Leffler * the 802.11 layer as we'll get called back to reclaim 663c42a7b7eSSam Leffler * node state and potentially want to use them 664c42a7b7eSSam Leffler * o to cleanup the tx queues the hal is called, so detach 665c42a7b7eSSam Leffler * it last 666c42a7b7eSSam Leffler * Other than that, it's straightforward... 667c42a7b7eSSam Leffler */ 668c42a7b7eSSam Leffler ieee80211_ifdetach(&sc->sc_ic); 66986e07743SSam Leffler #ifdef ATH_TX99_DIAG 67086e07743SSam Leffler if (sc->sc_tx99 != NULL) 67186e07743SSam Leffler sc->sc_tx99->detach(sc->sc_tx99); 67286e07743SSam Leffler #endif 6730bbf5441SSam Leffler taskqueue_free(sc->sc_tq); 674c42a7b7eSSam Leffler ath_rate_detach(sc->sc_rc); 6755591b213SSam Leffler ath_desc_free(sc); 676c42a7b7eSSam Leffler ath_tx_cleanup(sc); 6775591b213SSam Leffler ath_hal_detach(sc->sc_ah); 678c4c6f08fSRuslan Ermilov if_free(ifp); 679f0b2a0beSSam Leffler 6805591b213SSam Leffler return 0; 6815591b213SSam Leffler } 6825591b213SSam Leffler 6835591b213SSam Leffler void 6845591b213SSam Leffler ath_suspend(struct ath_softc *sc) 6855591b213SSam Leffler { 686fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6875591b213SSam Leffler 688c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 689c42a7b7eSSam Leffler __func__, ifp->if_flags); 6905591b213SSam Leffler 6915591b213SSam Leffler ath_stop(ifp); 6925591b213SSam Leffler } 6935591b213SSam Leffler 6945591b213SSam Leffler void 6955591b213SSam Leffler ath_resume(struct ath_softc *sc) 6965591b213SSam Leffler { 697fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 6985591b213SSam Leffler 699c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 700c42a7b7eSSam Leffler __func__, ifp->if_flags); 7015591b213SSam Leffler 7026b59f5e3SSam Leffler if (ifp->if_flags & IFF_UP) { 703fc74a9f9SBrooks Davis ath_init(sc); 70413f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 7055591b213SSam Leffler ath_start(ifp); 7065591b213SSam Leffler } 707b50c8bdeSSam Leffler if (sc->sc_softled) { 708b50c8bdeSSam Leffler ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); 709b50c8bdeSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); 710b50c8bdeSSam Leffler } 7116b59f5e3SSam Leffler } 7125591b213SSam Leffler 7135591b213SSam Leffler void 7145591b213SSam Leffler ath_shutdown(struct ath_softc *sc) 7155591b213SSam Leffler { 716fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 7175591b213SSam Leffler 718c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", 719c42a7b7eSSam Leffler __func__, ifp->if_flags); 7205591b213SSam Leffler 7215591b213SSam Leffler ath_stop(ifp); 7225591b213SSam Leffler } 7235591b213SSam Leffler 724c42a7b7eSSam Leffler /* 725c42a7b7eSSam Leffler * Interrupt handler. Most of the actual processing is deferred. 726c42a7b7eSSam Leffler */ 7275591b213SSam Leffler void 7285591b213SSam Leffler ath_intr(void *arg) 7295591b213SSam Leffler { 7305591b213SSam Leffler struct ath_softc *sc = arg; 731fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 7325591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 7335591b213SSam Leffler HAL_INT status; 7345591b213SSam Leffler 7355591b213SSam Leffler if (sc->sc_invalid) { 7365591b213SSam Leffler /* 737b58b3803SSam Leffler * The hardware is not ready/present, don't touch anything. 738b58b3803SSam Leffler * Note this can happen early on if the IRQ is shared. 7395591b213SSam Leffler */ 740c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid; ignored\n", __func__); 7415591b213SSam Leffler return; 7425591b213SSam Leffler } 743fdd758d4SSam Leffler if (!ath_hal_intrpend(ah)) /* shared irq, not for us */ 744fdd758d4SSam Leffler return; 74513f4c340SRobert Watson if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & 74613f4c340SRobert Watson IFF_DRV_RUNNING))) { 747c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 748c42a7b7eSSam Leffler __func__, ifp->if_flags); 7495591b213SSam Leffler ath_hal_getisr(ah, &status); /* clear ISR */ 7505591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable further intr's */ 7515591b213SSam Leffler return; 7525591b213SSam Leffler } 753c42a7b7eSSam Leffler /* 754c42a7b7eSSam Leffler * Figure out the reason(s) for the interrupt. Note 755c42a7b7eSSam Leffler * that the hal returns a pseudo-ISR that may include 756c42a7b7eSSam Leffler * bits we haven't explicitly enabled so we mask the 757c42a7b7eSSam Leffler * value to insure we only process bits we requested. 758c42a7b7eSSam Leffler */ 7595591b213SSam Leffler ath_hal_getisr(ah, &status); /* NB: clears ISR too */ 760c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status); 761ecddff40SSam Leffler status &= sc->sc_imask; /* discard unasked for bits */ 7625591b213SSam Leffler if (status & HAL_INT_FATAL) { 7635591b213SSam Leffler sc->sc_stats.ast_hardware++; 7645591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable intr's until reset */ 76516c8acaaSSam Leffler ath_fatal_proc(sc, 0); 7665591b213SSam Leffler } else if (status & HAL_INT_RXORN) { 7675591b213SSam Leffler sc->sc_stats.ast_rxorn++; 7685591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable intr's until reset */ 7690bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxorntask); 7705591b213SSam Leffler } else { 771c42a7b7eSSam Leffler if (status & HAL_INT_SWBA) { 772c42a7b7eSSam Leffler /* 773c42a7b7eSSam Leffler * Software beacon alert--time to send a beacon. 774c42a7b7eSSam Leffler * Handle beacon transmission directly; deferring 775c42a7b7eSSam Leffler * this is too slow to meet timing constraints 776c42a7b7eSSam Leffler * under load. 777c42a7b7eSSam Leffler */ 778c42a7b7eSSam Leffler ath_beacon_proc(sc, 0); 779c42a7b7eSSam Leffler } 7805591b213SSam Leffler if (status & HAL_INT_RXEOL) { 7815591b213SSam Leffler /* 7825591b213SSam Leffler * NB: the hardware should re-read the link when 7835591b213SSam Leffler * RXE bit is written, but it doesn't work at 7845591b213SSam Leffler * least on older hardware revs. 7855591b213SSam Leffler */ 7865591b213SSam Leffler sc->sc_stats.ast_rxeol++; 7875591b213SSam Leffler sc->sc_rxlink = NULL; 7885591b213SSam Leffler } 7895591b213SSam Leffler if (status & HAL_INT_TXURN) { 7905591b213SSam Leffler sc->sc_stats.ast_txurn++; 7915591b213SSam Leffler /* bump tx trigger level */ 7925591b213SSam Leffler ath_hal_updatetxtriglevel(ah, AH_TRUE); 7935591b213SSam Leffler } 7945591b213SSam Leffler if (status & HAL_INT_RX) 7950bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); 7965591b213SSam Leffler if (status & HAL_INT_TX) 7970bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask); 7985591b213SSam Leffler if (status & HAL_INT_BMISS) { 7995591b213SSam Leffler sc->sc_stats.ast_bmiss++; 8000bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bmisstask); 8015591b213SSam Leffler } 802c42a7b7eSSam Leffler if (status & HAL_INT_MIB) { 803c42a7b7eSSam Leffler sc->sc_stats.ast_mib++; 804c42a7b7eSSam Leffler /* 805c42a7b7eSSam Leffler * Disable interrupts until we service the MIB 806c42a7b7eSSam Leffler * interrupt; otherwise it will continue to fire. 807c42a7b7eSSam Leffler */ 808c42a7b7eSSam Leffler ath_hal_intrset(ah, 0); 809c42a7b7eSSam Leffler /* 810c42a7b7eSSam Leffler * Let the hal handle the event. We assume it will 811c42a7b7eSSam Leffler * clear whatever condition caused the interrupt. 812c42a7b7eSSam Leffler */ 813ffa2cab6SSam Leffler ath_hal_mibevent(ah, &sc->sc_halstats); 814c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 815c42a7b7eSSam Leffler } 8165591b213SSam Leffler } 8175591b213SSam Leffler } 8185591b213SSam Leffler 8195591b213SSam Leffler static void 8205591b213SSam Leffler ath_fatal_proc(void *arg, int pending) 8215591b213SSam Leffler { 8225591b213SSam Leffler struct ath_softc *sc = arg; 823fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 82416c8acaaSSam Leffler u_int32_t *state; 82516c8acaaSSam Leffler u_int32_t len; 8265591b213SSam Leffler 827c42a7b7eSSam Leffler if_printf(ifp, "hardware error; resetting\n"); 82816c8acaaSSam Leffler /* 82916c8acaaSSam Leffler * Fatal errors are unrecoverable. Typically these 83016c8acaaSSam Leffler * are caused by DMA errors. Collect h/w state from 83116c8acaaSSam Leffler * the hal so we can diagnose what's going on. 83216c8acaaSSam Leffler */ 83316c8acaaSSam Leffler if (ath_hal_getfatalstate(sc->sc_ah, &state, &len)) { 83416c8acaaSSam Leffler KASSERT(len >= 6*sizeof(u_int32_t), ("len %u bytes", len)); 83516c8acaaSSam Leffler if_printf(ifp, "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", 83616c8acaaSSam Leffler state[0], state[1] , state[2], state[3], 83716c8acaaSSam Leffler state[4], state[5]); 83816c8acaaSSam Leffler } 839c42a7b7eSSam Leffler ath_reset(ifp); 8405591b213SSam Leffler } 8415591b213SSam Leffler 8425591b213SSam Leffler static void 8435591b213SSam Leffler ath_rxorn_proc(void *arg, int pending) 8445591b213SSam Leffler { 8455591b213SSam Leffler struct ath_softc *sc = arg; 846fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 8475591b213SSam Leffler 848c42a7b7eSSam Leffler if_printf(ifp, "rx FIFO overrun; resetting\n"); 849c42a7b7eSSam Leffler ath_reset(ifp); 8505591b213SSam Leffler } 8515591b213SSam Leffler 8525591b213SSam Leffler static void 8535591b213SSam Leffler ath_bmiss_proc(void *arg, int pending) 8545591b213SSam Leffler { 8555591b213SSam Leffler struct ath_softc *sc = arg; 8565591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 8575591b213SSam Leffler 858c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); 8595591b213SSam Leffler KASSERT(ic->ic_opmode == IEEE80211_M_STA, 8605591b213SSam Leffler ("unexpect operating mode %u", ic->ic_opmode)); 861e585d188SSam Leffler if (ic->ic_state == IEEE80211_S_RUN) { 862d7736e13SSam Leffler u_int64_t lastrx = sc->sc_lastrx; 863d7736e13SSam Leffler u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); 864d7736e13SSam Leffler u_int bmisstimeout = 865d7736e13SSam Leffler ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024; 866d7736e13SSam Leffler 867d7736e13SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 868d7736e13SSam Leffler "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", 869d7736e13SSam Leffler __func__, (unsigned long long) tsf, 870d7736e13SSam Leffler (unsigned long long)(tsf - lastrx), 871d7736e13SSam Leffler (unsigned long long) lastrx, bmisstimeout); 872e585d188SSam Leffler /* 873d7736e13SSam Leffler * Workaround phantom bmiss interrupts by sanity-checking 874d7736e13SSam Leffler * the time of our last rx'd frame. If it is within the 875d7736e13SSam Leffler * beacon miss interval then ignore the interrupt. If it's 876d7736e13SSam Leffler * truly a bmiss we'll get another interrupt soon and that'll 877d7736e13SSam Leffler * be dispatched up for processing. 878e585d188SSam Leffler */ 879d7736e13SSam Leffler if (tsf - lastrx > bmisstimeout) { 880b5f4adb3SSam Leffler NET_LOCK_GIANT(); 881d7736e13SSam Leffler ieee80211_beacon_miss(ic); 882b5f4adb3SSam Leffler NET_UNLOCK_GIANT(); 883d7736e13SSam Leffler } else 884d7736e13SSam Leffler sc->sc_stats.ast_bmiss_phantom++; 885e585d188SSam Leffler } 8865591b213SSam Leffler } 8875591b213SSam Leffler 8885591b213SSam Leffler static u_int 8895591b213SSam Leffler ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan) 8905591b213SSam Leffler { 891c42a7b7eSSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 8925591b213SSam Leffler static const u_int modeflags[] = { 8935591b213SSam Leffler 0, /* IEEE80211_MODE_AUTO */ 8945591b213SSam Leffler CHANNEL_A, /* IEEE80211_MODE_11A */ 8955591b213SSam Leffler CHANNEL_B, /* IEEE80211_MODE_11B */ 8965591b213SSam Leffler CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 897c42a7b7eSSam Leffler 0, /* IEEE80211_MODE_FH */ 898bd5a9920SSam Leffler CHANNEL_ST, /* IEEE80211_MODE_TURBO_A */ 899c42a7b7eSSam Leffler CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ 9005591b213SSam Leffler }; 901c42a7b7eSSam Leffler enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan); 902c42a7b7eSSam Leffler 903c42a7b7eSSam Leffler KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode)); 904c42a7b7eSSam Leffler KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode)); 905aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) 906aaa70f2fSSam Leffler return modeflags[mode] | CHANNEL_HALF; 907aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_QUARTER(chan)) 908aaa70f2fSSam Leffler return modeflags[mode] | CHANNEL_QUARTER; 909c42a7b7eSSam Leffler return modeflags[mode]; 910c42a7b7eSSam Leffler #undef N 9115591b213SSam Leffler } 9125591b213SSam Leffler 9135591b213SSam Leffler static void 9145591b213SSam Leffler ath_init(void *arg) 9155591b213SSam Leffler { 9165591b213SSam Leffler struct ath_softc *sc = (struct ath_softc *) arg; 9175591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 918fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 9195591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 9205591b213SSam Leffler HAL_STATUS status; 9215591b213SSam Leffler 922c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", 923c42a7b7eSSam Leffler __func__, ifp->if_flags); 9245591b213SSam Leffler 925f0b2a0beSSam Leffler ATH_LOCK(sc); 9265591b213SSam Leffler /* 9275591b213SSam Leffler * Stop anything previously setup. This is safe 9285591b213SSam Leffler * whether this is the first time through or not. 9295591b213SSam Leffler */ 930c42a7b7eSSam Leffler ath_stop_locked(ifp); 9315591b213SSam Leffler 9325591b213SSam Leffler /* 9335591b213SSam Leffler * The basic interface to setting the hardware in a good 9345591b213SSam Leffler * state is ``reset''. On return the hardware is known to 9355591b213SSam Leffler * be powered up and with interrupts disabled. This must 9365591b213SSam Leffler * be followed by initialization of the appropriate bits 9375591b213SSam Leffler * and then setup of the interrupt mask. 9385591b213SSam Leffler */ 939b5c99415SSam Leffler sc->sc_curchan.channel = ic->ic_curchan->ic_freq; 940b5c99415SSam Leffler sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan); 9417a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { 9425591b213SSam Leffler if_printf(ifp, "unable to reset hardware; hal status %u\n", 9435591b213SSam Leffler status); 9445591b213SSam Leffler goto done; 9455591b213SSam Leffler } 9465591b213SSam Leffler 9475591b213SSam Leffler /* 948c42a7b7eSSam Leffler * This is needed only to setup initial state 949c42a7b7eSSam Leffler * but it's best done after a reset. 950c42a7b7eSSam Leffler */ 951c42a7b7eSSam Leffler ath_update_txpow(sc); 952c59005e9SSam Leffler /* 953c59005e9SSam Leffler * Likewise this is set during reset so update 954c59005e9SSam Leffler * state cached in the driver. 955c59005e9SSam Leffler */ 956c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 957bd5a9920SSam Leffler sc->sc_calinterval = 1; 958bd5a9920SSam Leffler sc->sc_caltries = 0; 959c42a7b7eSSam Leffler 960c42a7b7eSSam Leffler /* 9615591b213SSam Leffler * Setup the hardware after reset: the key cache 9625591b213SSam Leffler * is filled as needed and the receive engine is 9635591b213SSam Leffler * set going. Frame transmit is handled entirely 9645591b213SSam Leffler * in the frame output path; there's nothing to do 9655591b213SSam Leffler * here except setup the interrupt mask. 9665591b213SSam Leffler */ 9675591b213SSam Leffler if (ath_startrecv(sc) != 0) { 9685591b213SSam Leffler if_printf(ifp, "unable to start recv logic\n"); 9695591b213SSam Leffler goto done; 9705591b213SSam Leffler } 9715591b213SSam Leffler 9725591b213SSam Leffler /* 9735591b213SSam Leffler * Enable interrupts. 9745591b213SSam Leffler */ 9755591b213SSam Leffler sc->sc_imask = HAL_INT_RX | HAL_INT_TX 9765591b213SSam Leffler | HAL_INT_RXEOL | HAL_INT_RXORN 9775591b213SSam Leffler | HAL_INT_FATAL | HAL_INT_GLOBAL; 978c42a7b7eSSam Leffler /* 979c42a7b7eSSam Leffler * Enable MIB interrupts when there are hardware phy counters. 980c42a7b7eSSam Leffler * Note we only do this (at the moment) for station mode. 981c42a7b7eSSam Leffler */ 982c42a7b7eSSam Leffler if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) 983c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_MIB; 9845591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 9855591b213SSam Leffler 98613f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_RUNNING; 9875591b213SSam Leffler ic->ic_state = IEEE80211_S_INIT; 9885591b213SSam Leffler 9895591b213SSam Leffler /* 9905591b213SSam Leffler * The hardware should be ready to go now so it's safe 9915591b213SSam Leffler * to kick the 802.11 state machine as it's likely to 9925591b213SSam Leffler * immediately call back to us to send mgmt frames. 9935591b213SSam Leffler */ 994b5c99415SSam Leffler ath_chan_change(sc, ic->ic_curchan); 99586e07743SSam Leffler #ifdef ATH_TX99_DIAG 99686e07743SSam Leffler if (sc->sc_tx99 != NULL) 99786e07743SSam Leffler sc->sc_tx99->start(sc->sc_tx99); 99886e07743SSam Leffler else 99986e07743SSam Leffler #endif 1000c42a7b7eSSam Leffler if (ic->ic_opmode != IEEE80211_M_MONITOR) { 1001c42a7b7eSSam Leffler if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 100245bbf62fSSam Leffler ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1003c42a7b7eSSam Leffler } else 10046b59f5e3SSam Leffler ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 10055591b213SSam Leffler done: 1006f0b2a0beSSam Leffler ATH_UNLOCK(sc); 10075591b213SSam Leffler } 10085591b213SSam Leffler 10095591b213SSam Leffler static void 1010c42a7b7eSSam Leffler ath_stop_locked(struct ifnet *ifp) 10115591b213SSam Leffler { 10125591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 1013c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 10145591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 10155591b213SSam Leffler 1016c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", 1017c42a7b7eSSam Leffler __func__, sc->sc_invalid, ifp->if_flags); 10185591b213SSam Leffler 1019c42a7b7eSSam Leffler ATH_LOCK_ASSERT(sc); 102013f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 10215591b213SSam Leffler /* 10225591b213SSam Leffler * Shutdown the hardware and driver: 1023c42a7b7eSSam Leffler * reset 802.11 state machine 10245591b213SSam Leffler * turn off timers 1025c42a7b7eSSam Leffler * disable interrupts 1026c42a7b7eSSam Leffler * turn off the radio 10275591b213SSam Leffler * clear transmit machinery 10285591b213SSam Leffler * clear receive machinery 10295591b213SSam Leffler * drain and release tx queues 10305591b213SSam Leffler * reclaim beacon resources 10315591b213SSam Leffler * power down hardware 10325591b213SSam Leffler * 10335591b213SSam Leffler * Note that some of this work is not possible if the 10345591b213SSam Leffler * hardware is gone (invalid). 10355591b213SSam Leffler */ 103686e07743SSam Leffler #ifdef ATH_TX99_DIAG 103786e07743SSam Leffler if (sc->sc_tx99 != NULL) 103886e07743SSam Leffler sc->sc_tx99->stop(sc->sc_tx99); 103986e07743SSam Leffler #endif 1040c42a7b7eSSam Leffler ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 104113f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 10425591b213SSam Leffler ifp->if_timer = 0; 1043c42a7b7eSSam Leffler if (!sc->sc_invalid) { 10443e50ec2cSSam Leffler if (sc->sc_softled) { 10453e50ec2cSSam Leffler callout_stop(&sc->sc_ledtimer); 10463e50ec2cSSam Leffler ath_hal_gpioset(ah, sc->sc_ledpin, 10473e50ec2cSSam Leffler !sc->sc_ledon); 10483e50ec2cSSam Leffler sc->sc_blinking = 0; 10493e50ec2cSSam Leffler } 10505591b213SSam Leffler ath_hal_intrset(ah, 0); 1051c42a7b7eSSam Leffler } 10525591b213SSam Leffler ath_draintxq(sc); 1053c42a7b7eSSam Leffler if (!sc->sc_invalid) { 10545591b213SSam Leffler ath_stoprecv(sc); 1055c42a7b7eSSam Leffler ath_hal_phydisable(ah); 1056c42a7b7eSSam Leffler } else 10575591b213SSam Leffler sc->sc_rxlink = NULL; 1058154b8df2SMax Laier IFQ_DRV_PURGE(&ifp->if_snd); 10595591b213SSam Leffler ath_beacon_free(sc); 1060c42a7b7eSSam Leffler } 1061c42a7b7eSSam Leffler } 1062c42a7b7eSSam Leffler 1063c42a7b7eSSam Leffler static void 1064c42a7b7eSSam Leffler ath_stop(struct ifnet *ifp) 1065c42a7b7eSSam Leffler { 1066c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1067c42a7b7eSSam Leffler 1068c42a7b7eSSam Leffler ATH_LOCK(sc); 1069c42a7b7eSSam Leffler ath_stop_locked(ifp); 1070c42a7b7eSSam Leffler if (!sc->sc_invalid) { 1071c42a7b7eSSam Leffler /* 1072c42a7b7eSSam Leffler * Set the chip in full sleep mode. Note that we are 1073c42a7b7eSSam Leffler * careful to do this only when bringing the interface 1074c42a7b7eSSam Leffler * completely to a stop. When the chip is in this state 1075c42a7b7eSSam Leffler * it must be carefully woken up or references to 1076c42a7b7eSSam Leffler * registers in the PCI clock domain may freeze the bus 1077c42a7b7eSSam Leffler * (and system). This varies by chip and is mostly an 1078c42a7b7eSSam Leffler * issue with newer parts that go to sleep more quickly. 1079c42a7b7eSSam Leffler */ 1080bd5a9920SSam Leffler ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); 10815591b213SSam Leffler } 1082f0b2a0beSSam Leffler ATH_UNLOCK(sc); 10835591b213SSam Leffler } 10845591b213SSam Leffler 10855591b213SSam Leffler /* 10865591b213SSam Leffler * Reset the hardware w/o losing operational state. This is 10875591b213SSam Leffler * basically a more efficient way of doing ath_stop, ath_init, 10885591b213SSam Leffler * followed by state transitions to the current 802.11 1089c42a7b7eSSam Leffler * operational state. Used to recover from various errors and 1090c42a7b7eSSam Leffler * to reset or reload hardware state. 10915591b213SSam Leffler */ 1092c42a7b7eSSam Leffler static int 1093c42a7b7eSSam Leffler ath_reset(struct ifnet *ifp) 10945591b213SSam Leffler { 1095c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 10965591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 10975591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 10985591b213SSam Leffler struct ieee80211_channel *c; 10995591b213SSam Leffler HAL_STATUS status; 11005591b213SSam Leffler 11015591b213SSam Leffler /* 11025591b213SSam Leffler * Convert to a HAL channel description with the flags 11035591b213SSam Leffler * constrained to reflect the current operating mode. 11045591b213SSam Leffler */ 1105b5c99415SSam Leffler c = ic->ic_curchan; 1106c42a7b7eSSam Leffler sc->sc_curchan.channel = c->ic_freq; 1107c42a7b7eSSam Leffler sc->sc_curchan.channelFlags = ath_chan2flags(ic, c); 11085591b213SSam Leffler 11095591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 11105591b213SSam Leffler ath_draintxq(sc); /* stop xmit side */ 11115591b213SSam Leffler ath_stoprecv(sc); /* stop recv side */ 11125591b213SSam Leffler /* NB: indicate channel change so we do a full reset */ 11137a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status)) 11145591b213SSam Leffler if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", 11155591b213SSam Leffler __func__, status); 1116c42a7b7eSSam Leffler ath_update_txpow(sc); /* update tx power state */ 1117c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 1118bd5a9920SSam Leffler sc->sc_calinterval = 1; 1119bd5a9920SSam Leffler sc->sc_caltries = 0; 1120c42a7b7eSSam Leffler /* 1121c42a7b7eSSam Leffler * We may be doing a reset in response to an ioctl 1122c42a7b7eSSam Leffler * that changes the channel so update any state that 1123c42a7b7eSSam Leffler * might change as a result. 1124c42a7b7eSSam Leffler */ 1125c42a7b7eSSam Leffler ath_chan_change(sc, c); 1126bd5a9920SSam Leffler if (ath_startrecv(sc) != 0) /* restart recv */ 1127bd5a9920SSam Leffler if_printf(ifp, "%s: unable to start recv logic\n", __func__); 11285591b213SSam Leffler if (ic->ic_state == IEEE80211_S_RUN) 11295591b213SSam Leffler ath_beacon_config(sc); /* restart beacons */ 1130c42a7b7eSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 1131c42a7b7eSSam Leffler 1132c42a7b7eSSam Leffler ath_start(ifp); /* restart xmit */ 1133c42a7b7eSSam Leffler return 0; 11345591b213SSam Leffler } 11355591b213SSam Leffler 11365591b213SSam Leffler static void 11375591b213SSam Leffler ath_start(struct ifnet *ifp) 11385591b213SSam Leffler { 11395591b213SSam Leffler struct ath_softc *sc = ifp->if_softc; 11405591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 11415591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 11425591b213SSam Leffler struct ieee80211_node *ni; 11435591b213SSam Leffler struct ath_buf *bf; 11445591b213SSam Leffler struct mbuf *m; 11455591b213SSam Leffler struct ieee80211_frame *wh; 1146c42a7b7eSSam Leffler struct ether_header *eh; 11475591b213SSam Leffler 114813f4c340SRobert Watson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) 11495591b213SSam Leffler return; 11505591b213SSam Leffler for (;;) { 11515591b213SSam Leffler /* 11525591b213SSam Leffler * Grab a TX buffer and associated resources. 11535591b213SSam Leffler */ 1154f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1155c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_txbuf); 1156ebecf802SSam Leffler if (bf != NULL) 1157c42a7b7eSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); 1158f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11595591b213SSam Leffler if (bf == NULL) { 1160ebecf802SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", 1161ebecf802SSam Leffler __func__); 11625591b213SSam Leffler sc->sc_stats.ast_tx_qstop++; 116313f4c340SRobert Watson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 11645591b213SSam Leffler break; 11655591b213SSam Leffler } 11665591b213SSam Leffler /* 11675591b213SSam Leffler * Poll the management queue for frames; they 11685591b213SSam Leffler * have priority over normal data frames. 11695591b213SSam Leffler */ 11705591b213SSam Leffler IF_DEQUEUE(&ic->ic_mgtq, m); 11715591b213SSam Leffler if (m == NULL) { 11725591b213SSam Leffler /* 11735591b213SSam Leffler * No data frames go out unless we're associated. 11745591b213SSam Leffler */ 11755591b213SSam Leffler if (ic->ic_state != IEEE80211_S_RUN) { 1176370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1177370572d9SSam Leffler "%s: discard data packet, state %s\n", 1178370572d9SSam Leffler __func__, 1179370572d9SSam Leffler ieee80211_state_name[ic->ic_state]); 11805591b213SSam Leffler sc->sc_stats.ast_tx_discard++; 1181f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1182ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1183f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11845591b213SSam Leffler break; 11855591b213SSam Leffler } 1186154b8df2SMax Laier IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ 11875591b213SSam Leffler if (m == NULL) { 1188f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 1189ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1190f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 11915591b213SSam Leffler break; 11925591b213SSam Leffler } 1193c42a7b7eSSam Leffler /* 1194c42a7b7eSSam Leffler * Find the node for the destination so we can do 1195c42a7b7eSSam Leffler * things like power save and fast frames aggregation. 1196c42a7b7eSSam Leffler */ 1197c42a7b7eSSam Leffler if (m->m_len < sizeof(struct ether_header) && 1198c42a7b7eSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 1199c42a7b7eSSam Leffler ic->ic_stats.is_tx_nobuf++; /* XXX */ 1200c42a7b7eSSam Leffler ni = NULL; 1201c42a7b7eSSam Leffler goto bad; 1202c42a7b7eSSam Leffler } 1203c42a7b7eSSam Leffler eh = mtod(m, struct ether_header *); 1204c42a7b7eSSam Leffler ni = ieee80211_find_txnode(ic, eh->ether_dhost); 1205c42a7b7eSSam Leffler if (ni == NULL) { 1206c42a7b7eSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 1207fe234894SSam Leffler m_freem(m); 1208c42a7b7eSSam Leffler goto bad; 1209c42a7b7eSSam Leffler } 1210c42a7b7eSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 1211c42a7b7eSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 1212c42a7b7eSSam Leffler /* 1213c42a7b7eSSam Leffler * Station in power save mode; pass the frame 1214c42a7b7eSSam Leffler * to the 802.11 layer and continue. We'll get 1215c42a7b7eSSam Leffler * the frame back when the time is right. 1216c42a7b7eSSam Leffler */ 1217c42a7b7eSSam Leffler ieee80211_pwrsave(ic, ni, m); 1218c42a7b7eSSam Leffler goto reclaim; 1219c42a7b7eSSam Leffler } 1220c42a7b7eSSam Leffler /* calculate priority so we can find the tx queue */ 1221c42a7b7eSSam Leffler if (ieee80211_classify(ic, m, ni)) { 1222c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1223c42a7b7eSSam Leffler "%s: discard, classification failure\n", 1224c42a7b7eSSam Leffler __func__); 1225fe234894SSam Leffler m_freem(m); 1226c42a7b7eSSam Leffler goto bad; 1227c42a7b7eSSam Leffler } 12285591b213SSam Leffler ifp->if_opackets++; 12295591b213SSam Leffler BPF_MTAP(ifp, m); 12305591b213SSam Leffler /* 12315591b213SSam Leffler * Encapsulate the packet in prep for transmission. 12325591b213SSam Leffler */ 1233c42a7b7eSSam Leffler m = ieee80211_encap(ic, m, ni); 12345591b213SSam Leffler if (m == NULL) { 1235370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 1236c42a7b7eSSam Leffler "%s: encapsulation failure\n", 1237c42a7b7eSSam Leffler __func__); 12385591b213SSam Leffler sc->sc_stats.ast_tx_encap++; 12395591b213SSam Leffler goto bad; 12405591b213SSam Leffler } 12415591b213SSam Leffler } else { 12420a915fadSSam Leffler /* 12430a915fadSSam Leffler * Hack! The referenced node pointer is in the 12440a915fadSSam Leffler * rcvif field of the packet header. This is 12450a915fadSSam Leffler * placed there by ieee80211_mgmt_output because 12460a915fadSSam Leffler * we need to hold the reference with the frame 12470a915fadSSam Leffler * and there's no other way (other than packet 12480a915fadSSam Leffler * tags which we consider too expensive to use) 12490a915fadSSam Leffler * to pass it along. 12500a915fadSSam Leffler */ 12510a915fadSSam Leffler ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 12520a915fadSSam Leffler m->m_pkthdr.rcvif = NULL; 12530a915fadSSam Leffler 12545591b213SSam Leffler wh = mtod(m, struct ieee80211_frame *); 12555591b213SSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 12565591b213SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_RESP) { 12575591b213SSam Leffler /* fill time stamp */ 12585591b213SSam Leffler u_int64_t tsf; 12595591b213SSam Leffler u_int32_t *tstamp; 12605591b213SSam Leffler 12615591b213SSam Leffler tsf = ath_hal_gettsf64(ah); 12625591b213SSam Leffler /* XXX: adjust 100us delay to xmit */ 12635591b213SSam Leffler tsf += 100; 12645591b213SSam Leffler tstamp = (u_int32_t *)&wh[1]; 12655591b213SSam Leffler tstamp[0] = htole32(tsf & 0xffffffff); 12665591b213SSam Leffler tstamp[1] = htole32(tsf >> 32); 12675591b213SSam Leffler } 12685591b213SSam Leffler sc->sc_stats.ast_tx_mgmt++; 12695591b213SSam Leffler } 127073454c73SSam Leffler 12715591b213SSam Leffler if (ath_tx_start(sc, ni, bf, m)) { 12725591b213SSam Leffler bad: 12735591b213SSam Leffler ifp->if_oerrors++; 1274c42a7b7eSSam Leffler reclaim: 1275c42a7b7eSSam Leffler ATH_TXBUF_LOCK(sc); 1276ebecf802SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 1277c42a7b7eSSam Leffler ATH_TXBUF_UNLOCK(sc); 1278c42a7b7eSSam Leffler if (ni != NULL) 1279c42a7b7eSSam Leffler ieee80211_free_node(ni); 12805591b213SSam Leffler continue; 12815591b213SSam Leffler } 12825591b213SSam Leffler 12835591b213SSam Leffler sc->sc_tx_timer = 5; 12845591b213SSam Leffler ifp->if_timer = 1; 12855591b213SSam Leffler } 12865591b213SSam Leffler } 12875591b213SSam Leffler 12885591b213SSam Leffler static int 12895591b213SSam Leffler ath_media_change(struct ifnet *ifp) 12905591b213SSam Leffler { 1291c42a7b7eSSam Leffler #define IS_UP(ifp) \ 129213f4c340SRobert Watson ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 12935591b213SSam Leffler int error; 12945591b213SSam Leffler 12955591b213SSam Leffler error = ieee80211_media_change(ifp); 12965591b213SSam Leffler if (error == ENETRESET) { 12977a04dc27SSam Leffler struct ath_softc *sc = ifp->if_softc; 12987a04dc27SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 12997a04dc27SSam Leffler 13007a04dc27SSam Leffler if (ic->ic_opmode == IEEE80211_M_AHDEMO) { 13017a04dc27SSam Leffler /* 13027a04dc27SSam Leffler * Adhoc demo mode is just ibss mode w/o beacons 13037a04dc27SSam Leffler * (mostly). The hal knows nothing about it; 13047a04dc27SSam Leffler * tell it we're operating in ibss mode. 13057a04dc27SSam Leffler */ 13067a04dc27SSam Leffler sc->sc_opmode = HAL_M_IBSS; 13077a04dc27SSam Leffler } else 13087a04dc27SSam Leffler sc->sc_opmode = ic->ic_opmode; 1309c42a7b7eSSam Leffler if (IS_UP(ifp)) 1310fc74a9f9SBrooks Davis ath_init(ifp->if_softc); /* XXX lose error */ 13115591b213SSam Leffler error = 0; 13125591b213SSam Leffler } 13135591b213SSam Leffler return error; 1314c42a7b7eSSam Leffler #undef IS_UP 13155591b213SSam Leffler } 13165591b213SSam Leffler 1317a585a9a1SSam Leffler #ifdef ATH_DEBUG 1318c42a7b7eSSam Leffler static void 13195901d2d3SSam Leffler ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix, 1320c42a7b7eSSam Leffler const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) 13215591b213SSam Leffler { 1322c42a7b7eSSam Leffler static const char *ciphers[] = { 1323c42a7b7eSSam Leffler "WEP", 1324c42a7b7eSSam Leffler "AES-OCB", 1325c42a7b7eSSam Leffler "AES-CCM", 1326c42a7b7eSSam Leffler "CKIP", 1327c42a7b7eSSam Leffler "TKIP", 1328c42a7b7eSSam Leffler "CLR", 1329c42a7b7eSSam Leffler }; 1330c42a7b7eSSam Leffler int i, n; 13315591b213SSam Leffler 1332c42a7b7eSSam Leffler printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]); 1333c42a7b7eSSam Leffler for (i = 0, n = hk->kv_len; i < n; i++) 1334c42a7b7eSSam Leffler printf("%02x", hk->kv_val[i]); 1335c42a7b7eSSam Leffler printf(" mac %s", ether_sprintf(mac)); 1336c42a7b7eSSam Leffler if (hk->kv_type == HAL_CIPHER_TKIP) { 13375901d2d3SSam Leffler printf(" %s ", sc->sc_splitmic ? "mic" : "rxmic"); 1338c42a7b7eSSam Leffler for (i = 0; i < sizeof(hk->kv_mic); i++) 1339c42a7b7eSSam Leffler printf("%02x", hk->kv_mic[i]); 13405901d2d3SSam Leffler #if HAL_ABI_VERSION > 0x06052200 13415901d2d3SSam Leffler if (!sc->sc_splitmic) { 13425901d2d3SSam Leffler printf(" txmic "); 13435901d2d3SSam Leffler for (i = 0; i < sizeof(hk->kv_txmic); i++) 13445901d2d3SSam Leffler printf("%02x", hk->kv_txmic[i]); 13455901d2d3SSam Leffler } 13465901d2d3SSam Leffler #endif 13472075afbaSSam Leffler } 1348c42a7b7eSSam Leffler printf("\n"); 1349c42a7b7eSSam Leffler } 1350c42a7b7eSSam Leffler #endif 1351c42a7b7eSSam Leffler 13525591b213SSam Leffler /* 1353c42a7b7eSSam Leffler * Set a TKIP key into the hardware. This handles the 1354c42a7b7eSSam Leffler * potential distribution of key state to multiple key 1355c42a7b7eSSam Leffler * cache slots for TKIP. 13565591b213SSam Leffler */ 1357c42a7b7eSSam Leffler static int 1358c42a7b7eSSam Leffler ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k, 1359c42a7b7eSSam Leffler HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) 1360c42a7b7eSSam Leffler { 1361c42a7b7eSSam Leffler #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) 1362c42a7b7eSSam Leffler static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; 13638cec0ab9SSam Leffler struct ath_hal *ah = sc->sc_ah; 13648cec0ab9SSam Leffler 1365c42a7b7eSSam Leffler KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP, 1366c42a7b7eSSam Leffler ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher)); 1367c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { 13685901d2d3SSam Leffler if (sc->sc_splitmic) { 1369c42a7b7eSSam Leffler /* 1370c1225b52SSam Leffler * TX key goes at first index, RX key at the rx index. 1371c42a7b7eSSam Leffler * The hal handles the MIC keys at index+64. 1372c42a7b7eSSam Leffler */ 1373c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); 1374c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); 1375c42a7b7eSSam Leffler if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid)) 1376c42a7b7eSSam Leffler return 0; 1377c42a7b7eSSam Leffler 1378c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); 1379c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix+32, hk, mac); 1380c42a7b7eSSam Leffler /* XXX delete tx key on failure? */ 1381c42a7b7eSSam Leffler return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac); 13825901d2d3SSam Leffler } else { 13835901d2d3SSam Leffler /* 13845901d2d3SSam Leffler * Room for both TX+RX MIC keys in one key cache 13855901d2d3SSam Leffler * slot, just set key at the first index; the hal 13865901d2d3SSam Leffler * will handle the reset. 13875901d2d3SSam Leffler */ 13885901d2d3SSam Leffler memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); 13895901d2d3SSam Leffler #if HAL_ABI_VERSION > 0x06052200 13905901d2d3SSam Leffler memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic)); 13915901d2d3SSam Leffler #endif 13925901d2d3SSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, mac); 13935901d2d3SSam Leffler return ath_hal_keyset(ah, k->wk_keyix, hk, mac); 13945901d2d3SSam Leffler } 1395c42a7b7eSSam Leffler } else if (k->wk_flags & IEEE80211_KEY_XR) { 1396c42a7b7eSSam Leffler /* 1397c42a7b7eSSam Leffler * TX/RX key goes at first index. 1398c42a7b7eSSam Leffler * The hal handles the MIC keys are index+64. 1399c42a7b7eSSam Leffler */ 1400c42a7b7eSSam Leffler memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ? 1401c42a7b7eSSam Leffler k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic)); 1402e8fd88a3SSam Leffler KEYPRINTF(sc, k->wk_keyix, hk, mac); 1403e8fd88a3SSam Leffler return ath_hal_keyset(ah, k->wk_keyix, hk, mac); 1404c42a7b7eSSam Leffler } 1405c42a7b7eSSam Leffler return 0; 1406c42a7b7eSSam Leffler #undef IEEE80211_KEY_XR 1407c42a7b7eSSam Leffler } 1408c42a7b7eSSam Leffler 1409c42a7b7eSSam Leffler /* 1410c42a7b7eSSam Leffler * Set a net80211 key into the hardware. This handles the 1411c42a7b7eSSam Leffler * potential distribution of key state to multiple key 1412c42a7b7eSSam Leffler * cache slots for TKIP with hardware MIC support. 1413c42a7b7eSSam Leffler */ 1414c42a7b7eSSam Leffler static int 1415c42a7b7eSSam Leffler ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, 1416e8fd88a3SSam Leffler const u_int8_t mac0[IEEE80211_ADDR_LEN], 1417e8fd88a3SSam Leffler struct ieee80211_node *bss) 1418c42a7b7eSSam Leffler { 1419c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1420c42a7b7eSSam Leffler static const u_int8_t ciphermap[] = { 1421c42a7b7eSSam Leffler HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ 1422c42a7b7eSSam Leffler HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ 1423c42a7b7eSSam Leffler HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ 1424c42a7b7eSSam Leffler HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ 1425c42a7b7eSSam Leffler (u_int8_t) -1, /* 4 is not allocated */ 1426c42a7b7eSSam Leffler HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ 1427c42a7b7eSSam Leffler HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ 1428c42a7b7eSSam Leffler }; 1429c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1430c42a7b7eSSam Leffler const struct ieee80211_cipher *cip = k->wk_cipher; 1431e8fd88a3SSam Leffler u_int8_t gmac[IEEE80211_ADDR_LEN]; 1432e8fd88a3SSam Leffler const u_int8_t *mac; 1433c42a7b7eSSam Leffler HAL_KEYVAL hk; 1434c42a7b7eSSam Leffler 1435c42a7b7eSSam Leffler memset(&hk, 0, sizeof(hk)); 1436c42a7b7eSSam Leffler /* 1437c42a7b7eSSam Leffler * Software crypto uses a "clear key" so non-crypto 1438c42a7b7eSSam Leffler * state kept in the key cache are maintained and 1439c42a7b7eSSam Leffler * so that rx frames have an entry to match. 1440c42a7b7eSSam Leffler */ 1441c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 1442c42a7b7eSSam Leffler KASSERT(cip->ic_cipher < N(ciphermap), 1443c42a7b7eSSam Leffler ("invalid cipher type %u", cip->ic_cipher)); 1444c42a7b7eSSam Leffler hk.kv_type = ciphermap[cip->ic_cipher]; 1445c42a7b7eSSam Leffler hk.kv_len = k->wk_keylen; 1446c42a7b7eSSam Leffler memcpy(hk.kv_val, k->wk_key, k->wk_keylen); 14478cec0ab9SSam Leffler } else 1448c42a7b7eSSam Leffler hk.kv_type = HAL_CIPHER_CLR; 1449c42a7b7eSSam Leffler 1450e8fd88a3SSam Leffler if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) { 1451e8fd88a3SSam Leffler /* 1452e8fd88a3SSam Leffler * Group keys on hardware that supports multicast frame 1453e8fd88a3SSam Leffler * key search use a mac that is the sender's address with 1454e8fd88a3SSam Leffler * the high bit set instead of the app-specified address. 1455e8fd88a3SSam Leffler */ 1456e8fd88a3SSam Leffler IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr); 1457e8fd88a3SSam Leffler gmac[0] |= 0x80; 1458e8fd88a3SSam Leffler mac = gmac; 1459e8fd88a3SSam Leffler } else 1460e8fd88a3SSam Leffler mac = mac0; 1461e8fd88a3SSam Leffler 1462c42a7b7eSSam Leffler if (hk.kv_type == HAL_CIPHER_TKIP && 14635901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 1464c42a7b7eSSam Leffler return ath_keyset_tkip(sc, k, &hk, mac); 1465c42a7b7eSSam Leffler } else { 1466c42a7b7eSSam Leffler KEYPRINTF(sc, k->wk_keyix, &hk, mac); 1467c42a7b7eSSam Leffler return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); 14688cec0ab9SSam Leffler } 1469c42a7b7eSSam Leffler #undef N 14705591b213SSam Leffler } 14715591b213SSam Leffler 14725591b213SSam Leffler /* 1473c42a7b7eSSam Leffler * Allocate tx/rx key slots for TKIP. We allocate two slots for 1474c42a7b7eSSam Leffler * each key, one for decrypt/encrypt and the other for the MIC. 1475c42a7b7eSSam Leffler */ 1476c42a7b7eSSam Leffler static u_int16_t 1477c1225b52SSam Leffler key_alloc_2pair(struct ath_softc *sc, 1478c1225b52SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 1479c42a7b7eSSam Leffler { 1480c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1481c42a7b7eSSam Leffler u_int i, keyix; 1482c42a7b7eSSam Leffler 1483c42a7b7eSSam Leffler KASSERT(sc->sc_splitmic, ("key cache !split")); 1484c42a7b7eSSam Leffler /* XXX could optimize */ 1485c42a7b7eSSam Leffler for (i = 0; i < N(sc->sc_keymap)/4; i++) { 1486c42a7b7eSSam Leffler u_int8_t b = sc->sc_keymap[i]; 1487c42a7b7eSSam Leffler if (b != 0xff) { 1488c42a7b7eSSam Leffler /* 1489c42a7b7eSSam Leffler * One or more slots in this byte are free. 1490c42a7b7eSSam Leffler */ 1491c42a7b7eSSam Leffler keyix = i*NBBY; 1492c42a7b7eSSam Leffler while (b & 1) { 1493c42a7b7eSSam Leffler again: 1494c42a7b7eSSam Leffler keyix++; 1495c42a7b7eSSam Leffler b >>= 1; 1496c42a7b7eSSam Leffler } 1497c42a7b7eSSam Leffler /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ 1498c42a7b7eSSam Leffler if (isset(sc->sc_keymap, keyix+32) || 1499c42a7b7eSSam Leffler isset(sc->sc_keymap, keyix+64) || 1500c42a7b7eSSam Leffler isset(sc->sc_keymap, keyix+32+64)) { 1501c42a7b7eSSam Leffler /* full pair unavailable */ 1502c42a7b7eSSam Leffler /* XXX statistic */ 1503c42a7b7eSSam Leffler if (keyix == (i+1)*NBBY) { 1504c42a7b7eSSam Leffler /* no slots were appropriate, advance */ 1505c42a7b7eSSam Leffler continue; 1506c42a7b7eSSam Leffler } 1507c42a7b7eSSam Leffler goto again; 1508c42a7b7eSSam Leffler } 1509c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix); 1510c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+64); 1511c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+32); 1512c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix+32+64); 1513c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 1514c42a7b7eSSam Leffler "%s: key pair %u,%u %u,%u\n", 1515c42a7b7eSSam Leffler __func__, keyix, keyix+64, 1516c42a7b7eSSam Leffler keyix+32, keyix+32+64); 1517c1225b52SSam Leffler *txkeyix = keyix; 1518c1225b52SSam Leffler *rxkeyix = keyix+32; 1519c1225b52SSam Leffler return 1; 1520c42a7b7eSSam Leffler } 1521c42a7b7eSSam Leffler } 1522c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); 1523c1225b52SSam Leffler return 0; 1524c42a7b7eSSam Leffler #undef N 1525c42a7b7eSSam Leffler } 1526c42a7b7eSSam Leffler 1527c42a7b7eSSam Leffler /* 15285901d2d3SSam Leffler * Allocate tx/rx key slots for TKIP. We allocate two slots for 15295901d2d3SSam Leffler * each key, one for decrypt/encrypt and the other for the MIC. 15305901d2d3SSam Leffler */ 15315901d2d3SSam Leffler static u_int16_t 15325901d2d3SSam Leffler key_alloc_pair(struct ath_softc *sc, 15335901d2d3SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 15345901d2d3SSam Leffler { 15355901d2d3SSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 15365901d2d3SSam Leffler u_int i, keyix; 15375901d2d3SSam Leffler 15385901d2d3SSam Leffler KASSERT(!sc->sc_splitmic, ("key cache split")); 15395901d2d3SSam Leffler /* XXX could optimize */ 15405901d2d3SSam Leffler for (i = 0; i < N(sc->sc_keymap)/4; i++) { 15415901d2d3SSam Leffler u_int8_t b = sc->sc_keymap[i]; 15425901d2d3SSam Leffler if (b != 0xff) { 15435901d2d3SSam Leffler /* 15445901d2d3SSam Leffler * One or more slots in this byte are free. 15455901d2d3SSam Leffler */ 15465901d2d3SSam Leffler keyix = i*NBBY; 15475901d2d3SSam Leffler while (b & 1) { 15485901d2d3SSam Leffler again: 15495901d2d3SSam Leffler keyix++; 15505901d2d3SSam Leffler b >>= 1; 15515901d2d3SSam Leffler } 15525901d2d3SSam Leffler if (isset(sc->sc_keymap, keyix+64)) { 15535901d2d3SSam Leffler /* full pair unavailable */ 15545901d2d3SSam Leffler /* XXX statistic */ 15555901d2d3SSam Leffler if (keyix == (i+1)*NBBY) { 15565901d2d3SSam Leffler /* no slots were appropriate, advance */ 15575901d2d3SSam Leffler continue; 15585901d2d3SSam Leffler } 15595901d2d3SSam Leffler goto again; 15605901d2d3SSam Leffler } 15615901d2d3SSam Leffler setbit(sc->sc_keymap, keyix); 15625901d2d3SSam Leffler setbit(sc->sc_keymap, keyix+64); 15635901d2d3SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 15645901d2d3SSam Leffler "%s: key pair %u,%u\n", 15655901d2d3SSam Leffler __func__, keyix, keyix+64); 15665901d2d3SSam Leffler *txkeyix = *rxkeyix = keyix; 15675901d2d3SSam Leffler return 1; 15685901d2d3SSam Leffler } 15695901d2d3SSam Leffler } 15705901d2d3SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); 15715901d2d3SSam Leffler return 0; 15725901d2d3SSam Leffler #undef N 15735901d2d3SSam Leffler } 15745901d2d3SSam Leffler 15755901d2d3SSam Leffler /* 1576c42a7b7eSSam Leffler * Allocate a single key cache slot. 1577c42a7b7eSSam Leffler */ 1578c1225b52SSam Leffler static int 1579c1225b52SSam Leffler key_alloc_single(struct ath_softc *sc, 1580c1225b52SSam Leffler ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 1581c42a7b7eSSam Leffler { 1582c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 1583c42a7b7eSSam Leffler u_int i, keyix; 1584c42a7b7eSSam Leffler 1585c42a7b7eSSam Leffler /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ 1586c42a7b7eSSam Leffler for (i = 0; i < N(sc->sc_keymap); i++) { 1587c42a7b7eSSam Leffler u_int8_t b = sc->sc_keymap[i]; 1588c42a7b7eSSam Leffler if (b != 0xff) { 1589c42a7b7eSSam Leffler /* 1590c42a7b7eSSam Leffler * One or more slots are free. 1591c42a7b7eSSam Leffler */ 1592c42a7b7eSSam Leffler keyix = i*NBBY; 1593c42a7b7eSSam Leffler while (b & 1) 1594c42a7b7eSSam Leffler keyix++, b >>= 1; 1595c42a7b7eSSam Leffler setbit(sc->sc_keymap, keyix); 1596c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n", 1597c42a7b7eSSam Leffler __func__, keyix); 1598c1225b52SSam Leffler *txkeyix = *rxkeyix = keyix; 1599c1225b52SSam Leffler return 1; 1600c42a7b7eSSam Leffler } 1601c42a7b7eSSam Leffler } 1602c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__); 1603c1225b52SSam Leffler return 0; 1604c42a7b7eSSam Leffler #undef N 1605c42a7b7eSSam Leffler } 1606c42a7b7eSSam Leffler 1607c42a7b7eSSam Leffler /* 1608c42a7b7eSSam Leffler * Allocate one or more key cache slots for a uniacst key. The 1609c42a7b7eSSam Leffler * key itself is needed only to identify the cipher. For hardware 1610c42a7b7eSSam Leffler * TKIP with split cipher+MIC keys we allocate two key cache slot 1611c42a7b7eSSam Leffler * pairs so that we can setup separate TX and RX MIC keys. Note 1612c42a7b7eSSam Leffler * that the MIC key for a TKIP key at slot i is assumed by the 1613c42a7b7eSSam Leffler * hardware to be at slot i+64. This limits TKIP keys to the first 1614c42a7b7eSSam Leffler * 64 entries. 1615c42a7b7eSSam Leffler */ 1616c42a7b7eSSam Leffler static int 1617c1225b52SSam Leffler ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k, 1618c1225b52SSam Leffler ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 1619c42a7b7eSSam Leffler { 1620c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1621c42a7b7eSSam Leffler 1622c42a7b7eSSam Leffler /* 16238ca623d7SSam Leffler * Group key allocation must be handled specially for 16248ca623d7SSam Leffler * parts that do not support multicast key cache search 16258ca623d7SSam Leffler * functionality. For those parts the key id must match 16268ca623d7SSam Leffler * the h/w key index so lookups find the right key. On 16278ca623d7SSam Leffler * parts w/ the key search facility we install the sender's 16288ca623d7SSam Leffler * mac address (with the high bit set) and let the hardware 16298ca623d7SSam Leffler * find the key w/o using the key id. This is preferred as 16308ca623d7SSam Leffler * it permits us to support multiple users for adhoc and/or 16318ca623d7SSam Leffler * multi-station operation. 16328ca623d7SSam Leffler */ 16338ca623d7SSam Leffler if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) { 16348ca623d7SSam Leffler if (!(&ic->ic_nw_keys[0] <= k && 16358ca623d7SSam Leffler k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) { 16368ca623d7SSam Leffler /* should not happen */ 16378ca623d7SSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, 16388ca623d7SSam Leffler "%s: bogus group key\n", __func__); 1639c1225b52SSam Leffler return 0; 16408ca623d7SSam Leffler } 16418ca623d7SSam Leffler /* 16428ca623d7SSam Leffler * XXX we pre-allocate the global keys so 16438ca623d7SSam Leffler * have no way to check if they've already been allocated. 16448ca623d7SSam Leffler */ 1645c1225b52SSam Leffler *keyix = *rxkeyix = k - ic->ic_nw_keys; 1646c1225b52SSam Leffler return 1; 16478ca623d7SSam Leffler } 16488ca623d7SSam Leffler 16498ca623d7SSam Leffler /* 1650c42a7b7eSSam Leffler * We allocate two pair for TKIP when using the h/w to do 1651c42a7b7eSSam Leffler * the MIC. For everything else, including software crypto, 1652c42a7b7eSSam Leffler * we allocate a single entry. Note that s/w crypto requires 1653c42a7b7eSSam Leffler * a pass-through slot on the 5211 and 5212. The 5210 does 1654c42a7b7eSSam Leffler * not support pass-through cache entries and we map all 1655c42a7b7eSSam Leffler * those requests to slot 0. 1656c42a7b7eSSam Leffler */ 1657c42a7b7eSSam Leffler if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 1658c1225b52SSam Leffler return key_alloc_single(sc, keyix, rxkeyix); 1659c42a7b7eSSam Leffler } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP && 16605901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 16615901d2d3SSam Leffler if (sc->sc_splitmic) 1662c1225b52SSam Leffler return key_alloc_2pair(sc, keyix, rxkeyix); 16635901d2d3SSam Leffler else 16645901d2d3SSam Leffler return key_alloc_pair(sc, keyix, rxkeyix); 1665c42a7b7eSSam Leffler } else { 1666c1225b52SSam Leffler return key_alloc_single(sc, keyix, rxkeyix); 1667c42a7b7eSSam Leffler } 1668c42a7b7eSSam Leffler } 1669c42a7b7eSSam Leffler 1670c42a7b7eSSam Leffler /* 1671c42a7b7eSSam Leffler * Delete an entry in the key cache allocated by ath_key_alloc. 1672c42a7b7eSSam Leffler */ 1673c42a7b7eSSam Leffler static int 1674c42a7b7eSSam Leffler ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) 1675c42a7b7eSSam Leffler { 1676c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1677c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1678c42a7b7eSSam Leffler const struct ieee80211_cipher *cip = k->wk_cipher; 1679c42a7b7eSSam Leffler u_int keyix = k->wk_keyix; 1680c42a7b7eSSam Leffler 1681c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); 1682c42a7b7eSSam Leffler 1683c42a7b7eSSam Leffler ath_hal_keyreset(ah, keyix); 1684c42a7b7eSSam Leffler /* 1685c42a7b7eSSam Leffler * Handle split tx/rx keying required for TKIP with h/w MIC. 1686c42a7b7eSSam Leffler */ 1687c42a7b7eSSam Leffler if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 1688c1225b52SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) 1689c42a7b7eSSam Leffler ath_hal_keyreset(ah, keyix+32); /* RX key */ 1690c42a7b7eSSam Leffler if (keyix >= IEEE80211_WEP_NKID) { 1691c42a7b7eSSam Leffler /* 1692c42a7b7eSSam Leffler * Don't touch keymap entries for global keys so 1693c42a7b7eSSam Leffler * they are never considered for dynamic allocation. 1694c42a7b7eSSam Leffler */ 1695c42a7b7eSSam Leffler clrbit(sc->sc_keymap, keyix); 1696c42a7b7eSSam Leffler if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 16975901d2d3SSam Leffler (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { 1698c42a7b7eSSam Leffler clrbit(sc->sc_keymap, keyix+64); /* TX key MIC */ 16995901d2d3SSam Leffler if (sc->sc_splitmic) { 17005901d2d3SSam Leffler /* +32 for RX key, +32+64 for RX key MIC */ 17015901d2d3SSam Leffler clrbit(sc->sc_keymap, keyix+32); 17025901d2d3SSam Leffler clrbit(sc->sc_keymap, keyix+32+64); 17035901d2d3SSam Leffler } 1704c42a7b7eSSam Leffler } 1705c42a7b7eSSam Leffler } 1706c42a7b7eSSam Leffler return 1; 1707c42a7b7eSSam Leffler } 1708c42a7b7eSSam Leffler 1709c42a7b7eSSam Leffler /* 1710c42a7b7eSSam Leffler * Set the key cache contents for the specified key. Key cache 1711c42a7b7eSSam Leffler * slot(s) must already have been allocated by ath_key_alloc. 1712c42a7b7eSSam Leffler */ 1713c42a7b7eSSam Leffler static int 1714c42a7b7eSSam Leffler ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, 1715c42a7b7eSSam Leffler const u_int8_t mac[IEEE80211_ADDR_LEN]) 1716c42a7b7eSSam Leffler { 1717c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 1718c42a7b7eSSam Leffler 1719e8fd88a3SSam Leffler return ath_keyset(sc, k, mac, ic->ic_bss); 1720c42a7b7eSSam Leffler } 1721c42a7b7eSSam Leffler 1722c42a7b7eSSam Leffler /* 1723c42a7b7eSSam Leffler * Block/unblock tx+rx processing while a key change is done. 1724c42a7b7eSSam Leffler * We assume the caller serializes key management operations 1725c42a7b7eSSam Leffler * so we only need to worry about synchronization with other 1726c42a7b7eSSam Leffler * uses that originate in the driver. 1727c42a7b7eSSam Leffler */ 1728c42a7b7eSSam Leffler static void 1729c42a7b7eSSam Leffler ath_key_update_begin(struct ieee80211com *ic) 1730c42a7b7eSSam Leffler { 1731c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 1732c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1733c42a7b7eSSam Leffler 1734c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1735c42a7b7eSSam Leffler #if 0 1736c42a7b7eSSam Leffler tasklet_disable(&sc->sc_rxtq); 1737c42a7b7eSSam Leffler #endif 1738c42a7b7eSSam Leffler IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */ 1739c42a7b7eSSam Leffler } 1740c42a7b7eSSam Leffler 1741c42a7b7eSSam Leffler static void 1742c42a7b7eSSam Leffler ath_key_update_end(struct ieee80211com *ic) 1743c42a7b7eSSam Leffler { 1744c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 1745c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1746c42a7b7eSSam Leffler 1747c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); 1748c42a7b7eSSam Leffler IF_UNLOCK(&ifp->if_snd); 1749c42a7b7eSSam Leffler #if 0 1750c42a7b7eSSam Leffler tasklet_enable(&sc->sc_rxtq); 1751c42a7b7eSSam Leffler #endif 1752c42a7b7eSSam Leffler } 17535591b213SSam Leffler 17544bc0e754SSam Leffler /* 17554bc0e754SSam Leffler * Calculate the receive filter according to the 17564bc0e754SSam Leffler * operating mode and state: 17574bc0e754SSam Leffler * 17584bc0e754SSam Leffler * o always accept unicast, broadcast, and multicast traffic 1759c42a7b7eSSam Leffler * o maintain current state of phy error reception (the hal 1760c42a7b7eSSam Leffler * may enable phy error frames for noise immunity work) 17614bc0e754SSam Leffler * o probe request frames are accepted only when operating in 17624bc0e754SSam Leffler * hostap, adhoc, or monitor modes 17634bc0e754SSam Leffler * o enable promiscuous mode according to the interface state 17644bc0e754SSam Leffler * o accept beacons: 17654bc0e754SSam Leffler * - when operating in adhoc mode so the 802.11 layer creates 17664bc0e754SSam Leffler * node table entries for peers, 17674bc0e754SSam Leffler * - when operating in station mode for collecting rssi data when 17684bc0e754SSam Leffler * the station is otherwise quiet, or 17694bc0e754SSam Leffler * - when scanning 17706f48c956SSam Leffler * o accept control frames: 17716f48c956SSam Leffler * - when in monitor mode 17724bc0e754SSam Leffler */ 17734bc0e754SSam Leffler static u_int32_t 1774c42a7b7eSSam Leffler ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state) 17754bc0e754SSam Leffler { 1776bd5a9920SSam Leffler #define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR) 17774bc0e754SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 17784bc0e754SSam Leffler struct ath_hal *ah = sc->sc_ah; 1779fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 17804bc0e754SSam Leffler u_int32_t rfilt; 17814bc0e754SSam Leffler 1782bd5a9920SSam Leffler rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) 17834bc0e754SSam Leffler | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 17844bc0e754SSam Leffler if (ic->ic_opmode != IEEE80211_M_STA) 17854bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROBEREQ; 17864bc0e754SSam Leffler if (ic->ic_opmode != IEEE80211_M_HOSTAP && 17874bc0e754SSam Leffler (ifp->if_flags & IFF_PROMISC)) 17884bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_PROM; 17894bc0e754SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA || 17904bc0e754SSam Leffler ic->ic_opmode == IEEE80211_M_IBSS || 1791c42a7b7eSSam Leffler state == IEEE80211_S_SCAN) 17924bc0e754SSam Leffler rfilt |= HAL_RX_FILTER_BEACON; 17936f48c956SSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) 17946f48c956SSam Leffler rfilt |= HAL_RX_FILTER_CONTROL; 17954bc0e754SSam Leffler return rfilt; 1796bd5a9920SSam Leffler #undef RX_FILTER_PRESERVE 17974bc0e754SSam Leffler } 17984bc0e754SSam Leffler 17995591b213SSam Leffler static void 18005591b213SSam Leffler ath_mode_init(struct ath_softc *sc) 18015591b213SSam Leffler { 18025591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 18035591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 1804fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 18055591b213SSam Leffler u_int32_t rfilt, mfilt[2], val; 18065591b213SSam Leffler u_int8_t pos; 18075591b213SSam Leffler struct ifmultiaddr *ifma; 18085591b213SSam Leffler 18094bc0e754SSam Leffler /* configure rx filter */ 1810c42a7b7eSSam Leffler rfilt = ath_calcrxfilter(sc, ic->ic_state); 18114bc0e754SSam Leffler ath_hal_setrxfilter(ah, rfilt); 18124bc0e754SSam Leffler 18135591b213SSam Leffler /* configure operational mode */ 1814c42a7b7eSSam Leffler ath_hal_setopmode(ah); 1815c42a7b7eSSam Leffler 1816c42a7b7eSSam Leffler /* 1817c42a7b7eSSam Leffler * Handle any link-level address change. Note that we only 1818c42a7b7eSSam Leffler * need to force ic_myaddr; any other addresses are handled 1819c42a7b7eSSam Leffler * as a byproduct of the ifnet code marking the interface 1820c42a7b7eSSam Leffler * down then up. 1821c42a7b7eSSam Leffler * 1822c42a7b7eSSam Leffler * XXX should get from lladdr instead of arpcom but that's more work 1823c42a7b7eSSam Leffler */ 18244a0d6638SRuslan Ermilov IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 1825c42a7b7eSSam Leffler ath_hal_setmac(ah, ic->ic_myaddr); 18265591b213SSam Leffler 18275591b213SSam Leffler /* calculate and install multicast filter */ 18285591b213SSam Leffler if ((ifp->if_flags & IFF_ALLMULTI) == 0) { 18295591b213SSam Leffler mfilt[0] = mfilt[1] = 0; 183013b203d0SRobert Watson IF_ADDR_LOCK(ifp); 18315591b213SSam Leffler TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 18325591b213SSam Leffler caddr_t dl; 18335591b213SSam Leffler 18345591b213SSam Leffler /* calculate XOR of eight 6bit values */ 18355591b213SSam Leffler dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 18365591b213SSam Leffler val = LE_READ_4(dl + 0); 18375591b213SSam Leffler pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 18385591b213SSam Leffler val = LE_READ_4(dl + 3); 18395591b213SSam Leffler pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; 18405591b213SSam Leffler pos &= 0x3f; 18415591b213SSam Leffler mfilt[pos / 32] |= (1 << (pos % 32)); 18425591b213SSam Leffler } 184313b203d0SRobert Watson IF_ADDR_UNLOCK(ifp); 18445591b213SSam Leffler } else { 18455591b213SSam Leffler mfilt[0] = mfilt[1] = ~0; 18465591b213SSam Leffler } 18475591b213SSam Leffler ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]); 1848c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, MC filter %08x:%08x\n", 1849c42a7b7eSSam Leffler __func__, rfilt, mfilt[0], mfilt[1]); 18505591b213SSam Leffler } 18515591b213SSam Leffler 1852c42a7b7eSSam Leffler /* 1853c42a7b7eSSam Leffler * Set the slot time based on the current setting. 1854c42a7b7eSSam Leffler */ 1855c42a7b7eSSam Leffler static void 1856c42a7b7eSSam Leffler ath_setslottime(struct ath_softc *sc) 1857c42a7b7eSSam Leffler { 1858c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 1859c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 1860aaa70f2fSSam Leffler u_int usec; 1861c42a7b7eSSam Leffler 1862aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) { 1863aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) 1864aaa70f2fSSam Leffler usec = 13; 1865aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) 1866aaa70f2fSSam Leffler usec = 21; 1867c42a7b7eSSam Leffler else 1868aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_9; 1869aaa70f2fSSam Leffler } else if (ic->ic_flags & IEEE80211_F_SHSLOT) 1870aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_9; 1871aaa70f2fSSam Leffler else 1872aaa70f2fSSam Leffler usec = HAL_SLOT_TIME_20; 1873aaa70f2fSSam Leffler 1874aaa70f2fSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 1875aaa70f2fSSam Leffler "%s: chan %u MHz flags 0x%x %s slot, %u usec\n", 1876aaa70f2fSSam Leffler __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags, 1877aaa70f2fSSam Leffler ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec); 1878aaa70f2fSSam Leffler 1879aaa70f2fSSam Leffler ath_hal_setslottime(ah, usec); 1880c42a7b7eSSam Leffler sc->sc_updateslot = OK; 1881c42a7b7eSSam Leffler } 1882c42a7b7eSSam Leffler 1883c42a7b7eSSam Leffler /* 1884c42a7b7eSSam Leffler * Callback from the 802.11 layer to update the 1885c42a7b7eSSam Leffler * slot time based on the current setting. 1886c42a7b7eSSam Leffler */ 1887c42a7b7eSSam Leffler static void 1888c42a7b7eSSam Leffler ath_updateslot(struct ifnet *ifp) 1889c42a7b7eSSam Leffler { 1890c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 1891c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 1892c42a7b7eSSam Leffler 1893c42a7b7eSSam Leffler /* 1894c42a7b7eSSam Leffler * When not coordinating the BSS, change the hardware 1895c42a7b7eSSam Leffler * immediately. For other operation we defer the change 1896c42a7b7eSSam Leffler * until beacon updates have propagated to the stations. 1897c42a7b7eSSam Leffler */ 1898c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) 1899c42a7b7eSSam Leffler sc->sc_updateslot = UPDATE; 1900c42a7b7eSSam Leffler else 1901c42a7b7eSSam Leffler ath_setslottime(sc); 1902c42a7b7eSSam Leffler } 1903c42a7b7eSSam Leffler 1904c42a7b7eSSam Leffler /* 190580d2765fSSam Leffler * Setup a h/w transmit queue for beacons. 190680d2765fSSam Leffler */ 190780d2765fSSam Leffler static int 190880d2765fSSam Leffler ath_beaconq_setup(struct ath_hal *ah) 190980d2765fSSam Leffler { 191080d2765fSSam Leffler HAL_TXQ_INFO qi; 191180d2765fSSam Leffler 191280d2765fSSam Leffler memset(&qi, 0, sizeof(qi)); 191380d2765fSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 191480d2765fSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 191580d2765fSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 19160f2e86fbSSam Leffler /* NB: for dynamic turbo, don't enable any other interrupts */ 1917bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; 191880d2765fSSam Leffler return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi); 191980d2765fSSam Leffler } 192080d2765fSSam Leffler 192180d2765fSSam Leffler /* 19220f2e86fbSSam Leffler * Setup the transmit queue parameters for the beacon queue. 19230f2e86fbSSam Leffler */ 19240f2e86fbSSam Leffler static int 19250f2e86fbSSam Leffler ath_beaconq_config(struct ath_softc *sc) 19260f2e86fbSSam Leffler { 19270f2e86fbSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) 19280f2e86fbSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 19290f2e86fbSSam Leffler struct ath_hal *ah = sc->sc_ah; 19300f2e86fbSSam Leffler HAL_TXQ_INFO qi; 19310f2e86fbSSam Leffler 19320f2e86fbSSam Leffler ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi); 19330f2e86fbSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 19340f2e86fbSSam Leffler /* 19350f2e86fbSSam Leffler * Always burst out beacon and CAB traffic. 19360f2e86fbSSam Leffler */ 19370f2e86fbSSam Leffler qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; 19380f2e86fbSSam Leffler qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT; 19390f2e86fbSSam Leffler qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT; 19400f2e86fbSSam Leffler } else { 19410f2e86fbSSam Leffler struct wmeParams *wmep = 19420f2e86fbSSam Leffler &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE]; 19430f2e86fbSSam Leffler /* 19440f2e86fbSSam Leffler * Adhoc mode; important thing is to use 2x cwmin. 19450f2e86fbSSam Leffler */ 19460f2e86fbSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 19470f2e86fbSSam Leffler qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 19480f2e86fbSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 19490f2e86fbSSam Leffler } 19500f2e86fbSSam Leffler 19510f2e86fbSSam Leffler if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) { 19520f2e86fbSSam Leffler device_printf(sc->sc_dev, "unable to update parameters for " 19530f2e86fbSSam Leffler "beacon hardware queue!\n"); 19540f2e86fbSSam Leffler return 0; 19550f2e86fbSSam Leffler } else { 19560f2e86fbSSam Leffler ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ 19570f2e86fbSSam Leffler return 1; 19580f2e86fbSSam Leffler } 19590f2e86fbSSam Leffler #undef ATH_EXPONENT_TO_VALUE 19600f2e86fbSSam Leffler } 19610f2e86fbSSam Leffler 19620f2e86fbSSam Leffler /* 1963c42a7b7eSSam Leffler * Allocate and setup an initial beacon frame. 1964c42a7b7eSSam Leffler */ 19655591b213SSam Leffler static int 19665591b213SSam Leffler ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) 19675591b213SSam Leffler { 1968c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 19695591b213SSam Leffler struct ath_buf *bf; 19705591b213SSam Leffler struct mbuf *m; 1971c42a7b7eSSam Leffler int error; 19725591b213SSam Leffler 1973c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_bbuf); 1974c42a7b7eSSam Leffler if (bf == NULL) { 1975c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: no dma buffers\n", __func__); 1976c42a7b7eSSam Leffler sc->sc_stats.ast_be_nombuf++; /* XXX */ 1977c42a7b7eSSam Leffler return ENOMEM; /* XXX */ 1978c42a7b7eSSam Leffler } 19795591b213SSam Leffler /* 19805591b213SSam Leffler * NB: the beacon data buffer must be 32-bit aligned; 19815591b213SSam Leffler * we assume the mbuf routines will return us something 19825591b213SSam Leffler * with this alignment (perhaps should assert). 19835591b213SSam Leffler */ 1984c42a7b7eSSam Leffler m = ieee80211_beacon_alloc(ic, ni, &sc->sc_boff); 19855591b213SSam Leffler if (m == NULL) { 1986c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: cannot get mbuf\n", 1987c42a7b7eSSam Leffler __func__); 19885591b213SSam Leffler sc->sc_stats.ast_be_nombuf++; 19895591b213SSam Leffler return ENOMEM; 19905591b213SSam Leffler } 1991f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 1992f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 19935591b213SSam Leffler BUS_DMA_NOWAIT); 1994c42a7b7eSSam Leffler if (error == 0) { 1995c42a7b7eSSam Leffler bf->bf_m = m; 1996f818612bSSam Leffler bf->bf_node = ieee80211_ref_node(ni); 1997c42a7b7eSSam Leffler } else { 19985591b213SSam Leffler m_freem(m); 1999c42a7b7eSSam Leffler } 20005591b213SSam Leffler return error; 20015591b213SSam Leffler } 2002c42a7b7eSSam Leffler 2003c42a7b7eSSam Leffler /* 2004c42a7b7eSSam Leffler * Setup the beacon frame for transmit. 2005c42a7b7eSSam Leffler */ 2006c42a7b7eSSam Leffler static void 2007c42a7b7eSSam Leffler ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) 2008c42a7b7eSSam Leffler { 2009c42a7b7eSSam Leffler #define USE_SHPREAMBLE(_ic) \ 2010c42a7b7eSSam Leffler (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ 2011c42a7b7eSSam Leffler == IEEE80211_F_SHPREAMBLE) 2012c42a7b7eSSam Leffler struct ieee80211_node *ni = bf->bf_node; 2013c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2014c42a7b7eSSam Leffler struct mbuf *m = bf->bf_m; 2015c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2016c42a7b7eSSam Leffler struct ath_desc *ds; 2017c42a7b7eSSam Leffler int flags, antenna; 201855f63772SSam Leffler const HAL_RATE_TABLE *rt; 201955f63772SSam Leffler u_int8_t rix, rate; 2020c42a7b7eSSam Leffler 20214a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n", 2022c42a7b7eSSam Leffler __func__, m, m->m_len); 20235591b213SSam Leffler 20245591b213SSam Leffler /* setup descriptors */ 20255591b213SSam Leffler ds = bf->bf_desc; 20265591b213SSam Leffler 2027c42a7b7eSSam Leffler flags = HAL_TXDESC_NOACK; 2028c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) { 2029c42a7b7eSSam Leffler ds->ds_link = bf->bf_daddr; /* self-linked */ 2030c42a7b7eSSam Leffler flags |= HAL_TXDESC_VEOL; 2031c42a7b7eSSam Leffler /* 2032c42a7b7eSSam Leffler * Let hardware handle antenna switching. 2033c42a7b7eSSam Leffler */ 20344866e6c2SSam Leffler antenna = sc->sc_txantenna; 2035c42a7b7eSSam Leffler } else { 20365591b213SSam Leffler ds->ds_link = 0; 2037c42a7b7eSSam Leffler /* 2038c42a7b7eSSam Leffler * Switch antenna every 4 beacons. 2039c42a7b7eSSam Leffler * XXX assumes two antenna 2040c42a7b7eSSam Leffler */ 2041df4d04afSSam Leffler antenna = sc->sc_txantenna != 0 ? sc->sc_txantenna 2042df4d04afSSam Leffler : (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1); 2043c42a7b7eSSam Leffler } 2044c42a7b7eSSam Leffler 2045c42a7b7eSSam Leffler KASSERT(bf->bf_nseg == 1, 2046c42a7b7eSSam Leffler ("multi-segment beacon frame; nseg %u", bf->bf_nseg)); 20475591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 20485591b213SSam Leffler /* 20495591b213SSam Leffler * Calculate rate code. 20505591b213SSam Leffler * XXX everything at min xmit rate 20515591b213SSam Leffler */ 205255f63772SSam Leffler rix = sc->sc_minrateix; 205355f63772SSam Leffler rt = sc->sc_currates; 205455f63772SSam Leffler rate = rt->info[rix].rateCode; 2055c42a7b7eSSam Leffler if (USE_SHPREAMBLE(ic)) 205655f63772SSam Leffler rate |= rt->info[rix].shortPreamble; 20575591b213SSam Leffler ath_hal_setuptxdesc(ah, ds 2058c42a7b7eSSam Leffler , m->m_len + IEEE80211_CRC_LEN /* frame length */ 20595591b213SSam Leffler , sizeof(struct ieee80211_frame)/* header length */ 20605591b213SSam Leffler , HAL_PKT_TYPE_BEACON /* Atheros packet type */ 2061c42a7b7eSSam Leffler , ni->ni_txpower /* txpower XXX */ 20625591b213SSam Leffler , rate, 1 /* series 0 rate/tries */ 20635591b213SSam Leffler , HAL_TXKEYIX_INVALID /* no encryption */ 2064c42a7b7eSSam Leffler , antenna /* antenna mode */ 2065c42a7b7eSSam Leffler , flags /* no ack, veol for beacons */ 20665591b213SSam Leffler , 0 /* rts/cts rate */ 20675591b213SSam Leffler , 0 /* rts/cts duration */ 20685591b213SSam Leffler ); 20695591b213SSam Leffler /* NB: beacon's BufLen must be a multiple of 4 bytes */ 20705591b213SSam Leffler ath_hal_filltxdesc(ah, ds 2071c42a7b7eSSam Leffler , roundup(m->m_len, 4) /* buffer length */ 20725591b213SSam Leffler , AH_TRUE /* first segment */ 20735591b213SSam Leffler , AH_TRUE /* last segment */ 2074c42a7b7eSSam Leffler , ds /* first descriptor */ 20755591b213SSam Leffler ); 2076c42a7b7eSSam Leffler #undef USE_SHPREAMBLE 20775591b213SSam Leffler } 20785591b213SSam Leffler 2079c42a7b7eSSam Leffler /* 2080622b3fd2SSam Leffler * Append the contents of src to dst; both queues 2081622b3fd2SSam Leffler * are assumed to be locked. 2082622b3fd2SSam Leffler */ 2083622b3fd2SSam Leffler static void 2084622b3fd2SSam Leffler ath_txqmove(struct ath_txq *dst, struct ath_txq *src) 2085622b3fd2SSam Leffler { 2086622b3fd2SSam Leffler STAILQ_CONCAT(&dst->axq_q, &src->axq_q); 2087622b3fd2SSam Leffler dst->axq_link = src->axq_link; 2088622b3fd2SSam Leffler src->axq_link = NULL; 2089622b3fd2SSam Leffler dst->axq_depth += src->axq_depth; 2090622b3fd2SSam Leffler src->axq_depth = 0; 2091622b3fd2SSam Leffler } 2092622b3fd2SSam Leffler 2093622b3fd2SSam Leffler /* 2094c42a7b7eSSam Leffler * Transmit a beacon frame at SWBA. Dynamic updates to the 2095c42a7b7eSSam Leffler * frame contents are done as needed and the slot time is 2096c42a7b7eSSam Leffler * also adjusted based on current state. 2097c42a7b7eSSam Leffler */ 20985591b213SSam Leffler static void 20995591b213SSam Leffler ath_beacon_proc(void *arg, int pending) 21005591b213SSam Leffler { 21015591b213SSam Leffler struct ath_softc *sc = arg; 2102c42a7b7eSSam Leffler struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); 2103c42a7b7eSSam Leffler struct ieee80211_node *ni = bf->bf_node; 2104c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 21055591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 2106622b3fd2SSam Leffler struct ath_txq *cabq = sc->sc_cabq; 2107c42a7b7eSSam Leffler struct mbuf *m; 2108622b3fd2SSam Leffler int ncabq, nmcastq, error, otherant; 21095591b213SSam Leffler 2110c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n", 2111c42a7b7eSSam Leffler __func__, pending); 2112c42a7b7eSSam Leffler 21130a915fadSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA || 2114c42a7b7eSSam Leffler ic->ic_opmode == IEEE80211_M_MONITOR || 21150a915fadSSam Leffler bf == NULL || bf->bf_m == NULL) { 2116c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: ic_flags=%x bf=%p bf_m=%p\n", 2117c42a7b7eSSam Leffler __func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL); 21185591b213SSam Leffler return; 21195591b213SSam Leffler } 2120c42a7b7eSSam Leffler /* 2121c42a7b7eSSam Leffler * Check if the previous beacon has gone out. If 2122c66c48cbSSam Leffler * not don't try to post another, skip this period 2123c66c48cbSSam Leffler * and wait for the next. Missed beacons indicate 2124c66c48cbSSam Leffler * a problem and should not occur. If we miss too 2125c66c48cbSSam Leffler * many consecutive beacons reset the device. 2126c42a7b7eSSam Leffler */ 2127c42a7b7eSSam Leffler if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) { 2128c42a7b7eSSam Leffler sc->sc_bmisscount++; 21294a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2130c42a7b7eSSam Leffler "%s: missed %u consecutive beacons\n", 2131c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2132c42a7b7eSSam Leffler if (sc->sc_bmisscount > 3) /* NB: 3 is a guess */ 21330bbf5441SSam Leffler taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); 2134c42a7b7eSSam Leffler return; 2135c42a7b7eSSam Leffler } 2136c42a7b7eSSam Leffler if (sc->sc_bmisscount != 0) { 2137c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2138c42a7b7eSSam Leffler "%s: resume beacon xmit after %u misses\n", 2139c42a7b7eSSam Leffler __func__, sc->sc_bmisscount); 2140c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 2141c42a7b7eSSam Leffler } 2142c42a7b7eSSam Leffler 2143c42a7b7eSSam Leffler /* 2144c42a7b7eSSam Leffler * Update dynamic beacon contents. If this returns 2145c42a7b7eSSam Leffler * non-zero then we need to remap the memory because 2146c42a7b7eSSam Leffler * the beacon frame changed size (probably because 2147c42a7b7eSSam Leffler * of the TIM bitmap). 2148c42a7b7eSSam Leffler */ 2149c42a7b7eSSam Leffler m = bf->bf_m; 2150622b3fd2SSam Leffler nmcastq = sc->sc_mcastq.axq_depth; 2151622b3fd2SSam Leffler ncabq = ath_hal_numtxpending(ah, cabq->axq_qnum); 2152622b3fd2SSam Leffler if (ieee80211_beacon_update(ic, bf->bf_node, &sc->sc_boff, m, ncabq+nmcastq)) { 2153c42a7b7eSSam Leffler /* XXX too conservative? */ 2154c42a7b7eSSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 2155f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, 2156f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 2157c42a7b7eSSam Leffler BUS_DMA_NOWAIT); 2158c42a7b7eSSam Leffler if (error != 0) { 2159c42a7b7eSSam Leffler if_printf(ic->ic_ifp, 2160f9e6219bSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed, error %u\n", 2161c42a7b7eSSam Leffler __func__, error); 2162c42a7b7eSSam Leffler return; 2163c42a7b7eSSam Leffler } 2164c42a7b7eSSam Leffler } 2165622b3fd2SSam Leffler if (ncabq && (sc->sc_boff.bo_tim[4] & 1)) { 2166622b3fd2SSam Leffler /* 2167622b3fd2SSam Leffler * CABQ traffic from the previous DTIM is still pending. 2168622b3fd2SSam Leffler * This is ok for now but when there are multiple vap's 2169622b3fd2SSam Leffler * and we are using staggered beacons we'll want to drain 2170622b3fd2SSam Leffler * the cabq before loading frames for the different vap. 2171622b3fd2SSam Leffler */ 2172622b3fd2SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 2173622b3fd2SSam Leffler "%s: cabq did not drain, mcastq %u cabq %u/%u\n", 2174622b3fd2SSam Leffler __func__, nmcastq, ncabq, cabq->axq_depth); 2175622b3fd2SSam Leffler sc->sc_stats.ast_cabq_busy++; 2176622b3fd2SSam Leffler } 2177c42a7b7eSSam Leffler 2178c42a7b7eSSam Leffler /* 2179c42a7b7eSSam Leffler * Handle slot time change when a non-ERP station joins/leaves 2180c42a7b7eSSam Leffler * an 11g network. The 802.11 layer notifies us via callback, 2181c42a7b7eSSam Leffler * we mark updateslot, then wait one beacon before effecting 2182c42a7b7eSSam Leffler * the change. This gives associated stations at least one 2183c42a7b7eSSam Leffler * beacon interval to note the state change. 2184c42a7b7eSSam Leffler */ 2185c42a7b7eSSam Leffler /* XXX locking */ 2186c42a7b7eSSam Leffler if (sc->sc_updateslot == UPDATE) 2187c42a7b7eSSam Leffler sc->sc_updateslot = COMMIT; /* commit next beacon */ 2188c42a7b7eSSam Leffler else if (sc->sc_updateslot == COMMIT) 2189c42a7b7eSSam Leffler ath_setslottime(sc); /* commit change to h/w */ 2190c42a7b7eSSam Leffler 2191c42a7b7eSSam Leffler /* 2192c42a7b7eSSam Leffler * Check recent per-antenna transmit statistics and flip 2193c42a7b7eSSam Leffler * the default antenna if noticeably more frames went out 2194c42a7b7eSSam Leffler * on the non-default antenna. 2195c42a7b7eSSam Leffler * XXX assumes 2 anntenae 2196c42a7b7eSSam Leffler */ 2197c42a7b7eSSam Leffler otherant = sc->sc_defant & 1 ? 2 : 1; 2198c42a7b7eSSam Leffler if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) 2199c42a7b7eSSam Leffler ath_setdefantenna(sc, otherant); 2200c42a7b7eSSam Leffler sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; 2201c42a7b7eSSam Leffler 2202c42a7b7eSSam Leffler /* 2203c42a7b7eSSam Leffler * Construct tx descriptor. 2204c42a7b7eSSam Leffler */ 2205c42a7b7eSSam Leffler ath_beacon_setup(sc, bf); 2206c42a7b7eSSam Leffler 2207c42a7b7eSSam Leffler /* 2208c42a7b7eSSam Leffler * Stop any current dma and put the new frame on the queue. 2209c42a7b7eSSam Leffler * This should never fail since we check above that no frames 2210c42a7b7eSSam Leffler * are still pending on the queue. 2211c42a7b7eSSam Leffler */ 22125591b213SSam Leffler if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { 2213c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2214c42a7b7eSSam Leffler "%s: beacon queue %u did not stop?\n", 2215c42a7b7eSSam Leffler __func__, sc->sc_bhalq); 22165591b213SSam Leffler } 22175591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 22185591b213SSam Leffler 2219c42a7b7eSSam Leffler /* 2220c42a7b7eSSam Leffler * Enable the CAB queue before the beacon queue to 2221c42a7b7eSSam Leffler * insure cab frames are triggered by this beacon. 2222c42a7b7eSSam Leffler */ 2223f3af83f7SSam Leffler if (sc->sc_boff.bo_tim_len && (sc->sc_boff.bo_tim[4] & 1)) { 2224f3af83f7SSam Leffler /* NB: only at DTIM */ 2225622b3fd2SSam Leffler ATH_TXQ_LOCK(cabq); 2226622b3fd2SSam Leffler ATH_TXQ_LOCK(&sc->sc_mcastq); 2227622b3fd2SSam Leffler if (nmcastq) { 2228622b3fd2SSam Leffler struct ath_buf *bfm; 2229622b3fd2SSam Leffler 2230622b3fd2SSam Leffler /* 2231622b3fd2SSam Leffler * Move frames from the s/w mcast q to the h/w cab q. 2232622b3fd2SSam Leffler */ 2233622b3fd2SSam Leffler bfm = STAILQ_FIRST(&sc->sc_mcastq.axq_q); 2234622b3fd2SSam Leffler if (cabq->axq_link != NULL) { 2235622b3fd2SSam Leffler *cabq->axq_link = bfm->bf_daddr; 2236622b3fd2SSam Leffler } else 2237622b3fd2SSam Leffler ath_hal_puttxbuf(ah, cabq->axq_qnum, 2238622b3fd2SSam Leffler bfm->bf_daddr); 2239622b3fd2SSam Leffler ath_txqmove(cabq, &sc->sc_mcastq); 2240622b3fd2SSam Leffler 2241622b3fd2SSam Leffler sc->sc_stats.ast_cabq_xmit += nmcastq; 2242622b3fd2SSam Leffler } 2243622b3fd2SSam Leffler /* NB: gated by beacon so safe to start here */ 2244622b3fd2SSam Leffler ath_hal_txstart(ah, cabq->axq_qnum); 2245622b3fd2SSam Leffler ATH_TXQ_UNLOCK(cabq); 2246622b3fd2SSam Leffler ATH_TXQ_UNLOCK(&sc->sc_mcastq); 2247622b3fd2SSam Leffler } 22485591b213SSam Leffler ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); 22495591b213SSam Leffler ath_hal_txstart(ah, sc->sc_bhalq); 2250c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON_PROC, 2251c42a7b7eSSam Leffler "%s: TXDP[%u] = %p (%p)\n", __func__, 2252c42a7b7eSSam Leffler sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc); 2253c42a7b7eSSam Leffler 2254c42a7b7eSSam Leffler sc->sc_stats.ast_be_xmit++; 22555591b213SSam Leffler } 22565591b213SSam Leffler 2257c42a7b7eSSam Leffler /* 2258c42a7b7eSSam Leffler * Reset the hardware after detecting beacons have stopped. 2259c42a7b7eSSam Leffler */ 2260c42a7b7eSSam Leffler static void 2261c42a7b7eSSam Leffler ath_bstuck_proc(void *arg, int pending) 2262c42a7b7eSSam Leffler { 2263c42a7b7eSSam Leffler struct ath_softc *sc = arg; 2264fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2265c42a7b7eSSam Leffler 2266c42a7b7eSSam Leffler if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n", 2267c42a7b7eSSam Leffler sc->sc_bmisscount); 2268c42a7b7eSSam Leffler ath_reset(ifp); 2269c42a7b7eSSam Leffler } 2270c42a7b7eSSam Leffler 2271c42a7b7eSSam Leffler /* 2272c42a7b7eSSam Leffler * Reclaim beacon resources. 2273c42a7b7eSSam Leffler */ 22745591b213SSam Leffler static void 22755591b213SSam Leffler ath_beacon_free(struct ath_softc *sc) 22765591b213SSam Leffler { 2277c42a7b7eSSam Leffler struct ath_buf *bf; 22785591b213SSam Leffler 2279f818612bSSam Leffler STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { 22805591b213SSam Leffler if (bf->bf_m != NULL) { 22815591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 22825591b213SSam Leffler m_freem(bf->bf_m); 22835591b213SSam Leffler bf->bf_m = NULL; 2284f818612bSSam Leffler } 2285f818612bSSam Leffler if (bf->bf_node != NULL) { 2286f818612bSSam Leffler ieee80211_free_node(bf->bf_node); 22875591b213SSam Leffler bf->bf_node = NULL; 22885591b213SSam Leffler } 22895591b213SSam Leffler } 2290f818612bSSam Leffler } 22915591b213SSam Leffler 22925591b213SSam Leffler /* 22935591b213SSam Leffler * Configure the beacon and sleep timers. 22945591b213SSam Leffler * 22955591b213SSam Leffler * When operating as an AP this resets the TSF and sets 22965591b213SSam Leffler * up the hardware to notify us when we need to issue beacons. 22975591b213SSam Leffler * 22985591b213SSam Leffler * When operating in station mode this sets up the beacon 22995591b213SSam Leffler * timers according to the timestamp of the last received 23005591b213SSam Leffler * beacon and the current TSF, configures PCF and DTIM 23015591b213SSam Leffler * handling, programs the sleep registers so the hardware 23025591b213SSam Leffler * will wakeup in time to receive beacons, and configures 23035591b213SSam Leffler * the beacon miss handling so we'll receive a BMISS 23045591b213SSam Leffler * interrupt when we stop seeing beacons from the AP 23055591b213SSam Leffler * we've associated with. 23065591b213SSam Leffler */ 23075591b213SSam Leffler static void 23085591b213SSam Leffler ath_beacon_config(struct ath_softc *sc) 23095591b213SSam Leffler { 231080d939bfSSam Leffler #define TSF_TO_TU(_h,_l) \ 231180d939bfSSam Leffler ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) 231280d939bfSSam Leffler #define FUDGE 2 23135591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 23145591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 23155591b213SSam Leffler struct ieee80211_node *ni = ic->ic_bss; 231680d939bfSSam Leffler u_int32_t nexttbtt, intval, tsftu; 231780d939bfSSam Leffler u_int64_t tsf; 23185591b213SSam Leffler 23198371372bSSam Leffler /* extract tstamp from last beacon and convert to TU */ 23208371372bSSam Leffler nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), 23218371372bSSam Leffler LE_READ_4(ni->ni_tstamp.data)); 23228371372bSSam Leffler /* NB: the beacon interval is kept internally in TU's */ 23234bacf7c1SSam Leffler intval = ni->ni_intval & HAL_BEACON_PERIOD; 2324a6c992f4SSam Leffler if (nexttbtt == 0) /* e.g. for ap mode */ 2325a6c992f4SSam Leffler nexttbtt = intval; 2326a6c992f4SSam Leffler else if (intval) /* NB: can be 0 for monitor mode */ 2327a6c992f4SSam Leffler nexttbtt = roundup(nexttbtt, intval); 2328a6c992f4SSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", 2329a6c992f4SSam Leffler __func__, nexttbtt, intval, ni->ni_intval); 23306b59f5e3SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) { 23315591b213SSam Leffler HAL_BEACON_STATE bs; 23328371372bSSam Leffler int dtimperiod, dtimcount; 23338371372bSSam Leffler int cfpperiod, cfpcount; 23345591b213SSam Leffler 23358371372bSSam Leffler /* 23368371372bSSam Leffler * Setup dtim and cfp parameters according to 23378371372bSSam Leffler * last beacon we received (which may be none). 23388371372bSSam Leffler */ 23398371372bSSam Leffler dtimperiod = ni->ni_dtim_period; 23408371372bSSam Leffler if (dtimperiod <= 0) /* NB: 0 if not known */ 23418371372bSSam Leffler dtimperiod = 1; 23428371372bSSam Leffler dtimcount = ni->ni_dtim_count; 23438371372bSSam Leffler if (dtimcount >= dtimperiod) /* NB: sanity check */ 23448371372bSSam Leffler dtimcount = 0; /* XXX? */ 23458371372bSSam Leffler cfpperiod = 1; /* NB: no PCF support yet */ 23468371372bSSam Leffler cfpcount = 0; 23478371372bSSam Leffler /* 23488371372bSSam Leffler * Pull nexttbtt forward to reflect the current 23498371372bSSam Leffler * TSF and calculate dtim+cfp state for the result. 23508371372bSSam Leffler */ 23518371372bSSam Leffler tsf = ath_hal_gettsf64(ah); 235280d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 23538371372bSSam Leffler do { 23548371372bSSam Leffler nexttbtt += intval; 23558371372bSSam Leffler if (--dtimcount < 0) { 23568371372bSSam Leffler dtimcount = dtimperiod - 1; 23578371372bSSam Leffler if (--cfpcount < 0) 23588371372bSSam Leffler cfpcount = cfpperiod - 1; 23598371372bSSam Leffler } 23608371372bSSam Leffler } while (nexttbtt < tsftu); 23615591b213SSam Leffler memset(&bs, 0, sizeof(bs)); 2362a6c992f4SSam Leffler bs.bs_intval = intval; 23635591b213SSam Leffler bs.bs_nexttbtt = nexttbtt; 23648371372bSSam Leffler bs.bs_dtimperiod = dtimperiod*intval; 23658371372bSSam Leffler bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; 23668371372bSSam Leffler bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; 23678371372bSSam Leffler bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; 23688371372bSSam Leffler bs.bs_cfpmaxduration = 0; 23698371372bSSam Leffler #if 0 23705591b213SSam Leffler /* 2371c42a7b7eSSam Leffler * The 802.11 layer records the offset to the DTIM 2372c42a7b7eSSam Leffler * bitmap while receiving beacons; use it here to 2373c42a7b7eSSam Leffler * enable h/w detection of our AID being marked in 2374c42a7b7eSSam Leffler * the bitmap vector (to indicate frames for us are 2375c42a7b7eSSam Leffler * pending at the AP). 23768371372bSSam Leffler * XXX do DTIM handling in s/w to WAR old h/w bugs 23778371372bSSam Leffler * XXX enable based on h/w rev for newer chips 2378c42a7b7eSSam Leffler */ 2379c42a7b7eSSam Leffler bs.bs_timoffset = ni->ni_timoff; 23808371372bSSam Leffler #endif 2381c42a7b7eSSam Leffler /* 23825591b213SSam Leffler * Calculate the number of consecutive beacons to miss 23835591b213SSam Leffler * before taking a BMISS interrupt. The configuration 23845591b213SSam Leffler * is specified in ms, so we need to convert that to 23855591b213SSam Leffler * TU's and then calculate based on the beacon interval. 23865591b213SSam Leffler * Note that we clamp the result to at most 10 beacons. 23875591b213SSam Leffler */ 2388b9919097SSam Leffler bs.bs_bmissthreshold = ic->ic_bmissthreshold; 23895591b213SSam Leffler if (bs.bs_bmissthreshold > 10) 23905591b213SSam Leffler bs.bs_bmissthreshold = 10; 23915591b213SSam Leffler else if (bs.bs_bmissthreshold <= 0) 23925591b213SSam Leffler bs.bs_bmissthreshold = 1; 23935591b213SSam Leffler 23945591b213SSam Leffler /* 23955591b213SSam Leffler * Calculate sleep duration. The configuration is 23965591b213SSam Leffler * given in ms. We insure a multiple of the beacon 23975591b213SSam Leffler * period is used. Also, if the sleep duration is 23985591b213SSam Leffler * greater than the DTIM period then it makes senses 23995591b213SSam Leffler * to make it a multiple of that. 24005591b213SSam Leffler * 24015591b213SSam Leffler * XXX fixed at 100ms 24025591b213SSam Leffler */ 24034bacf7c1SSam Leffler bs.bs_sleepduration = 24044bacf7c1SSam Leffler roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval); 24055591b213SSam Leffler if (bs.bs_sleepduration > bs.bs_dtimperiod) 24065591b213SSam Leffler bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 24075591b213SSam Leffler 2408c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_BEACON, 24098371372bSSam 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" 24105591b213SSam Leffler , __func__ 24118371372bSSam Leffler , tsf, tsftu 24125591b213SSam Leffler , bs.bs_intval 24135591b213SSam Leffler , bs.bs_nexttbtt 24145591b213SSam Leffler , bs.bs_dtimperiod 24155591b213SSam Leffler , bs.bs_nextdtim 24165591b213SSam Leffler , bs.bs_bmissthreshold 24175591b213SSam Leffler , bs.bs_sleepduration 2418c42a7b7eSSam Leffler , bs.bs_cfpperiod 2419c42a7b7eSSam Leffler , bs.bs_cfpmaxduration 2420c42a7b7eSSam Leffler , bs.bs_cfpnext 2421c42a7b7eSSam Leffler , bs.bs_timoffset 2422c42a7b7eSSam Leffler ); 24235591b213SSam Leffler ath_hal_intrset(ah, 0); 2424c42a7b7eSSam Leffler ath_hal_beacontimers(ah, &bs); 24255591b213SSam Leffler sc->sc_imask |= HAL_INT_BMISS; 24265591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 24275591b213SSam Leffler } else { 24285591b213SSam Leffler ath_hal_intrset(ah, 0); 2429a6c992f4SSam Leffler if (nexttbtt == intval) 2430c42a7b7eSSam Leffler intval |= HAL_BEACON_RESET_TSF; 2431c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS) { 2432c42a7b7eSSam Leffler /* 2433c42a7b7eSSam Leffler * In IBSS mode enable the beacon timers but only 2434c42a7b7eSSam Leffler * enable SWBA interrupts if we need to manually 2435c42a7b7eSSam Leffler * prepare beacon frames. Otherwise we use a 2436c42a7b7eSSam Leffler * self-linked tx descriptor and let the hardware 2437c42a7b7eSSam Leffler * deal with things. 2438c42a7b7eSSam Leffler */ 2439c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 2440c42a7b7eSSam Leffler if (!sc->sc_hasveol) 2441c42a7b7eSSam Leffler sc->sc_imask |= HAL_INT_SWBA; 244280d939bfSSam Leffler if ((intval & HAL_BEACON_RESET_TSF) == 0) { 244380d939bfSSam Leffler /* 244480d939bfSSam Leffler * Pull nexttbtt forward to reflect 244580d939bfSSam Leffler * the current TSF. 244680d939bfSSam Leffler */ 244780d939bfSSam Leffler tsf = ath_hal_gettsf64(ah); 244880d939bfSSam Leffler tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 244980d939bfSSam Leffler do { 245080d939bfSSam Leffler nexttbtt += intval; 245180d939bfSSam Leffler } while (nexttbtt < tsftu); 245280d939bfSSam Leffler } 24530f2e86fbSSam Leffler ath_beaconq_config(sc); 2454c42a7b7eSSam Leffler } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 2455c42a7b7eSSam Leffler /* 2456c42a7b7eSSam Leffler * In AP mode we enable the beacon timers and 2457c42a7b7eSSam Leffler * SWBA interrupts to prepare beacon frames. 2458c42a7b7eSSam Leffler */ 2459c42a7b7eSSam Leffler intval |= HAL_BEACON_ENA; 24605591b213SSam Leffler sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */ 24610f2e86fbSSam Leffler ath_beaconq_config(sc); 2462c42a7b7eSSam Leffler } 2463c42a7b7eSSam Leffler ath_hal_beaconinit(ah, nexttbtt, intval); 2464c42a7b7eSSam Leffler sc->sc_bmisscount = 0; 24655591b213SSam Leffler ath_hal_intrset(ah, sc->sc_imask); 2466c42a7b7eSSam Leffler /* 2467c42a7b7eSSam Leffler * When using a self-linked beacon descriptor in 2468c42a7b7eSSam Leffler * ibss mode load it once here. 2469c42a7b7eSSam Leffler */ 2470c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) 2471c42a7b7eSSam Leffler ath_beacon_proc(sc, 0); 24725591b213SSam Leffler } 247380d939bfSSam Leffler sc->sc_syncbeacon = 0; 247480d939bfSSam Leffler #undef FUDGE 24758371372bSSam Leffler #undef TSF_TO_TU 24765591b213SSam Leffler } 24775591b213SSam Leffler 24785591b213SSam Leffler static void 24795591b213SSam Leffler ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 24805591b213SSam Leffler { 24815591b213SSam Leffler bus_addr_t *paddr = (bus_addr_t*) arg; 2482d77367bfSSam Leffler KASSERT(error == 0, ("error %u on bus_dma callback", error)); 24835591b213SSam Leffler *paddr = segs->ds_addr; 24845591b213SSam Leffler } 24855591b213SSam Leffler 24865591b213SSam Leffler static int 2487c42a7b7eSSam Leffler ath_descdma_setup(struct ath_softc *sc, 2488c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head, 2489c42a7b7eSSam Leffler const char *name, int nbuf, int ndesc) 2490c42a7b7eSSam Leffler { 2491c42a7b7eSSam Leffler #define DS2PHYS(_dd, _ds) \ 2492c42a7b7eSSam Leffler ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) 2493fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 2494c42a7b7eSSam Leffler struct ath_desc *ds; 2495c42a7b7eSSam Leffler struct ath_buf *bf; 2496c42a7b7eSSam Leffler int i, bsize, error; 2497c42a7b7eSSam Leffler 2498c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n", 2499c42a7b7eSSam Leffler __func__, name, nbuf, ndesc); 2500c42a7b7eSSam Leffler 2501c42a7b7eSSam Leffler dd->dd_name = name; 2502c42a7b7eSSam Leffler dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; 2503c42a7b7eSSam Leffler 2504c42a7b7eSSam Leffler /* 2505c42a7b7eSSam Leffler * Setup DMA descriptor area. 2506c42a7b7eSSam Leffler */ 2507c42a7b7eSSam Leffler error = bus_dma_tag_create(NULL, /* parent */ 2508c42a7b7eSSam Leffler PAGE_SIZE, 0, /* alignment, bounds */ 2509c42a7b7eSSam Leffler BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 2510c42a7b7eSSam Leffler BUS_SPACE_MAXADDR, /* highaddr */ 2511c42a7b7eSSam Leffler NULL, NULL, /* filter, filterarg */ 2512c42a7b7eSSam Leffler dd->dd_desc_len, /* maxsize */ 2513c42a7b7eSSam Leffler 1, /* nsegments */ 25146ccb8ea7SSam Leffler dd->dd_desc_len, /* maxsegsize */ 2515c42a7b7eSSam Leffler BUS_DMA_ALLOCNOW, /* flags */ 2516c42a7b7eSSam Leffler NULL, /* lockfunc */ 2517c42a7b7eSSam Leffler NULL, /* lockarg */ 2518c42a7b7eSSam Leffler &dd->dd_dmat); 2519c42a7b7eSSam Leffler if (error != 0) { 2520c42a7b7eSSam Leffler if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); 2521c42a7b7eSSam Leffler return error; 2522c42a7b7eSSam Leffler } 2523c42a7b7eSSam Leffler 2524c42a7b7eSSam Leffler /* allocate descriptors */ 2525c42a7b7eSSam Leffler error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap); 2526c42a7b7eSSam Leffler if (error != 0) { 2527c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s descriptors, " 2528c42a7b7eSSam Leffler "error %u\n", dd->dd_name, error); 2529c42a7b7eSSam Leffler goto fail0; 2530c42a7b7eSSam Leffler } 2531c42a7b7eSSam Leffler 2532c42a7b7eSSam Leffler error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc, 25330553a01fSSam Leffler BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 25340553a01fSSam Leffler &dd->dd_dmamap); 2535c42a7b7eSSam Leffler if (error != 0) { 2536c42a7b7eSSam Leffler if_printf(ifp, "unable to alloc memory for %u %s descriptors, " 2537c42a7b7eSSam Leffler "error %u\n", nbuf * ndesc, dd->dd_name, error); 2538c42a7b7eSSam Leffler goto fail1; 2539c42a7b7eSSam Leffler } 2540c42a7b7eSSam Leffler 2541c42a7b7eSSam Leffler error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap, 2542c42a7b7eSSam Leffler dd->dd_desc, dd->dd_desc_len, 2543c42a7b7eSSam Leffler ath_load_cb, &dd->dd_desc_paddr, 2544c42a7b7eSSam Leffler BUS_DMA_NOWAIT); 2545c42a7b7eSSam Leffler if (error != 0) { 2546c42a7b7eSSam Leffler if_printf(ifp, "unable to map %s descriptors, error %u\n", 2547c42a7b7eSSam Leffler dd->dd_name, error); 2548c42a7b7eSSam Leffler goto fail2; 2549c42a7b7eSSam Leffler } 2550c42a7b7eSSam Leffler 2551c42a7b7eSSam Leffler ds = dd->dd_desc; 2552c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n", 2553c42a7b7eSSam Leffler __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len, 2554c42a7b7eSSam Leffler (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len); 2555c42a7b7eSSam Leffler 2556ebecf802SSam Leffler /* allocate rx buffers */ 2557c42a7b7eSSam Leffler bsize = sizeof(struct ath_buf) * nbuf; 2558c42a7b7eSSam Leffler bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO); 2559c42a7b7eSSam Leffler if (bf == NULL) { 2560c42a7b7eSSam Leffler if_printf(ifp, "malloc of %s buffers failed, size %u\n", 2561c42a7b7eSSam Leffler dd->dd_name, bsize); 2562c42a7b7eSSam Leffler goto fail3; 2563c42a7b7eSSam Leffler } 2564c42a7b7eSSam Leffler dd->dd_bufptr = bf; 2565c42a7b7eSSam Leffler 2566c42a7b7eSSam Leffler STAILQ_INIT(head); 2567c42a7b7eSSam Leffler for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { 2568c42a7b7eSSam Leffler bf->bf_desc = ds; 2569c42a7b7eSSam Leffler bf->bf_daddr = DS2PHYS(dd, ds); 2570c42a7b7eSSam Leffler error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, 2571c42a7b7eSSam Leffler &bf->bf_dmamap); 2572c42a7b7eSSam Leffler if (error != 0) { 2573c42a7b7eSSam Leffler if_printf(ifp, "unable to create dmamap for %s " 2574c42a7b7eSSam Leffler "buffer %u, error %u\n", dd->dd_name, i, error); 2575c42a7b7eSSam Leffler ath_descdma_cleanup(sc, dd, head); 2576c42a7b7eSSam Leffler return error; 2577c42a7b7eSSam Leffler } 2578c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(head, bf, bf_list); 2579c42a7b7eSSam Leffler } 2580c42a7b7eSSam Leffler return 0; 2581c42a7b7eSSam Leffler fail3: 2582c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 2583c42a7b7eSSam Leffler fail2: 2584c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 2585c42a7b7eSSam Leffler fail1: 2586c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 2587c42a7b7eSSam Leffler fail0: 2588c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 2589c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 2590c42a7b7eSSam Leffler return error; 2591c42a7b7eSSam Leffler #undef DS2PHYS 2592c42a7b7eSSam Leffler } 2593c42a7b7eSSam Leffler 2594c42a7b7eSSam Leffler static void 2595c42a7b7eSSam Leffler ath_descdma_cleanup(struct ath_softc *sc, 2596c42a7b7eSSam Leffler struct ath_descdma *dd, ath_bufhead *head) 2597c42a7b7eSSam Leffler { 2598c42a7b7eSSam Leffler struct ath_buf *bf; 2599c42a7b7eSSam Leffler struct ieee80211_node *ni; 2600c42a7b7eSSam Leffler 2601c42a7b7eSSam Leffler bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap); 2602c42a7b7eSSam Leffler bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap); 2603c42a7b7eSSam Leffler bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); 2604c42a7b7eSSam Leffler bus_dma_tag_destroy(dd->dd_dmat); 2605c42a7b7eSSam Leffler 2606c42a7b7eSSam Leffler STAILQ_FOREACH(bf, head, bf_list) { 2607c42a7b7eSSam Leffler if (bf->bf_m) { 2608c42a7b7eSSam Leffler m_freem(bf->bf_m); 2609c42a7b7eSSam Leffler bf->bf_m = NULL; 2610c42a7b7eSSam Leffler } 2611c42a7b7eSSam Leffler if (bf->bf_dmamap != NULL) { 2612c42a7b7eSSam Leffler bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap); 2613c42a7b7eSSam Leffler bf->bf_dmamap = NULL; 2614c42a7b7eSSam Leffler } 2615c42a7b7eSSam Leffler ni = bf->bf_node; 2616c42a7b7eSSam Leffler bf->bf_node = NULL; 2617c42a7b7eSSam Leffler if (ni != NULL) { 2618c42a7b7eSSam Leffler /* 2619c42a7b7eSSam Leffler * Reclaim node reference. 2620c42a7b7eSSam Leffler */ 2621c42a7b7eSSam Leffler ieee80211_free_node(ni); 2622c42a7b7eSSam Leffler } 2623c42a7b7eSSam Leffler } 2624c42a7b7eSSam Leffler 2625c42a7b7eSSam Leffler STAILQ_INIT(head); 2626c42a7b7eSSam Leffler free(dd->dd_bufptr, M_ATHDEV); 2627c42a7b7eSSam Leffler memset(dd, 0, sizeof(*dd)); 2628c42a7b7eSSam Leffler } 2629c42a7b7eSSam Leffler 2630c42a7b7eSSam Leffler static int 26315591b213SSam Leffler ath_desc_alloc(struct ath_softc *sc) 26325591b213SSam Leffler { 2633c42a7b7eSSam Leffler int error; 26345591b213SSam Leffler 2635c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, 2636e2d787faSSam Leffler "rx", ath_rxbuf, 1); 26375591b213SSam Leffler if (error != 0) 26385591b213SSam Leffler return error; 26395591b213SSam Leffler 2640c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, 2641e2d787faSSam Leffler "tx", ath_txbuf, ATH_TXDESC); 2642c42a7b7eSSam Leffler if (error != 0) { 2643c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 26445591b213SSam Leffler return error; 2645c42a7b7eSSam Leffler } 2646c42a7b7eSSam Leffler 2647c42a7b7eSSam Leffler error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, 2648c42a7b7eSSam Leffler "beacon", 1, 1); 2649c42a7b7eSSam Leffler if (error != 0) { 2650c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 2651c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 2652c42a7b7eSSam Leffler return error; 2653c42a7b7eSSam Leffler } 26545591b213SSam Leffler return 0; 26555591b213SSam Leffler } 26565591b213SSam Leffler 26575591b213SSam Leffler static void 26585591b213SSam Leffler ath_desc_free(struct ath_softc *sc) 26595591b213SSam Leffler { 26605591b213SSam Leffler 2661c42a7b7eSSam Leffler if (sc->sc_bdma.dd_desc_len != 0) 2662c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); 2663c42a7b7eSSam Leffler if (sc->sc_txdma.dd_desc_len != 0) 2664c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); 2665c42a7b7eSSam Leffler if (sc->sc_rxdma.dd_desc_len != 0) 2666c42a7b7eSSam Leffler ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 26675591b213SSam Leffler } 26685591b213SSam Leffler 26695591b213SSam Leffler static struct ieee80211_node * 2670c42a7b7eSSam Leffler ath_node_alloc(struct ieee80211_node_table *nt) 26715591b213SSam Leffler { 2672c42a7b7eSSam Leffler struct ieee80211com *ic = nt->nt_ic; 2673c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 2674c42a7b7eSSam Leffler const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; 2675c42a7b7eSSam Leffler struct ath_node *an; 2676c42a7b7eSSam Leffler 2677c42a7b7eSSam Leffler an = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO); 2678c42a7b7eSSam Leffler if (an == NULL) { 2679c42a7b7eSSam Leffler /* XXX stat+msg */ 2680de5af704SSam Leffler return NULL; 26815591b213SSam Leffler } 2682c42a7b7eSSam Leffler an->an_avgrssi = ATH_RSSI_DUMMY_MARKER; 2683c42a7b7eSSam Leffler ath_rate_node_init(sc, an); 26845591b213SSam Leffler 2685c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); 2686c42a7b7eSSam Leffler return &an->an_node; 2687c42a7b7eSSam Leffler } 2688c42a7b7eSSam Leffler 26895591b213SSam Leffler static void 2690c42a7b7eSSam Leffler ath_node_free(struct ieee80211_node *ni) 26915591b213SSam Leffler { 2692c42a7b7eSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2693c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 26941e774079SSam Leffler 2695c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_NODE, "%s: ni %p\n", __func__, ni); 2696c42a7b7eSSam Leffler 2697c42a7b7eSSam Leffler ath_rate_node_cleanup(sc, ATH_NODE(ni)); 2698c42a7b7eSSam Leffler sc->sc_node_free(ni); 26995591b213SSam Leffler } 27005591b213SSam Leffler 2701de5af704SSam Leffler static u_int8_t 2702c42a7b7eSSam Leffler ath_node_getrssi(const struct ieee80211_node *ni) 2703de5af704SSam Leffler { 2704c42a7b7eSSam Leffler #define HAL_EP_RND(x, mul) \ 2705c42a7b7eSSam Leffler ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) 2706c42a7b7eSSam Leffler u_int32_t avgrssi = ATH_NODE_CONST(ni)->an_avgrssi; 2707c42a7b7eSSam Leffler int32_t rssi; 2708de5af704SSam Leffler 2709de5af704SSam Leffler /* 2710c42a7b7eSSam Leffler * When only one frame is received there will be no state in 2711c42a7b7eSSam Leffler * avgrssi so fallback on the value recorded by the 802.11 layer. 2712de5af704SSam Leffler */ 2713c42a7b7eSSam Leffler if (avgrssi != ATH_RSSI_DUMMY_MARKER) 2714c42a7b7eSSam Leffler rssi = HAL_EP_RND(avgrssi, HAL_RSSI_EP_MULTIPLIER); 2715de5af704SSam Leffler else 2716c42a7b7eSSam Leffler rssi = ni->ni_rssi; 2717c42a7b7eSSam Leffler return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; 2718c42a7b7eSSam Leffler #undef HAL_EP_RND 2719de5af704SSam Leffler } 2720de5af704SSam Leffler 27215591b213SSam Leffler static int 27225591b213SSam Leffler ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) 27235591b213SSam Leffler { 27245591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 27255591b213SSam Leffler int error; 27265591b213SSam Leffler struct mbuf *m; 27275591b213SSam Leffler struct ath_desc *ds; 27285591b213SSam Leffler 27295591b213SSam Leffler m = bf->bf_m; 27305591b213SSam Leffler if (m == NULL) { 27315591b213SSam Leffler /* 27325591b213SSam Leffler * NB: by assigning a page to the rx dma buffer we 27335591b213SSam Leffler * implicitly satisfy the Atheros requirement that 27345591b213SSam Leffler * this buffer be cache-line-aligned and sized to be 27355591b213SSam Leffler * multiple of the cache line size. Not doing this 27365591b213SSam Leffler * causes weird stuff to happen (for the 5210 at least). 27375591b213SSam Leffler */ 27385591b213SSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 27395591b213SSam Leffler if (m == NULL) { 2740c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2741c42a7b7eSSam Leffler "%s: no mbuf/cluster\n", __func__); 27425591b213SSam Leffler sc->sc_stats.ast_rx_nombuf++; 27435591b213SSam Leffler return ENOMEM; 27445591b213SSam Leffler } 27455591b213SSam Leffler m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 27465591b213SSam Leffler 2747f9e6219bSSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, 2748c42a7b7eSSam Leffler bf->bf_dmamap, m, 2749f9e6219bSSam Leffler bf->bf_segs, &bf->bf_nseg, 27505591b213SSam Leffler BUS_DMA_NOWAIT); 27515591b213SSam Leffler if (error != 0) { 2752c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 2753f9e6219bSSam Leffler "%s: bus_dmamap_load_mbuf_sg failed; error %d\n", 2754c42a7b7eSSam Leffler __func__, error); 27555591b213SSam Leffler sc->sc_stats.ast_rx_busdma++; 2756b2792ff6SSam Leffler m_freem(m); 27575591b213SSam Leffler return error; 27585591b213SSam Leffler } 2759d77367bfSSam Leffler KASSERT(bf->bf_nseg == 1, 2760d77367bfSSam Leffler ("multi-segment packet; nseg %u", bf->bf_nseg)); 2761b2792ff6SSam Leffler bf->bf_m = m; 27625591b213SSam Leffler } 27635591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD); 27645591b213SSam Leffler 276504e22a02SSam Leffler /* 276604e22a02SSam Leffler * Setup descriptors. For receive we always terminate 276704e22a02SSam Leffler * the descriptor list with a self-linked entry so we'll 276804e22a02SSam Leffler * not get overrun under high load (as can happen with a 2769c42a7b7eSSam Leffler * 5212 when ANI processing enables PHY error frames). 277004e22a02SSam Leffler * 277104e22a02SSam Leffler * To insure the last descriptor is self-linked we create 277204e22a02SSam Leffler * each descriptor as self-linked and add it to the end. As 277304e22a02SSam Leffler * each additional descriptor is added the previous self-linked 277404e22a02SSam Leffler * entry is ``fixed'' naturally. This should be safe even 277504e22a02SSam Leffler * if DMA is happening. When processing RX interrupts we 277604e22a02SSam Leffler * never remove/process the last, self-linked, entry on the 277704e22a02SSam Leffler * descriptor list. This insures the hardware always has 277804e22a02SSam Leffler * someplace to write a new frame. 277904e22a02SSam Leffler */ 27805591b213SSam Leffler ds = bf->bf_desc; 278104e22a02SSam Leffler ds->ds_link = bf->bf_daddr; /* link to self */ 27825591b213SSam Leffler ds->ds_data = bf->bf_segs[0].ds_addr; 27835591b213SSam Leffler ath_hal_setuprxdesc(ah, ds 27845591b213SSam Leffler , m->m_len /* buffer size */ 27855591b213SSam Leffler , 0 27865591b213SSam Leffler ); 27875591b213SSam Leffler 27885591b213SSam Leffler if (sc->sc_rxlink != NULL) 27895591b213SSam Leffler *sc->sc_rxlink = bf->bf_daddr; 27905591b213SSam Leffler sc->sc_rxlink = &ds->ds_link; 27915591b213SSam Leffler return 0; 27925591b213SSam Leffler } 27935591b213SSam Leffler 2794c42a7b7eSSam Leffler /* 279503ed599aSSam Leffler * Extend 15-bit time stamp from rx descriptor to 27967b0c77ecSSam Leffler * a full 64-bit TSF using the specified TSF. 279703ed599aSSam Leffler */ 279803ed599aSSam Leffler static __inline u_int64_t 27997b0c77ecSSam Leffler ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf) 280003ed599aSSam Leffler { 280103ed599aSSam Leffler if ((tsf & 0x7fff) < rstamp) 280203ed599aSSam Leffler tsf -= 0x8000; 280303ed599aSSam Leffler return ((tsf &~ 0x7fff) | rstamp); 280403ed599aSSam Leffler } 280503ed599aSSam Leffler 280603ed599aSSam Leffler /* 2807c42a7b7eSSam Leffler * Intercept management frames to collect beacon rssi data 2808c42a7b7eSSam Leffler * and to do ibss merges. 2809c42a7b7eSSam Leffler */ 2810c42a7b7eSSam Leffler static void 2811c42a7b7eSSam Leffler ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, 2812c42a7b7eSSam Leffler struct ieee80211_node *ni, 2813c42a7b7eSSam Leffler int subtype, int rssi, u_int32_t rstamp) 2814c42a7b7eSSam Leffler { 2815c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 2816c42a7b7eSSam Leffler 2817c42a7b7eSSam Leffler /* 2818c42a7b7eSSam Leffler * Call up first so subsequent work can use information 2819c42a7b7eSSam Leffler * potentially stored in the node (e.g. for ibss merge). 2820c42a7b7eSSam Leffler */ 2821c42a7b7eSSam Leffler sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, rstamp); 2822c42a7b7eSSam Leffler switch (subtype) { 2823c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_BEACON: 2824c42a7b7eSSam Leffler /* update rssi statistics for use by the hal */ 2825ffa2cab6SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); 282680d939bfSSam Leffler if (sc->sc_syncbeacon && 282780d939bfSSam Leffler ni == ic->ic_bss && ic->ic_state == IEEE80211_S_RUN) { 282880d939bfSSam Leffler /* 282980d939bfSSam Leffler * Resync beacon timers using the tsf of the beacon 283080d939bfSSam Leffler * frame we just received. 283180d939bfSSam Leffler */ 283280d939bfSSam Leffler ath_beacon_config(sc); 283380d939bfSSam Leffler } 2834c42a7b7eSSam Leffler /* fall thru... */ 2835c42a7b7eSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 2836c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && 2837c42a7b7eSSam Leffler ic->ic_state == IEEE80211_S_RUN) { 28387b0c77ecSSam Leffler u_int64_t tsf = ath_extend_tsf(rstamp, 28397b0c77ecSSam Leffler ath_hal_gettsf64(sc->sc_ah)); 2840c42a7b7eSSam Leffler /* 2841c42a7b7eSSam Leffler * Handle ibss merge as needed; check the tsf on the 2842c42a7b7eSSam Leffler * frame before attempting the merge. The 802.11 spec 2843c42a7b7eSSam Leffler * says the station should change it's bssid to match 2844c42a7b7eSSam Leffler * the oldest station with the same ssid, where oldest 2845f818612bSSam Leffler * is determined by the tsf. Note that hardware 2846f818612bSSam Leffler * reconfiguration happens through callback to 284703ed599aSSam Leffler * ath_newstate as the state machine will go from 284803ed599aSSam Leffler * RUN -> RUN when this happens. 2849c42a7b7eSSam Leffler */ 285003ed599aSSam Leffler if (le64toh(ni->ni_tstamp.tsf) >= tsf) { 285103ed599aSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 285233d7d80cSTai-hwa Liang "ibss merge, rstamp %u tsf %ju " 285333d7d80cSTai-hwa Liang "tstamp %ju\n", rstamp, (uintmax_t)tsf, 285433d7d80cSTai-hwa Liang (uintmax_t)ni->ni_tstamp.tsf); 2855641b4d0bSSam Leffler (void) ieee80211_ibss_merge(ni); 2856c42a7b7eSSam Leffler } 285703ed599aSSam Leffler } 2858c42a7b7eSSam Leffler break; 2859c42a7b7eSSam Leffler } 2860c42a7b7eSSam Leffler } 2861c42a7b7eSSam Leffler 2862c42a7b7eSSam Leffler /* 2863c42a7b7eSSam Leffler * Set the default antenna. 2864c42a7b7eSSam Leffler */ 2865c42a7b7eSSam Leffler static void 2866c42a7b7eSSam Leffler ath_setdefantenna(struct ath_softc *sc, u_int antenna) 2867c42a7b7eSSam Leffler { 2868c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 2869c42a7b7eSSam Leffler 2870c42a7b7eSSam Leffler /* XXX block beacon interrupts */ 2871c42a7b7eSSam Leffler ath_hal_setdefantenna(ah, antenna); 2872c42a7b7eSSam Leffler if (sc->sc_defant != antenna) 2873c42a7b7eSSam Leffler sc->sc_stats.ast_ant_defswitch++; 2874c42a7b7eSSam Leffler sc->sc_defant = antenna; 2875c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 2876c42a7b7eSSam Leffler } 2877c42a7b7eSSam Leffler 28787b0c77ecSSam Leffler static int 28797b0c77ecSSam Leffler ath_rx_tap(struct ath_softc *sc, struct mbuf *m, 288065f9edeeSSam Leffler const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf) 28817b0c77ecSSam Leffler { 28827b0c77ecSSam Leffler u_int8_t rix; 28837b0c77ecSSam Leffler 28847b0c77ecSSam Leffler KASSERT(sc->sc_drvbpf != NULL, ("no tap")); 28857b0c77ecSSam Leffler 28867b0c77ecSSam Leffler /* 28877b0c77ecSSam Leffler * Discard anything shorter than an ack or cts. 28887b0c77ecSSam Leffler */ 28897b0c77ecSSam Leffler if (m->m_pkthdr.len < IEEE80211_ACK_LEN) { 28907b0c77ecSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, "%s: runt packet %d\n", 28917b0c77ecSSam Leffler __func__, m->m_pkthdr.len); 28927b0c77ecSSam Leffler sc->sc_stats.ast_rx_tooshort++; 28937b0c77ecSSam Leffler return 0; 28947b0c77ecSSam Leffler } 289565f9edeeSSam Leffler sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf)); 289665f9edeeSSam Leffler rix = rs->rs_rate; 28977b0c77ecSSam Leffler sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; 289865f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 28997b0c77ecSSam Leffler sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; 29007b0c77ecSSam Leffler /* XXX propagate other error flags from descriptor */ 29017b0c77ecSSam Leffler sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate; 290265f9edeeSSam Leffler sc->sc_rx_th.wr_antsignal = rs->rs_rssi + nf; 29037b0c77ecSSam Leffler sc->sc_rx_th.wr_antnoise = nf; 290465f9edeeSSam Leffler sc->sc_rx_th.wr_antenna = rs->rs_antenna; 29057b0c77ecSSam Leffler 29067b0c77ecSSam Leffler bpf_mtap2(sc->sc_drvbpf, &sc->sc_rx_th, sc->sc_rx_th_len, m); 29077b0c77ecSSam Leffler 29087b0c77ecSSam Leffler return 1; 29097b0c77ecSSam Leffler } 29107b0c77ecSSam Leffler 29115591b213SSam Leffler static void 29125591b213SSam Leffler ath_rx_proc(void *arg, int npending) 29135591b213SSam Leffler { 29148cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 2915c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 2916c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 29175591b213SSam Leffler struct ath_softc *sc = arg; 29185591b213SSam Leffler struct ath_buf *bf; 2919d1d0cf62SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 2920fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 29215591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 29225591b213SSam Leffler struct ath_desc *ds; 292365f9edeeSSam Leffler struct ath_rx_status *rs; 29245591b213SSam Leffler struct mbuf *m; 29250a915fadSSam Leffler struct ieee80211_node *ni; 2926de5af704SSam Leffler struct ath_node *an; 2927d7736e13SSam Leffler int len, type, ngood; 29285591b213SSam Leffler u_int phyerr; 29295591b213SSam Leffler HAL_STATUS status; 29307b0c77ecSSam Leffler int16_t nf; 29317b0c77ecSSam Leffler u_int64_t tsf; 29325591b213SSam Leffler 2933b5f4adb3SSam Leffler NET_LOCK_GIANT(); /* XXX */ 2934b5f4adb3SSam Leffler 2935c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); 2936d7736e13SSam Leffler ngood = 0; 29377b0c77ecSSam Leffler nf = ath_hal_getchannoise(ah, &sc->sc_curchan); 29387b0c77ecSSam Leffler tsf = ath_hal_gettsf64(ah); 29395591b213SSam Leffler do { 2940c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 29415591b213SSam Leffler if (bf == NULL) { /* NB: shouldn't happen */ 2942c42a7b7eSSam Leffler if_printf(ifp, "%s: no buffer!\n", __func__); 29435591b213SSam Leffler break; 29445591b213SSam Leffler } 2945b2792ff6SSam Leffler m = bf->bf_m; 2946b2792ff6SSam Leffler if (m == NULL) { /* NB: shouldn't happen */ 2947b2792ff6SSam Leffler /* 2948b2792ff6SSam Leffler * If mbuf allocation failed previously there 2949b2792ff6SSam Leffler * will be no mbuf; try again to re-populate it. 2950b2792ff6SSam Leffler */ 2951b2792ff6SSam Leffler /* XXX make debug msg */ 2952b2792ff6SSam Leffler if_printf(ifp, "%s: no mbuf!\n", __func__); 2953b2792ff6SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 2954b2792ff6SSam Leffler goto rx_next; 2955b2792ff6SSam Leffler } 295604e22a02SSam Leffler ds = bf->bf_desc; 295704e22a02SSam Leffler if (ds->ds_link == bf->bf_daddr) { 295804e22a02SSam Leffler /* NB: never process the self-linked entry at the end */ 295904e22a02SSam Leffler break; 296004e22a02SSam Leffler } 29618cec0ab9SSam Leffler /* XXX sync descriptor memory */ 29628cec0ab9SSam Leffler /* 29638cec0ab9SSam Leffler * Must provide the virtual address of the current 29648cec0ab9SSam Leffler * descriptor, the physical address, and the virtual 29658cec0ab9SSam Leffler * address of the next descriptor in the h/w chain. 29668cec0ab9SSam Leffler * This allows the HAL to look ahead to see if the 29678cec0ab9SSam Leffler * hardware is done with a descriptor by checking the 29688cec0ab9SSam Leffler * done bit in the following descriptor and the address 29698cec0ab9SSam Leffler * of the current descriptor the DMA engine is working 29708cec0ab9SSam Leffler * on. All this is necessary because of our use of 29718cec0ab9SSam Leffler * a self-linked list to avoid rx overruns. 29728cec0ab9SSam Leffler */ 297365f9edeeSSam Leffler rs = &bf->bf_status.ds_rxstat; 29748cec0ab9SSam Leffler status = ath_hal_rxprocdesc(ah, ds, 297565f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 2976a585a9a1SSam Leffler #ifdef ATH_DEBUG 2977c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_RECV_DESC) 29787a4c5ed9SSam Leffler ath_printrxbuf(bf, 0, status == HAL_OK); 29795591b213SSam Leffler #endif 29805591b213SSam Leffler if (status == HAL_EINPROGRESS) 29815591b213SSam Leffler break; 2982c42a7b7eSSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); 298365f9edeeSSam Leffler if (rs->rs_more) { 2984c42a7b7eSSam Leffler /* 2985c42a7b7eSSam Leffler * Frame spans multiple descriptors; this 2986c42a7b7eSSam Leffler * cannot happen yet as we don't support 2987c42a7b7eSSam Leffler * jumbograms. If not in monitor mode, 2988c42a7b7eSSam Leffler * discard the frame. 2989c42a7b7eSSam Leffler */ 2990c42a7b7eSSam Leffler if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2991c42a7b7eSSam Leffler sc->sc_stats.ast_rx_toobig++; 2992c42a7b7eSSam Leffler goto rx_next; 2993c42a7b7eSSam Leffler } 2994c42a7b7eSSam Leffler /* fall thru for monitor mode handling... */ 299565f9edeeSSam Leffler } else if (rs->rs_status != 0) { 299665f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_CRC) 29975591b213SSam Leffler sc->sc_stats.ast_rx_crcerr++; 299865f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_FIFO) 29995591b213SSam Leffler sc->sc_stats.ast_rx_fifoerr++; 300065f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_PHY) { 30015591b213SSam Leffler sc->sc_stats.ast_rx_phyerr++; 300265f9edeeSSam Leffler phyerr = rs->rs_phyerr & 0x1f; 30035591b213SSam Leffler sc->sc_stats.ast_rx_phy[phyerr]++; 3004c42a7b7eSSam Leffler goto rx_next; 3005c42a7b7eSSam Leffler } 300665f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_DECRYPT) { 300785643802SSam Leffler /* 3008c42a7b7eSSam Leffler * Decrypt error. If the error occurred 3009c42a7b7eSSam Leffler * because there was no hardware key, then 3010c42a7b7eSSam Leffler * let the frame through so the upper layers 3011c42a7b7eSSam Leffler * can process it. This is necessary for 5210 3012c42a7b7eSSam Leffler * parts which have no way to setup a ``clear'' 3013c42a7b7eSSam Leffler * key cache entry. 3014c42a7b7eSSam Leffler * 3015c42a7b7eSSam Leffler * XXX do key cache faulting 301685643802SSam Leffler */ 301765f9edeeSSam Leffler if (rs->rs_keyix == HAL_RXKEYIX_INVALID) 3018c42a7b7eSSam Leffler goto rx_accept; 3019c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badcrypt++; 30205591b213SSam Leffler } 302165f9edeeSSam Leffler if (rs->rs_status & HAL_RXERR_MIC) { 3022c42a7b7eSSam Leffler sc->sc_stats.ast_rx_badmic++; 3023c42a7b7eSSam Leffler /* 3024c42a7b7eSSam Leffler * Do minimal work required to hand off 3025c42a7b7eSSam Leffler * the 802.11 header for notifcation. 3026c42a7b7eSSam Leffler */ 3027c42a7b7eSSam Leffler /* XXX frag's and qos frames */ 302865f9edeeSSam Leffler len = rs->rs_datalen; 3029c42a7b7eSSam Leffler if (len >= sizeof (struct ieee80211_frame)) { 3030c42a7b7eSSam Leffler bus_dmamap_sync(sc->sc_dmat, 3031c42a7b7eSSam Leffler bf->bf_dmamap, 3032c42a7b7eSSam Leffler BUS_DMASYNC_POSTREAD); 3033c42a7b7eSSam Leffler ieee80211_notify_michael_failure(ic, 3034c42a7b7eSSam Leffler mtod(m, struct ieee80211_frame *), 30350ab4040aSSam Leffler sc->sc_splitmic ? 303665f9edeeSSam Leffler rs->rs_keyix-32 : rs->rs_keyix 30370ab4040aSSam Leffler ); 3038c42a7b7eSSam Leffler } 3039c42a7b7eSSam Leffler } 3040c42a7b7eSSam Leffler ifp->if_ierrors++; 3041c42a7b7eSSam Leffler /* 30427b0c77ecSSam Leffler * When a tap is present pass error frames 30437b0c77ecSSam Leffler * that have been requested. By default we 30447b0c77ecSSam Leffler * pass decrypt+mic errors but others may be 30457b0c77ecSSam Leffler * interesting (e.g. crc). 3046c42a7b7eSSam Leffler */ 304716d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf) && 304865f9edeeSSam Leffler (rs->rs_status & sc->sc_monpass)) { 30497b0c77ecSSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 30507b0c77ecSSam Leffler BUS_DMASYNC_POSTREAD); 30517b0c77ecSSam Leffler /* NB: bpf needs the mbuf length setup */ 305265f9edeeSSam Leffler len = rs->rs_datalen; 30537b0c77ecSSam Leffler m->m_pkthdr.len = m->m_len = len; 305465f9edeeSSam Leffler (void) ath_rx_tap(sc, m, rs, tsf, nf); 30557b0c77ecSSam Leffler } 30567b0c77ecSSam Leffler /* XXX pass MIC errors up for s/w reclaculation */ 30575591b213SSam Leffler goto rx_next; 30585591b213SSam Leffler } 3059c42a7b7eSSam Leffler rx_accept: 3060c42a7b7eSSam Leffler /* 3061c42a7b7eSSam Leffler * Sync and unmap the frame. At this point we're 3062c42a7b7eSSam Leffler * committed to passing the mbuf somewhere so clear 3063c66c48cbSSam Leffler * bf_m; this means a new mbuf must be allocated 3064c42a7b7eSSam Leffler * when the rx descriptor is setup again to receive 3065c42a7b7eSSam Leffler * another frame. 3066c42a7b7eSSam Leffler */ 30675591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 30685591b213SSam Leffler BUS_DMASYNC_POSTREAD); 30695591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 30705591b213SSam Leffler bf->bf_m = NULL; 3071c42a7b7eSSam Leffler 30725591b213SSam Leffler m->m_pkthdr.rcvif = ifp; 307365f9edeeSSam Leffler len = rs->rs_datalen; 30745591b213SSam Leffler m->m_pkthdr.len = m->m_len = len; 307573454c73SSam Leffler 307665f9edeeSSam Leffler sc->sc_stats.ast_ant_rx[rs->rs_antenna]++; 3077c42a7b7eSSam Leffler 307816d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf) && 307965f9edeeSSam Leffler !ath_rx_tap(sc, m, rs, tsf, nf)) { 30807b0c77ecSSam Leffler m_freem(m); /* XXX reclaim */ 3081c42a7b7eSSam Leffler goto rx_next; 3082c42a7b7eSSam Leffler } 30830a915fadSSam Leffler 30845591b213SSam Leffler /* 3085c42a7b7eSSam Leffler * From this point on we assume the frame is at least 3086c42a7b7eSSam Leffler * as large as ieee80211_frame_min; verify that. 30875591b213SSam Leffler */ 3088c42a7b7eSSam Leffler if (len < IEEE80211_MIN_LEN) { 3089c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, "%s: short packet %d\n", 3090c42a7b7eSSam Leffler __func__, len); 3091c42a7b7eSSam Leffler sc->sc_stats.ast_rx_tooshort++; 3092c42a7b7eSSam Leffler m_freem(m); 3093c42a7b7eSSam Leffler goto rx_next; 30945591b213SSam Leffler } 30950a915fadSSam Leffler 3096c42a7b7eSSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) { 3097c42a7b7eSSam Leffler ieee80211_dump_pkt(mtod(m, caddr_t), len, 309865f9edeeSSam Leffler sc->sc_hwmap[rs->rs_rate].ieeerate, 309965f9edeeSSam Leffler rs->rs_rssi); 3100c42a7b7eSSam Leffler } 3101c42a7b7eSSam Leffler 3102c42a7b7eSSam Leffler m_adj(m, -IEEE80211_CRC_LEN); 3103de5af704SSam Leffler 3104de5af704SSam Leffler /* 3105c42a7b7eSSam Leffler * Locate the node for sender, track state, and then 3106c42a7b7eSSam Leffler * pass the (referenced) node up to the 802.11 layer 3107c42a7b7eSSam Leffler * for its use. 3108c42a7b7eSSam Leffler */ 3109c1225b52SSam Leffler ni = ieee80211_find_rxnode_withkey(ic, 3110c1225b52SSam Leffler mtod(m, const struct ieee80211_frame_min *), 311165f9edeeSSam Leffler rs->rs_keyix == HAL_RXKEYIX_INVALID ? 311265f9edeeSSam Leffler IEEE80211_KEYIX_NONE : rs->rs_keyix); 3113c42a7b7eSSam Leffler /* 3114c42a7b7eSSam Leffler * Track rx rssi and do any rx antenna management. 3115de5af704SSam Leffler */ 3116de5af704SSam Leffler an = ATH_NODE(ni); 311765f9edeeSSam Leffler ATH_RSSI_LPF(an->an_avgrssi, rs->rs_rssi); 311865f9edeeSSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi); 3119e8fd88a3SSam Leffler /* 3120e8fd88a3SSam Leffler * Send frame up for processing. 3121e8fd88a3SSam Leffler */ 312265f9edeeSSam Leffler type = ieee80211_input(ic, m, ni, rs->rs_rssi, rs->rs_tstamp); 3123e8fd88a3SSam Leffler ieee80211_free_node(ni); 3124c42a7b7eSSam Leffler if (sc->sc_diversity) { 3125c42a7b7eSSam Leffler /* 3126c42a7b7eSSam Leffler * When using fast diversity, change the default rx 3127c42a7b7eSSam Leffler * antenna if diversity chooses the other antenna 3 3128c42a7b7eSSam Leffler * times in a row. 3129c42a7b7eSSam Leffler */ 313065f9edeeSSam Leffler if (sc->sc_defant != rs->rs_antenna) { 3131c42a7b7eSSam Leffler if (++sc->sc_rxotherant >= 3) 313265f9edeeSSam Leffler ath_setdefantenna(sc, rs->rs_antenna); 3133c42a7b7eSSam Leffler } else 3134c42a7b7eSSam Leffler sc->sc_rxotherant = 0; 3135c42a7b7eSSam Leffler } 31363e50ec2cSSam Leffler if (sc->sc_softled) { 31373e50ec2cSSam Leffler /* 31383e50ec2cSSam Leffler * Blink for any data frame. Otherwise do a 31393e50ec2cSSam Leffler * heartbeat-style blink when idle. The latter 31403e50ec2cSSam Leffler * is mainly for station mode where we depend on 31413e50ec2cSSam Leffler * periodic beacon frames to trigger the poll event. 31423e50ec2cSSam Leffler */ 314331640eb7SSam Leffler if (type == IEEE80211_FC0_TYPE_DATA) { 314465f9edeeSSam Leffler sc->sc_rxrate = rs->rs_rate; 31453e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_RX); 31463e50ec2cSSam Leffler } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) 31473e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_POLL); 31483e50ec2cSSam Leffler } 3149d7736e13SSam Leffler /* 3150d7736e13SSam Leffler * Arrange to update the last rx timestamp only for 3151d7736e13SSam Leffler * frames from our ap when operating in station mode. 3152d7736e13SSam Leffler * This assumes the rx key is always setup when associated. 3153d7736e13SSam Leffler */ 3154d7736e13SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA && 315565f9edeeSSam Leffler rs->rs_keyix != HAL_RXKEYIX_INVALID) 3156d7736e13SSam Leffler ngood++; 31575591b213SSam Leffler rx_next: 3158c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); 31595591b213SSam Leffler } while (ath_rxbuf_init(sc, bf) == 0); 31605591b213SSam Leffler 3161c42a7b7eSSam Leffler /* rx signal state monitoring */ 3162bd5a9920SSam Leffler ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan); 3163d7736e13SSam Leffler if (ngood) 3164d7736e13SSam Leffler sc->sc_lastrx = tsf; 3165b5f4adb3SSam Leffler 3166b5f4adb3SSam Leffler NET_UNLOCK_GIANT(); /* XXX */ 31678cec0ab9SSam Leffler #undef PA2DESC 31685591b213SSam Leffler } 31695591b213SSam Leffler 3170622b3fd2SSam Leffler static void 3171622b3fd2SSam Leffler ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum) 3172622b3fd2SSam Leffler { 3173622b3fd2SSam Leffler txq->axq_qnum = qnum; 3174622b3fd2SSam Leffler txq->axq_depth = 0; 3175622b3fd2SSam Leffler txq->axq_intrcnt = 0; 3176622b3fd2SSam Leffler txq->axq_link = NULL; 3177622b3fd2SSam Leffler STAILQ_INIT(&txq->axq_q); 3178622b3fd2SSam Leffler ATH_TXQ_LOCK_INIT(sc, txq); 3179622b3fd2SSam Leffler } 3180622b3fd2SSam Leffler 31815591b213SSam Leffler /* 3182c42a7b7eSSam Leffler * Setup a h/w transmit queue. 31835591b213SSam Leffler */ 3184c42a7b7eSSam Leffler static struct ath_txq * 3185c42a7b7eSSam Leffler ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) 3186c42a7b7eSSam Leffler { 3187c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3188c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3189c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3190c42a7b7eSSam Leffler int qnum; 3191c42a7b7eSSam Leffler 3192c42a7b7eSSam Leffler memset(&qi, 0, sizeof(qi)); 3193c42a7b7eSSam Leffler qi.tqi_subtype = subtype; 3194c42a7b7eSSam Leffler qi.tqi_aifs = HAL_TXQ_USEDEFAULT; 3195c42a7b7eSSam Leffler qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; 3196c42a7b7eSSam Leffler qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; 3197c42a7b7eSSam Leffler /* 3198c42a7b7eSSam Leffler * Enable interrupts only for EOL and DESC conditions. 3199c42a7b7eSSam Leffler * We mark tx descriptors to receive a DESC interrupt 3200c42a7b7eSSam Leffler * when a tx queue gets deep; otherwise waiting for the 3201c42a7b7eSSam Leffler * EOL to reap descriptors. Note that this is done to 3202c42a7b7eSSam Leffler * reduce interrupt load and this only defers reaping 3203c42a7b7eSSam Leffler * descriptors, never transmitting frames. Aside from 3204c42a7b7eSSam Leffler * reducing interrupts this also permits more concurrency. 3205c42a7b7eSSam Leffler * The only potential downside is if the tx queue backs 3206c42a7b7eSSam Leffler * up in which case the top half of the kernel may backup 3207c42a7b7eSSam Leffler * due to a lack of tx descriptors. 3208c42a7b7eSSam Leffler */ 3209bd5a9920SSam Leffler qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; 3210c42a7b7eSSam Leffler qnum = ath_hal_setuptxqueue(ah, qtype, &qi); 3211c42a7b7eSSam Leffler if (qnum == -1) { 3212c42a7b7eSSam Leffler /* 3213c42a7b7eSSam Leffler * NB: don't print a message, this happens 3214a614e076SSam Leffler * normally on parts with too few tx queues 3215c42a7b7eSSam Leffler */ 3216c42a7b7eSSam Leffler return NULL; 3217c42a7b7eSSam Leffler } 3218c42a7b7eSSam Leffler if (qnum >= N(sc->sc_txq)) { 32196891c875SPeter Wemm device_printf(sc->sc_dev, 32206891c875SPeter Wemm "hal qnum %u out of range, max %zu!\n", 3221c42a7b7eSSam Leffler qnum, N(sc->sc_txq)); 3222c42a7b7eSSam Leffler ath_hal_releasetxqueue(ah, qnum); 3223c42a7b7eSSam Leffler return NULL; 3224c42a7b7eSSam Leffler } 3225c42a7b7eSSam Leffler if (!ATH_TXQ_SETUP(sc, qnum)) { 3226622b3fd2SSam Leffler ath_txq_init(sc, &sc->sc_txq[qnum], qnum); 3227c42a7b7eSSam Leffler sc->sc_txqsetup |= 1<<qnum; 3228c42a7b7eSSam Leffler } 3229c42a7b7eSSam Leffler return &sc->sc_txq[qnum]; 3230c42a7b7eSSam Leffler #undef N 3231c42a7b7eSSam Leffler } 3232c42a7b7eSSam Leffler 3233c42a7b7eSSam Leffler /* 3234c42a7b7eSSam Leffler * Setup a hardware data transmit queue for the specified 3235c42a7b7eSSam Leffler * access control. The hal may not support all requested 3236c42a7b7eSSam Leffler * queues in which case it will return a reference to a 3237c42a7b7eSSam Leffler * previously setup queue. We record the mapping from ac's 3238c42a7b7eSSam Leffler * to h/w queues for use by ath_tx_start and also track 3239c42a7b7eSSam Leffler * the set of h/w queues being used to optimize work in the 3240c42a7b7eSSam Leffler * transmit interrupt handler and related routines. 3241c42a7b7eSSam Leffler */ 3242c42a7b7eSSam Leffler static int 3243c42a7b7eSSam Leffler ath_tx_setup(struct ath_softc *sc, int ac, int haltype) 3244c42a7b7eSSam Leffler { 3245c42a7b7eSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 3246c42a7b7eSSam Leffler struct ath_txq *txq; 3247c42a7b7eSSam Leffler 3248c42a7b7eSSam Leffler if (ac >= N(sc->sc_ac2q)) { 32496891c875SPeter Wemm device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n", 3250c42a7b7eSSam Leffler ac, N(sc->sc_ac2q)); 3251c42a7b7eSSam Leffler return 0; 3252c42a7b7eSSam Leffler } 3253c42a7b7eSSam Leffler txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype); 3254c42a7b7eSSam Leffler if (txq != NULL) { 3255c42a7b7eSSam Leffler sc->sc_ac2q[ac] = txq; 3256c42a7b7eSSam Leffler return 1; 3257c42a7b7eSSam Leffler } else 3258c42a7b7eSSam Leffler return 0; 3259c42a7b7eSSam Leffler #undef N 3260c42a7b7eSSam Leffler } 3261c42a7b7eSSam Leffler 3262c42a7b7eSSam Leffler /* 3263c42a7b7eSSam Leffler * Update WME parameters for a transmit queue. 3264c42a7b7eSSam Leffler */ 3265c42a7b7eSSam Leffler static int 3266c42a7b7eSSam Leffler ath_txq_update(struct ath_softc *sc, int ac) 3267c42a7b7eSSam Leffler { 3268c42a7b7eSSam Leffler #define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1) 3269c42a7b7eSSam Leffler #define ATH_TXOP_TO_US(v) (v<<5) 3270c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 3271c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[ac]; 3272c42a7b7eSSam Leffler struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; 3273c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 3274c42a7b7eSSam Leffler HAL_TXQ_INFO qi; 3275c42a7b7eSSam Leffler 3276c42a7b7eSSam Leffler ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi); 3277c42a7b7eSSam Leffler qi.tqi_aifs = wmep->wmep_aifsn; 3278c42a7b7eSSam Leffler qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); 3279c42a7b7eSSam Leffler qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); 3280c42a7b7eSSam Leffler qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit); 3281c42a7b7eSSam Leffler 3282c42a7b7eSSam Leffler if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) { 3283c42a7b7eSSam Leffler device_printf(sc->sc_dev, "unable to update hardware queue " 3284c42a7b7eSSam Leffler "parameters for %s traffic!\n", 3285c42a7b7eSSam Leffler ieee80211_wme_acnames[ac]); 3286c42a7b7eSSam Leffler return 0; 3287c42a7b7eSSam Leffler } else { 3288c42a7b7eSSam Leffler ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */ 3289c42a7b7eSSam Leffler return 1; 3290c42a7b7eSSam Leffler } 3291c42a7b7eSSam Leffler #undef ATH_TXOP_TO_US 3292c42a7b7eSSam Leffler #undef ATH_EXPONENT_TO_VALUE 3293c42a7b7eSSam Leffler } 3294c42a7b7eSSam Leffler 3295c42a7b7eSSam Leffler /* 3296c42a7b7eSSam Leffler * Callback from the 802.11 layer to update WME parameters. 3297c42a7b7eSSam Leffler */ 3298c42a7b7eSSam Leffler static int 3299c42a7b7eSSam Leffler ath_wme_update(struct ieee80211com *ic) 3300c42a7b7eSSam Leffler { 3301c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 3302c42a7b7eSSam Leffler 3303c42a7b7eSSam Leffler return !ath_txq_update(sc, WME_AC_BE) || 3304c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_BK) || 3305c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VI) || 3306c42a7b7eSSam Leffler !ath_txq_update(sc, WME_AC_VO) ? EIO : 0; 3307c42a7b7eSSam Leffler } 3308c42a7b7eSSam Leffler 3309c42a7b7eSSam Leffler /* 3310c42a7b7eSSam Leffler * Reclaim resources for a setup queue. 3311c42a7b7eSSam Leffler */ 3312c42a7b7eSSam Leffler static void 3313c42a7b7eSSam Leffler ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) 3314c42a7b7eSSam Leffler { 3315c42a7b7eSSam Leffler 3316c42a7b7eSSam Leffler ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum); 3317c42a7b7eSSam Leffler ATH_TXQ_LOCK_DESTROY(txq); 3318c42a7b7eSSam Leffler sc->sc_txqsetup &= ~(1<<txq->axq_qnum); 3319c42a7b7eSSam Leffler } 3320c42a7b7eSSam Leffler 3321c42a7b7eSSam Leffler /* 3322c42a7b7eSSam Leffler * Reclaim all tx queue resources. 3323c42a7b7eSSam Leffler */ 3324c42a7b7eSSam Leffler static void 3325c42a7b7eSSam Leffler ath_tx_cleanup(struct ath_softc *sc) 3326c42a7b7eSSam Leffler { 3327c42a7b7eSSam Leffler int i; 3328c42a7b7eSSam Leffler 3329c42a7b7eSSam Leffler ATH_TXBUF_LOCK_DESTROY(sc); 3330c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 3331c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 3332c42a7b7eSSam Leffler ath_tx_cleanupq(sc, &sc->sc_txq[i]); 3333622b3fd2SSam Leffler ATH_TXQ_LOCK_DESTROY(&sc->sc_mcastq); 3334c42a7b7eSSam Leffler } 33355591b213SSam Leffler 333699d258fdSSam Leffler /* 333799d258fdSSam Leffler * Defragment an mbuf chain, returning at most maxfrags separate 333899d258fdSSam Leffler * mbufs+clusters. If this is not possible NULL is returned and 3339a7073e8bSSam Leffler * the original mbuf chain is left in it's present (potentially 3340a7073e8bSSam Leffler * modified) state. We use two techniques: collapsing consecutive 3341a7073e8bSSam Leffler * mbufs and replacing consecutive mbufs by a cluster. 334299d258fdSSam Leffler */ 334399d258fdSSam Leffler static struct mbuf * 334499d258fdSSam Leffler ath_defrag(struct mbuf *m0, int how, int maxfrags) 334599d258fdSSam Leffler { 334699d258fdSSam Leffler struct mbuf *m, *n, *n2, **prev; 334799d258fdSSam Leffler u_int curfrags; 334899d258fdSSam Leffler 334999d258fdSSam Leffler /* 335099d258fdSSam Leffler * Calculate the current number of frags. 335199d258fdSSam Leffler */ 335299d258fdSSam Leffler curfrags = 0; 335399d258fdSSam Leffler for (m = m0; m != NULL; m = m->m_next) 335499d258fdSSam Leffler curfrags++; 335599d258fdSSam Leffler /* 335699d258fdSSam Leffler * First, try to collapse mbufs. Note that we always collapse 335799d258fdSSam Leffler * towards the front so we don't need to deal with moving the 335899d258fdSSam Leffler * pkthdr. This may be suboptimal if the first mbuf has much 335999d258fdSSam Leffler * less data than the following. 336099d258fdSSam Leffler */ 336199d258fdSSam Leffler m = m0; 336299d258fdSSam Leffler again: 336399d258fdSSam Leffler for (;;) { 336499d258fdSSam Leffler n = m->m_next; 336599d258fdSSam Leffler if (n == NULL) 336699d258fdSSam Leffler break; 3367019b9669SSam Leffler if ((m->m_flags & M_RDONLY) == 0 && 3368019b9669SSam Leffler n->m_len < M_TRAILINGSPACE(m)) { 336999d258fdSSam Leffler bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, 337099d258fdSSam Leffler n->m_len); 337199d258fdSSam Leffler m->m_len += n->m_len; 337299d258fdSSam Leffler m->m_next = n->m_next; 337399d258fdSSam Leffler m_free(n); 337499d258fdSSam Leffler if (--curfrags <= maxfrags) 337599d258fdSSam Leffler return m0; 337699d258fdSSam Leffler } else 337799d258fdSSam Leffler m = n; 337899d258fdSSam Leffler } 337999d258fdSSam Leffler KASSERT(maxfrags > 1, 338099d258fdSSam Leffler ("maxfrags %u, but normal collapse failed", maxfrags)); 338199d258fdSSam Leffler /* 338299d258fdSSam Leffler * Collapse consecutive mbufs to a cluster. 338399d258fdSSam Leffler */ 338499d258fdSSam Leffler prev = &m0->m_next; /* NB: not the first mbuf */ 338599d258fdSSam Leffler while ((n = *prev) != NULL) { 338699d258fdSSam Leffler if ((n2 = n->m_next) != NULL && 338799d258fdSSam Leffler n->m_len + n2->m_len < MCLBYTES) { 338899d258fdSSam Leffler m = m_getcl(how, MT_DATA, 0); 338999d258fdSSam Leffler if (m == NULL) 339099d258fdSSam Leffler goto bad; 339199d258fdSSam Leffler bcopy(mtod(n, void *), mtod(m, void *), n->m_len); 339299d258fdSSam Leffler bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, 339399d258fdSSam Leffler n2->m_len); 339499d258fdSSam Leffler m->m_len = n->m_len + n2->m_len; 339599d258fdSSam Leffler m->m_next = n2->m_next; 339699d258fdSSam Leffler *prev = m; 339799d258fdSSam Leffler m_free(n); 339899d258fdSSam Leffler m_free(n2); 339999d258fdSSam Leffler if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ 340099d258fdSSam Leffler return m0; 340199d258fdSSam Leffler /* 340299d258fdSSam Leffler * Still not there, try the normal collapse 340399d258fdSSam Leffler * again before we allocate another cluster. 340499d258fdSSam Leffler */ 340599d258fdSSam Leffler goto again; 340699d258fdSSam Leffler } 340799d258fdSSam Leffler prev = &n->m_next; 340899d258fdSSam Leffler } 340999d258fdSSam Leffler /* 341099d258fdSSam Leffler * No place where we can collapse to a cluster; punt. 341199d258fdSSam Leffler * This can occur if, for example, you request 2 frags 341299d258fdSSam Leffler * but the packet requires that both be clusters (we 341399d258fdSSam Leffler * never reallocate the first mbuf to avoid moving the 341499d258fdSSam Leffler * packet header). 341599d258fdSSam Leffler */ 341699d258fdSSam Leffler bad: 341799d258fdSSam Leffler return NULL; 341899d258fdSSam Leffler } 341999d258fdSSam Leffler 34208b5341deSSam Leffler /* 34218b5341deSSam Leffler * Return h/w rate index for an IEEE rate (w/o basic rate bit). 34228b5341deSSam Leffler */ 34238b5341deSSam Leffler static int 34248b5341deSSam Leffler ath_tx_findrix(const HAL_RATE_TABLE *rt, int rate) 34258b5341deSSam Leffler { 34268b5341deSSam Leffler int i; 34278b5341deSSam Leffler 34288b5341deSSam Leffler for (i = 0; i < rt->rateCount; i++) 34298b5341deSSam Leffler if ((rt->info[i].dot11Rate & IEEE80211_RATE_VAL) == rate) 34308b5341deSSam Leffler return i; 34318b5341deSSam Leffler return 0; /* NB: lowest rate */ 34328b5341deSSam Leffler } 34338b5341deSSam Leffler 34345591b213SSam Leffler static int 3435664443d0SSam Leffler ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0) 3436664443d0SSam Leffler { 3437664443d0SSam Leffler struct mbuf *m; 3438664443d0SSam Leffler int error; 3439664443d0SSam Leffler 3440664443d0SSam Leffler /* 3441664443d0SSam Leffler * Load the DMA map so any coalescing is done. This 3442664443d0SSam Leffler * also calculates the number of descriptors we need. 3443664443d0SSam Leffler */ 3444664443d0SSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 3445664443d0SSam Leffler bf->bf_segs, &bf->bf_nseg, 3446664443d0SSam Leffler BUS_DMA_NOWAIT); 3447664443d0SSam Leffler if (error == EFBIG) { 3448664443d0SSam Leffler /* XXX packet requires too many descriptors */ 3449664443d0SSam Leffler bf->bf_nseg = ATH_TXDESC+1; 3450664443d0SSam Leffler } else if (error != 0) { 3451664443d0SSam Leffler sc->sc_stats.ast_tx_busdma++; 3452664443d0SSam Leffler m_freem(m0); 3453664443d0SSam Leffler return error; 3454664443d0SSam Leffler } 3455664443d0SSam Leffler /* 3456664443d0SSam Leffler * Discard null packets and check for packets that 3457664443d0SSam Leffler * require too many TX descriptors. We try to convert 3458664443d0SSam Leffler * the latter to a cluster. 3459664443d0SSam Leffler */ 3460664443d0SSam Leffler if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */ 3461664443d0SSam Leffler sc->sc_stats.ast_tx_linear++; 3462664443d0SSam Leffler m = ath_defrag(m0, M_DONTWAIT, ATH_TXDESC); 3463664443d0SSam Leffler if (m == NULL) { 3464664443d0SSam Leffler m_freem(m0); 3465664443d0SSam Leffler sc->sc_stats.ast_tx_nombuf++; 3466664443d0SSam Leffler return ENOMEM; 3467664443d0SSam Leffler } 3468664443d0SSam Leffler m0 = m; 3469664443d0SSam Leffler error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m0, 3470664443d0SSam Leffler bf->bf_segs, &bf->bf_nseg, 3471664443d0SSam Leffler BUS_DMA_NOWAIT); 3472664443d0SSam Leffler if (error != 0) { 3473664443d0SSam Leffler sc->sc_stats.ast_tx_busdma++; 3474664443d0SSam Leffler m_freem(m0); 3475664443d0SSam Leffler return error; 3476664443d0SSam Leffler } 3477664443d0SSam Leffler KASSERT(bf->bf_nseg <= ATH_TXDESC, 3478664443d0SSam Leffler ("too many segments after defrag; nseg %u", bf->bf_nseg)); 3479664443d0SSam Leffler } else if (bf->bf_nseg == 0) { /* null packet, discard */ 3480664443d0SSam Leffler sc->sc_stats.ast_tx_nodata++; 3481664443d0SSam Leffler m_freem(m0); 3482664443d0SSam Leffler return EIO; 3483664443d0SSam Leffler } 3484664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n", 3485664443d0SSam Leffler __func__, m0, m0->m_pkthdr.len); 3486664443d0SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE); 3487664443d0SSam Leffler bf->bf_m = m0; 3488664443d0SSam Leffler 3489664443d0SSam Leffler return 0; 3490664443d0SSam Leffler } 3491664443d0SSam Leffler 3492664443d0SSam Leffler static void 3493664443d0SSam Leffler ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) 3494664443d0SSam Leffler { 3495664443d0SSam Leffler struct ath_hal *ah = sc->sc_ah; 3496664443d0SSam Leffler struct ath_desc *ds, *ds0; 3497664443d0SSam Leffler int i; 3498664443d0SSam Leffler 3499664443d0SSam Leffler /* 3500664443d0SSam Leffler * Fillin the remainder of the descriptor info. 3501664443d0SSam Leffler */ 3502664443d0SSam Leffler ds0 = ds = bf->bf_desc; 3503664443d0SSam Leffler for (i = 0; i < bf->bf_nseg; i++, ds++) { 3504664443d0SSam Leffler ds->ds_data = bf->bf_segs[i].ds_addr; 3505664443d0SSam Leffler if (i == bf->bf_nseg - 1) 3506664443d0SSam Leffler ds->ds_link = 0; 3507664443d0SSam Leffler else 3508664443d0SSam Leffler ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1); 3509664443d0SSam Leffler ath_hal_filltxdesc(ah, ds 3510664443d0SSam Leffler , bf->bf_segs[i].ds_len /* segment length */ 3511664443d0SSam Leffler , i == 0 /* first segment */ 3512664443d0SSam Leffler , i == bf->bf_nseg - 1 /* last segment */ 3513664443d0SSam Leffler , ds0 /* first descriptor */ 3514664443d0SSam Leffler ); 3515664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3516664443d0SSam Leffler "%s: %d: %08x %08x %08x %08x %08x %08x\n", 3517664443d0SSam Leffler __func__, i, ds->ds_link, ds->ds_data, 3518664443d0SSam Leffler ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]); 3519664443d0SSam Leffler } 3520664443d0SSam Leffler /* 3521664443d0SSam Leffler * Insert the frame on the outbound list and pass it on 3522664443d0SSam Leffler * to the hardware. Multicast frames buffered for power 3523664443d0SSam Leffler * save stations and transmit from the CAB queue are stored 3524664443d0SSam Leffler * on a s/w only queue and loaded on to the CAB queue in 3525664443d0SSam Leffler * the SWBA handler since frames only go out on DTIM and 3526664443d0SSam Leffler * to avoid possible races. 3527664443d0SSam Leffler */ 3528664443d0SSam Leffler ATH_TXQ_LOCK(txq); 3529664443d0SSam Leffler ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); 3530664443d0SSam Leffler if (txq != &sc->sc_mcastq) { 3531664443d0SSam Leffler if (txq->axq_link == NULL) { 3532664443d0SSam Leffler ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); 3533664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3534664443d0SSam Leffler "%s: TXDP[%u] = %p (%p) depth %d\n", __func__, 3535664443d0SSam Leffler txq->axq_qnum, (caddr_t)bf->bf_daddr, bf->bf_desc, 3536664443d0SSam Leffler txq->axq_depth); 3537664443d0SSam Leffler } else { 3538664443d0SSam Leffler *txq->axq_link = bf->bf_daddr; 3539664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, 3540664443d0SSam Leffler "%s: link[%u](%p)=%p (%p) depth %d\n", __func__, 3541664443d0SSam Leffler txq->axq_qnum, txq->axq_link, 3542664443d0SSam Leffler (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth); 3543664443d0SSam Leffler } 3544664443d0SSam Leffler txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 3545664443d0SSam Leffler ath_hal_txstart(ah, txq->axq_qnum); 3546664443d0SSam Leffler } else { 3547664443d0SSam Leffler if (txq->axq_link != NULL) 3548664443d0SSam Leffler *txq->axq_link = bf->bf_daddr; 3549664443d0SSam Leffler txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link; 3550664443d0SSam Leffler } 3551664443d0SSam Leffler ATH_TXQ_UNLOCK(txq); 3552664443d0SSam Leffler } 3553664443d0SSam Leffler 3554664443d0SSam Leffler static int 35555591b213SSam Leffler ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, 35565591b213SSam Leffler struct mbuf *m0) 35575591b213SSam Leffler { 35585591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 35595591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 3560fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 3561c4c3cb46SSam Leffler const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; 3562664443d0SSam Leffler int error, iswep, ismcast, ismrr; 3563be613480SSam Leffler int keyix, hdrlen, pktlen, try0; 3564c42a7b7eSSam Leffler u_int8_t rix, txrate, ctsrate; 3565c42a7b7eSSam Leffler u_int8_t cix = 0xff; /* NB: silence compiler */ 3566664443d0SSam Leffler struct ath_desc *ds; 3567c42a7b7eSSam Leffler struct ath_txq *txq; 35685591b213SSam Leffler struct ieee80211_frame *wh; 3569c42a7b7eSSam Leffler u_int subtype, flags, ctsduration; 35705591b213SSam Leffler HAL_PKT_TYPE atype; 35715591b213SSam Leffler const HAL_RATE_TABLE *rt; 35725591b213SSam Leffler HAL_BOOL shortPreamble; 35735591b213SSam Leffler struct ath_node *an; 3574c4c3cb46SSam Leffler u_int pri; 35755591b213SSam Leffler 35765591b213SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 35775591b213SSam Leffler iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; 3578c42a7b7eSSam Leffler ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 3579c42a7b7eSSam Leffler hdrlen = ieee80211_anyhdrsize(wh); 3580c42a7b7eSSam Leffler /* 3581a614e076SSam Leffler * Packet length must not include any 3582a614e076SSam Leffler * pad bytes; deduct them here. 3583c42a7b7eSSam Leffler */ 3584c42a7b7eSSam Leffler pktlen = m0->m_pkthdr.len - (hdrlen & 3); 35855591b213SSam Leffler 35865591b213SSam Leffler if (iswep) { 3587c42a7b7eSSam Leffler const struct ieee80211_cipher *cip; 3588c42a7b7eSSam Leffler struct ieee80211_key *k; 3589c42a7b7eSSam Leffler 3590c42a7b7eSSam Leffler /* 3591c42a7b7eSSam Leffler * Construct the 802.11 header+trailer for an encrypted 3592c42a7b7eSSam Leffler * frame. The only reason this can fail is because of an 3593c42a7b7eSSam Leffler * unknown or unsupported cipher/key type. 3594c42a7b7eSSam Leffler */ 3595c42a7b7eSSam Leffler k = ieee80211_crypto_encap(ic, ni, m0); 3596c42a7b7eSSam Leffler if (k == NULL) { 3597c42a7b7eSSam Leffler /* 3598c42a7b7eSSam Leffler * This can happen when the key is yanked after the 3599c42a7b7eSSam Leffler * frame was queued. Just discard the frame; the 3600c42a7b7eSSam Leffler * 802.11 layer counts failures and provides 3601c42a7b7eSSam Leffler * debugging/diagnostics. 3602c42a7b7eSSam Leffler */ 36030c97ab96SSam Leffler m_freem(m0); 3604c42a7b7eSSam Leffler return EIO; 36055591b213SSam Leffler } 3606c42a7b7eSSam Leffler /* 3607c42a7b7eSSam Leffler * Adjust the packet + header lengths for the crypto 3608c42a7b7eSSam Leffler * additions and calculate the h/w key index. When 3609c42a7b7eSSam Leffler * a s/w mic is done the frame will have had any mic 3610f9748b9dSSam Leffler * added to it prior to entry so m0->m_pkthdr.len above will 3611c42a7b7eSSam Leffler * account for it. Otherwise we need to add it to the 3612c42a7b7eSSam Leffler * packet length. 3613c42a7b7eSSam Leffler */ 3614c42a7b7eSSam Leffler cip = k->wk_cipher; 3615c42a7b7eSSam Leffler hdrlen += cip->ic_header; 3616c42a7b7eSSam Leffler pktlen += cip->ic_header + cip->ic_trailer; 3617c42a7b7eSSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0) 3618c42a7b7eSSam Leffler pktlen += cip->ic_miclen; 3619c42a7b7eSSam Leffler keyix = k->wk_keyix; 3620c42a7b7eSSam Leffler 3621c42a7b7eSSam Leffler /* packet header may have moved, reset our local pointer */ 3622167ecdcaSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 3623e8fd88a3SSam Leffler } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { 3624e8fd88a3SSam Leffler /* 3625e8fd88a3SSam Leffler * Use station key cache slot, if assigned. 3626e8fd88a3SSam Leffler */ 3627e8fd88a3SSam Leffler keyix = ni->ni_ucastkey.wk_keyix; 3628e8fd88a3SSam Leffler if (keyix == IEEE80211_KEYIX_NONE) 3629e8fd88a3SSam Leffler keyix = HAL_TXKEYIX_INVALID; 3630c42a7b7eSSam Leffler } else 3631c42a7b7eSSam Leffler keyix = HAL_TXKEYIX_INVALID; 3632c42a7b7eSSam Leffler 36335591b213SSam Leffler pktlen += IEEE80211_CRC_LEN; 36345591b213SSam Leffler 36355591b213SSam Leffler /* 36365591b213SSam Leffler * Load the DMA map so any coalescing is done. This 36375591b213SSam Leffler * also calculates the number of descriptors we need. 36385591b213SSam Leffler */ 3639664443d0SSam Leffler error = ath_tx_dmasetup(sc, bf, m0); 364005680ab6SSam Leffler if (error != 0) 364105680ab6SSam Leffler return error; 36420a915fadSSam Leffler bf->bf_node = ni; /* NB: held reference */ 3643664443d0SSam Leffler m0 = bf->bf_m; /* NB: may have changed */ 3644664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 36455591b213SSam Leffler 36465591b213SSam Leffler /* setup descriptors */ 36475591b213SSam Leffler ds = bf->bf_desc; 36485591b213SSam Leffler rt = sc->sc_currates; 36495591b213SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 36505591b213SSam Leffler 36515591b213SSam Leffler /* 3652c42a7b7eSSam Leffler * NB: the 802.11 layer marks whether or not we should 3653c42a7b7eSSam Leffler * use short preamble based on the current mode and 3654c42a7b7eSSam Leffler * negotiated parameters. 36555591b213SSam Leffler */ 3656c42a7b7eSSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 3657c42a7b7eSSam Leffler (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { 3658c42a7b7eSSam Leffler shortPreamble = AH_TRUE; 3659c42a7b7eSSam Leffler sc->sc_stats.ast_tx_shortpre++; 3660c42a7b7eSSam Leffler } else { 3661c42a7b7eSSam Leffler shortPreamble = AH_FALSE; 3662c42a7b7eSSam Leffler } 3663c42a7b7eSSam Leffler 3664c42a7b7eSSam Leffler an = ATH_NODE(ni); 3665c42a7b7eSSam Leffler flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 3666be613480SSam Leffler ismrr = 0; /* default no multi-rate retry*/ 3667c42a7b7eSSam Leffler /* 3668c42a7b7eSSam Leffler * Calculate Atheros packet type from IEEE80211 packet header, 3669c42a7b7eSSam Leffler * setup for rate calculations, and select h/w transmit queue. 3670c42a7b7eSSam Leffler */ 36715591b213SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 36725591b213SSam Leffler case IEEE80211_FC0_TYPE_MGT: 36735591b213SSam Leffler subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 36745591b213SSam Leffler if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) 36755591b213SSam Leffler atype = HAL_PKT_TYPE_BEACON; 36765591b213SSam Leffler else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 36775591b213SSam Leffler atype = HAL_PKT_TYPE_PROBE_RESP; 36785591b213SSam Leffler else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) 36795591b213SSam Leffler atype = HAL_PKT_TYPE_ATIM; 3680c42a7b7eSSam Leffler else 3681c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_NORMAL; /* XXX */ 368255f63772SSam Leffler rix = sc->sc_minrateix; 368355f63772SSam Leffler txrate = rt->info[rix].rateCode; 3684c42a7b7eSSam Leffler if (shortPreamble) 368555f63772SSam Leffler txrate |= rt->info[rix].shortPreamble; 3686be613480SSam Leffler try0 = ATH_TXMGTTRY; 3687c42a7b7eSSam Leffler /* NB: force all management frames to highest queue */ 3688c42a7b7eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 3689c42a7b7eSSam Leffler /* NB: force all management frames to highest queue */ 3690c4c3cb46SSam Leffler pri = WME_AC_VO; 3691c42a7b7eSSam Leffler } else 3692c4c3cb46SSam Leffler pri = WME_AC_BE; 3693c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 36945591b213SSam Leffler break; 36955591b213SSam Leffler case IEEE80211_FC0_TYPE_CTL: 3696c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ 369755f63772SSam Leffler rix = sc->sc_minrateix; 369855f63772SSam Leffler txrate = rt->info[rix].rateCode; 3699c42a7b7eSSam Leffler if (shortPreamble) 370055f63772SSam Leffler txrate |= rt->info[rix].shortPreamble; 3701be613480SSam Leffler try0 = ATH_TXMGTTRY; 3702c42a7b7eSSam Leffler /* NB: force all ctl frames to highest queue */ 3703c42a7b7eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 3704c42a7b7eSSam Leffler /* NB: force all ctl frames to highest queue */ 3705c4c3cb46SSam Leffler pri = WME_AC_VO; 3706c42a7b7eSSam Leffler } else 3707c4c3cb46SSam Leffler pri = WME_AC_BE; 3708c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 3709c42a7b7eSSam Leffler break; 3710c42a7b7eSSam Leffler case IEEE80211_FC0_TYPE_DATA: 3711c42a7b7eSSam Leffler atype = HAL_PKT_TYPE_NORMAL; /* default */ 3712c42a7b7eSSam Leffler /* 37138b5341deSSam Leffler * Data frames: multicast frames go out at a fixed rate, 37148b5341deSSam Leffler * otherwise consult the rate control module for the 37158b5341deSSam Leffler * rate to use. 3716c42a7b7eSSam Leffler */ 37178b5341deSSam Leffler if (ismcast) { 37188b5341deSSam Leffler /* 37198b5341deSSam Leffler * Check mcast rate setting in case it's changed. 37208b5341deSSam Leffler * XXX move out of fastpath 37218b5341deSSam Leffler */ 37228b5341deSSam Leffler if (ic->ic_mcast_rate != sc->sc_mcastrate) { 37238b5341deSSam Leffler sc->sc_mcastrix = 37248b5341deSSam Leffler ath_tx_findrix(rt, ic->ic_mcast_rate); 37258b5341deSSam Leffler sc->sc_mcastrate = ic->ic_mcast_rate; 37268b5341deSSam Leffler } 37278b5341deSSam Leffler rix = sc->sc_mcastrix; 37288b5341deSSam Leffler txrate = rt->info[rix].rateCode; 37298b5341deSSam Leffler if (shortPreamble) 37308b5341deSSam Leffler txrate |= rt->info[rix].shortPreamble; 37318b5341deSSam Leffler try0 = 1; 37328b5341deSSam Leffler } else { 3733c42a7b7eSSam Leffler ath_rate_findrate(sc, an, shortPreamble, pktlen, 3734c42a7b7eSSam Leffler &rix, &try0, &txrate); 37353e50ec2cSSam Leffler sc->sc_txrate = txrate; /* for LED blinking */ 3736be613480SSam Leffler if (try0 != ATH_TXMAXTRY) 3737be613480SSam Leffler ismrr = 1; 37388b5341deSSam Leffler } 3739c4c3cb46SSam Leffler pri = M_WME_GETAC(m0); 3740f9748b9dSSam Leffler if (cap->cap_wmeParams[pri].wmep_noackPolicy) 3741c42a7b7eSSam Leffler flags |= HAL_TXDESC_NOACK; 37425591b213SSam Leffler break; 37435591b213SSam Leffler default: 3744c42a7b7eSSam Leffler if_printf(ifp, "bogus frame type 0x%x (%s)\n", 3745c42a7b7eSSam Leffler wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); 3746c42a7b7eSSam Leffler /* XXX statistic */ 37475591b213SSam Leffler m_freem(m0); 37485591b213SSam Leffler return EIO; 37495591b213SSam Leffler } 3750c4c3cb46SSam Leffler txq = sc->sc_ac2q[pri]; 3751c42a7b7eSSam Leffler 37525591b213SSam Leffler /* 3753c42a7b7eSSam Leffler * When servicing one or more stations in power-save mode 3754622b3fd2SSam Leffler * (or) if there is some mcast data waiting on the mcast 3755622b3fd2SSam Leffler * queue (to prevent out of order delivery) multicast 3756622b3fd2SSam Leffler * frames must be buffered until after the beacon. 37575591b213SSam Leffler */ 3758622b3fd2SSam Leffler if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth)) { 3759622b3fd2SSam Leffler txq = &sc->sc_mcastq; 3760c42a7b7eSSam Leffler /* XXX? more bit in 802.11 frame header */ 37615591b213SSam Leffler } 37625591b213SSam Leffler 37635591b213SSam Leffler /* 37645591b213SSam Leffler * Calculate miscellaneous flags. 37655591b213SSam Leffler */ 3766c42a7b7eSSam Leffler if (ismcast) { 37675591b213SSam Leffler flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ 37685591b213SSam Leffler } else if (pktlen > ic->ic_rtsthreshold) { 37695591b213SSam Leffler flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */ 3770c42a7b7eSSam Leffler cix = rt->info[rix].controlRate; 37715591b213SSam Leffler sc->sc_stats.ast_tx_rts++; 37725591b213SSam Leffler } 3773f9748b9dSSam Leffler if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */ 3774f9748b9dSSam Leffler sc->sc_stats.ast_tx_noack++; 37755591b213SSam Leffler 37765591b213SSam Leffler /* 3777c42a7b7eSSam Leffler * If 802.11g protection is enabled, determine whether 3778c42a7b7eSSam Leffler * to use RTS/CTS or just CTS. Note that this is only 3779c42a7b7eSSam Leffler * done for OFDM unicast frames. 3780c42a7b7eSSam Leffler */ 3781c42a7b7eSSam Leffler if ((ic->ic_flags & IEEE80211_F_USEPROT) && 3782c42a7b7eSSam Leffler rt->info[rix].phy == IEEE80211_T_OFDM && 3783c42a7b7eSSam Leffler (flags & HAL_TXDESC_NOACK) == 0) { 3784c42a7b7eSSam Leffler /* XXX fragments must use CCK rates w/ protection */ 3785c42a7b7eSSam Leffler if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 3786c42a7b7eSSam Leffler flags |= HAL_TXDESC_RTSENA; 3787c42a7b7eSSam Leffler else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 3788c42a7b7eSSam Leffler flags |= HAL_TXDESC_CTSENA; 3789c42a7b7eSSam Leffler cix = rt->info[sc->sc_protrix].controlRate; 3790c42a7b7eSSam Leffler sc->sc_stats.ast_tx_protect++; 3791c42a7b7eSSam Leffler } 3792c42a7b7eSSam Leffler 3793c42a7b7eSSam Leffler /* 3794f6aa038bSSam Leffler * Calculate duration. This logically belongs in the 802.11 3795f6aa038bSSam Leffler * layer but it lacks sufficient information to calculate it. 3796f6aa038bSSam Leffler */ 3797f6aa038bSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0 && 3798f6aa038bSSam Leffler (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) { 3799f6aa038bSSam Leffler u_int16_t dur; 3800f6aa038bSSam Leffler /* 3801f6aa038bSSam Leffler * XXX not right with fragmentation. 3802f6aa038bSSam Leffler */ 3803c42a7b7eSSam Leffler if (shortPreamble) 3804c42a7b7eSSam Leffler dur = rt->info[rix].spAckDuration; 3805c42a7b7eSSam Leffler else 3806c42a7b7eSSam Leffler dur = rt->info[rix].lpAckDuration; 3807c42a7b7eSSam Leffler *(u_int16_t *)wh->i_dur = htole16(dur); 3808f6aa038bSSam Leffler } 3809f6aa038bSSam Leffler 3810f6aa038bSSam Leffler /* 38115591b213SSam Leffler * Calculate RTS/CTS rate and duration if needed. 38125591b213SSam Leffler */ 38135591b213SSam Leffler ctsduration = 0; 38145591b213SSam Leffler if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { 38155591b213SSam Leffler /* 38165591b213SSam Leffler * CTS transmit rate is derived from the transmit rate 38175591b213SSam Leffler * by looking in the h/w rate table. We must also factor 38185591b213SSam Leffler * in whether or not a short preamble is to be used. 38195591b213SSam Leffler */ 3820c42a7b7eSSam Leffler /* NB: cix is set above where RTS/CTS is enabled */ 3821c42a7b7eSSam Leffler KASSERT(cix != 0xff, ("cix not setup")); 38225591b213SSam Leffler ctsrate = rt->info[cix].rateCode; 38235591b213SSam Leffler /* 3824c42a7b7eSSam Leffler * Compute the transmit duration based on the frame 3825c42a7b7eSSam Leffler * size and the size of an ACK frame. We call into the 3826c42a7b7eSSam Leffler * HAL to do the computation since it depends on the 3827c42a7b7eSSam Leffler * characteristics of the actual PHY being used. 3828c42a7b7eSSam Leffler * 3829c42a7b7eSSam Leffler * NB: CTS is assumed the same size as an ACK so we can 3830c42a7b7eSSam Leffler * use the precalculated ACK durations. 38315591b213SSam Leffler */ 3832c42a7b7eSSam Leffler if (shortPreamble) { 3833c42a7b7eSSam Leffler ctsrate |= rt->info[cix].shortPreamble; 3834c42a7b7eSSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 3835c42a7b7eSSam Leffler ctsduration += rt->info[cix].spAckDuration; 38365591b213SSam Leffler ctsduration += ath_hal_computetxtime(ah, 3837c42a7b7eSSam Leffler rt, pktlen, rix, AH_TRUE); 3838c42a7b7eSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 38396ee571b2SSam Leffler ctsduration += rt->info[rix].spAckDuration; 3840c42a7b7eSSam Leffler } else { 3841c42a7b7eSSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 3842c42a7b7eSSam Leffler ctsduration += rt->info[cix].lpAckDuration; 3843c42a7b7eSSam Leffler ctsduration += ath_hal_computetxtime(ah, 3844c42a7b7eSSam Leffler rt, pktlen, rix, AH_FALSE); 3845c42a7b7eSSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 38466ee571b2SSam Leffler ctsduration += rt->info[rix].lpAckDuration; 38475591b213SSam Leffler } 3848c42a7b7eSSam Leffler /* 3849c42a7b7eSSam Leffler * Must disable multi-rate retry when using RTS/CTS. 3850c42a7b7eSSam Leffler */ 3851be613480SSam Leffler ismrr = 0; 3852be613480SSam Leffler try0 = ATH_TXMGTTRY; /* XXX */ 38535591b213SSam Leffler } else 38545591b213SSam Leffler ctsrate = 0; 38555591b213SSam Leffler 3856c42a7b7eSSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 3857c42a7b7eSSam Leffler ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len, 38583e50ec2cSSam Leffler sc->sc_hwmap[txrate].ieeerate, -1); 38595591b213SSam Leffler 3860ff046a6cSSam Leffler if (bpf_peers_present(ic->ic_rawbpf)) 3861eb2cdcb1SSam Leffler bpf_mtap(ic->ic_rawbpf, m0); 386216d878ccSChristian S.J. Peron if (bpf_peers_present(sc->sc_drvbpf)) { 38637b0c77ecSSam Leffler u_int64_t tsf = ath_hal_gettsf64(ah); 38647b0c77ecSSam Leffler 38657b0c77ecSSam Leffler sc->sc_tx_th.wt_tsf = htole64(tsf); 3866d3be6f5bSSam Leffler sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags; 3867eb2cdcb1SSam Leffler if (iswep) 3868eb2cdcb1SSam Leffler sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 38693e50ec2cSSam Leffler sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate; 3870c42a7b7eSSam Leffler sc->sc_tx_th.wt_txpower = ni->ni_txpower; 3871c42a7b7eSSam Leffler sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 3872eb2cdcb1SSam Leffler 3873eb2cdcb1SSam Leffler bpf_mtap2(sc->sc_drvbpf, 38742f1ad18bSSam Leffler &sc->sc_tx_th, sc->sc_tx_th_len, m0); 3875eb2cdcb1SSam Leffler } 3876eb2cdcb1SSam Leffler 38775591b213SSam Leffler /* 3878c42a7b7eSSam Leffler * Determine if a tx interrupt should be generated for 3879c42a7b7eSSam Leffler * this descriptor. We take a tx interrupt to reap 3880c42a7b7eSSam Leffler * descriptors when the h/w hits an EOL condition or 3881c42a7b7eSSam Leffler * when the descriptor is specifically marked to generate 3882c42a7b7eSSam Leffler * an interrupt. We periodically mark descriptors in this 3883c42a7b7eSSam Leffler * way to insure timely replenishing of the supply needed 3884c42a7b7eSSam Leffler * for sending frames. Defering interrupts reduces system 3885c42a7b7eSSam Leffler * load and potentially allows more concurrent work to be 3886c42a7b7eSSam Leffler * done but if done to aggressively can cause senders to 3887c42a7b7eSSam Leffler * backup. 3888c42a7b7eSSam Leffler * 3889c42a7b7eSSam Leffler * NB: use >= to deal with sc_txintrperiod changing 3890c42a7b7eSSam Leffler * dynamically through sysctl. 3891c42a7b7eSSam Leffler */ 3892c42a7b7eSSam Leffler if (flags & HAL_TXDESC_INTREQ) { 3893c42a7b7eSSam Leffler txq->axq_intrcnt = 0; 3894c42a7b7eSSam Leffler } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) { 3895c42a7b7eSSam Leffler flags |= HAL_TXDESC_INTREQ; 3896c42a7b7eSSam Leffler txq->axq_intrcnt = 0; 3897c42a7b7eSSam Leffler } 3898c42a7b7eSSam Leffler 3899c42a7b7eSSam Leffler /* 39005591b213SSam Leffler * Formulate first tx descriptor with tx controls. 39015591b213SSam Leffler */ 39025591b213SSam Leffler /* XXX check return value? */ 39035591b213SSam Leffler ath_hal_setuptxdesc(ah, ds 39045591b213SSam Leffler , pktlen /* packet length */ 39055591b213SSam Leffler , hdrlen /* header length */ 39065591b213SSam Leffler , atype /* Atheros packet type */ 3907c42a7b7eSSam Leffler , ni->ni_txpower /* txpower */ 3908c42a7b7eSSam Leffler , txrate, try0 /* series 0 rate/tries */ 3909c42a7b7eSSam Leffler , keyix /* key cache index */ 3910c42a7b7eSSam Leffler , sc->sc_txantenna /* antenna mode */ 39115591b213SSam Leffler , flags /* flags */ 39125591b213SSam Leffler , ctsrate /* rts/cts rate */ 39135591b213SSam Leffler , ctsduration /* rts/cts duration */ 39145591b213SSam Leffler ); 3915ebecf802SSam Leffler bf->bf_flags = flags; 3916c42a7b7eSSam Leffler /* 3917c42a7b7eSSam Leffler * Setup the multi-rate retry state only when we're 3918c42a7b7eSSam Leffler * going to use it. This assumes ath_hal_setuptxdesc 3919c42a7b7eSSam Leffler * initializes the descriptors (so we don't have to) 3920c42a7b7eSSam Leffler * when the hardware supports multi-rate retry and 3921c42a7b7eSSam Leffler * we don't use it. 3922c42a7b7eSSam Leffler */ 3923be613480SSam Leffler if (ismrr) 3924c42a7b7eSSam Leffler ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix); 3925c42a7b7eSSam Leffler 3926664443d0SSam Leffler ath_tx_handoff(sc, txq, bf); 39275591b213SSam Leffler return 0; 39285591b213SSam Leffler } 39295591b213SSam Leffler 3930c42a7b7eSSam Leffler /* 3931c42a7b7eSSam Leffler * Process completed xmit descriptors from the specified queue. 3932c42a7b7eSSam Leffler */ 3933d7736e13SSam Leffler static int 3934c42a7b7eSSam Leffler ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) 39355591b213SSam Leffler { 39365591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 39370a915fadSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 3938ebecf802SSam Leffler struct ath_buf *bf; 3939c4c3cb46SSam Leffler struct ath_desc *ds, *ds0; 394065f9edeeSSam Leffler struct ath_tx_status *ts; 39415591b213SSam Leffler struct ieee80211_node *ni; 39425591b213SSam Leffler struct ath_node *an; 3943d7736e13SSam Leffler int sr, lr, pri, nacked; 39445591b213SSam Leffler HAL_STATUS status; 39455591b213SSam Leffler 3946c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n", 3947c42a7b7eSSam Leffler __func__, txq->axq_qnum, 3948c42a7b7eSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum), 3949c42a7b7eSSam Leffler txq->axq_link); 3950d7736e13SSam Leffler nacked = 0; 39515591b213SSam Leffler for (;;) { 3952c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 3953c42a7b7eSSam Leffler txq->axq_intrcnt = 0; /* reset periodic desc intr count */ 3954c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 39555591b213SSam Leffler if (bf == NULL) { 3956c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39575591b213SSam Leffler break; 39585591b213SSam Leffler } 3959c4c3cb46SSam Leffler ds0 = &bf->bf_desc[0]; 39605591b213SSam Leffler ds = &bf->bf_desc[bf->bf_nseg - 1]; 396165f9edeeSSam Leffler ts = &bf->bf_status.ds_txstat; 396265f9edeeSSam Leffler status = ath_hal_txprocdesc(ah, ds, ts); 3963a585a9a1SSam Leffler #ifdef ATH_DEBUG 3964c42a7b7eSSam Leffler if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) 39657a4c5ed9SSam Leffler ath_printtxbuf(bf, txq->axq_qnum, 0, status == HAL_OK); 39665591b213SSam Leffler #endif 39675591b213SSam Leffler if (status == HAL_EINPROGRESS) { 3968c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39695591b213SSam Leffler break; 39705591b213SSam Leffler } 3971c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 3972ebecf802SSam Leffler if (txq->axq_depth == 0) 39731539af1eSSam Leffler txq->axq_link = NULL; 3974c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 39755591b213SSam Leffler 39765591b213SSam Leffler ni = bf->bf_node; 39775591b213SSam Leffler if (ni != NULL) { 3978c42a7b7eSSam Leffler an = ATH_NODE(ni); 397965f9edeeSSam Leffler if (ts->ts_status == 0) { 398065f9edeeSSam Leffler u_int8_t txant = ts->ts_antenna; 3981c42a7b7eSSam Leffler sc->sc_stats.ast_ant_tx[txant]++; 3982c42a7b7eSSam Leffler sc->sc_ant_tx[txant]++; 398365f9edeeSSam Leffler if (ts->ts_rate & HAL_TXSTAT_ALTRATE) 3984c42a7b7eSSam Leffler sc->sc_stats.ast_tx_altrate++; 398565f9edeeSSam Leffler sc->sc_stats.ast_tx_rssi = ts->ts_rssi; 3986ffa2cab6SSam Leffler ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, 398765f9edeeSSam Leffler ts->ts_rssi); 3988c42a7b7eSSam Leffler pri = M_WME_GETAC(bf->bf_m); 3989c42a7b7eSSam Leffler if (pri >= WME_AC_VO) 3990c42a7b7eSSam Leffler ic->ic_wme.wme_hipri_traffic++; 3991c42a7b7eSSam Leffler ni->ni_inact = ni->ni_inact_reload; 39925591b213SSam Leffler } else { 399365f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_XRETRY) 39945591b213SSam Leffler sc->sc_stats.ast_tx_xretries++; 399565f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FIFO) 39965591b213SSam Leffler sc->sc_stats.ast_tx_fifoerr++; 399765f9edeeSSam Leffler if (ts->ts_status & HAL_TXERR_FILT) 39985591b213SSam Leffler sc->sc_stats.ast_tx_filtered++; 39995591b213SSam Leffler } 400065f9edeeSSam Leffler sr = ts->ts_shortretry; 400165f9edeeSSam Leffler lr = ts->ts_longretry; 40025591b213SSam Leffler sc->sc_stats.ast_tx_shortretry += sr; 40035591b213SSam Leffler sc->sc_stats.ast_tx_longretry += lr; 4004c42a7b7eSSam Leffler /* 4005c42a7b7eSSam Leffler * Hand the descriptor to the rate control algorithm. 4006c42a7b7eSSam Leffler */ 400765f9edeeSSam Leffler if ((ts->ts_status & HAL_TXERR_FILT) == 0 && 4008ebecf802SSam Leffler (bf->bf_flags & HAL_TXDESC_NOACK) == 0) { 4009d7736e13SSam Leffler /* 4010d7736e13SSam Leffler * If frame was ack'd update the last rx time 4011d7736e13SSam Leffler * used to workaround phantom bmiss interrupts. 4012d7736e13SSam Leffler */ 401365f9edeeSSam Leffler if (ts->ts_status == 0) 4014d7736e13SSam Leffler nacked++; 401565f9edeeSSam Leffler ath_rate_tx_complete(sc, an, bf); 4016d7736e13SSam Leffler } 40170a915fadSSam Leffler /* 40180a915fadSSam Leffler * Reclaim reference to node. 40190a915fadSSam Leffler * 40200a915fadSSam Leffler * NB: the node may be reclaimed here if, for example 40210a915fadSSam Leffler * this is a DEAUTH message that was sent and the 40220a915fadSSam Leffler * node was timed out due to inactivity. 40230a915fadSSam Leffler */ 4024c42a7b7eSSam Leffler ieee80211_free_node(ni); 40255591b213SSam Leffler } 40265591b213SSam Leffler bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 40275591b213SSam Leffler BUS_DMASYNC_POSTWRITE); 40285591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 40295591b213SSam Leffler m_freem(bf->bf_m); 40305591b213SSam Leffler bf->bf_m = NULL; 40315591b213SSam Leffler bf->bf_node = NULL; 40325591b213SSam Leffler 4033f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 4034c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4035f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 40365591b213SSam Leffler } 4037d7736e13SSam Leffler return nacked; 4038d7736e13SSam Leffler } 4039d7736e13SSam Leffler 4040d7736e13SSam Leffler static __inline int 4041d7736e13SSam Leffler txqactive(struct ath_hal *ah, int qnum) 4042d7736e13SSam Leffler { 4043e2815d69SSam Leffler u_int32_t txqs = 1<<qnum; 4044e2815d69SSam Leffler ath_hal_gettxintrtxqs(ah, &txqs); 40459760f8aeSSam Leffler return (txqs & (1<<qnum)); 4046c42a7b7eSSam Leffler } 4047c42a7b7eSSam Leffler 4048c42a7b7eSSam Leffler /* 4049c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4050c42a7b7eSSam Leffler * for a single hardware transmit queue (e.g. 5210 and 5211). 4051c42a7b7eSSam Leffler */ 4052c42a7b7eSSam Leffler static void 4053c42a7b7eSSam Leffler ath_tx_proc_q0(void *arg, int npending) 4054c42a7b7eSSam Leffler { 4055c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4056fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4057c42a7b7eSSam Leffler 4058d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0])) 4059d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4060d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4061d7736e13SSam Leffler ath_tx_processq(sc, sc->sc_cabq); 406213f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 40635591b213SSam Leffler sc->sc_tx_timer = 0; 40645591b213SSam Leffler 40653e50ec2cSSam Leffler if (sc->sc_softled) 40663e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 40673e50ec2cSSam Leffler 40685591b213SSam Leffler ath_start(ifp); 40695591b213SSam Leffler } 40705591b213SSam Leffler 40715591b213SSam Leffler /* 4072c42a7b7eSSam Leffler * Deferred processing of transmit interrupt; special-cased 4073c42a7b7eSSam Leffler * for four hardware queues, 0-3 (e.g. 5212 w/ WME support). 40745591b213SSam Leffler */ 40755591b213SSam Leffler static void 4076c42a7b7eSSam Leffler ath_tx_proc_q0123(void *arg, int npending) 4077c42a7b7eSSam Leffler { 4078c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4079fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4080d7736e13SSam Leffler int nacked; 4081c42a7b7eSSam Leffler 4082c42a7b7eSSam Leffler /* 4083c42a7b7eSSam Leffler * Process each active queue. 4084c42a7b7eSSam Leffler */ 4085d7736e13SSam Leffler nacked = 0; 4086d7736e13SSam Leffler if (txqactive(sc->sc_ah, 0)) 4087d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[0]); 4088d7736e13SSam Leffler if (txqactive(sc->sc_ah, 1)) 4089d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[1]); 4090d7736e13SSam Leffler if (txqactive(sc->sc_ah, 2)) 4091d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[2]); 4092d7736e13SSam Leffler if (txqactive(sc->sc_ah, 3)) 4093d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[3]); 4094d7736e13SSam Leffler if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) 4095c42a7b7eSSam Leffler ath_tx_processq(sc, sc->sc_cabq); 4096d7736e13SSam Leffler if (nacked) 4097d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4098c42a7b7eSSam Leffler 409913f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4100c42a7b7eSSam Leffler sc->sc_tx_timer = 0; 4101c42a7b7eSSam Leffler 41023e50ec2cSSam Leffler if (sc->sc_softled) 41033e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 41043e50ec2cSSam Leffler 4105c42a7b7eSSam Leffler ath_start(ifp); 4106c42a7b7eSSam Leffler } 4107c42a7b7eSSam Leffler 4108c42a7b7eSSam Leffler /* 4109c42a7b7eSSam Leffler * Deferred processing of transmit interrupt. 4110c42a7b7eSSam Leffler */ 4111c42a7b7eSSam Leffler static void 4112c42a7b7eSSam Leffler ath_tx_proc(void *arg, int npending) 4113c42a7b7eSSam Leffler { 4114c42a7b7eSSam Leffler struct ath_softc *sc = arg; 4115fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4116d7736e13SSam Leffler int i, nacked; 4117c42a7b7eSSam Leffler 4118c42a7b7eSSam Leffler /* 4119c42a7b7eSSam Leffler * Process each active queue. 4120c42a7b7eSSam Leffler */ 4121d7736e13SSam Leffler nacked = 0; 4122c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4123d7736e13SSam Leffler if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i)) 4124d7736e13SSam Leffler nacked += ath_tx_processq(sc, &sc->sc_txq[i]); 4125d7736e13SSam Leffler if (nacked) 4126d7736e13SSam Leffler sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); 4127c42a7b7eSSam Leffler 412813f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4129c42a7b7eSSam Leffler sc->sc_tx_timer = 0; 4130c42a7b7eSSam Leffler 41313e50ec2cSSam Leffler if (sc->sc_softled) 41323e50ec2cSSam Leffler ath_led_event(sc, ATH_LED_TX); 41333e50ec2cSSam Leffler 4134c42a7b7eSSam Leffler ath_start(ifp); 4135c42a7b7eSSam Leffler } 4136c42a7b7eSSam Leffler 4137c42a7b7eSSam Leffler static void 4138c42a7b7eSSam Leffler ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) 41395591b213SSam Leffler { 4140a585a9a1SSam Leffler #ifdef ATH_DEBUG 41415591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4142d2f6ed15SSam Leffler #endif 414323428eafSSam Leffler struct ieee80211_node *ni; 41445591b213SSam Leffler struct ath_buf *bf; 41457a4c5ed9SSam Leffler u_int ix; 41465591b213SSam Leffler 4147c42a7b7eSSam Leffler /* 4148c42a7b7eSSam Leffler * NB: this assumes output has been stopped and 4149ebecf802SSam Leffler * we do not need to block ath_tx_tasklet 4150c42a7b7eSSam Leffler */ 41517a4c5ed9SSam Leffler for (ix = 0;; ix++) { 4152c42a7b7eSSam Leffler ATH_TXQ_LOCK(txq); 4153c42a7b7eSSam Leffler bf = STAILQ_FIRST(&txq->axq_q); 41545591b213SSam Leffler if (bf == NULL) { 4155ebecf802SSam Leffler txq->axq_link = NULL; 4156c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 41575591b213SSam Leffler break; 41585591b213SSam Leffler } 4159c42a7b7eSSam Leffler ATH_TXQ_REMOVE_HEAD(txq, bf_list); 4160c42a7b7eSSam Leffler ATH_TXQ_UNLOCK(txq); 4161a585a9a1SSam Leffler #ifdef ATH_DEBUG 41624a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 41637a4c5ed9SSam Leffler ath_printtxbuf(bf, txq->axq_qnum, ix, 416465f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 416565f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 41664a3ac3fcSSam Leffler ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t), 41674a3ac3fcSSam Leffler bf->bf_m->m_len, 0, -1); 41684a3ac3fcSSam Leffler } 4169a585a9a1SSam Leffler #endif /* ATH_DEBUG */ 41705591b213SSam Leffler bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); 41715591b213SSam Leffler m_freem(bf->bf_m); 41725591b213SSam Leffler bf->bf_m = NULL; 417323428eafSSam Leffler ni = bf->bf_node; 41745591b213SSam Leffler bf->bf_node = NULL; 4175c42a7b7eSSam Leffler if (ni != NULL) { 417623428eafSSam Leffler /* 417723428eafSSam Leffler * Reclaim node reference. 417823428eafSSam Leffler */ 4179c42a7b7eSSam Leffler ieee80211_free_node(ni); 418023428eafSSam Leffler } 4181f0b2a0beSSam Leffler ATH_TXBUF_LOCK(sc); 4182c42a7b7eSSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 4183f0b2a0beSSam Leffler ATH_TXBUF_UNLOCK(sc); 41845591b213SSam Leffler } 4185c42a7b7eSSam Leffler } 4186c42a7b7eSSam Leffler 4187c42a7b7eSSam Leffler static void 4188c42a7b7eSSam Leffler ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) 4189c42a7b7eSSam Leffler { 4190c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4191c42a7b7eSSam Leffler 4192c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 4193c42a7b7eSSam Leffler __func__, txq->axq_qnum, 41946891c875SPeter Wemm (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, txq->axq_qnum), 41956891c875SPeter Wemm txq->axq_link); 41964a3ac3fcSSam Leffler (void) ath_hal_stoptxdma(ah, txq->axq_qnum); 4197c42a7b7eSSam Leffler } 4198c42a7b7eSSam Leffler 4199c42a7b7eSSam Leffler /* 4200c42a7b7eSSam Leffler * Drain the transmit queues and reclaim resources. 4201c42a7b7eSSam Leffler */ 4202c42a7b7eSSam Leffler static void 4203c42a7b7eSSam Leffler ath_draintxq(struct ath_softc *sc) 4204c42a7b7eSSam Leffler { 4205c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4206fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 4207c42a7b7eSSam Leffler int i; 4208c42a7b7eSSam Leffler 4209c42a7b7eSSam Leffler /* XXX return value */ 4210c42a7b7eSSam Leffler if (!sc->sc_invalid) { 4211c42a7b7eSSam Leffler /* don't touch the hardware if marked invalid */ 42124a3ac3fcSSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n", 42134a3ac3fcSSam Leffler __func__, sc->sc_bhalq, 42144a3ac3fcSSam Leffler (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq), 42154a3ac3fcSSam Leffler NULL); 4216c42a7b7eSSam Leffler (void) ath_hal_stoptxdma(ah, sc->sc_bhalq); 4217c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4218c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4219c42a7b7eSSam Leffler ath_tx_stopdma(sc, &sc->sc_txq[i]); 4220c42a7b7eSSam Leffler } 4221c42a7b7eSSam Leffler for (i = 0; i < HAL_NUM_TX_QUEUES; i++) 4222c42a7b7eSSam Leffler if (ATH_TXQ_SETUP(sc, i)) 4223c42a7b7eSSam Leffler ath_tx_draintxq(sc, &sc->sc_txq[i]); 4224622b3fd2SSam Leffler ath_tx_draintxq(sc, &sc->sc_mcastq); 42254a3ac3fcSSam Leffler #ifdef ATH_DEBUG 42264a3ac3fcSSam Leffler if (sc->sc_debug & ATH_DEBUG_RESET) { 42274a3ac3fcSSam Leffler struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); 42284a3ac3fcSSam Leffler if (bf != NULL && bf->bf_m != NULL) { 42294a3ac3fcSSam Leffler ath_printtxbuf(bf, sc->sc_bhalq, 0, 423065f9edeeSSam Leffler ath_hal_txprocdesc(ah, bf->bf_desc, 423165f9edeeSSam Leffler &bf->bf_status.ds_txstat) == HAL_OK); 42324a3ac3fcSSam Leffler ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t), 42334a3ac3fcSSam Leffler bf->bf_m->m_len, 0, -1); 42344a3ac3fcSSam Leffler } 42354a3ac3fcSSam Leffler } 42364a3ac3fcSSam Leffler #endif /* ATH_DEBUG */ 423713f4c340SRobert Watson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 42385591b213SSam Leffler sc->sc_tx_timer = 0; 42395591b213SSam Leffler } 42405591b213SSam Leffler 42415591b213SSam Leffler /* 42425591b213SSam Leffler * Disable the receive h/w in preparation for a reset. 42435591b213SSam Leffler */ 42445591b213SSam Leffler static void 42455591b213SSam Leffler ath_stoprecv(struct ath_softc *sc) 42465591b213SSam Leffler { 42478cec0ab9SSam Leffler #define PA2DESC(_sc, _pa) \ 4248c42a7b7eSSam Leffler ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ 4249c42a7b7eSSam Leffler ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) 42505591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 42515591b213SSam Leffler 42525591b213SSam Leffler ath_hal_stoppcurecv(ah); /* disable PCU */ 42535591b213SSam Leffler ath_hal_setrxfilter(ah, 0); /* clear recv filter */ 42545591b213SSam Leffler ath_hal_stopdmarecv(ah); /* disable DMA engine */ 4255c42a7b7eSSam Leffler DELAY(3000); /* 3ms is long enough for 1 frame */ 4256a585a9a1SSam Leffler #ifdef ATH_DEBUG 4257c42a7b7eSSam Leffler if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) { 42585591b213SSam Leffler struct ath_buf *bf; 42597a4c5ed9SSam Leffler u_int ix; 42605591b213SSam Leffler 4261e325e530SSam Leffler printf("%s: rx queue %p, link %p\n", __func__, 426230310634SPeter Wemm (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); 42637a4c5ed9SSam Leffler ix = 0; 4264c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 42658cec0ab9SSam Leffler struct ath_desc *ds = bf->bf_desc; 426665f9edeeSSam Leffler struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; 4267c42a7b7eSSam Leffler HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, 426865f9edeeSSam Leffler bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs); 4269c42a7b7eSSam Leffler if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL)) 42707a4c5ed9SSam Leffler ath_printrxbuf(bf, ix, status == HAL_OK); 42717a4c5ed9SSam Leffler ix++; 42725591b213SSam Leffler } 42735591b213SSam Leffler } 42745591b213SSam Leffler #endif 42755591b213SSam Leffler sc->sc_rxlink = NULL; /* just in case */ 42768cec0ab9SSam Leffler #undef PA2DESC 42775591b213SSam Leffler } 42785591b213SSam Leffler 42795591b213SSam Leffler /* 42805591b213SSam Leffler * Enable the receive h/w following a reset. 42815591b213SSam Leffler */ 42825591b213SSam Leffler static int 42835591b213SSam Leffler ath_startrecv(struct ath_softc *sc) 42845591b213SSam Leffler { 42855591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 42865591b213SSam Leffler struct ath_buf *bf; 42875591b213SSam Leffler 42885591b213SSam Leffler sc->sc_rxlink = NULL; 4289c42a7b7eSSam Leffler STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { 42905591b213SSam Leffler int error = ath_rxbuf_init(sc, bf); 42915591b213SSam Leffler if (error != 0) { 4292c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_RECV, 4293c42a7b7eSSam Leffler "%s: ath_rxbuf_init failed %d\n", 4294c42a7b7eSSam Leffler __func__, error); 42955591b213SSam Leffler return error; 42965591b213SSam Leffler } 42975591b213SSam Leffler } 42985591b213SSam Leffler 4299c42a7b7eSSam Leffler bf = STAILQ_FIRST(&sc->sc_rxbuf); 43005591b213SSam Leffler ath_hal_putrxbuf(ah, bf->bf_daddr); 43015591b213SSam Leffler ath_hal_rxena(ah); /* enable recv descriptors */ 43025591b213SSam Leffler ath_mode_init(sc); /* set filters, etc. */ 43035591b213SSam Leffler ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ 43045591b213SSam Leffler return 0; 43055591b213SSam Leffler } 43065591b213SSam Leffler 43075591b213SSam Leffler /* 4308c42a7b7eSSam Leffler * Update internal state after a channel change. 4309c42a7b7eSSam Leffler */ 4310c42a7b7eSSam Leffler static void 4311c42a7b7eSSam Leffler ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan) 4312c42a7b7eSSam Leffler { 4313c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4314c42a7b7eSSam Leffler enum ieee80211_phymode mode; 431516b4851aSSam Leffler u_int16_t flags; 4316c42a7b7eSSam Leffler 4317c42a7b7eSSam Leffler /* 4318c42a7b7eSSam Leffler * Change channels and update the h/w rate map 4319c42a7b7eSSam Leffler * if we're switching; e.g. 11a to 11b/g. 4320c42a7b7eSSam Leffler */ 4321c42a7b7eSSam Leffler mode = ieee80211_chan2mode(ic, chan); 4322aaa70f2fSSam Leffler if (mode == IEEE80211_MODE_11A) { 4323aaa70f2fSSam Leffler if (IEEE80211_IS_CHAN_HALF(chan)) 4324aaa70f2fSSam Leffler mode = IEEE80211_MODE_11A_HALF; 4325aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(chan)) 4326aaa70f2fSSam Leffler mode = IEEE80211_MODE_11A_QUARTER; 4327aaa70f2fSSam Leffler } 4328c42a7b7eSSam Leffler if (mode != sc->sc_curmode) 4329c42a7b7eSSam Leffler ath_setcurmode(sc, mode); 4330c42a7b7eSSam Leffler /* 433116b4851aSSam Leffler * Update BPF state. NB: ethereal et. al. don't handle 433216b4851aSSam Leffler * merged flags well so pick a unique mode for their use. 4333c42a7b7eSSam Leffler */ 433416b4851aSSam Leffler if (IEEE80211_IS_CHAN_A(chan)) 433516b4851aSSam Leffler flags = IEEE80211_CHAN_A; 433616b4851aSSam Leffler /* XXX 11g schizophrenia */ 4337aaa70f2fSSam Leffler else if (IEEE80211_IS_CHAN_ANYG(chan)) 433816b4851aSSam Leffler flags = IEEE80211_CHAN_G; 433916b4851aSSam Leffler else 434016b4851aSSam Leffler flags = IEEE80211_CHAN_B; 434116b4851aSSam Leffler if (IEEE80211_IS_CHAN_T(chan)) 434216b4851aSSam Leffler flags |= IEEE80211_CHAN_TURBO; 4343c42a7b7eSSam Leffler sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq = 4344c42a7b7eSSam Leffler htole16(chan->ic_freq); 4345c42a7b7eSSam Leffler sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = 434616b4851aSSam Leffler htole16(flags); 4347c42a7b7eSSam Leffler } 4348c42a7b7eSSam Leffler 4349c42a7b7eSSam Leffler /* 4350bd5a9920SSam Leffler * Poll for a channel clear indication; this is required 4351bd5a9920SSam Leffler * for channels requiring DFS and not previously visited 4352bd5a9920SSam Leffler * and/or with a recent radar detection. 4353bd5a9920SSam Leffler */ 4354bd5a9920SSam Leffler static void 4355bd5a9920SSam Leffler ath_dfswait(void *arg) 4356bd5a9920SSam Leffler { 4357bd5a9920SSam Leffler struct ath_softc *sc = arg; 4358bd5a9920SSam Leffler struct ath_hal *ah = sc->sc_ah; 4359bd5a9920SSam Leffler HAL_CHANNEL hchan; 4360bd5a9920SSam Leffler 4361bd5a9920SSam Leffler ath_hal_radar_wait(ah, &hchan); 4362bd5a9920SSam Leffler DPRINTF(sc, ATH_DEBUG_DFS, "%s: radar_wait %u/%x/%x\n", 4363bd5a9920SSam Leffler __func__, hchan.channel, hchan.channelFlags, hchan.privFlags); 4364bd5a9920SSam Leffler 4365bd5a9920SSam Leffler if (hchan.privFlags & CHANNEL_INTERFERENCE) { 4366bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4367bd5a9920SSam Leffler "channel %u/0x%x/0x%x has interference\n", 4368bd5a9920SSam Leffler hchan.channel, hchan.channelFlags, hchan.privFlags); 4369bd5a9920SSam Leffler return; 4370bd5a9920SSam Leffler } 4371bd5a9920SSam Leffler if ((hchan.privFlags & CHANNEL_DFS) == 0) { 4372bd5a9920SSam Leffler /* XXX should not happen */ 4373bd5a9920SSam Leffler return; 4374bd5a9920SSam Leffler } 4375bd5a9920SSam Leffler if (hchan.privFlags & CHANNEL_DFS_CLEAR) { 4376bd5a9920SSam Leffler sc->sc_curchan.privFlags |= CHANNEL_DFS_CLEAR; 4377bd5a9920SSam Leffler sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4378bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4379bd5a9920SSam Leffler "channel %u/0x%x/0x%x marked clear\n", 4380bd5a9920SSam Leffler hchan.channel, hchan.channelFlags, hchan.privFlags); 4381bd5a9920SSam Leffler } else 4382bd5a9920SSam Leffler callout_reset(&sc->sc_dfs_ch, 2 * hz, ath_dfswait, sc); 4383bd5a9920SSam Leffler } 4384bd5a9920SSam Leffler 4385bd5a9920SSam Leffler /* 43865591b213SSam Leffler * Set/change channels. If the channel is really being changed, 4387c42a7b7eSSam Leffler * it's done by reseting the chip. To accomplish this we must 43885591b213SSam Leffler * first cleanup any pending DMA, then restart stuff after a la 43895591b213SSam Leffler * ath_init. 43905591b213SSam Leffler */ 43915591b213SSam Leffler static int 43925591b213SSam Leffler ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) 43935591b213SSam Leffler { 43945591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 43955591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 43965591b213SSam Leffler HAL_CHANNEL hchan; 4397c42a7b7eSSam Leffler 4398c42a7b7eSSam Leffler /* 4399c42a7b7eSSam Leffler * Convert to a HAL channel description with 4400c42a7b7eSSam Leffler * the flags constrained to reflect the current 4401c42a7b7eSSam Leffler * operating mode. 4402c42a7b7eSSam Leffler */ 4403c42a7b7eSSam Leffler hchan.channel = chan->ic_freq; 4404c42a7b7eSSam Leffler hchan.channelFlags = ath_chan2flags(ic, chan); 4405c42a7b7eSSam Leffler 4406370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_RESET, 4407370572d9SSam Leffler "%s: %u (%u MHz, hal flags 0x%x) -> %u (%u MHz, hal flags 0x%x)\n", 4408c42a7b7eSSam Leffler __func__, 4409bd5a9920SSam Leffler ath_hal_mhz2ieee(ah, sc->sc_curchan.channel, 4410c42a7b7eSSam Leffler sc->sc_curchan.channelFlags), 4411370572d9SSam Leffler sc->sc_curchan.channel, sc->sc_curchan.channelFlags, 4412bd5a9920SSam Leffler ath_hal_mhz2ieee(ah, hchan.channel, hchan.channelFlags), 4413370572d9SSam Leffler hchan.channel, hchan.channelFlags); 4414c42a7b7eSSam Leffler if (hchan.channel != sc->sc_curchan.channel || 4415c42a7b7eSSam Leffler hchan.channelFlags != sc->sc_curchan.channelFlags) { 4416c42a7b7eSSam Leffler HAL_STATUS status; 44175591b213SSam Leffler 44185591b213SSam Leffler /* 44195591b213SSam Leffler * To switch channels clear any pending DMA operations; 44205591b213SSam Leffler * wait long enough for the RX fifo to drain, reset the 44215591b213SSam Leffler * hardware at the new frequency, and then re-enable 44225591b213SSam Leffler * the relevant bits of the h/w. 44235591b213SSam Leffler */ 44245591b213SSam Leffler ath_hal_intrset(ah, 0); /* disable interrupts */ 44255591b213SSam Leffler ath_draintxq(sc); /* clear pending tx frames */ 44265591b213SSam Leffler ath_stoprecv(sc); /* turn off frame recv */ 44277a04dc27SSam Leffler if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)) { 4428370572d9SSam Leffler if_printf(ic->ic_ifp, "%s: unable to reset " 4429370572d9SSam Leffler "channel %u (%u Mhz, flags 0x%x hal flags 0x%x)\n", 4430370572d9SSam Leffler __func__, ieee80211_chan2ieee(ic, chan), 4431370572d9SSam Leffler chan->ic_freq, chan->ic_flags, hchan.channelFlags); 44325591b213SSam Leffler return EIO; 44335591b213SSam Leffler } 4434c42a7b7eSSam Leffler sc->sc_curchan = hchan; 4435c42a7b7eSSam Leffler ath_update_txpow(sc); /* update tx power state */ 4436c59005e9SSam Leffler sc->sc_diversity = ath_hal_getdiversity(ah); 4437bd5a9920SSam Leffler sc->sc_calinterval = 1; 4438bd5a9920SSam Leffler sc->sc_caltries = 0; 4439c42a7b7eSSam Leffler 44405591b213SSam Leffler /* 44415591b213SSam Leffler * Re-enable rx framework. 44425591b213SSam Leffler */ 44435591b213SSam Leffler if (ath_startrecv(sc) != 0) { 4444c42a7b7eSSam Leffler if_printf(ic->ic_ifp, 4445370572d9SSam Leffler "%s: unable to restart recv logic\n", __func__); 44465591b213SSam Leffler return EIO; 44475591b213SSam Leffler } 44485591b213SSam Leffler 44495591b213SSam Leffler /* 44505591b213SSam Leffler * Change channels and update the h/w rate map 44515591b213SSam Leffler * if we're switching; e.g. 11a to 11b/g. 44525591b213SSam Leffler */ 44535591b213SSam Leffler ic->ic_ibss_chan = chan; 4454c42a7b7eSSam Leffler ath_chan_change(sc, chan); 44550a915fadSSam Leffler 44560a915fadSSam Leffler /* 4457bd5a9920SSam Leffler * Handle DFS required waiting period to determine 4458bd5a9920SSam Leffler * if channel is clear of radar traffic. 4459bd5a9920SSam Leffler */ 4460bd5a9920SSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 4461bd5a9920SSam Leffler #define DFS_AND_NOT_CLEAR(_c) \ 4462bd5a9920SSam Leffler (((_c)->privFlags & (CHANNEL_DFS | CHANNEL_DFS_CLEAR)) == CHANNEL_DFS) 4463bd5a9920SSam Leffler if (DFS_AND_NOT_CLEAR(&sc->sc_curchan)) { 4464bd5a9920SSam Leffler if_printf(sc->sc_ifp, 4465bd5a9920SSam Leffler "wait for DFS clear channel signal\n"); 4466bd5a9920SSam Leffler /* XXX stop sndq */ 4467bd5a9920SSam Leffler sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 4468bd5a9920SSam Leffler callout_reset(&sc->sc_dfs_ch, 4469bd5a9920SSam Leffler 2 * hz, ath_dfswait, sc); 4470bd5a9920SSam Leffler } else 4471bd5a9920SSam Leffler callout_stop(&sc->sc_dfs_ch); 4472bd5a9920SSam Leffler #undef DFS_NOT_CLEAR 4473bd5a9920SSam Leffler } 4474bd5a9920SSam Leffler 4475bd5a9920SSam Leffler /* 44760a915fadSSam Leffler * Re-enable interrupts. 44770a915fadSSam Leffler */ 44780a915fadSSam Leffler ath_hal_intrset(ah, sc->sc_imask); 44795591b213SSam Leffler } 44805591b213SSam Leffler return 0; 44815591b213SSam Leffler } 44825591b213SSam Leffler 44835591b213SSam Leffler static void 44845591b213SSam Leffler ath_next_scan(void *arg) 44855591b213SSam Leffler { 44865591b213SSam Leffler struct ath_softc *sc = arg; 44875591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 44885591b213SSam Leffler 44895591b213SSam Leffler if (ic->ic_state == IEEE80211_S_SCAN) 4490c42a7b7eSSam Leffler ieee80211_next_scan(ic); 44915591b213SSam Leffler } 44925591b213SSam Leffler 44935591b213SSam Leffler /* 44945591b213SSam Leffler * Periodically recalibrate the PHY to account 44955591b213SSam Leffler * for temperature/environment changes. 44965591b213SSam Leffler */ 44975591b213SSam Leffler static void 44985591b213SSam Leffler ath_calibrate(void *arg) 44995591b213SSam Leffler { 45005591b213SSam Leffler struct ath_softc *sc = arg; 45015591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 4502bd5a9920SSam Leffler HAL_BOOL iqCalDone; 45035591b213SSam Leffler 45045591b213SSam Leffler sc->sc_stats.ast_per_cal++; 45055591b213SSam Leffler 45065591b213SSam Leffler if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { 45075591b213SSam Leffler /* 45085591b213SSam Leffler * Rfgain is out of bounds, reset the chip 45095591b213SSam Leffler * to load new gain values. 45105591b213SSam Leffler */ 4511370572d9SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 4512370572d9SSam Leffler "%s: rfgain change\n", __func__); 45135591b213SSam Leffler sc->sc_stats.ast_per_rfgain++; 4514fc74a9f9SBrooks Davis ath_reset(sc->sc_ifp); 45155591b213SSam Leffler } 4516bd5a9920SSam Leffler if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) { 4517c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, 4518c42a7b7eSSam Leffler "%s: calibration of channel %u failed\n", 4519c42a7b7eSSam Leffler __func__, sc->sc_curchan.channel); 45205591b213SSam Leffler sc->sc_stats.ast_per_calfail++; 45215591b213SSam Leffler } 45227b0c77ecSSam Leffler /* 45237b0c77ecSSam Leffler * Calibrate noise floor data again in case of change. 45247b0c77ecSSam Leffler */ 45257b0c77ecSSam Leffler ath_hal_process_noisefloor(ah); 4526bd5a9920SSam Leffler /* 4527bd5a9920SSam Leffler * Poll more frequently when the IQ calibration is in 4528bd5a9920SSam Leffler * progress to speedup loading the final settings. 4529bd5a9920SSam Leffler * We temper this aggressive polling with an exponential 4530bd5a9920SSam Leffler * back off after 4 tries up to ath_calinterval. 4531bd5a9920SSam Leffler */ 4532bd5a9920SSam Leffler if (iqCalDone || sc->sc_calinterval >= ath_calinterval) { 4533bd5a9920SSam Leffler sc->sc_caltries = 0; 4534bd5a9920SSam Leffler sc->sc_calinterval = ath_calinterval; 4535bd5a9920SSam Leffler } else if (sc->sc_caltries > 4) { 4536bd5a9920SSam Leffler sc->sc_caltries = 0; 4537bd5a9920SSam Leffler sc->sc_calinterval <<= 1; 4538bd5a9920SSam Leffler if (sc->sc_calinterval > ath_calinterval) 4539bd5a9920SSam Leffler sc->sc_calinterval = ath_calinterval; 4540bd5a9920SSam Leffler } 4541bd5a9920SSam Leffler KASSERT(0 < sc->sc_calinterval && sc->sc_calinterval <= ath_calinterval, 4542bd5a9920SSam Leffler ("bad calibration interval %u", sc->sc_calinterval)); 4543bd5a9920SSam Leffler 4544bd5a9920SSam Leffler DPRINTF(sc, ATH_DEBUG_CALIBRATE, 4545bd5a9920SSam Leffler "%s: next +%u (%siqCalDone tries %u)\n", __func__, 4546bd5a9920SSam Leffler sc->sc_calinterval, iqCalDone ? "" : "!", sc->sc_caltries); 4547bd5a9920SSam Leffler sc->sc_caltries++; 4548bd5a9920SSam Leffler callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, 4549bd5a9920SSam Leffler ath_calibrate, sc); 45505591b213SSam Leffler } 45515591b213SSam Leffler 45525591b213SSam Leffler static int 455345bbf62fSSam Leffler ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 45545591b213SSam Leffler { 4555c42a7b7eSSam Leffler struct ifnet *ifp = ic->ic_ifp; 455645bbf62fSSam Leffler struct ath_softc *sc = ifp->if_softc; 455745bbf62fSSam Leffler struct ath_hal *ah = sc->sc_ah; 45585591b213SSam Leffler struct ieee80211_node *ni; 45595591b213SSam Leffler int i, error; 45608cec0ab9SSam Leffler const u_int8_t *bssid; 45615591b213SSam Leffler u_int32_t rfilt; 45625591b213SSam Leffler static const HAL_LED_STATE leds[] = { 45635591b213SSam Leffler HAL_LED_INIT, /* IEEE80211_S_INIT */ 45645591b213SSam Leffler HAL_LED_SCAN, /* IEEE80211_S_SCAN */ 45655591b213SSam Leffler HAL_LED_AUTH, /* IEEE80211_S_AUTH */ 45665591b213SSam Leffler HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */ 45675591b213SSam Leffler HAL_LED_RUN, /* IEEE80211_S_RUN */ 45685591b213SSam Leffler }; 45695591b213SSam Leffler 4570c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__, 457145bbf62fSSam Leffler ieee80211_state_name[ic->ic_state], 4572c42a7b7eSSam Leffler ieee80211_state_name[nstate]); 45735591b213SSam Leffler 4574c42a7b7eSSam Leffler callout_stop(&sc->sc_scan_ch); 4575c42a7b7eSSam Leffler callout_stop(&sc->sc_cal_ch); 4576bd5a9920SSam Leffler callout_stop(&sc->sc_dfs_ch); 45775591b213SSam Leffler ath_hal_setledstate(ah, leds[nstate]); /* set LED */ 45785591b213SSam Leffler 45795591b213SSam Leffler if (nstate == IEEE80211_S_INIT) { 45805591b213SSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 45814c24deacSSam Leffler /* 45824c24deacSSam Leffler * NB: disable interrupts so we don't rx frames. 45834c24deacSSam Leffler */ 4584e8fd88a3SSam Leffler ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL); 4585c42a7b7eSSam Leffler /* 4586c42a7b7eSSam Leffler * Notify the rate control algorithm. 4587c42a7b7eSSam Leffler */ 4588c42a7b7eSSam Leffler ath_rate_newstate(sc, nstate); 4589c42a7b7eSSam Leffler goto done; 45905591b213SSam Leffler } 45915591b213SSam Leffler ni = ic->ic_bss; 4592b5c99415SSam Leffler error = ath_chan_set(sc, ic->ic_curchan); 45935591b213SSam Leffler if (error != 0) 45945591b213SSam Leffler goto bad; 4595c42a7b7eSSam Leffler rfilt = ath_calcrxfilter(sc, nstate); 4596c42a7b7eSSam Leffler if (nstate == IEEE80211_S_SCAN) 45975591b213SSam Leffler bssid = ifp->if_broadcastaddr; 4598c42a7b7eSSam Leffler else 45995591b213SSam Leffler bssid = ni->ni_bssid; 46005591b213SSam Leffler ath_hal_setrxfilter(ah, rfilt); 4601c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s\n", 4602c42a7b7eSSam Leffler __func__, rfilt, ether_sprintf(bssid)); 46035591b213SSam Leffler 46045591b213SSam Leffler if (nstate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA) 46055591b213SSam Leffler ath_hal_setassocid(ah, bssid, ni->ni_associd); 46065591b213SSam Leffler else 46075591b213SSam Leffler ath_hal_setassocid(ah, bssid, 0); 4608c42a7b7eSSam Leffler if (ic->ic_flags & IEEE80211_F_PRIVACY) { 46095591b213SSam Leffler for (i = 0; i < IEEE80211_WEP_NKID; i++) 46105591b213SSam Leffler if (ath_hal_keyisvalid(ah, i)) 46115591b213SSam Leffler ath_hal_keysetmac(ah, i, bssid); 46125591b213SSam Leffler } 46135591b213SSam Leffler 4614c42a7b7eSSam Leffler /* 4615c42a7b7eSSam Leffler * Notify the rate control algorithm so rates 4616c42a7b7eSSam Leffler * are setup should ath_beacon_alloc be called. 4617c42a7b7eSSam Leffler */ 4618c42a7b7eSSam Leffler ath_rate_newstate(sc, nstate); 4619c42a7b7eSSam Leffler 4620c42a7b7eSSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) { 4621c42a7b7eSSam Leffler /* nothing to do */; 4622c42a7b7eSSam Leffler } else if (nstate == IEEE80211_S_RUN) { 4623c42a7b7eSSam Leffler DPRINTF(sc, ATH_DEBUG_STATE, 4624c42a7b7eSSam Leffler "%s(RUN): ic_flags=0x%08x iv=%d bssid=%s " 46255591b213SSam Leffler "capinfo=0x%04x chan=%d\n" 46265591b213SSam Leffler , __func__ 46275591b213SSam Leffler , ic->ic_flags 46285591b213SSam Leffler , ni->ni_intval 46295591b213SSam Leffler , ether_sprintf(ni->ni_bssid) 46305591b213SSam Leffler , ni->ni_capinfo 4631b5c99415SSam Leffler , ieee80211_chan2ieee(ic, ic->ic_curchan)); 46325591b213SSam Leffler 4633e8fd88a3SSam Leffler switch (ic->ic_opmode) { 4634e8fd88a3SSam Leffler case IEEE80211_M_HOSTAP: 4635e8fd88a3SSam Leffler case IEEE80211_M_IBSS: 46365591b213SSam Leffler /* 4637e8fd88a3SSam Leffler * Allocate and setup the beacon frame. 4638e8fd88a3SSam Leffler * 4639f818612bSSam Leffler * Stop any previous beacon DMA. This may be 4640f818612bSSam Leffler * necessary, for example, when an ibss merge 4641f818612bSSam Leffler * causes reconfiguration; there will be a state 4642f818612bSSam Leffler * transition from RUN->RUN that means we may 4643f818612bSSam Leffler * be called with beacon transmission active. 4644f818612bSSam Leffler */ 4645f818612bSSam Leffler ath_hal_stoptxdma(ah, sc->sc_bhalq); 4646f818612bSSam Leffler ath_beacon_free(sc); 46475591b213SSam Leffler error = ath_beacon_alloc(sc, ni); 46485591b213SSam Leffler if (error != 0) 46495591b213SSam Leffler goto bad; 46507a04dc27SSam Leffler /* 465180d939bfSSam Leffler * If joining an adhoc network defer beacon timer 465280d939bfSSam Leffler * configuration to the next beacon frame so we 465380d939bfSSam Leffler * have a current TSF to use. Otherwise we're 465480d939bfSSam Leffler * starting an ibss/bss so there's no need to delay. 46557a04dc27SSam Leffler */ 465680d939bfSSam Leffler if (ic->ic_opmode == IEEE80211_M_IBSS && 465780d939bfSSam Leffler ic->ic_bss->ni_tstamp.tsf != 0) 465880d939bfSSam Leffler sc->sc_syncbeacon = 1; 465980d939bfSSam Leffler else 46607a04dc27SSam Leffler ath_beacon_config(sc); 4661e8fd88a3SSam Leffler break; 4662e8fd88a3SSam Leffler case IEEE80211_M_STA: 4663e8fd88a3SSam Leffler /* 4664e8fd88a3SSam Leffler * Allocate a key cache slot to the station. 4665e8fd88a3SSam Leffler */ 4666e8fd88a3SSam Leffler if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && 4667e8fd88a3SSam Leffler sc->sc_hasclrkey && 4668e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE) 4669e8fd88a3SSam Leffler ath_setup_stationkey(ni); 46707a04dc27SSam Leffler /* 467180d939bfSSam Leffler * Defer beacon timer configuration to the next 467280d939bfSSam Leffler * beacon frame so we have a current TSF to use 467380d939bfSSam Leffler * (any TSF collected when scanning is likely old). 46747a04dc27SSam Leffler */ 467580d939bfSSam Leffler sc->sc_syncbeacon = 1; 4676e8fd88a3SSam Leffler break; 4677e8fd88a3SSam Leffler default: 4678e8fd88a3SSam Leffler break; 46795591b213SSam Leffler } 46805591b213SSam Leffler 46815591b213SSam Leffler /* 46827b0c77ecSSam Leffler * Let the hal process statistics collected during a 46837b0c77ecSSam Leffler * scan so it can provide calibrated noise floor data. 46847b0c77ecSSam Leffler */ 46857b0c77ecSSam Leffler ath_hal_process_noisefloor(ah); 46867b0c77ecSSam Leffler /* 4687ffa2cab6SSam Leffler * Reset rssi stats; maybe not the best place... 4688ffa2cab6SSam Leffler */ 4689ffa2cab6SSam Leffler sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; 4690ffa2cab6SSam Leffler sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; 4691ffa2cab6SSam Leffler sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; 46925591b213SSam Leffler } else { 4693c42a7b7eSSam Leffler ath_hal_intrset(ah, 4694c42a7b7eSSam Leffler sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); 46955591b213SSam Leffler sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); 46965591b213SSam Leffler } 4697c42a7b7eSSam Leffler done: 469845bbf62fSSam Leffler /* 469945bbf62fSSam Leffler * Invoke the parent method to complete the work. 470045bbf62fSSam Leffler */ 4701c42a7b7eSSam Leffler error = sc->sc_newstate(ic, nstate, arg); 4702c42a7b7eSSam Leffler /* 4703c42a7b7eSSam Leffler * Finally, start any timers. 4704c42a7b7eSSam Leffler */ 4705c42a7b7eSSam Leffler if (nstate == IEEE80211_S_RUN) { 4706c42a7b7eSSam Leffler /* start periodic recalibration timer */ 4707bd5a9920SSam Leffler callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, 4708c42a7b7eSSam Leffler ath_calibrate, sc); 4709c42a7b7eSSam Leffler } else if (nstate == IEEE80211_S_SCAN) { 4710c42a7b7eSSam Leffler /* start ap/neighbor scan timer */ 4711c42a7b7eSSam Leffler callout_reset(&sc->sc_scan_ch, (ath_dwelltime * hz) / 1000, 4712c42a7b7eSSam Leffler ath_next_scan, sc); 4713c42a7b7eSSam Leffler } 47145591b213SSam Leffler bad: 47155591b213SSam Leffler return error; 47165591b213SSam Leffler } 47175591b213SSam Leffler 47185591b213SSam Leffler /* 4719e8fd88a3SSam Leffler * Allocate a key cache slot to the station so we can 4720e8fd88a3SSam Leffler * setup a mapping from key index to node. The key cache 4721e8fd88a3SSam Leffler * slot is needed for managing antenna state and for 4722e8fd88a3SSam Leffler * compression when stations do not use crypto. We do 4723e8fd88a3SSam Leffler * it uniliaterally here; if crypto is employed this slot 4724e8fd88a3SSam Leffler * will be reassigned. 4725e8fd88a3SSam Leffler */ 4726e8fd88a3SSam Leffler static void 4727e8fd88a3SSam Leffler ath_setup_stationkey(struct ieee80211_node *ni) 4728e8fd88a3SSam Leffler { 4729e8fd88a3SSam Leffler struct ieee80211com *ic = ni->ni_ic; 4730e8fd88a3SSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 4731c1225b52SSam Leffler ieee80211_keyix keyix, rxkeyix; 4732e8fd88a3SSam Leffler 4733c1225b52SSam Leffler if (!ath_key_alloc(ic, &ni->ni_ucastkey, &keyix, &rxkeyix)) { 4734e8fd88a3SSam Leffler /* 4735e8fd88a3SSam Leffler * Key cache is full; we'll fall back to doing 4736e8fd88a3SSam Leffler * the more expensive lookup in software. Note 4737e8fd88a3SSam Leffler * this also means no h/w compression. 4738e8fd88a3SSam Leffler */ 4739e8fd88a3SSam Leffler /* XXX msg+statistic */ 4740e8fd88a3SSam Leffler } else { 4741c1225b52SSam Leffler /* XXX locking? */ 4742e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix = keyix; 4743c1225b52SSam Leffler ni->ni_ucastkey.wk_rxkeyix = rxkeyix; 4744e8fd88a3SSam Leffler /* NB: this will create a pass-thru key entry */ 4745e8fd88a3SSam Leffler ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, ic->ic_bss); 4746e8fd88a3SSam Leffler } 4747e8fd88a3SSam Leffler } 4748e8fd88a3SSam Leffler 4749e8fd88a3SSam Leffler /* 47505591b213SSam Leffler * Setup driver-specific state for a newly associated node. 47515591b213SSam Leffler * Note that we're called also on a re-associate, the isnew 47525591b213SSam Leffler * param tells us if this is the first time or not. 47535591b213SSam Leffler */ 47545591b213SSam Leffler static void 4755e9962332SSam Leffler ath_newassoc(struct ieee80211_node *ni, int isnew) 47565591b213SSam Leffler { 4757e9962332SSam Leffler struct ieee80211com *ic = ni->ni_ic; 4758c42a7b7eSSam Leffler struct ath_softc *sc = ic->ic_ifp->if_softc; 47595591b213SSam Leffler 4760c42a7b7eSSam Leffler ath_rate_newassoc(sc, ATH_NODE(ni), isnew); 4761e8fd88a3SSam Leffler if (isnew && 4762e8fd88a3SSam Leffler (ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey) { 4763e8fd88a3SSam Leffler KASSERT(ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE, 4764e8fd88a3SSam Leffler ("new assoc with a unicast key already setup (keyix %u)", 4765e8fd88a3SSam Leffler ni->ni_ucastkey.wk_keyix)); 4766e8fd88a3SSam Leffler ath_setup_stationkey(ni); 4767e8fd88a3SSam Leffler } 47685591b213SSam Leffler } 47695591b213SSam Leffler 47705591b213SSam Leffler static int 4771aaa70f2fSSam Leffler ath_getchannels(struct ath_softc *sc, 4772aaa70f2fSSam Leffler HAL_REG_DOMAIN rd, HAL_CTRY_CODE cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) 47735591b213SSam Leffler { 4774aaa70f2fSSam Leffler #define COMPAT \ 4775aaa70f2fSSam Leffler (CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE|CHANNEL_HALF|CHANNEL_QUARTER) 4776ae2734b6SSam Leffler #define IS_CHAN_PUBLIC_SAFETY(_c) \ 4777ae2734b6SSam Leffler (((_c)->channelFlags & CHANNEL_5GHZ) && \ 4778ae2734b6SSam Leffler ((_c)->channel > 4940 && (_c)->channel < 4990)) 47795591b213SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4780fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 47815591b213SSam Leffler struct ath_hal *ah = sc->sc_ah; 47825591b213SSam Leffler HAL_CHANNEL *chans; 47835591b213SSam Leffler int i, ix, nchan; 4784aaa70f2fSSam Leffler u_int32_t regdomain; 47855591b213SSam Leffler 47865591b213SSam Leffler chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL), 47875591b213SSam Leffler M_TEMP, M_NOWAIT); 47885591b213SSam Leffler if (chans == NULL) { 47895591b213SSam Leffler if_printf(ifp, "unable to allocate channel table\n"); 47905591b213SSam Leffler return ENOMEM; 47915591b213SSam Leffler } 47925591b213SSam Leffler if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, 4793aaa70f2fSSam Leffler NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) { 4794aaa70f2fSSam Leffler ath_hal_getregdomain(ah, ®domain); 4795c42a7b7eSSam Leffler if_printf(ifp, "unable to collect channel list from hal; " 4796aaa70f2fSSam Leffler "regdomain likely %u country code %u\n", regdomain, cc); 47975591b213SSam Leffler free(chans, M_TEMP); 47985591b213SSam Leffler return EINVAL; 47995591b213SSam Leffler } 48005591b213SSam Leffler 48015591b213SSam Leffler /* 48025591b213SSam Leffler * Convert HAL channels to ieee80211 ones and insert 48035591b213SSam Leffler * them in the table according to their channel number. 48045591b213SSam Leffler */ 4805aaa70f2fSSam Leffler memset(ic->ic_channels, 0, sizeof(ic->ic_channels)); 48065591b213SSam Leffler for (i = 0; i < nchan; i++) { 48075591b213SSam Leffler HAL_CHANNEL *c = &chans[i]; 4808bd5a9920SSam Leffler u_int16_t flags; 4809bd5a9920SSam Leffler 4810ae2734b6SSam Leffler /* 4811ae2734b6SSam Leffler * XXX we're not ready to handle the ieee number mapping 4812ae2734b6SSam Leffler * for public safety channels as they overlap with any 4813aaa70f2fSSam Leffler * 2GHz channels; for now use a non-public safety 4814aaa70f2fSSam Leffler * numbering that is non-overlapping. 4815ae2734b6SSam Leffler */ 4816bd5a9920SSam Leffler ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags); 4817aaa70f2fSSam Leffler if (IS_CHAN_PUBLIC_SAFETY(c)) 4818aaa70f2fSSam Leffler ix += 37; /* XXX */ 48195591b213SSam Leffler if (ix > IEEE80211_CHAN_MAX) { 4820bd5a9920SSam Leffler if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n", 48215591b213SSam Leffler ix, c->channel, c->channelFlags); 48225591b213SSam Leffler continue; 48235591b213SSam Leffler } 4824bd5a9920SSam Leffler if (ix < 0) { 4825bd5a9920SSam Leffler /* XXX can't handle stuff <2400 right now */ 4826bd5a9920SSam Leffler if (bootverbose) 4827bd5a9920SSam Leffler if_printf(ifp, "hal channel %d (%u/%x) " 4828bd5a9920SSam Leffler "cannot be handled; ignored\n", 4829bd5a9920SSam Leffler ix, c->channel, c->channelFlags); 4830bd5a9920SSam Leffler continue; 4831bd5a9920SSam Leffler } 4832bd5a9920SSam Leffler /* 4833bd5a9920SSam Leffler * Calculate net80211 flags; most are compatible 4834bd5a9920SSam Leffler * but some need massaging. Note the static turbo 4835bd5a9920SSam Leffler * conversion can be removed once net80211 is updated 4836bd5a9920SSam Leffler * to understand static vs. dynamic turbo. 4837bd5a9920SSam Leffler */ 4838bd5a9920SSam Leffler flags = c->channelFlags & COMPAT; 4839bd5a9920SSam Leffler if (c->channelFlags & CHANNEL_STURBO) 4840bd5a9920SSam Leffler flags |= IEEE80211_CHAN_TURBO; 48415591b213SSam Leffler if (ic->ic_channels[ix].ic_freq == 0) { 48425591b213SSam Leffler ic->ic_channels[ix].ic_freq = c->channel; 4843bd5a9920SSam Leffler ic->ic_channels[ix].ic_flags = flags; 48445591b213SSam Leffler } else { 48455591b213SSam Leffler /* channels overlap; e.g. 11g and 11b */ 4846bd5a9920SSam Leffler ic->ic_channels[ix].ic_flags |= flags; 48475591b213SSam Leffler } 48485591b213SSam Leffler } 48495591b213SSam Leffler free(chans, M_TEMP); 4850aaa70f2fSSam Leffler ath_hal_getregdomain(ah, &sc->sc_regdomain); 4851aaa70f2fSSam Leffler ath_hal_getcountrycode(ah, &sc->sc_countrycode); 4852aaa70f2fSSam Leffler sc->sc_xchanmode = xchanmode; 4853aaa70f2fSSam Leffler sc->sc_outdoor = outdoor; 48545591b213SSam Leffler return 0; 4855ae2734b6SSam Leffler #undef IS_CHAN_PUBLIC_SAFETY 4856bd5a9920SSam Leffler #undef COMPAT 48575591b213SSam Leffler } 48585591b213SSam Leffler 4859c42a7b7eSSam Leffler static void 48603e50ec2cSSam Leffler ath_led_done(void *arg) 4861c42a7b7eSSam Leffler { 48623e50ec2cSSam Leffler struct ath_softc *sc = arg; 48633e50ec2cSSam Leffler 48643e50ec2cSSam Leffler sc->sc_blinking = 0; 48653e50ec2cSSam Leffler } 4866c42a7b7eSSam Leffler 4867c42a7b7eSSam Leffler /* 48683e50ec2cSSam Leffler * Turn the LED off: flip the pin and then set a timer so no 48693e50ec2cSSam Leffler * update will happen for the specified duration. 4870c42a7b7eSSam Leffler */ 48713e50ec2cSSam Leffler static void 48723e50ec2cSSam Leffler ath_led_off(void *arg) 48733e50ec2cSSam Leffler { 48743e50ec2cSSam Leffler struct ath_softc *sc = arg; 48753e50ec2cSSam Leffler 48763e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); 48773e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc); 4878c42a7b7eSSam Leffler } 48793e50ec2cSSam Leffler 48803e50ec2cSSam Leffler /* 48813e50ec2cSSam Leffler * Blink the LED according to the specified on/off times. 48823e50ec2cSSam Leffler */ 48833e50ec2cSSam Leffler static void 48843e50ec2cSSam Leffler ath_led_blink(struct ath_softc *sc, int on, int off) 48853e50ec2cSSam Leffler { 48863e50ec2cSSam Leffler DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off); 48873e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon); 48883e50ec2cSSam Leffler sc->sc_blinking = 1; 48893e50ec2cSSam Leffler sc->sc_ledoff = off; 48903e50ec2cSSam Leffler callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc); 48913e50ec2cSSam Leffler } 48923e50ec2cSSam Leffler 48933e50ec2cSSam Leffler static void 48943e50ec2cSSam Leffler ath_led_event(struct ath_softc *sc, int event) 48953e50ec2cSSam Leffler { 48963e50ec2cSSam Leffler 48973e50ec2cSSam Leffler sc->sc_ledevent = ticks; /* time of last event */ 48983e50ec2cSSam Leffler if (sc->sc_blinking) /* don't interrupt active blink */ 48993e50ec2cSSam Leffler return; 49003e50ec2cSSam Leffler switch (event) { 49013e50ec2cSSam Leffler case ATH_LED_POLL: 49023e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[0].ledon, 49033e50ec2cSSam Leffler sc->sc_hwmap[0].ledoff); 49043e50ec2cSSam Leffler break; 49053e50ec2cSSam Leffler case ATH_LED_TX: 49063e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[sc->sc_txrate].ledon, 49073e50ec2cSSam Leffler sc->sc_hwmap[sc->sc_txrate].ledoff); 49083e50ec2cSSam Leffler break; 49093e50ec2cSSam Leffler case ATH_LED_RX: 49103e50ec2cSSam Leffler ath_led_blink(sc, sc->sc_hwmap[sc->sc_rxrate].ledon, 49113e50ec2cSSam Leffler sc->sc_hwmap[sc->sc_rxrate].ledoff); 49123e50ec2cSSam Leffler break; 4913c42a7b7eSSam Leffler } 4914c42a7b7eSSam Leffler } 4915c42a7b7eSSam Leffler 4916c42a7b7eSSam Leffler static void 4917c42a7b7eSSam Leffler ath_update_txpow(struct ath_softc *sc) 4918c42a7b7eSSam Leffler { 4919c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 4920c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 4921c42a7b7eSSam Leffler u_int32_t txpow; 4922c42a7b7eSSam Leffler 4923c42a7b7eSSam Leffler if (sc->sc_curtxpow != ic->ic_txpowlimit) { 4924c42a7b7eSSam Leffler ath_hal_settxpowlimit(ah, ic->ic_txpowlimit); 4925c42a7b7eSSam Leffler /* read back in case value is clamped */ 4926c42a7b7eSSam Leffler ath_hal_gettxpowlimit(ah, &txpow); 4927c42a7b7eSSam Leffler ic->ic_txpowlimit = sc->sc_curtxpow = txpow; 4928c42a7b7eSSam Leffler } 4929c42a7b7eSSam Leffler /* 4930c42a7b7eSSam Leffler * Fetch max tx power level for status requests. 4931c42a7b7eSSam Leffler */ 4932c42a7b7eSSam Leffler ath_hal_getmaxtxpow(sc->sc_ah, &txpow); 4933c42a7b7eSSam Leffler ic->ic_bss->ni_txpower = txpow; 4934c42a7b7eSSam Leffler } 4935c42a7b7eSSam Leffler 49366c4612b9SSam Leffler static int 49376c4612b9SSam Leffler ath_rate_setup(struct ath_softc *sc, u_int mode) 49386c4612b9SSam Leffler { 49396c4612b9SSam Leffler struct ath_hal *ah = sc->sc_ah; 49406c4612b9SSam Leffler const HAL_RATE_TABLE *rt; 49416c4612b9SSam Leffler 49426c4612b9SSam Leffler switch (mode) { 49436c4612b9SSam Leffler case IEEE80211_MODE_11A: 49446c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A); 49456c4612b9SSam Leffler break; 4946aaa70f2fSSam Leffler case IEEE80211_MODE_11A_HALF: 4947aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE); 4948aaa70f2fSSam Leffler break; 4949aaa70f2fSSam Leffler case IEEE80211_MODE_11A_QUARTER: 4950aaa70f2fSSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE); 4951aaa70f2fSSam Leffler break; 49526c4612b9SSam Leffler case IEEE80211_MODE_11B: 49536c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11B); 49546c4612b9SSam Leffler break; 49556c4612b9SSam Leffler case IEEE80211_MODE_11G: 49566c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_11G); 49576c4612b9SSam Leffler break; 49586c4612b9SSam Leffler case IEEE80211_MODE_TURBO_A: 49596c4612b9SSam Leffler /* XXX until static/dynamic turbo is fixed */ 49606c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_TURBO); 49616c4612b9SSam Leffler break; 49626c4612b9SSam Leffler case IEEE80211_MODE_TURBO_G: 49636c4612b9SSam Leffler rt = ath_hal_getratetable(ah, HAL_MODE_108G); 49646c4612b9SSam Leffler break; 49656c4612b9SSam Leffler default: 49666c4612b9SSam Leffler DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid mode %u\n", 49676c4612b9SSam Leffler __func__, mode); 49686c4612b9SSam Leffler return 0; 49696c4612b9SSam Leffler } 49706c4612b9SSam Leffler sc->sc_rates[mode] = rt; 4971aaa70f2fSSam Leffler return (rt != NULL); 49725591b213SSam Leffler } 49735591b213SSam Leffler 49745591b213SSam Leffler static void 49755591b213SSam Leffler ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) 49765591b213SSam Leffler { 49773e50ec2cSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 49783e50ec2cSSam Leffler /* NB: on/off times from the Atheros NDIS driver, w/ permission */ 49793e50ec2cSSam Leffler static const struct { 49803e50ec2cSSam Leffler u_int rate; /* tx/rx 802.11 rate */ 49813e50ec2cSSam Leffler u_int16_t timeOn; /* LED on time (ms) */ 49823e50ec2cSSam Leffler u_int16_t timeOff; /* LED off time (ms) */ 49833e50ec2cSSam Leffler } blinkrates[] = { 49843e50ec2cSSam Leffler { 108, 40, 10 }, 49853e50ec2cSSam Leffler { 96, 44, 11 }, 49863e50ec2cSSam Leffler { 72, 50, 13 }, 49873e50ec2cSSam Leffler { 48, 57, 14 }, 49883e50ec2cSSam Leffler { 36, 67, 16 }, 49893e50ec2cSSam Leffler { 24, 80, 20 }, 49903e50ec2cSSam Leffler { 22, 100, 25 }, 49913e50ec2cSSam Leffler { 18, 133, 34 }, 49923e50ec2cSSam Leffler { 12, 160, 40 }, 49933e50ec2cSSam Leffler { 10, 200, 50 }, 49943e50ec2cSSam Leffler { 6, 240, 58 }, 49953e50ec2cSSam Leffler { 4, 267, 66 }, 49963e50ec2cSSam Leffler { 2, 400, 100 }, 49973e50ec2cSSam Leffler { 0, 500, 130 }, 49983e50ec2cSSam Leffler }; 49995591b213SSam Leffler const HAL_RATE_TABLE *rt; 50003e50ec2cSSam Leffler int i, j; 50015591b213SSam Leffler 50025591b213SSam Leffler memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); 50035591b213SSam Leffler rt = sc->sc_rates[mode]; 50045591b213SSam Leffler KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode)); 50055591b213SSam Leffler for (i = 0; i < rt->rateCount; i++) 50065591b213SSam Leffler sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; 50071b1a8e41SSam Leffler memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); 5008c42a7b7eSSam Leffler for (i = 0; i < 32; i++) { 5009c42a7b7eSSam Leffler u_int8_t ix = rt->rateCodeToIndex[i]; 50103e50ec2cSSam Leffler if (ix == 0xff) { 50113e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (500 * hz) / 1000; 50123e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (130 * hz) / 1000; 501316b4851aSSam Leffler continue; 50143e50ec2cSSam Leffler } 50153e50ec2cSSam Leffler sc->sc_hwmap[i].ieeerate = 50163e50ec2cSSam Leffler rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; 5017d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; 501816b4851aSSam Leffler if (rt->info[ix].shortPreamble || 501916b4851aSSam Leffler rt->info[ix].phy == IEEE80211_T_OFDM) 5020d3be6f5bSSam Leffler sc->sc_hwmap[i].txflags |= IEEE80211_RADIOTAP_F_SHORTPRE; 5021d3be6f5bSSam Leffler /* NB: receive frames include FCS */ 5022d3be6f5bSSam Leffler sc->sc_hwmap[i].rxflags = sc->sc_hwmap[i].txflags | 5023d3be6f5bSSam Leffler IEEE80211_RADIOTAP_F_FCS; 50243e50ec2cSSam Leffler /* setup blink rate table to avoid per-packet lookup */ 50253e50ec2cSSam Leffler for (j = 0; j < N(blinkrates)-1; j++) 50263e50ec2cSSam Leffler if (blinkrates[j].rate == sc->sc_hwmap[i].ieeerate) 50273e50ec2cSSam Leffler break; 50283e50ec2cSSam Leffler /* NB: this uses the last entry if the rate isn't found */ 50293e50ec2cSSam Leffler /* XXX beware of overlow */ 50303e50ec2cSSam Leffler sc->sc_hwmap[i].ledon = (blinkrates[j].timeOn * hz) / 1000; 50313e50ec2cSSam Leffler sc->sc_hwmap[i].ledoff = (blinkrates[j].timeOff * hz) / 1000; 5032c42a7b7eSSam Leffler } 50335591b213SSam Leffler sc->sc_currates = rt; 50345591b213SSam Leffler sc->sc_curmode = mode; 50355591b213SSam Leffler /* 5036c42a7b7eSSam Leffler * All protection frames are transmited at 2Mb/s for 5037c42a7b7eSSam Leffler * 11g, otherwise at 1Mb/s. 50385591b213SSam Leffler */ 5039913a1ba1SSam Leffler if (mode == IEEE80211_MODE_11G) 5040913a1ba1SSam Leffler sc->sc_protrix = ath_tx_findrix(rt, 2*2); 5041913a1ba1SSam Leffler else 5042913a1ba1SSam Leffler sc->sc_protrix = ath_tx_findrix(rt, 2*1); 504355f63772SSam Leffler /* rate index used to send management frames */ 504455f63772SSam Leffler sc->sc_minrateix = 0; 50458b5341deSSam Leffler /* 50468b5341deSSam Leffler * Setup multicast rate state. 50478b5341deSSam Leffler */ 50488b5341deSSam Leffler /* XXX layering violation */ 50498b5341deSSam Leffler sc->sc_mcastrix = ath_tx_findrix(rt, sc->sc_ic.ic_mcast_rate); 50508b5341deSSam Leffler sc->sc_mcastrate = sc->sc_ic.ic_mcast_rate; 5051c42a7b7eSSam Leffler /* NB: caller is responsible for reseting rate control state */ 50523e50ec2cSSam Leffler #undef N 50535591b213SSam Leffler } 50545591b213SSam Leffler 5055a585a9a1SSam Leffler #ifdef ATH_DEBUG 50565591b213SSam Leffler static void 505765f9edeeSSam Leffler ath_printrxbuf(const struct ath_buf *bf, u_int ix, int done) 50585591b213SSam Leffler { 505965f9edeeSSam Leffler const struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; 506065f9edeeSSam Leffler const struct ath_desc *ds; 50615591b213SSam Leffler int i; 50625591b213SSam Leffler 50635591b213SSam Leffler for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { 50647a4c5ed9SSam Leffler printf("R[%2u] (DS.V:%p DS.P:%p) L:%08x D:%08x%s\n" 50657a4c5ed9SSam Leffler " %08x %08x %08x %08x\n", 506665f9edeeSSam Leffler ix, ds, (const struct ath_desc *)bf->bf_daddr + i, 50675591b213SSam Leffler ds->ds_link, ds->ds_data, 506865f9edeeSSam Leffler !done ? "" : (rs->rs_status == 0) ? " *" : " !", 50695591b213SSam Leffler ds->ds_ctl0, ds->ds_ctl1, 50707a4c5ed9SSam Leffler ds->ds_hw[0], ds->ds_hw[1]); 50715591b213SSam Leffler } 50725591b213SSam Leffler } 50735591b213SSam Leffler 50745591b213SSam Leffler static void 507565f9edeeSSam Leffler ath_printtxbuf(const struct ath_buf *bf, u_int qnum, u_int ix, int done) 50765591b213SSam Leffler { 507765f9edeeSSam Leffler const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; 507865f9edeeSSam Leffler const struct ath_desc *ds; 50795591b213SSam Leffler int i; 50805591b213SSam Leffler 50817a4c5ed9SSam Leffler printf("Q%u[%3u]", qnum, ix); 50825591b213SSam Leffler for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { 5083ebecf802SSam Leffler printf(" (DS.V:%p DS.P:%p) L:%08x D:%08x F:04%x%s\n" 50847a4c5ed9SSam Leffler " %08x %08x %08x %08x %08x %08x\n", 508565f9edeeSSam Leffler ds, (const struct ath_desc *)bf->bf_daddr + i, 5086ebecf802SSam Leffler ds->ds_link, ds->ds_data, bf->bf_flags, 508765f9edeeSSam Leffler !done ? "" : (ts->ts_status == 0) ? " *" : " !", 50885591b213SSam Leffler ds->ds_ctl0, ds->ds_ctl1, 50897a4c5ed9SSam Leffler ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3]); 50905591b213SSam Leffler } 50915591b213SSam Leffler } 5092a585a9a1SSam Leffler #endif /* ATH_DEBUG */ 5093c42a7b7eSSam Leffler 5094c42a7b7eSSam Leffler static void 5095c42a7b7eSSam Leffler ath_watchdog(struct ifnet *ifp) 5096c42a7b7eSSam Leffler { 5097c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 5098c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5099c42a7b7eSSam Leffler 5100c42a7b7eSSam Leffler ifp->if_timer = 0; 510113f4c340SRobert Watson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) 5102c42a7b7eSSam Leffler return; 5103c42a7b7eSSam Leffler if (sc->sc_tx_timer) { 5104c42a7b7eSSam Leffler if (--sc->sc_tx_timer == 0) { 5105c42a7b7eSSam Leffler if_printf(ifp, "device timeout\n"); 5106c42a7b7eSSam Leffler ath_reset(ifp); 5107c42a7b7eSSam Leffler ifp->if_oerrors++; 5108c42a7b7eSSam Leffler sc->sc_stats.ast_watchdog++; 5109c42a7b7eSSam Leffler } else 5110c42a7b7eSSam Leffler ifp->if_timer = 1; 5111c42a7b7eSSam Leffler } 5112c42a7b7eSSam Leffler ieee80211_watchdog(ic); 5113c42a7b7eSSam Leffler } 5114c42a7b7eSSam Leffler 5115a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5116c42a7b7eSSam Leffler /* 5117c42a7b7eSSam Leffler * Diagnostic interface to the HAL. This is used by various 5118c42a7b7eSSam Leffler * tools to do things like retrieve register contents for 5119c42a7b7eSSam Leffler * debugging. The mechanism is intentionally opaque so that 5120c42a7b7eSSam Leffler * it can change frequently w/o concern for compatiblity. 5121c42a7b7eSSam Leffler */ 5122c42a7b7eSSam Leffler static int 5123c42a7b7eSSam Leffler ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) 5124c42a7b7eSSam Leffler { 5125c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5126c42a7b7eSSam Leffler u_int id = ad->ad_id & ATH_DIAG_ID; 5127c42a7b7eSSam Leffler void *indata = NULL; 5128c42a7b7eSSam Leffler void *outdata = NULL; 5129c42a7b7eSSam Leffler u_int32_t insize = ad->ad_in_size; 5130c42a7b7eSSam Leffler u_int32_t outsize = ad->ad_out_size; 5131c42a7b7eSSam Leffler int error = 0; 5132c42a7b7eSSam Leffler 5133c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_IN) { 5134c42a7b7eSSam Leffler /* 5135c42a7b7eSSam Leffler * Copy in data. 5136c42a7b7eSSam Leffler */ 5137c42a7b7eSSam Leffler indata = malloc(insize, M_TEMP, M_NOWAIT); 5138c42a7b7eSSam Leffler if (indata == NULL) { 5139c42a7b7eSSam Leffler error = ENOMEM; 5140c42a7b7eSSam Leffler goto bad; 5141c42a7b7eSSam Leffler } 5142c42a7b7eSSam Leffler error = copyin(ad->ad_in_data, indata, insize); 5143c42a7b7eSSam Leffler if (error) 5144c42a7b7eSSam Leffler goto bad; 5145c42a7b7eSSam Leffler } 5146c42a7b7eSSam Leffler if (ad->ad_id & ATH_DIAG_DYN) { 5147c42a7b7eSSam Leffler /* 5148c42a7b7eSSam Leffler * Allocate a buffer for the results (otherwise the HAL 5149c42a7b7eSSam Leffler * returns a pointer to a buffer where we can read the 5150c42a7b7eSSam Leffler * results). Note that we depend on the HAL leaving this 5151c42a7b7eSSam Leffler * pointer for us to use below in reclaiming the buffer; 5152c42a7b7eSSam Leffler * may want to be more defensive. 5153c42a7b7eSSam Leffler */ 5154c42a7b7eSSam Leffler outdata = malloc(outsize, M_TEMP, M_NOWAIT); 5155c42a7b7eSSam Leffler if (outdata == NULL) { 5156c42a7b7eSSam Leffler error = ENOMEM; 5157c42a7b7eSSam Leffler goto bad; 5158c42a7b7eSSam Leffler } 5159c42a7b7eSSam Leffler } 5160c42a7b7eSSam Leffler if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { 5161c42a7b7eSSam Leffler if (outsize < ad->ad_out_size) 5162c42a7b7eSSam Leffler ad->ad_out_size = outsize; 5163c42a7b7eSSam Leffler if (outdata != NULL) 5164c42a7b7eSSam Leffler error = copyout(outdata, ad->ad_out_data, 5165c42a7b7eSSam Leffler ad->ad_out_size); 5166c42a7b7eSSam Leffler } else { 5167c42a7b7eSSam Leffler error = EINVAL; 5168c42a7b7eSSam Leffler } 5169c42a7b7eSSam Leffler bad: 5170c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 5171c42a7b7eSSam Leffler free(indata, M_TEMP); 5172c42a7b7eSSam Leffler if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 5173c42a7b7eSSam Leffler free(outdata, M_TEMP); 5174c42a7b7eSSam Leffler return error; 5175c42a7b7eSSam Leffler } 5176a585a9a1SSam Leffler #endif /* ATH_DIAGAPI */ 5177c42a7b7eSSam Leffler 5178c42a7b7eSSam Leffler static int 5179c42a7b7eSSam Leffler ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 5180c42a7b7eSSam Leffler { 5181c42a7b7eSSam Leffler #define IS_RUNNING(ifp) \ 518213f4c340SRobert Watson ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 5183c42a7b7eSSam Leffler struct ath_softc *sc = ifp->if_softc; 5184c42a7b7eSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5185c42a7b7eSSam Leffler struct ifreq *ifr = (struct ifreq *)data; 5186c42a7b7eSSam Leffler int error = 0; 5187c42a7b7eSSam Leffler 5188c42a7b7eSSam Leffler ATH_LOCK(sc); 5189c42a7b7eSSam Leffler switch (cmd) { 5190c42a7b7eSSam Leffler case SIOCSIFFLAGS: 5191c42a7b7eSSam Leffler if (IS_RUNNING(ifp)) { 5192c42a7b7eSSam Leffler /* 5193c42a7b7eSSam Leffler * To avoid rescanning another access point, 5194c42a7b7eSSam Leffler * do not call ath_init() here. Instead, 5195c42a7b7eSSam Leffler * only reflect promisc mode settings. 5196c42a7b7eSSam Leffler */ 5197c42a7b7eSSam Leffler ath_mode_init(sc); 5198c42a7b7eSSam Leffler } else if (ifp->if_flags & IFF_UP) { 5199c42a7b7eSSam Leffler /* 5200c42a7b7eSSam Leffler * Beware of being called during attach/detach 5201c42a7b7eSSam Leffler * to reset promiscuous mode. In that case we 5202c42a7b7eSSam Leffler * will still be marked UP but not RUNNING. 5203c42a7b7eSSam Leffler * However trying to re-init the interface 5204c42a7b7eSSam Leffler * is the wrong thing to do as we've already 5205c42a7b7eSSam Leffler * torn down much of our state. There's 5206c42a7b7eSSam Leffler * probably a better way to deal with this. 5207c42a7b7eSSam Leffler */ 5208c42a7b7eSSam Leffler if (!sc->sc_invalid && ic->ic_bss != NULL) 5209fc74a9f9SBrooks Davis ath_init(sc); /* XXX lose error */ 5210c42a7b7eSSam Leffler } else 5211c42a7b7eSSam Leffler ath_stop_locked(ifp); 5212c42a7b7eSSam Leffler break; 5213c42a7b7eSSam Leffler case SIOCADDMULTI: 5214c42a7b7eSSam Leffler case SIOCDELMULTI: 5215c42a7b7eSSam Leffler /* 5216c42a7b7eSSam Leffler * The upper layer has already installed/removed 5217c42a7b7eSSam Leffler * the multicast address(es), just recalculate the 5218c42a7b7eSSam Leffler * multicast filter for the card. 5219c42a7b7eSSam Leffler */ 522013f4c340SRobert Watson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 5221c42a7b7eSSam Leffler ath_mode_init(sc); 5222c42a7b7eSSam Leffler break; 5223c42a7b7eSSam Leffler case SIOCGATHSTATS: 5224c42a7b7eSSam Leffler /* NB: embed these numbers to get a consistent view */ 5225c42a7b7eSSam Leffler sc->sc_stats.ast_tx_packets = ifp->if_opackets; 5226c42a7b7eSSam Leffler sc->sc_stats.ast_rx_packets = ifp->if_ipackets; 5227c42a7b7eSSam Leffler sc->sc_stats.ast_rx_rssi = ieee80211_getrssi(ic); 52286bf62dd1SSam Leffler sc->sc_stats.ast_rx_noise = 52296bf62dd1SSam Leffler ath_hal_getchannoise(sc->sc_ah, &sc->sc_curchan); 52306bf62dd1SSam Leffler sc->sc_stats.ast_tx_rate = sc->sc_hwmap[sc->sc_txrate].ieeerate; 5231c42a7b7eSSam Leffler ATH_UNLOCK(sc); 5232c42a7b7eSSam Leffler /* 5233c42a7b7eSSam Leffler * NB: Drop the softc lock in case of a page fault; 5234c42a7b7eSSam Leffler * we'll accept any potential inconsisentcy in the 5235c42a7b7eSSam Leffler * statistics. The alternative is to copy the data 5236c42a7b7eSSam Leffler * to a local structure. 5237c42a7b7eSSam Leffler */ 5238c42a7b7eSSam Leffler return copyout(&sc->sc_stats, 5239c42a7b7eSSam Leffler ifr->ifr_data, sizeof (sc->sc_stats)); 5240a585a9a1SSam Leffler #ifdef ATH_DIAGAPI 5241c42a7b7eSSam Leffler case SIOCGATHDIAG: 52421d89d44fSSam Leffler ATH_UNLOCK(sc); 5243c42a7b7eSSam Leffler error = ath_ioctl_diag(sc, (struct ath_diag *) ifr); 52441d89d44fSSam Leffler ATH_LOCK(sc); 5245c42a7b7eSSam Leffler break; 5246a585a9a1SSam Leffler #endif 5247c42a7b7eSSam Leffler default: 5248c42a7b7eSSam Leffler error = ieee80211_ioctl(ic, cmd, data); 5249c42a7b7eSSam Leffler if (error == ENETRESET) { 5250c42a7b7eSSam Leffler if (IS_RUNNING(ifp) && 5251c42a7b7eSSam Leffler ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 5252fc74a9f9SBrooks Davis ath_init(sc); /* XXX lose error */ 5253c42a7b7eSSam Leffler error = 0; 5254c42a7b7eSSam Leffler } 5255c42a7b7eSSam Leffler if (error == ERESTART) 5256c42a7b7eSSam Leffler error = IS_RUNNING(ifp) ? ath_reset(ifp) : 0; 5257c42a7b7eSSam Leffler break; 5258c42a7b7eSSam Leffler } 5259c42a7b7eSSam Leffler ATH_UNLOCK(sc); 5260c42a7b7eSSam Leffler return error; 5261a614e076SSam Leffler #undef IS_RUNNING 5262c42a7b7eSSam Leffler } 5263c42a7b7eSSam Leffler 5264c42a7b7eSSam Leffler static int 5265c42a7b7eSSam Leffler ath_sysctl_slottime(SYSCTL_HANDLER_ARGS) 5266c42a7b7eSSam Leffler { 5267c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5268c42a7b7eSSam Leffler u_int slottime = ath_hal_getslottime(sc->sc_ah); 5269c42a7b7eSSam Leffler int error; 5270c42a7b7eSSam Leffler 5271c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &slottime, 0, req); 5272c42a7b7eSSam Leffler if (error || !req->newptr) 5273c42a7b7eSSam Leffler return error; 5274c42a7b7eSSam Leffler return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; 5275c42a7b7eSSam Leffler } 5276c42a7b7eSSam Leffler 5277c42a7b7eSSam Leffler static int 5278c42a7b7eSSam Leffler ath_sysctl_acktimeout(SYSCTL_HANDLER_ARGS) 5279c42a7b7eSSam Leffler { 5280c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5281c42a7b7eSSam Leffler u_int acktimeout = ath_hal_getacktimeout(sc->sc_ah); 5282c42a7b7eSSam Leffler int error; 5283c42a7b7eSSam Leffler 5284c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &acktimeout, 0, req); 5285c42a7b7eSSam Leffler if (error || !req->newptr) 5286c42a7b7eSSam Leffler return error; 5287c42a7b7eSSam Leffler return !ath_hal_setacktimeout(sc->sc_ah, acktimeout) ? EINVAL : 0; 5288c42a7b7eSSam Leffler } 5289c42a7b7eSSam Leffler 5290c42a7b7eSSam Leffler static int 5291c42a7b7eSSam Leffler ath_sysctl_ctstimeout(SYSCTL_HANDLER_ARGS) 5292c42a7b7eSSam Leffler { 5293c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5294c42a7b7eSSam Leffler u_int ctstimeout = ath_hal_getctstimeout(sc->sc_ah); 5295c42a7b7eSSam Leffler int error; 5296c42a7b7eSSam Leffler 5297c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &ctstimeout, 0, req); 5298c42a7b7eSSam Leffler if (error || !req->newptr) 5299c42a7b7eSSam Leffler return error; 5300c42a7b7eSSam Leffler return !ath_hal_setctstimeout(sc->sc_ah, ctstimeout) ? EINVAL : 0; 5301c42a7b7eSSam Leffler } 5302c42a7b7eSSam Leffler 5303c42a7b7eSSam Leffler static int 5304c42a7b7eSSam Leffler ath_sysctl_softled(SYSCTL_HANDLER_ARGS) 5305c42a7b7eSSam Leffler { 5306c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5307c42a7b7eSSam Leffler int softled = sc->sc_softled; 5308c42a7b7eSSam Leffler int error; 5309c42a7b7eSSam Leffler 5310c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &softled, 0, req); 5311c42a7b7eSSam Leffler if (error || !req->newptr) 5312c42a7b7eSSam Leffler return error; 53133e50ec2cSSam Leffler softled = (softled != 0); 5314c42a7b7eSSam Leffler if (softled != sc->sc_softled) { 53153e50ec2cSSam Leffler if (softled) { 53163e50ec2cSSam Leffler /* NB: handle any sc_ledpin change */ 5317c42a7b7eSSam Leffler ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); 53183e50ec2cSSam Leffler ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, 53193e50ec2cSSam Leffler !sc->sc_ledon); 53203e50ec2cSSam Leffler } 5321c42a7b7eSSam Leffler sc->sc_softled = softled; 5322c42a7b7eSSam Leffler } 5323c42a7b7eSSam Leffler return 0; 5324c42a7b7eSSam Leffler } 5325c42a7b7eSSam Leffler 5326c42a7b7eSSam Leffler static int 5327c42a7b7eSSam Leffler ath_sysctl_rxantenna(SYSCTL_HANDLER_ARGS) 5328c42a7b7eSSam Leffler { 5329c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5330c42a7b7eSSam Leffler u_int defantenna = ath_hal_getdefantenna(sc->sc_ah); 5331c42a7b7eSSam Leffler int error; 5332c42a7b7eSSam Leffler 5333c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &defantenna, 0, req); 5334c42a7b7eSSam Leffler if (!error && req->newptr) 5335c42a7b7eSSam Leffler ath_hal_setdefantenna(sc->sc_ah, defantenna); 5336c42a7b7eSSam Leffler return error; 5337c42a7b7eSSam Leffler } 5338c42a7b7eSSam Leffler 5339c42a7b7eSSam Leffler static int 5340c42a7b7eSSam Leffler ath_sysctl_diversity(SYSCTL_HANDLER_ARGS) 5341c42a7b7eSSam Leffler { 5342c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5343c59005e9SSam Leffler u_int diversity = ath_hal_getdiversity(sc->sc_ah); 5344c42a7b7eSSam Leffler int error; 5345c42a7b7eSSam Leffler 5346c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &diversity, 0, req); 5347c42a7b7eSSam Leffler if (error || !req->newptr) 5348c42a7b7eSSam Leffler return error; 5349c59005e9SSam Leffler if (!ath_hal_setdiversity(sc->sc_ah, diversity)) 5350c59005e9SSam Leffler return EINVAL; 5351c42a7b7eSSam Leffler sc->sc_diversity = diversity; 5352c59005e9SSam Leffler return 0; 5353c42a7b7eSSam Leffler } 5354c42a7b7eSSam Leffler 5355c42a7b7eSSam Leffler static int 5356c42a7b7eSSam Leffler ath_sysctl_diag(SYSCTL_HANDLER_ARGS) 5357c42a7b7eSSam Leffler { 5358c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5359c42a7b7eSSam Leffler u_int32_t diag; 5360c42a7b7eSSam Leffler int error; 5361c42a7b7eSSam Leffler 5362c42a7b7eSSam Leffler if (!ath_hal_getdiag(sc->sc_ah, &diag)) 5363c42a7b7eSSam Leffler return EINVAL; 5364c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &diag, 0, req); 5365c42a7b7eSSam Leffler if (error || !req->newptr) 5366c42a7b7eSSam Leffler return error; 5367c42a7b7eSSam Leffler return !ath_hal_setdiag(sc->sc_ah, diag) ? EINVAL : 0; 5368c42a7b7eSSam Leffler } 5369c42a7b7eSSam Leffler 5370c42a7b7eSSam Leffler static int 5371c42a7b7eSSam Leffler ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) 5372c42a7b7eSSam Leffler { 5373c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5374fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5375c42a7b7eSSam Leffler u_int32_t scale; 5376c42a7b7eSSam Leffler int error; 5377c42a7b7eSSam Leffler 5378c42a7b7eSSam Leffler ath_hal_gettpscale(sc->sc_ah, &scale); 5379c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &scale, 0, req); 5380c42a7b7eSSam Leffler if (error || !req->newptr) 5381c42a7b7eSSam Leffler return error; 5382c42a7b7eSSam Leffler return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : ath_reset(ifp); 5383c42a7b7eSSam Leffler } 5384c42a7b7eSSam Leffler 5385c42a7b7eSSam Leffler static int 5386c42a7b7eSSam Leffler ath_sysctl_tpc(SYSCTL_HANDLER_ARGS) 5387c42a7b7eSSam Leffler { 5388c42a7b7eSSam Leffler struct ath_softc *sc = arg1; 5389c42a7b7eSSam Leffler u_int tpc = ath_hal_gettpc(sc->sc_ah); 5390c42a7b7eSSam Leffler int error; 5391c42a7b7eSSam Leffler 5392c42a7b7eSSam Leffler error = sysctl_handle_int(oidp, &tpc, 0, req); 5393c42a7b7eSSam Leffler if (error || !req->newptr) 5394c42a7b7eSSam Leffler return error; 5395c42a7b7eSSam Leffler return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0; 5396c42a7b7eSSam Leffler } 5397c42a7b7eSSam Leffler 539817f3f177SSam Leffler static int 5399bd5a9920SSam Leffler ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) 5400bd5a9920SSam Leffler { 5401bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5402bd5a9920SSam Leffler struct ath_hal *ah = sc->sc_ah; 5403bd5a9920SSam Leffler u_int rfkill = ath_hal_getrfkill(ah); 5404bd5a9920SSam Leffler int error; 5405bd5a9920SSam Leffler 5406bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &rfkill, 0, req); 5407bd5a9920SSam Leffler if (error || !req->newptr) 5408bd5a9920SSam Leffler return error; 5409bd5a9920SSam Leffler if (rfkill == ath_hal_getrfkill(ah)) /* unchanged */ 5410bd5a9920SSam Leffler return 0; 5411bd5a9920SSam Leffler if (!ath_hal_setrfkill(ah, rfkill) || ath_reset(sc->sc_ifp) != 0) 5412bd5a9920SSam Leffler return EINVAL; 5413bd5a9920SSam Leffler else 5414bd5a9920SSam Leffler return 0; 5415bd5a9920SSam Leffler } 5416bd5a9920SSam Leffler 5417bd5a9920SSam Leffler static int 5418bd5a9920SSam Leffler ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS) 5419bd5a9920SSam Leffler { 5420bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5421bd5a9920SSam Leffler u_int rfsilent; 5422bd5a9920SSam Leffler int error; 5423bd5a9920SSam Leffler 5424bd5a9920SSam Leffler ath_hal_getrfsilent(sc->sc_ah, &rfsilent); 5425bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &rfsilent, 0, req); 5426bd5a9920SSam Leffler if (error || !req->newptr) 5427bd5a9920SSam Leffler return error; 5428bd5a9920SSam Leffler if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent)) 5429bd5a9920SSam Leffler return EINVAL; 5430bd5a9920SSam Leffler sc->sc_rfsilentpin = rfsilent & 0x1c; 5431bd5a9920SSam Leffler sc->sc_rfsilentpol = (rfsilent & 0x2) != 0; 5432bd5a9920SSam Leffler return 0; 5433bd5a9920SSam Leffler } 5434bd5a9920SSam Leffler 5435bd5a9920SSam Leffler static int 5436aaa70f2fSSam Leffler ath_sysctl_countrycode(SYSCTL_HANDLER_ARGS) 5437aaa70f2fSSam Leffler { 5438aaa70f2fSSam Leffler struct ath_softc *sc = arg1; 5439aaa70f2fSSam Leffler u_int32_t cc = sc->sc_countrycode; 5440aaa70f2fSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5441aaa70f2fSSam Leffler int error; 5442aaa70f2fSSam Leffler 5443aaa70f2fSSam Leffler error = sysctl_handle_int(oidp, &cc, 0, req); 5444aaa70f2fSSam Leffler if (error || !req->newptr) 5445aaa70f2fSSam Leffler return error; 5446aaa70f2fSSam Leffler error = ath_getchannels(sc, sc->sc_regdomain, cc, 5447aaa70f2fSSam Leffler sc->sc_outdoor, sc->sc_xchanmode); 5448aaa70f2fSSam Leffler if (error != 0) 5449aaa70f2fSSam Leffler return error; 5450aaa70f2fSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 5451aaa70f2fSSam Leffler /* setcurmode? */ 5452aaa70f2fSSam Leffler return 0; 5453aaa70f2fSSam Leffler } 5454aaa70f2fSSam Leffler 5455aaa70f2fSSam Leffler static int 545617f3f177SSam Leffler ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS) 545717f3f177SSam Leffler { 545817f3f177SSam Leffler struct ath_softc *sc = arg1; 5459aaa70f2fSSam Leffler u_int32_t rd = sc->sc_regdomain; 5460aaa70f2fSSam Leffler struct ieee80211com *ic = &sc->sc_ic; 546117f3f177SSam Leffler int error; 546217f3f177SSam Leffler 546317f3f177SSam Leffler error = sysctl_handle_int(oidp, &rd, 0, req); 546417f3f177SSam Leffler if (error || !req->newptr) 546517f3f177SSam Leffler return error; 5466aaa70f2fSSam Leffler if (!ath_hal_setregdomain(sc->sc_ah, rd)) 5467aaa70f2fSSam Leffler return EINVAL; 5468aaa70f2fSSam Leffler error = ath_getchannels(sc, rd, sc->sc_countrycode, 5469aaa70f2fSSam Leffler sc->sc_outdoor, sc->sc_xchanmode); 5470aaa70f2fSSam Leffler if (error != 0) 5471aaa70f2fSSam Leffler return error; 5472aaa70f2fSSam Leffler ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); 5473aaa70f2fSSam Leffler /* setcurmode? */ 5474aaa70f2fSSam Leffler return 0; 547517f3f177SSam Leffler } 547617f3f177SSam Leffler 5477bd5a9920SSam Leffler static int 5478bd5a9920SSam Leffler ath_sysctl_tpack(SYSCTL_HANDLER_ARGS) 5479bd5a9920SSam Leffler { 5480bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5481bd5a9920SSam Leffler u_int32_t tpack; 5482bd5a9920SSam Leffler int error; 5483bd5a9920SSam Leffler 5484bd5a9920SSam Leffler ath_hal_gettpack(sc->sc_ah, &tpack); 5485bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &tpack, 0, req); 5486bd5a9920SSam Leffler if (error || !req->newptr) 5487bd5a9920SSam Leffler return error; 5488bd5a9920SSam Leffler return !ath_hal_settpack(sc->sc_ah, tpack) ? EINVAL : 0; 5489bd5a9920SSam Leffler } 5490bd5a9920SSam Leffler 5491bd5a9920SSam Leffler static int 5492bd5a9920SSam Leffler ath_sysctl_tpcts(SYSCTL_HANDLER_ARGS) 5493bd5a9920SSam Leffler { 5494bd5a9920SSam Leffler struct ath_softc *sc = arg1; 5495bd5a9920SSam Leffler u_int32_t tpcts; 5496bd5a9920SSam Leffler int error; 5497bd5a9920SSam Leffler 5498bd5a9920SSam Leffler ath_hal_gettpcts(sc->sc_ah, &tpcts); 5499bd5a9920SSam Leffler error = sysctl_handle_int(oidp, &tpcts, 0, req); 5500bd5a9920SSam Leffler if (error || !req->newptr) 5501bd5a9920SSam Leffler return error; 5502bd5a9920SSam Leffler return !ath_hal_settpcts(sc->sc_ah, tpcts) ? EINVAL : 0; 5503bd5a9920SSam Leffler } 5504bd5a9920SSam Leffler 5505c42a7b7eSSam Leffler static void 5506c42a7b7eSSam Leffler ath_sysctlattach(struct ath_softc *sc) 5507c42a7b7eSSam Leffler { 5508c42a7b7eSSam Leffler struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 5509c42a7b7eSSam Leffler struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 5510c59005e9SSam Leffler struct ath_hal *ah = sc->sc_ah; 5511c42a7b7eSSam Leffler 5512aaa70f2fSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5513aaa70f2fSSam Leffler "countrycode", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5514aaa70f2fSSam Leffler ath_sysctl_countrycode, "I", "country code"); 551517f3f177SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 551617f3f177SSam Leffler "regdomain", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 551717f3f177SSam Leffler ath_sysctl_regdomain, "I", "EEPROM regdomain code"); 5518a585a9a1SSam Leffler #ifdef ATH_DEBUG 5519c42a7b7eSSam Leffler sc->sc_debug = ath_debug; 5520c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5521c42a7b7eSSam Leffler "debug", CTLFLAG_RW, &sc->sc_debug, 0, 5522c42a7b7eSSam Leffler "control debugging printfs"); 5523d2f6ed15SSam Leffler #endif 5524c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5525c42a7b7eSSam Leffler "slottime", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5526c42a7b7eSSam Leffler ath_sysctl_slottime, "I", "802.11 slot time (us)"); 5527c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5528c42a7b7eSSam Leffler "acktimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5529c42a7b7eSSam Leffler ath_sysctl_acktimeout, "I", "802.11 ACK timeout (us)"); 5530c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5531c42a7b7eSSam Leffler "ctstimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5532c42a7b7eSSam Leffler ath_sysctl_ctstimeout, "I", "802.11 CTS timeout (us)"); 5533c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5534c42a7b7eSSam Leffler "softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5535c42a7b7eSSam Leffler ath_sysctl_softled, "I", "enable/disable software LED support"); 5536c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5537c42a7b7eSSam Leffler "ledpin", CTLFLAG_RW, &sc->sc_ledpin, 0, 5538c42a7b7eSSam Leffler "GPIO pin connected to LED"); 5539c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 55403e50ec2cSSam Leffler "ledon", CTLFLAG_RW, &sc->sc_ledon, 0, 55413e50ec2cSSam Leffler "setting to turn LED on"); 55423e50ec2cSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 55433e50ec2cSSam Leffler "ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0, 55443e50ec2cSSam Leffler "idle time for inactivity LED (ticks)"); 55453e50ec2cSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5546c42a7b7eSSam Leffler "txantenna", CTLFLAG_RW, &sc->sc_txantenna, 0, 5547c42a7b7eSSam Leffler "tx antenna (0=auto)"); 5548c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5549c42a7b7eSSam Leffler "rxantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5550c42a7b7eSSam Leffler ath_sysctl_rxantenna, "I", "default/rx antenna"); 5551c59005e9SSam Leffler if (ath_hal_hasdiversity(ah)) 5552c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5553c42a7b7eSSam Leffler "diversity", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5554c42a7b7eSSam Leffler ath_sysctl_diversity, "I", "antenna diversity"); 5555c42a7b7eSSam Leffler sc->sc_txintrperiod = ATH_TXINTR_PERIOD; 5556c42a7b7eSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5557c42a7b7eSSam Leffler "txintrperiod", CTLFLAG_RW, &sc->sc_txintrperiod, 0, 5558c42a7b7eSSam Leffler "tx descriptor batching"); 5559c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5560c42a7b7eSSam Leffler "diag", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5561c42a7b7eSSam Leffler ath_sysctl_diag, "I", "h/w diagnostic control"); 5562c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5563c42a7b7eSSam Leffler "tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5564c42a7b7eSSam Leffler ath_sysctl_tpscale, "I", "tx power scaling"); 5565bd5a9920SSam Leffler if (ath_hal_hastpc(ah)) { 5566c42a7b7eSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5567c42a7b7eSSam Leffler "tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5568c42a7b7eSSam Leffler ath_sysctl_tpc, "I", "enable/disable per-packet TPC"); 5569bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5570bd5a9920SSam Leffler "tpack", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5571bd5a9920SSam Leffler ath_sysctl_tpack, "I", "tx power for ack frames"); 5572bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5573bd5a9920SSam Leffler "tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5574bd5a9920SSam Leffler ath_sysctl_tpcts, "I", "tx power for cts frames"); 5575bd5a9920SSam Leffler } 5576bd5a9920SSam Leffler if (ath_hal_hasrfsilent(ah)) { 5577bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5578bd5a9920SSam Leffler "rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5579bd5a9920SSam Leffler ath_sysctl_rfsilent, "I", "h/w RF silent config"); 5580bd5a9920SSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 5581bd5a9920SSam Leffler "rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 5582bd5a9920SSam Leffler ath_sysctl_rfkill, "I", "enable/disable RF kill switch"); 5583bd5a9920SSam Leffler } 55847b0c77ecSSam Leffler sc->sc_monpass = HAL_RXERR_DECRYPT | HAL_RXERR_MIC; 55857b0c77ecSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 55867b0c77ecSSam Leffler "monpass", CTLFLAG_RW, &sc->sc_monpass, 0, 55877b0c77ecSSam Leffler "mask of error frames to pass when monitoring"); 5588c42a7b7eSSam Leffler } 5589c42a7b7eSSam Leffler 5590c42a7b7eSSam Leffler static void 5591c42a7b7eSSam Leffler ath_bpfattach(struct ath_softc *sc) 5592c42a7b7eSSam Leffler { 5593fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5594c42a7b7eSSam Leffler 5595c42a7b7eSSam Leffler bpfattach2(ifp, DLT_IEEE802_11_RADIO, 5596c42a7b7eSSam Leffler sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th), 5597c42a7b7eSSam Leffler &sc->sc_drvbpf); 5598c42a7b7eSSam Leffler /* 5599c42a7b7eSSam Leffler * Initialize constant fields. 5600c42a7b7eSSam Leffler * XXX make header lengths a multiple of 32-bits so subsequent 5601c42a7b7eSSam Leffler * headers are properly aligned; this is a kludge to keep 5602c42a7b7eSSam Leffler * certain applications happy. 5603c42a7b7eSSam Leffler * 5604c42a7b7eSSam Leffler * NB: the channel is setup each time we transition to the 5605c42a7b7eSSam Leffler * RUN state to avoid filling it in for each frame. 5606c42a7b7eSSam Leffler */ 5607c42a7b7eSSam Leffler sc->sc_tx_th_len = roundup(sizeof(sc->sc_tx_th), sizeof(u_int32_t)); 5608c42a7b7eSSam Leffler sc->sc_tx_th.wt_ihdr.it_len = htole16(sc->sc_tx_th_len); 5609c42a7b7eSSam Leffler sc->sc_tx_th.wt_ihdr.it_present = htole32(ATH_TX_RADIOTAP_PRESENT); 5610c42a7b7eSSam Leffler 5611d3be6f5bSSam Leffler sc->sc_rx_th_len = roundup(sizeof(sc->sc_rx_th), sizeof(u_int32_t)); 5612d3be6f5bSSam Leffler sc->sc_rx_th.wr_ihdr.it_len = htole16(sc->sc_rx_th_len); 5613c42a7b7eSSam Leffler sc->sc_rx_th.wr_ihdr.it_present = htole32(ATH_RX_RADIOTAP_PRESENT); 5614c42a7b7eSSam Leffler } 5615c42a7b7eSSam Leffler 5616664443d0SSam Leffler static int 5617664443d0SSam Leffler ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, 5618664443d0SSam Leffler struct ath_buf *bf, struct mbuf *m0, 5619664443d0SSam Leffler const struct ieee80211_bpf_params *params) 5620664443d0SSam Leffler { 5621664443d0SSam Leffler struct ieee80211com *ic = &sc->sc_ic; 5622664443d0SSam Leffler struct ath_hal *ah = sc->sc_ah; 5623664443d0SSam Leffler int error, ismcast, ismrr; 5624664443d0SSam Leffler int hdrlen, pktlen, try0, txantenna; 5625664443d0SSam Leffler u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3; 5626664443d0SSam Leffler struct ath_txq *txq; 5627664443d0SSam Leffler struct ieee80211_frame *wh; 5628664443d0SSam Leffler u_int flags, ctsduration; 5629664443d0SSam Leffler HAL_PKT_TYPE atype; 5630664443d0SSam Leffler const HAL_RATE_TABLE *rt; 5631664443d0SSam Leffler struct ath_desc *ds; 5632664443d0SSam Leffler u_int pri; 5633664443d0SSam Leffler 5634664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 5635664443d0SSam Leffler ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 5636664443d0SSam Leffler hdrlen = ieee80211_anyhdrsize(wh); 5637664443d0SSam Leffler /* 5638664443d0SSam Leffler * Packet length must not include any 5639664443d0SSam Leffler * pad bytes; deduct them here. 5640664443d0SSam Leffler */ 5641664443d0SSam Leffler /* XXX honor IEEE80211_BPF_DATAPAD */ 5642664443d0SSam Leffler pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN; 5643664443d0SSam Leffler 5644664443d0SSam Leffler error = ath_tx_dmasetup(sc, bf, m0); 5645664443d0SSam Leffler if (error != 0) 5646664443d0SSam Leffler return error; 5647664443d0SSam Leffler m0 = bf->bf_m; /* NB: may have changed */ 5648664443d0SSam Leffler wh = mtod(m0, struct ieee80211_frame *); 5649664443d0SSam Leffler bf->bf_node = ni; /* NB: held reference */ 5650664443d0SSam Leffler 5651664443d0SSam Leffler flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ 5652664443d0SSam Leffler flags |= HAL_TXDESC_INTREQ; /* force interrupt */ 5653664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_RTS) 5654664443d0SSam Leffler flags |= HAL_TXDESC_RTSENA; 5655664443d0SSam Leffler else if (params->ibp_flags & IEEE80211_BPF_CTS) 5656664443d0SSam Leffler flags |= HAL_TXDESC_CTSENA; 5657664443d0SSam Leffler /* XXX leave ismcast to injector? */ 5658664443d0SSam Leffler if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast) 5659664443d0SSam Leffler flags |= HAL_TXDESC_NOACK; 5660664443d0SSam Leffler 5661664443d0SSam Leffler rt = sc->sc_currates; 5662664443d0SSam Leffler KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); 5663664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate0); 5664664443d0SSam Leffler txrate = rt->info[rix].rateCode; 5665664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5666664443d0SSam Leffler txrate |= rt->info[rix].shortPreamble; 56676bf62dd1SSam Leffler sc->sc_txrate = txrate; 5668664443d0SSam Leffler try0 = params->ibp_try0; 5669664443d0SSam Leffler ismrr = (params->ibp_try1 != 0); 5670664443d0SSam Leffler txantenna = params->ibp_pri >> 2; 5671664443d0SSam Leffler if (txantenna == 0) /* XXX? */ 5672664443d0SSam Leffler txantenna = sc->sc_txantenna; 5673664443d0SSam Leffler ctsduration = 0; 5674664443d0SSam Leffler if (flags & (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) { 5675664443d0SSam Leffler cix = ath_tx_findrix(rt, params->ibp_ctsrate); 5676664443d0SSam Leffler ctsrate = rt->info[cix].rateCode; 5677664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) { 5678664443d0SSam Leffler ctsrate |= rt->info[cix].shortPreamble; 5679664443d0SSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 5680664443d0SSam Leffler ctsduration += rt->info[cix].spAckDuration; 5681664443d0SSam Leffler ctsduration += ath_hal_computetxtime(ah, 5682664443d0SSam Leffler rt, pktlen, rix, AH_TRUE); 5683664443d0SSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 5684664443d0SSam Leffler ctsduration += rt->info[rix].spAckDuration; 5685664443d0SSam Leffler } else { 5686664443d0SSam Leffler if (flags & HAL_TXDESC_RTSENA) /* SIFS + CTS */ 5687664443d0SSam Leffler ctsduration += rt->info[cix].lpAckDuration; 5688664443d0SSam Leffler ctsduration += ath_hal_computetxtime(ah, 5689664443d0SSam Leffler rt, pktlen, rix, AH_FALSE); 5690664443d0SSam Leffler if ((flags & HAL_TXDESC_NOACK) == 0) /* SIFS + ACK */ 5691664443d0SSam Leffler ctsduration += rt->info[rix].lpAckDuration; 5692664443d0SSam Leffler } 5693664443d0SSam Leffler ismrr = 0; /* XXX */ 5694664443d0SSam Leffler } else 5695664443d0SSam Leffler ctsrate = 0; 5696664443d0SSam Leffler pri = params->ibp_pri & 3; 5697664443d0SSam Leffler /* 5698664443d0SSam Leffler * NB: we mark all packets as type PSPOLL so the h/w won't 5699664443d0SSam Leffler * set the sequence number, duration, etc. 5700664443d0SSam Leffler */ 5701664443d0SSam Leffler atype = HAL_PKT_TYPE_PSPOLL; 5702664443d0SSam Leffler 5703664443d0SSam Leffler if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT)) 5704664443d0SSam Leffler ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len, 5705664443d0SSam Leffler sc->sc_hwmap[txrate].ieeerate, -1); 5706664443d0SSam Leffler 5707664443d0SSam Leffler if (bpf_peers_present(ic->ic_rawbpf)) 5708664443d0SSam Leffler bpf_mtap(ic->ic_rawbpf, m0); 5709664443d0SSam Leffler if (bpf_peers_present(sc->sc_drvbpf)) { 5710664443d0SSam Leffler u_int64_t tsf = ath_hal_gettsf64(ah); 5711664443d0SSam Leffler 5712664443d0SSam Leffler sc->sc_tx_th.wt_tsf = htole64(tsf); 5713664443d0SSam Leffler sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags; 5714664443d0SSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) 5715664443d0SSam Leffler sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; 5716664443d0SSam Leffler sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate; 5717664443d0SSam Leffler sc->sc_tx_th.wt_txpower = ni->ni_txpower; 5718664443d0SSam Leffler sc->sc_tx_th.wt_antenna = sc->sc_txantenna; 5719664443d0SSam Leffler 5720664443d0SSam Leffler bpf_mtap2(sc->sc_drvbpf, 5721664443d0SSam Leffler &sc->sc_tx_th, sc->sc_tx_th_len, m0); 5722664443d0SSam Leffler } 5723664443d0SSam Leffler 5724664443d0SSam Leffler /* 5725664443d0SSam Leffler * Formulate first tx descriptor with tx controls. 5726664443d0SSam Leffler */ 5727664443d0SSam Leffler ds = bf->bf_desc; 5728664443d0SSam Leffler /* XXX check return value? */ 5729664443d0SSam Leffler ath_hal_setuptxdesc(ah, ds 5730664443d0SSam Leffler , pktlen /* packet length */ 5731664443d0SSam Leffler , hdrlen /* header length */ 5732664443d0SSam Leffler , atype /* Atheros packet type */ 5733664443d0SSam Leffler , params->ibp_power /* txpower */ 5734664443d0SSam Leffler , txrate, try0 /* series 0 rate/tries */ 5735664443d0SSam Leffler , HAL_TXKEYIX_INVALID /* key cache index */ 5736664443d0SSam Leffler , txantenna /* antenna mode */ 5737664443d0SSam Leffler , flags /* flags */ 5738664443d0SSam Leffler , ctsrate /* rts/cts rate */ 5739664443d0SSam Leffler , ctsduration /* rts/cts duration */ 5740664443d0SSam Leffler ); 5741664443d0SSam Leffler bf->bf_flags = flags; 5742664443d0SSam Leffler 5743664443d0SSam Leffler if (ismrr) { 5744664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate1); 5745664443d0SSam Leffler rate1 = rt->info[rix].rateCode; 5746664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5747664443d0SSam Leffler rate1 |= rt->info[rix].shortPreamble; 5748664443d0SSam Leffler if (params->ibp_try2) { 5749664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate2); 5750664443d0SSam Leffler rate2 = rt->info[rix].rateCode; 5751664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5752664443d0SSam Leffler rate2 |= rt->info[rix].shortPreamble; 5753664443d0SSam Leffler } else 5754664443d0SSam Leffler rate2 = 0; 5755664443d0SSam Leffler if (params->ibp_try3) { 5756664443d0SSam Leffler rix = ath_tx_findrix(rt, params->ibp_rate3); 5757664443d0SSam Leffler rate3 = rt->info[rix].rateCode; 5758664443d0SSam Leffler if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) 5759664443d0SSam Leffler rate3 |= rt->info[rix].shortPreamble; 5760664443d0SSam Leffler } else 5761664443d0SSam Leffler rate3 = 0; 5762664443d0SSam Leffler ath_hal_setupxtxdesc(ah, ds 5763664443d0SSam Leffler , rate1, params->ibp_try1 /* series 1 */ 5764664443d0SSam Leffler , rate2, params->ibp_try2 /* series 2 */ 5765664443d0SSam Leffler , rate3, params->ibp_try3 /* series 3 */ 5766664443d0SSam Leffler ); 5767664443d0SSam Leffler } 5768664443d0SSam Leffler 5769664443d0SSam Leffler /* 5770664443d0SSam Leffler * When servicing one or more stations in power-save mode 5771664443d0SSam Leffler * (or) if there is some mcast data waiting on the mcast 5772664443d0SSam Leffler * queue (to prevent out of order delivery) multicast 5773664443d0SSam Leffler * frames must be buffered until after the beacon. 5774664443d0SSam Leffler */ 5775664443d0SSam Leffler txq = sc->sc_ac2q[pri]; 5776664443d0SSam Leffler if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth)) 5777664443d0SSam Leffler txq = &sc->sc_mcastq; 5778664443d0SSam Leffler ath_tx_handoff(sc, txq, bf); 5779664443d0SSam Leffler return 0; 5780664443d0SSam Leffler } 5781664443d0SSam Leffler 5782664443d0SSam Leffler static int 5783664443d0SSam Leffler ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 5784664443d0SSam Leffler const struct ieee80211_bpf_params *params) 5785664443d0SSam Leffler { 5786664443d0SSam Leffler struct ieee80211com *ic = ni->ni_ic; 5787664443d0SSam Leffler struct ifnet *ifp = ic->ic_ifp; 5788664443d0SSam Leffler struct ath_softc *sc = ifp->if_softc; 5789664443d0SSam Leffler struct ath_buf *bf; 5790664443d0SSam Leffler 5791664443d0SSam Leffler if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { 5792664443d0SSam Leffler m_freem(m); 5793664443d0SSam Leffler return ENETDOWN; 5794664443d0SSam Leffler } 5795664443d0SSam Leffler /* 5796664443d0SSam Leffler * Grab a TX buffer and associated resources. 5797664443d0SSam Leffler */ 5798664443d0SSam Leffler ATH_TXBUF_LOCK(sc); 5799664443d0SSam Leffler bf = STAILQ_FIRST(&sc->sc_txbuf); 5800664443d0SSam Leffler if (bf != NULL) 5801664443d0SSam Leffler STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); 5802664443d0SSam Leffler ATH_TXBUF_UNLOCK(sc); 5803664443d0SSam Leffler if (bf == NULL) { 5804664443d0SSam Leffler DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", 5805664443d0SSam Leffler __func__); 5806664443d0SSam Leffler sc->sc_stats.ast_tx_qstop++; 5807664443d0SSam Leffler ifp->if_drv_flags |= IFF_DRV_OACTIVE; 5808664443d0SSam Leffler m_freem(m); 5809664443d0SSam Leffler return ENOBUFS; 5810664443d0SSam Leffler } 5811664443d0SSam Leffler 5812664443d0SSam Leffler ifp->if_opackets++; 5813664443d0SSam Leffler sc->sc_stats.ast_tx_raw++; 5814664443d0SSam Leffler 5815664443d0SSam Leffler if (params == NULL) { 5816664443d0SSam Leffler /* 5817664443d0SSam Leffler * Legacy path; interpret frame contents to decide 5818664443d0SSam Leffler * precisely how to send the frame. 5819664443d0SSam Leffler */ 5820664443d0SSam Leffler if (ath_tx_start(sc, ni, bf, m)) 5821664443d0SSam Leffler goto bad; 5822664443d0SSam Leffler } else { 5823664443d0SSam Leffler /* 5824664443d0SSam Leffler * Caller supplied explicit parameters to use in 5825664443d0SSam Leffler * sending the frame. 5826664443d0SSam Leffler */ 5827664443d0SSam Leffler if (ath_tx_raw_start(sc, ni, bf, m, params)) 5828664443d0SSam Leffler goto bad; 5829664443d0SSam Leffler } 5830664443d0SSam Leffler sc->sc_tx_timer = 5; 5831664443d0SSam Leffler ifp->if_timer = 1; 5832664443d0SSam Leffler 5833664443d0SSam Leffler return 0; 5834664443d0SSam Leffler bad: 5835664443d0SSam Leffler ifp->if_oerrors++; 5836664443d0SSam Leffler ATH_TXBUF_LOCK(sc); 5837664443d0SSam Leffler STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); 5838664443d0SSam Leffler ATH_TXBUF_UNLOCK(sc); 5839664443d0SSam Leffler ieee80211_free_node(ni); 5840664443d0SSam Leffler return EIO; /* XXX */ 5841664443d0SSam Leffler } 5842664443d0SSam Leffler 5843c42a7b7eSSam Leffler /* 5844c42a7b7eSSam Leffler * Announce various information on device/driver attach. 5845c42a7b7eSSam Leffler */ 5846c42a7b7eSSam Leffler static void 5847c42a7b7eSSam Leffler ath_announce(struct ath_softc *sc) 5848c42a7b7eSSam Leffler { 5849c42a7b7eSSam Leffler #define HAL_MODE_DUALBAND (HAL_MODE_11A|HAL_MODE_11B) 5850fc74a9f9SBrooks Davis struct ifnet *ifp = sc->sc_ifp; 5851c42a7b7eSSam Leffler struct ath_hal *ah = sc->sc_ah; 5852c42a7b7eSSam Leffler u_int modes, cc; 5853c42a7b7eSSam Leffler 5854c42a7b7eSSam Leffler if_printf(ifp, "mac %d.%d phy %d.%d", 5855c42a7b7eSSam Leffler ah->ah_macVersion, ah->ah_macRev, 5856c42a7b7eSSam Leffler ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf); 5857c42a7b7eSSam Leffler /* 5858c42a7b7eSSam Leffler * Print radio revision(s). We check the wireless modes 5859c42a7b7eSSam Leffler * to avoid falsely printing revs for inoperable parts. 5860c42a7b7eSSam Leffler * Dual-band radio revs are returned in the 5Ghz rev number. 5861c42a7b7eSSam Leffler */ 5862c42a7b7eSSam Leffler ath_hal_getcountrycode(ah, &cc); 5863c42a7b7eSSam Leffler modes = ath_hal_getwirelessmodes(ah, cc); 5864c42a7b7eSSam Leffler if ((modes & HAL_MODE_DUALBAND) == HAL_MODE_DUALBAND) { 5865c42a7b7eSSam Leffler if (ah->ah_analog5GhzRev && ah->ah_analog2GhzRev) 5866c42a7b7eSSam Leffler printf(" 5ghz radio %d.%d 2ghz radio %d.%d", 5867c42a7b7eSSam Leffler ah->ah_analog5GhzRev >> 4, 5868c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf, 5869c42a7b7eSSam Leffler ah->ah_analog2GhzRev >> 4, 5870c42a7b7eSSam Leffler ah->ah_analog2GhzRev & 0xf); 5871c42a7b7eSSam Leffler else 5872c42a7b7eSSam Leffler printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4, 5873c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf); 5874c42a7b7eSSam Leffler } else 5875c42a7b7eSSam Leffler printf(" radio %d.%d", ah->ah_analog5GhzRev >> 4, 5876c42a7b7eSSam Leffler ah->ah_analog5GhzRev & 0xf); 5877c42a7b7eSSam Leffler printf("\n"); 5878c42a7b7eSSam Leffler if (bootverbose) { 5879c42a7b7eSSam Leffler int i; 5880c42a7b7eSSam Leffler for (i = 0; i <= WME_AC_VO; i++) { 5881c42a7b7eSSam Leffler struct ath_txq *txq = sc->sc_ac2q[i]; 5882c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for %s traffic\n", 5883c42a7b7eSSam Leffler txq->axq_qnum, ieee80211_wme_acnames[i]); 5884c42a7b7eSSam Leffler } 5885c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for CAB traffic\n", 5886c42a7b7eSSam Leffler sc->sc_cabq->axq_qnum); 5887c42a7b7eSSam Leffler if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq); 5888c42a7b7eSSam Leffler } 5889e2d787faSSam Leffler if (ath_rxbuf != ATH_RXBUF) 5890e2d787faSSam Leffler if_printf(ifp, "using %u rx buffers\n", ath_rxbuf); 5891e2d787faSSam Leffler if (ath_txbuf != ATH_TXBUF) 5892e2d787faSSam Leffler if_printf(ifp, "using %u tx buffers\n", ath_txbuf); 5893c42a7b7eSSam Leffler #undef HAL_MODE_DUALBAND 5894c42a7b7eSSam Leffler } 5895