1*b45de1ebSAdrian Chadd /*- 2*b45de1ebSAdrian Chadd * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3*b45de1ebSAdrian Chadd * All rights reserved. 4*b45de1ebSAdrian Chadd * 5*b45de1ebSAdrian Chadd * Redistribution and use in source and binary forms, with or without 6*b45de1ebSAdrian Chadd * modification, are permitted provided that the following conditions 7*b45de1ebSAdrian Chadd * are met: 8*b45de1ebSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9*b45de1ebSAdrian Chadd * notice, this list of conditions and the following disclaimer, 10*b45de1ebSAdrian Chadd * without modification. 11*b45de1ebSAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*b45de1ebSAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13*b45de1ebSAdrian Chadd * redistribution must be conditioned upon including a substantially 14*b45de1ebSAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 15*b45de1ebSAdrian Chadd * 16*b45de1ebSAdrian Chadd * NO WARRANTY 17*b45de1ebSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*b45de1ebSAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*b45de1ebSAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20*b45de1ebSAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21*b45de1ebSAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22*b45de1ebSAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*b45de1ebSAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*b45de1ebSAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25*b45de1ebSAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*b45de1ebSAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27*b45de1ebSAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 28*b45de1ebSAdrian Chadd */ 29*b45de1ebSAdrian Chadd 30*b45de1ebSAdrian Chadd #include <sys/cdefs.h> 31*b45de1ebSAdrian Chadd __FBSDID("$FreeBSD$"); 32*b45de1ebSAdrian Chadd 33*b45de1ebSAdrian Chadd /* 34*b45de1ebSAdrian Chadd * Driver for the Atheros Wireless LAN controller. 35*b45de1ebSAdrian Chadd * 36*b45de1ebSAdrian Chadd * This software is derived from work of Atsushi Onoe; his contribution 37*b45de1ebSAdrian Chadd * is greatly appreciated. 38*b45de1ebSAdrian Chadd */ 39*b45de1ebSAdrian Chadd 40*b45de1ebSAdrian Chadd #include "opt_inet.h" 41*b45de1ebSAdrian Chadd #include "opt_ath.h" 42*b45de1ebSAdrian Chadd /* 43*b45de1ebSAdrian Chadd * This is needed for register operations which are performed 44*b45de1ebSAdrian Chadd * by the driver - eg, calls to ath_hal_gettsf32(). 45*b45de1ebSAdrian Chadd * 46*b45de1ebSAdrian Chadd * It's also required for any AH_DEBUG checks in here, eg the 47*b45de1ebSAdrian Chadd * module dependencies. 48*b45de1ebSAdrian Chadd */ 49*b45de1ebSAdrian Chadd #include "opt_ah.h" 50*b45de1ebSAdrian Chadd #include "opt_wlan.h" 51*b45de1ebSAdrian Chadd 52*b45de1ebSAdrian Chadd #include <sys/param.h> 53*b45de1ebSAdrian Chadd #include <sys/systm.h> 54*b45de1ebSAdrian Chadd #include <sys/sysctl.h> 55*b45de1ebSAdrian Chadd #include <sys/mbuf.h> 56*b45de1ebSAdrian Chadd #include <sys/malloc.h> 57*b45de1ebSAdrian Chadd #include <sys/lock.h> 58*b45de1ebSAdrian Chadd #include <sys/mutex.h> 59*b45de1ebSAdrian Chadd #include <sys/kernel.h> 60*b45de1ebSAdrian Chadd #include <sys/socket.h> 61*b45de1ebSAdrian Chadd #include <sys/sockio.h> 62*b45de1ebSAdrian Chadd #include <sys/errno.h> 63*b45de1ebSAdrian Chadd #include <sys/callout.h> 64*b45de1ebSAdrian Chadd #include <sys/bus.h> 65*b45de1ebSAdrian Chadd #include <sys/endian.h> 66*b45de1ebSAdrian Chadd #include <sys/kthread.h> 67*b45de1ebSAdrian Chadd #include <sys/taskqueue.h> 68*b45de1ebSAdrian Chadd #include <sys/priv.h> 69*b45de1ebSAdrian Chadd #include <sys/module.h> 70*b45de1ebSAdrian Chadd #include <sys/ktr.h> 71*b45de1ebSAdrian Chadd #include <sys/smp.h> /* for mp_ncpus */ 72*b45de1ebSAdrian Chadd 73*b45de1ebSAdrian Chadd #include <machine/bus.h> 74*b45de1ebSAdrian Chadd 75*b45de1ebSAdrian Chadd #include <net/if.h> 76*b45de1ebSAdrian Chadd #include <net/if_var.h> 77*b45de1ebSAdrian Chadd #include <net/if_dl.h> 78*b45de1ebSAdrian Chadd #include <net/if_media.h> 79*b45de1ebSAdrian Chadd #include <net/if_types.h> 80*b45de1ebSAdrian Chadd #include <net/if_arp.h> 81*b45de1ebSAdrian Chadd #include <net/ethernet.h> 82*b45de1ebSAdrian Chadd #include <net/if_llc.h> 83*b45de1ebSAdrian Chadd 84*b45de1ebSAdrian Chadd #include <net80211/ieee80211_var.h> 85*b45de1ebSAdrian Chadd #include <net80211/ieee80211_regdomain.h> 86*b45de1ebSAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG 87*b45de1ebSAdrian Chadd #include <net80211/ieee80211_superg.h> 88*b45de1ebSAdrian Chadd #endif 89*b45de1ebSAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 90*b45de1ebSAdrian Chadd #include <net80211/ieee80211_tdma.h> 91*b45de1ebSAdrian Chadd #endif 92*b45de1ebSAdrian Chadd 93*b45de1ebSAdrian Chadd #include <net/bpf.h> 94*b45de1ebSAdrian Chadd 95*b45de1ebSAdrian Chadd #ifdef INET 96*b45de1ebSAdrian Chadd #include <netinet/in.h> 97*b45de1ebSAdrian Chadd #include <netinet/if_ether.h> 98*b45de1ebSAdrian Chadd #endif 99*b45de1ebSAdrian Chadd 100*b45de1ebSAdrian Chadd #include <dev/ath/if_athvar.h> 101*b45de1ebSAdrian Chadd #include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */ 102*b45de1ebSAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h> 103*b45de1ebSAdrian Chadd 104*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_debug.h> 105*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_misc.h> 106*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_btcoex.h> 107*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_spectral.h> 108*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_lna_div.h> 109*b45de1ebSAdrian Chadd #include <dev/ath/if_athdfs.h> 110*b45de1ebSAdrian Chadd 111*b45de1ebSAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 112*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_tdma.h> 113*b45de1ebSAdrian Chadd #endif 114*b45de1ebSAdrian Chadd 115*b45de1ebSAdrian Chadd #include <dev/ath/if_ath_ioctl.h> 116*b45de1ebSAdrian Chadd 117*b45de1ebSAdrian Chadd /* 118*b45de1ebSAdrian Chadd * ioctl() related pieces. 119*b45de1ebSAdrian Chadd * 120*b45de1ebSAdrian Chadd * Some subsystems (eg spectral, dfs) have their own ioctl method which 121*b45de1ebSAdrian Chadd * we call. 122*b45de1ebSAdrian Chadd */ 123*b45de1ebSAdrian Chadd 124*b45de1ebSAdrian Chadd /* 125*b45de1ebSAdrian Chadd * Fetch the rate control statistics for the given node. 126*b45de1ebSAdrian Chadd */ 127*b45de1ebSAdrian Chadd static int 128*b45de1ebSAdrian Chadd ath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs) 129*b45de1ebSAdrian Chadd { 130*b45de1ebSAdrian Chadd struct ath_node *an; 131*b45de1ebSAdrian Chadd struct ieee80211com *ic = &sc->sc_ic; 132*b45de1ebSAdrian Chadd struct ieee80211_node *ni; 133*b45de1ebSAdrian Chadd int error = 0; 134*b45de1ebSAdrian Chadd 135*b45de1ebSAdrian Chadd /* Perform a lookup on the given node */ 136*b45de1ebSAdrian Chadd ni = ieee80211_find_node(&ic->ic_sta, rs->is_u.macaddr); 137*b45de1ebSAdrian Chadd if (ni == NULL) { 138*b45de1ebSAdrian Chadd error = EINVAL; 139*b45de1ebSAdrian Chadd goto bad; 140*b45de1ebSAdrian Chadd } 141*b45de1ebSAdrian Chadd 142*b45de1ebSAdrian Chadd /* Lock the ath_node */ 143*b45de1ebSAdrian Chadd an = ATH_NODE(ni); 144*b45de1ebSAdrian Chadd ATH_NODE_LOCK(an); 145*b45de1ebSAdrian Chadd 146*b45de1ebSAdrian Chadd /* Fetch the rate control stats for this node */ 147*b45de1ebSAdrian Chadd error = ath_rate_fetch_node_stats(sc, an, rs); 148*b45de1ebSAdrian Chadd 149*b45de1ebSAdrian Chadd /* No matter what happens here, just drop through */ 150*b45de1ebSAdrian Chadd 151*b45de1ebSAdrian Chadd /* Unlock the ath_node */ 152*b45de1ebSAdrian Chadd ATH_NODE_UNLOCK(an); 153*b45de1ebSAdrian Chadd 154*b45de1ebSAdrian Chadd /* Unref the node */ 155*b45de1ebSAdrian Chadd ieee80211_node_decref(ni); 156*b45de1ebSAdrian Chadd 157*b45de1ebSAdrian Chadd bad: 158*b45de1ebSAdrian Chadd return (error); 159*b45de1ebSAdrian Chadd } 160*b45de1ebSAdrian Chadd 161*b45de1ebSAdrian Chadd #ifdef ATH_DIAGAPI 162*b45de1ebSAdrian Chadd /* 163*b45de1ebSAdrian Chadd * Diagnostic interface to the HAL. This is used by various 164*b45de1ebSAdrian Chadd * tools to do things like retrieve register contents for 165*b45de1ebSAdrian Chadd * debugging. The mechanism is intentionally opaque so that 166*b45de1ebSAdrian Chadd * it can change frequently w/o concern for compatiblity. 167*b45de1ebSAdrian Chadd */ 168*b45de1ebSAdrian Chadd static int 169*b45de1ebSAdrian Chadd ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) 170*b45de1ebSAdrian Chadd { 171*b45de1ebSAdrian Chadd struct ath_hal *ah = sc->sc_ah; 172*b45de1ebSAdrian Chadd u_int id = ad->ad_id & ATH_DIAG_ID; 173*b45de1ebSAdrian Chadd void *indata = NULL; 174*b45de1ebSAdrian Chadd void *outdata = NULL; 175*b45de1ebSAdrian Chadd u_int32_t insize = ad->ad_in_size; 176*b45de1ebSAdrian Chadd u_int32_t outsize = ad->ad_out_size; 177*b45de1ebSAdrian Chadd int error = 0; 178*b45de1ebSAdrian Chadd 179*b45de1ebSAdrian Chadd if (ad->ad_id & ATH_DIAG_IN) { 180*b45de1ebSAdrian Chadd /* 181*b45de1ebSAdrian Chadd * Copy in data. 182*b45de1ebSAdrian Chadd */ 183*b45de1ebSAdrian Chadd indata = malloc(insize, M_TEMP, M_NOWAIT); 184*b45de1ebSAdrian Chadd if (indata == NULL) { 185*b45de1ebSAdrian Chadd error = ENOMEM; 186*b45de1ebSAdrian Chadd goto bad; 187*b45de1ebSAdrian Chadd } 188*b45de1ebSAdrian Chadd error = copyin(ad->ad_in_data, indata, insize); 189*b45de1ebSAdrian Chadd if (error) 190*b45de1ebSAdrian Chadd goto bad; 191*b45de1ebSAdrian Chadd } 192*b45de1ebSAdrian Chadd if (ad->ad_id & ATH_DIAG_DYN) { 193*b45de1ebSAdrian Chadd /* 194*b45de1ebSAdrian Chadd * Allocate a buffer for the results (otherwise the HAL 195*b45de1ebSAdrian Chadd * returns a pointer to a buffer where we can read the 196*b45de1ebSAdrian Chadd * results). Note that we depend on the HAL leaving this 197*b45de1ebSAdrian Chadd * pointer for us to use below in reclaiming the buffer; 198*b45de1ebSAdrian Chadd * may want to be more defensive. 199*b45de1ebSAdrian Chadd */ 200*b45de1ebSAdrian Chadd outdata = malloc(outsize, M_TEMP, M_NOWAIT); 201*b45de1ebSAdrian Chadd if (outdata == NULL) { 202*b45de1ebSAdrian Chadd error = ENOMEM; 203*b45de1ebSAdrian Chadd goto bad; 204*b45de1ebSAdrian Chadd } 205*b45de1ebSAdrian Chadd } 206*b45de1ebSAdrian Chadd 207*b45de1ebSAdrian Chadd 208*b45de1ebSAdrian Chadd ATH_LOCK(sc); 209*b45de1ebSAdrian Chadd if (id != HAL_DIAG_REGS) 210*b45de1ebSAdrian Chadd ath_power_set_power_state(sc, HAL_PM_AWAKE); 211*b45de1ebSAdrian Chadd ATH_UNLOCK(sc); 212*b45de1ebSAdrian Chadd 213*b45de1ebSAdrian Chadd if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { 214*b45de1ebSAdrian Chadd if (outsize < ad->ad_out_size) 215*b45de1ebSAdrian Chadd ad->ad_out_size = outsize; 216*b45de1ebSAdrian Chadd if (outdata != NULL) 217*b45de1ebSAdrian Chadd error = copyout(outdata, ad->ad_out_data, 218*b45de1ebSAdrian Chadd ad->ad_out_size); 219*b45de1ebSAdrian Chadd } else { 220*b45de1ebSAdrian Chadd error = EINVAL; 221*b45de1ebSAdrian Chadd } 222*b45de1ebSAdrian Chadd 223*b45de1ebSAdrian Chadd ATH_LOCK(sc); 224*b45de1ebSAdrian Chadd if (id != HAL_DIAG_REGS) 225*b45de1ebSAdrian Chadd ath_power_restore_power_state(sc); 226*b45de1ebSAdrian Chadd ATH_UNLOCK(sc); 227*b45de1ebSAdrian Chadd 228*b45de1ebSAdrian Chadd bad: 229*b45de1ebSAdrian Chadd if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 230*b45de1ebSAdrian Chadd free(indata, M_TEMP); 231*b45de1ebSAdrian Chadd if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 232*b45de1ebSAdrian Chadd free(outdata, M_TEMP); 233*b45de1ebSAdrian Chadd return error; 234*b45de1ebSAdrian Chadd } 235*b45de1ebSAdrian Chadd #endif /* ATH_DIAGAPI */ 236*b45de1ebSAdrian Chadd 237*b45de1ebSAdrian Chadd int 238*b45de1ebSAdrian Chadd ath_ioctl(struct ieee80211com *ic, u_long cmd, void *data) 239*b45de1ebSAdrian Chadd { 240*b45de1ebSAdrian Chadd struct ifreq *ifr = data; 241*b45de1ebSAdrian Chadd struct ath_softc *sc = ic->ic_softc; 242*b45de1ebSAdrian Chadd 243*b45de1ebSAdrian Chadd switch (cmd) { 244*b45de1ebSAdrian Chadd case SIOCGATHSTATS: { 245*b45de1ebSAdrian Chadd struct ieee80211vap *vap; 246*b45de1ebSAdrian Chadd struct ifnet *ifp; 247*b45de1ebSAdrian Chadd const HAL_RATE_TABLE *rt; 248*b45de1ebSAdrian Chadd 249*b45de1ebSAdrian Chadd /* NB: embed these numbers to get a consistent view */ 250*b45de1ebSAdrian Chadd sc->sc_stats.ast_tx_packets = 0; 251*b45de1ebSAdrian Chadd sc->sc_stats.ast_rx_packets = 0; 252*b45de1ebSAdrian Chadd TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 253*b45de1ebSAdrian Chadd ifp = vap->iv_ifp; 254*b45de1ebSAdrian Chadd sc->sc_stats.ast_tx_packets += ifp->if_get_counter(ifp, 255*b45de1ebSAdrian Chadd IFCOUNTER_OPACKETS); 256*b45de1ebSAdrian Chadd sc->sc_stats.ast_rx_packets += ifp->if_get_counter(ifp, 257*b45de1ebSAdrian Chadd IFCOUNTER_IPACKETS); 258*b45de1ebSAdrian Chadd } 259*b45de1ebSAdrian Chadd sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi); 260*b45de1ebSAdrian Chadd sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi); 261*b45de1ebSAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA 262*b45de1ebSAdrian Chadd sc->sc_stats.ast_tdma_tsfadjp = TDMA_AVG(sc->sc_avgtsfdeltap); 263*b45de1ebSAdrian Chadd sc->sc_stats.ast_tdma_tsfadjm = TDMA_AVG(sc->sc_avgtsfdeltam); 264*b45de1ebSAdrian Chadd #endif 265*b45de1ebSAdrian Chadd rt = sc->sc_currates; 266*b45de1ebSAdrian Chadd sc->sc_stats.ast_tx_rate = 267*b45de1ebSAdrian Chadd rt->info[sc->sc_txrix].dot11Rate &~ IEEE80211_RATE_BASIC; 268*b45de1ebSAdrian Chadd if (rt->info[sc->sc_txrix].phy & IEEE80211_T_HT) 269*b45de1ebSAdrian Chadd sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS; 270*b45de1ebSAdrian Chadd return copyout(&sc->sc_stats, 271*b45de1ebSAdrian Chadd ifr->ifr_data, sizeof (sc->sc_stats)); 272*b45de1ebSAdrian Chadd } 273*b45de1ebSAdrian Chadd case SIOCGATHAGSTATS: 274*b45de1ebSAdrian Chadd return copyout(&sc->sc_aggr_stats, 275*b45de1ebSAdrian Chadd ifr->ifr_data, sizeof (sc->sc_aggr_stats)); 276*b45de1ebSAdrian Chadd case SIOCZATHSTATS: { 277*b45de1ebSAdrian Chadd int error; 278*b45de1ebSAdrian Chadd 279*b45de1ebSAdrian Chadd error = priv_check(curthread, PRIV_DRIVER); 280*b45de1ebSAdrian Chadd if (error == 0) { 281*b45de1ebSAdrian Chadd memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); 282*b45de1ebSAdrian Chadd memset(&sc->sc_aggr_stats, 0, 283*b45de1ebSAdrian Chadd sizeof(sc->sc_aggr_stats)); 284*b45de1ebSAdrian Chadd memset(&sc->sc_intr_stats, 0, 285*b45de1ebSAdrian Chadd sizeof(sc->sc_intr_stats)); 286*b45de1ebSAdrian Chadd } 287*b45de1ebSAdrian Chadd return (error); 288*b45de1ebSAdrian Chadd } 289*b45de1ebSAdrian Chadd #ifdef ATH_DIAGAPI 290*b45de1ebSAdrian Chadd case SIOCGATHDIAG: 291*b45de1ebSAdrian Chadd return (ath_ioctl_diag(sc, data)); 292*b45de1ebSAdrian Chadd case SIOCGATHPHYERR: 293*b45de1ebSAdrian Chadd return (ath_ioctl_phyerr(sc, data)); 294*b45de1ebSAdrian Chadd #endif 295*b45de1ebSAdrian Chadd case SIOCGATHSPECTRAL: 296*b45de1ebSAdrian Chadd return (ath_ioctl_spectral(sc, data)); 297*b45de1ebSAdrian Chadd case SIOCGATHNODERATESTATS: 298*b45de1ebSAdrian Chadd return (ath_ioctl_ratestats(sc, data)); 299*b45de1ebSAdrian Chadd default: 300*b45de1ebSAdrian Chadd /* 301*b45de1ebSAdrian Chadd * This signals the net80211 layer that we didn't handle this 302*b45de1ebSAdrian Chadd * ioctl. 303*b45de1ebSAdrian Chadd */ 304*b45de1ebSAdrian Chadd return (ENOTTY); 305*b45de1ebSAdrian Chadd } 306*b45de1ebSAdrian Chadd } 307*b45de1ebSAdrian Chadd 308