Annotation of sys/dev/ic/ath.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ath.c,v 1.66 2007/07/18 18:10:31 damien Exp $ */
! 2: /* $NetBSD: ath.c,v 1.37 2004/08/18 21:59:39 dyoung Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer,
! 13: * without modification.
! 14: * 2. Redistributions in binary form must reproduce at minimum a disclaimer
! 15: * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
! 16: * redistribution must be conditioned upon including a substantially
! 17: * similar Disclaimer requirement for further binary redistribution.
! 18: * 3. Neither the names of the above-listed copyright holders nor the names
! 19: * of any contributors may be used to endorse or promote products derived
! 20: * from this software without specific prior written permission.
! 21: *
! 22: * NO WARRANTY
! 23: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 24: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 25: * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
! 26: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 27: * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
! 28: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 29: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 30: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
! 31: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 32: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 33: * THE POSSIBILITY OF SUCH DAMAGES.
! 34: */
! 35:
! 36: /*
! 37: * Driver for the Atheros Wireless LAN controller.
! 38: *
! 39: * This software is derived from work of Atsushi Onoe; his contribution
! 40: * is greatly appreciated. It has been modified for OpenBSD to use an
! 41: * open source HAL instead of the original binary-only HAL.
! 42: */
! 43:
! 44: #include "bpfilter.h"
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/systm.h>
! 48: #include <sys/sysctl.h>
! 49: #include <sys/mbuf.h>
! 50: #include <sys/malloc.h>
! 51: #include <sys/lock.h>
! 52: #include <sys/kernel.h>
! 53: #include <sys/socket.h>
! 54: #include <sys/sockio.h>
! 55: #include <sys/device.h>
! 56: #include <sys/errno.h>
! 57: #include <sys/timeout.h>
! 58: #include <sys/gpio.h>
! 59:
! 60: #include <machine/endian.h>
! 61: #include <machine/bus.h>
! 62:
! 63: #include <net/if.h>
! 64: #include <net/if_dl.h>
! 65: #include <net/if_media.h>
! 66: #include <net/if_arp.h>
! 67: #include <net/if_llc.h>
! 68: #if NBPFILTER > 0
! 69: #include <net/bpf.h>
! 70: #endif
! 71: #ifdef INET
! 72: #include <netinet/in.h>
! 73: #include <netinet/if_ether.h>
! 74: #endif
! 75:
! 76: #include <net80211/ieee80211_var.h>
! 77: #include <net80211/ieee80211_rssadapt.h>
! 78:
! 79: #include <dev/pci/pcidevs.h>
! 80: #include <dev/gpio/gpiovar.h>
! 81: #include <dev/ic/athvar.h>
! 82:
! 83: int ath_init(struct ifnet *);
! 84: int ath_init1(struct ath_softc *);
! 85: int ath_intr1(struct ath_softc *);
! 86: void ath_stop(struct ifnet *);
! 87: void ath_start(struct ifnet *);
! 88: void ath_reset(struct ath_softc *, int);
! 89: int ath_media_change(struct ifnet *);
! 90: void ath_watchdog(struct ifnet *);
! 91: int ath_ioctl(struct ifnet *, u_long, caddr_t);
! 92: void ath_fatal_proc(void *, int);
! 93: void ath_rxorn_proc(void *, int);
! 94: void ath_bmiss_proc(void *, int);
! 95: u_int ath_chan2flags(struct ieee80211com *, struct ieee80211_channel *);
! 96: int ath_initkeytable(struct ath_softc *);
! 97: void ath_mcastfilter_accum(caddr_t, u_int32_t (*)[2]);
! 98: void ath_mcastfilter_compute(struct ath_softc *, u_int32_t (*)[2]);
! 99: u_int32_t ath_calcrxfilter(struct ath_softc *);
! 100: void ath_mode_init(struct ath_softc *);
! 101: int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
! 102: void ath_beacon_proc(void *, int);
! 103: void ath_beacon_free(struct ath_softc *);
! 104: void ath_beacon_config(struct ath_softc *);
! 105: int ath_desc_alloc(struct ath_softc *);
! 106: void ath_desc_free(struct ath_softc *);
! 107: struct ieee80211_node *ath_node_alloc(struct ieee80211com *);
! 108: struct mbuf *ath_getmbuf(int, int, u_int);
! 109: void ath_node_free(struct ieee80211com *, struct ieee80211_node *);
! 110: void ath_node_copy(struct ieee80211com *,
! 111: struct ieee80211_node *, const struct ieee80211_node *);
! 112: u_int8_t ath_node_getrssi(struct ieee80211com *,
! 113: const struct ieee80211_node *);
! 114: int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
! 115: void ath_rx_proc(void *, int);
! 116: int ath_tx_start(struct ath_softc *, struct ieee80211_node *,
! 117: struct ath_buf *, struct mbuf *);
! 118: void ath_tx_proc(void *, int);
! 119: int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
! 120: void ath_draintxq(struct ath_softc *);
! 121: void ath_stoprecv(struct ath_softc *);
! 122: int ath_startrecv(struct ath_softc *);
! 123: void ath_next_scan(void *);
! 124: int ath_set_slot_time(struct ath_softc *);
! 125: void ath_calibrate(void *);
! 126: void ath_ledstate(struct ath_softc *, enum ieee80211_state);
! 127: int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 128: void ath_newassoc(struct ieee80211com *,
! 129: struct ieee80211_node *, int);
! 130: int ath_getchannels(struct ath_softc *, HAL_BOOL outdoor,
! 131: HAL_BOOL xchanmode);
! 132: int ath_rate_setup(struct ath_softc *sc, u_int mode);
! 133: void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
! 134: void ath_rssadapt_updatenode(void *, struct ieee80211_node *);
! 135: void ath_rssadapt_updatestats(void *);
! 136: void ath_recv_mgmt(struct ieee80211com *, struct mbuf *,
! 137: struct ieee80211_node *, int, int, u_int32_t);
! 138: void ath_disable(struct ath_softc *);
! 139: void ath_power(int, void *);
! 140:
! 141: int ath_gpio_attach(struct ath_softc *, u_int16_t);
! 142: int ath_gpio_pin_read(void *, int);
! 143: void ath_gpio_pin_write(void *, int, int);
! 144: void ath_gpio_pin_ctl(void *, int, int);
! 145:
! 146: #ifdef AR_DEBUG
! 147: void ath_printrxbuf(struct ath_buf *, int);
! 148: void ath_printtxbuf(struct ath_buf *, int);
! 149: int ath_debug = 0;
! 150: #endif
! 151:
! 152: int ath_dwelltime = 200; /* 5 channels/second */
! 153: int ath_calinterval = 30; /* calibrate every 30 secs */
! 154: int ath_outdoor = AH_TRUE; /* outdoor operation */
! 155: int ath_xchanmode = AH_TRUE; /* enable extended channels */
! 156:
! 157: struct cfdriver ath_cd = {
! 158: NULL, "ath", DV_IFNET
! 159: };
! 160:
! 161: #if 0
! 162: int
! 163: ath_activate(struct device *self, enum devact act)
! 164: {
! 165: struct ath_softc *sc = (struct ath_softc *)self;
! 166: int rv = 0, s;
! 167:
! 168: s = splnet();
! 169: switch (act) {
! 170: case DVACT_ACTIVATE:
! 171: break;
! 172: case DVACT_DEACTIVATE:
! 173: if_deactivate(&sc->sc_ic.ic_if);
! 174: break;
! 175: }
! 176: splx(s);
! 177: return rv;
! 178: }
! 179: #endif
! 180:
! 181: int
! 182: ath_enable(struct ath_softc *sc)
! 183: {
! 184: if (ATH_IS_ENABLED(sc) == 0) {
! 185: if (sc->sc_enable != NULL && (*sc->sc_enable)(sc) != 0) {
! 186: printf("%s: device enable failed\n",
! 187: sc->sc_dev.dv_xname);
! 188: return (EIO);
! 189: }
! 190: sc->sc_flags |= ATH_ENABLED;
! 191: }
! 192: return (0);
! 193: }
! 194:
! 195: void
! 196: ath_disable(struct ath_softc *sc)
! 197: {
! 198: if (!ATH_IS_ENABLED(sc))
! 199: return;
! 200: if (sc->sc_disable != NULL)
! 201: (*sc->sc_disable)(sc);
! 202: sc->sc_flags &= ~ATH_ENABLED;
! 203: }
! 204:
! 205: int
! 206: ath_attach(u_int16_t devid, struct ath_softc *sc)
! 207: {
! 208: struct ieee80211com *ic = &sc->sc_ic;
! 209: struct ifnet *ifp = &ic->ic_if;
! 210: struct ath_hal *ah;
! 211: HAL_STATUS status;
! 212: HAL_TXQ_INFO qinfo;
! 213: int error = 0, i;
! 214:
! 215: DPRINTF(ATH_DEBUG_ANY, ("%s: devid 0x%x\n", __func__, devid));
! 216:
! 217: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 218: sc->sc_flags &= ~ATH_ATTACHED; /* make sure that it's not attached */
! 219:
! 220: ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, sc->sc_64bit,
! 221: &status);
! 222: if (ah == NULL) {
! 223: printf("%s: unable to attach hardware; HAL status %d\n",
! 224: ifp->if_xname, status);
! 225: error = ENXIO;
! 226: goto bad;
! 227: }
! 228: if (ah->ah_abi != HAL_ABI_VERSION) {
! 229: printf("%s: HAL ABI mismatch detected (0x%x != 0x%x)\n",
! 230: ifp->if_xname, ah->ah_abi, HAL_ABI_VERSION);
! 231: error = ENXIO;
! 232: goto bad;
! 233: }
! 234:
! 235: if (ah->ah_single_chip == AH_TRUE) {
! 236: printf("%s: AR%s %u.%u phy %u.%u rf %u.%u", ifp->if_xname,
! 237: ar5k_printver(AR5K_VERSION_DEV, devid),
! 238: ah->ah_mac_version, ah->ah_mac_revision,
! 239: ah->ah_phy_revision >> 4, ah->ah_phy_revision & 0xf,
! 240: ah->ah_radio_5ghz_revision >> 4,
! 241: ah->ah_radio_5ghz_revision & 0xf);
! 242: } else {
! 243: printf("%s: AR%s %u.%u phy %u.%u", ifp->if_xname,
! 244: ar5k_printver(AR5K_VERSION_VER, ah->ah_mac_srev),
! 245: ah->ah_mac_version, ah->ah_mac_revision,
! 246: ah->ah_phy_revision >> 4, ah->ah_phy_revision & 0xf);
! 247: printf(" rf%s %u.%u",
! 248: ar5k_printver(AR5K_VERSION_RAD, ah->ah_radio_5ghz_revision),
! 249: ah->ah_radio_5ghz_revision >> 4,
! 250: ah->ah_radio_5ghz_revision & 0xf);
! 251: if (ah->ah_radio_2ghz_revision != 0) {
! 252: printf(" rf%s %u.%u",
! 253: ar5k_printver(AR5K_VERSION_RAD,
! 254: ah->ah_radio_2ghz_revision),
! 255: ah->ah_radio_2ghz_revision >> 4,
! 256: ah->ah_radio_2ghz_revision & 0xf);
! 257: }
! 258: }
! 259:
! 260: #if 0
! 261: if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_UNSUPP ||
! 262: ah->ah_radio_2ghz_revision >= AR5K_SREV_RAD_UNSUPP) {
! 263: printf(": RF radio not supported\n");
! 264: error = EOPNOTSUPP;
! 265: goto bad;
! 266: }
! 267: #endif
! 268:
! 269: sc->sc_ah = ah;
! 270: sc->sc_invalid = 0; /* ready to go, enable interrupt handling */
! 271:
! 272: /*
! 273: * Get regulation domain either stored in the EEPROM or defined
! 274: * as the default value. Some devices are known to have broken
! 275: * regulation domain values in their EEPROM.
! 276: */
! 277: ath_hal_get_regdomain(ah, &ah->ah_regdomain);
! 278:
! 279: /*
! 280: * Construct channel list based on the current regulation domain.
! 281: */
! 282: error = ath_getchannels(sc, ath_outdoor, ath_xchanmode);
! 283: if (error != 0)
! 284: goto bad;
! 285:
! 286: /*
! 287: * Setup rate tables for all potential media types.
! 288: */
! 289: ath_rate_setup(sc, IEEE80211_MODE_11A);
! 290: ath_rate_setup(sc, IEEE80211_MODE_11B);
! 291: ath_rate_setup(sc, IEEE80211_MODE_11G);
! 292: ath_rate_setup(sc, IEEE80211_MODE_TURBO);
! 293:
! 294: error = ath_desc_alloc(sc);
! 295: if (error != 0) {
! 296: printf(": failed to allocate descriptors: %d\n", error);
! 297: goto bad;
! 298: }
! 299: timeout_set(&sc->sc_scan_to, ath_next_scan, sc);
! 300: timeout_set(&sc->sc_cal_to, ath_calibrate, sc);
! 301: timeout_set(&sc->sc_rssadapt_to, ath_rssadapt_updatestats, sc);
! 302:
! 303: #ifdef __FreeBSD__
! 304: ATH_TXBUF_LOCK_INIT(sc);
! 305: ATH_TXQ_LOCK_INIT(sc);
! 306: #endif
! 307:
! 308: ATH_TASK_INIT(&sc->sc_txtask, ath_tx_proc, sc);
! 309: ATH_TASK_INIT(&sc->sc_rxtask, ath_rx_proc, sc);
! 310: ATH_TASK_INIT(&sc->sc_rxorntask, ath_rxorn_proc, sc);
! 311: ATH_TASK_INIT(&sc->sc_fataltask, ath_fatal_proc, sc);
! 312: ATH_TASK_INIT(&sc->sc_bmisstask, ath_bmiss_proc, sc);
! 313: ATH_TASK_INIT(&sc->sc_swbatask, ath_beacon_proc, sc);
! 314:
! 315: /*
! 316: * For now just pre-allocate one data queue and one
! 317: * beacon queue. Note that the HAL handles resetting
! 318: * them at the needed time. Eventually we'll want to
! 319: * allocate more tx queues for splitting management
! 320: * frames and for QOS support.
! 321: */
! 322: sc->sc_bhalq = ath_hal_setup_tx_queue(ah, HAL_TX_QUEUE_BEACON, NULL);
! 323: if (sc->sc_bhalq == (u_int) -1) {
! 324: printf(": unable to setup a beacon xmit queue!\n");
! 325: goto bad2;
! 326: }
! 327:
! 328: for (i = 0; i <= HAL_TX_QUEUE_ID_DATA_MAX; i++) {
! 329: bzero(&qinfo, sizeof(qinfo));
! 330: qinfo.tqi_type = HAL_TX_QUEUE_DATA;
! 331: qinfo.tqi_subtype = i; /* should be mapped to WME types */
! 332: sc->sc_txhalq[i] = ath_hal_setup_tx_queue(ah,
! 333: HAL_TX_QUEUE_DATA, &qinfo);
! 334: if (sc->sc_txhalq[i] == (u_int) -1) {
! 335: printf(": unable to setup a data xmit queue %u!\n", i);
! 336: goto bad2;
! 337: }
! 338: }
! 339:
! 340: ifp->if_softc = sc;
! 341: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST
! 342: | IFF_NOTRAILERS;
! 343: ifp->if_start = ath_start;
! 344: ifp->if_watchdog = ath_watchdog;
! 345: ifp->if_ioctl = ath_ioctl;
! 346: #ifndef __OpenBSD__
! 347: ifp->if_init = ath_init;
! 348: ifp->if_stop = ath_stop; /* XXX */
! 349: #endif
! 350: IFQ_SET_MAXLEN(&ifp->if_snd, ATH_TXBUF * ATH_TXDESC);
! 351: IFQ_SET_READY(&ifp->if_snd);
! 352:
! 353: ic->ic_softc = sc;
! 354: ic->ic_newassoc = ath_newassoc;
! 355: /* XXX not right but it's not used anywhere important */
! 356: ic->ic_phytype = IEEE80211_T_OFDM;
! 357: ic->ic_opmode = IEEE80211_M_STA;
! 358: ic->ic_caps = IEEE80211_C_WEP /* wep supported */
! 359: | IEEE80211_C_PMGT /* power management */
! 360: | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */
! 361: | IEEE80211_C_HOSTAP /* hostap mode */
! 362: | IEEE80211_C_MONITOR /* monitor mode */
! 363: | IEEE80211_C_SHSLOT /* short slot time supported */
! 364: | IEEE80211_C_SHPREAMBLE; /* short preamble supported */
! 365:
! 366: /*
! 367: * Not all chips have the VEOL support we want to use with
! 368: * IBSS beacon; check here for it.
! 369: */
! 370: sc->sc_veol = ath_hal_has_veol(ah);
! 371:
! 372: /* get mac address from hardware */
! 373: ath_hal_get_lladdr(ah, ic->ic_myaddr);
! 374:
! 375: if_attach(ifp);
! 376:
! 377: /* call MI attach routine. */
! 378: ieee80211_ifattach(ifp);
! 379:
! 380: /* override default methods */
! 381: ic->ic_node_alloc = ath_node_alloc;
! 382: sc->sc_node_free = ic->ic_node_free;
! 383: ic->ic_node_free = ath_node_free;
! 384: sc->sc_node_copy = ic->ic_node_copy;
! 385: ic->ic_node_copy = ath_node_copy;
! 386: ic->ic_node_getrssi = ath_node_getrssi;
! 387: sc->sc_newstate = ic->ic_newstate;
! 388: ic->ic_newstate = ath_newstate;
! 389: sc->sc_recv_mgmt = ic->ic_recv_mgmt;
! 390: ic->ic_recv_mgmt = ath_recv_mgmt;
! 391: ic->ic_max_rssi = AR5K_MAX_RSSI;
! 392: bcopy(etherbroadcastaddr, sc->sc_broadcast_addr, IEEE80211_ADDR_LEN);
! 393:
! 394: /* complete initialization */
! 395: ieee80211_media_init(ifp, ath_media_change, ieee80211_media_status);
! 396:
! 397: #if NBPFILTER > 0
! 398: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 399: sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
! 400:
! 401: sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
! 402: bzero(&sc->sc_rxtapu, sc->sc_rxtap_len);
! 403: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
! 404: sc->sc_rxtap.wr_ihdr.it_present = htole32(ATH_RX_RADIOTAP_PRESENT);
! 405:
! 406: sc->sc_txtap_len = sizeof(sc->sc_txtapu);
! 407: bzero(&sc->sc_txtapu, sc->sc_txtap_len);
! 408: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
! 409: sc->sc_txtap.wt_ihdr.it_present = htole32(ATH_TX_RADIOTAP_PRESENT);
! 410: #endif
! 411:
! 412: sc->sc_flags |= ATH_ATTACHED;
! 413: /*
! 414: * Make sure the interface is shutdown during reboot.
! 415: */
! 416: sc->sc_sdhook = shutdownhook_establish(ath_shutdown, sc);
! 417: if (sc->sc_sdhook == NULL)
! 418: printf(": WARNING: unable to establish shutdown hook\n");
! 419: sc->sc_powerhook = powerhook_establish(ath_power, sc);
! 420: if (sc->sc_powerhook == NULL)
! 421: printf(": WARNING: unable to establish power hook\n");
! 422:
! 423: /*
! 424: * Print regulation domain and the mac address. The regulation domain
! 425: * will be marked with a * if the EEPROM value has been overwritten.
! 426: */
! 427: printf(", %s%s, address %s\n",
! 428: ieee80211_regdomain2name(ah->ah_regdomain),
! 429: ah->ah_regdomain != ah->ah_regdomain_hw ? "*" : "",
! 430: ether_sprintf(ic->ic_myaddr));
! 431:
! 432: if (ath_gpio_attach(sc, devid) == 0)
! 433: sc->sc_flags |= ATH_GPIO;
! 434:
! 435: return 0;
! 436: bad2:
! 437: ath_desc_free(sc);
! 438: bad:
! 439: if (ah)
! 440: ath_hal_detach(ah);
! 441: sc->sc_invalid = 1;
! 442: return error;
! 443: }
! 444:
! 445: int
! 446: ath_detach(struct ath_softc *sc, int flags)
! 447: {
! 448: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 449: int s;
! 450:
! 451: if ((sc->sc_flags & ATH_ATTACHED) == 0)
! 452: return (0);
! 453:
! 454: config_detach_children(&sc->sc_dev, flags);
! 455:
! 456: DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
! 457:
! 458: timeout_del(&sc->sc_scan_to);
! 459: timeout_del(&sc->sc_cal_to);
! 460: timeout_del(&sc->sc_rssadapt_to);
! 461:
! 462: s = splnet();
! 463: ath_stop(ifp);
! 464: ath_desc_free(sc);
! 465: ath_hal_detach(sc->sc_ah);
! 466:
! 467: ieee80211_ifdetach(ifp);
! 468: if_detach(ifp);
! 469:
! 470: splx(s);
! 471: if (sc->sc_powerhook != NULL)
! 472: powerhook_disestablish(sc->sc_powerhook);
! 473: if (sc->sc_sdhook != NULL)
! 474: shutdownhook_disestablish(sc->sc_sdhook);
! 475: #ifdef __FreeBSD__
! 476: ATH_TXBUF_LOCK_DESTROY(sc);
! 477: ATH_TXQ_LOCK_DESTROY(sc);
! 478: #endif
! 479:
! 480: return 0;
! 481: }
! 482:
! 483: void
! 484: ath_power(int why, void *arg)
! 485: {
! 486: struct ath_softc *sc = arg;
! 487: int s;
! 488:
! 489: DPRINTF(ATH_DEBUG_ANY, ("ath_power(%d)\n", why));
! 490:
! 491: s = splnet();
! 492: switch (why) {
! 493: case PWR_SUSPEND:
! 494: case PWR_STANDBY:
! 495: ath_suspend(sc, why);
! 496: break;
! 497: case PWR_RESUME:
! 498: ath_resume(sc, why);
! 499: break;
! 500: #if !defined(__OpenBSD__)
! 501: case PWR_SOFTSUSPEND:
! 502: case PWR_SOFTSTANDBY:
! 503: case PWR_SOFTRESUME:
! 504: break;
! 505: #endif
! 506: }
! 507: splx(s);
! 508: }
! 509:
! 510: void
! 511: ath_suspend(struct ath_softc *sc, int why)
! 512: {
! 513: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 514:
! 515: DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
! 516:
! 517: ath_stop(ifp);
! 518: if (sc->sc_power != NULL)
! 519: (*sc->sc_power)(sc, why);
! 520: }
! 521:
! 522: void
! 523: ath_resume(struct ath_softc *sc, int why)
! 524: {
! 525: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 526:
! 527: DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
! 528:
! 529: if (ifp->if_flags & IFF_UP) {
! 530: ath_init(ifp);
! 531: #if 0
! 532: (void)ath_intr(sc);
! 533: #endif
! 534: if (sc->sc_power != NULL)
! 535: (*sc->sc_power)(sc, why);
! 536: if (ifp->if_flags & IFF_RUNNING)
! 537: ath_start(ifp);
! 538: }
! 539: }
! 540:
! 541: void
! 542: ath_shutdown(void *arg)
! 543: {
! 544: struct ath_softc *sc = arg;
! 545:
! 546: ath_stop(&sc->sc_ic.ic_if);
! 547: }
! 548:
! 549: int
! 550: ath_intr(void *arg)
! 551: {
! 552: return ath_intr1((struct ath_softc *)arg);
! 553: }
! 554:
! 555: int
! 556: ath_intr1(struct ath_softc *sc)
! 557: {
! 558: struct ieee80211com *ic = &sc->sc_ic;
! 559: struct ifnet *ifp = &ic->ic_if;
! 560: struct ath_hal *ah = sc->sc_ah;
! 561: HAL_INT status;
! 562:
! 563: if (sc->sc_invalid) {
! 564: /*
! 565: * The hardware is not ready/present, don't touch anything.
! 566: * Note this can happen early on if the IRQ is shared.
! 567: */
! 568: DPRINTF(ATH_DEBUG_ANY, ("%s: invalid; ignored\n", __func__));
! 569: return 0;
! 570: }
! 571: if (!ath_hal_is_intr_pending(ah)) /* shared irq, not for us */
! 572: return 0;
! 573: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) {
! 574: DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags 0x%x\n",
! 575: __func__, ifp->if_flags));
! 576: ath_hal_get_isr(ah, &status); /* clear ISR */
! 577: ath_hal_set_intr(ah, 0); /* disable further intr's */
! 578: return 1; /* XXX */
! 579: }
! 580: ath_hal_get_isr(ah, &status); /* NB: clears ISR too */
! 581: DPRINTF(ATH_DEBUG_INTR, ("%s: status 0x%x\n", __func__, status));
! 582: status &= sc->sc_imask; /* discard unasked for bits */
! 583: if (status & HAL_INT_FATAL) {
! 584: sc->sc_stats.ast_hardware++;
! 585: ath_hal_set_intr(ah, 0); /* disable intr's until reset */
! 586: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_fataltask);
! 587: } else if (status & HAL_INT_RXORN) {
! 588: sc->sc_stats.ast_rxorn++;
! 589: ath_hal_set_intr(ah, 0); /* disable intr's until reset */
! 590: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_rxorntask);
! 591: } else if (status & HAL_INT_MIB) {
! 592: DPRINTF(ATH_DEBUG_INTR,
! 593: ("%s: resetting MIB counters\n", __func__));
! 594: sc->sc_stats.ast_mib++;
! 595: ath_hal_update_mib_counters(ah, &sc->sc_mib_stats);
! 596: } else {
! 597: if (status & HAL_INT_RXEOL) {
! 598: /*
! 599: * NB: the hardware should re-read the link when
! 600: * RXE bit is written, but it doesn't work at
! 601: * least on older hardware revs.
! 602: */
! 603: sc->sc_stats.ast_rxeol++;
! 604: sc->sc_rxlink = NULL;
! 605: }
! 606: if (status & HAL_INT_TXURN) {
! 607: sc->sc_stats.ast_txurn++;
! 608: /* bump tx trigger level */
! 609: ath_hal_update_tx_triglevel(ah, AH_TRUE);
! 610: }
! 611: if (status & HAL_INT_RX)
! 612: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_rxtask);
! 613: if (status & HAL_INT_TX)
! 614: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_txtask);
! 615: if (status & HAL_INT_SWBA)
! 616: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_swbatask);
! 617: if (status & HAL_INT_BMISS) {
! 618: sc->sc_stats.ast_bmiss++;
! 619: ATH_TASK_RUN_OR_ENQUEUE(&sc->sc_bmisstask);
! 620: }
! 621: }
! 622: return 1;
! 623: }
! 624:
! 625: void
! 626: ath_fatal_proc(void *arg, int pending)
! 627: {
! 628: struct ath_softc *sc = arg;
! 629: struct ieee80211com *ic = &sc->sc_ic;
! 630: struct ifnet *ifp = &ic->ic_if;
! 631:
! 632: if (ifp->if_flags & IFF_DEBUG)
! 633: printf("%s: hardware error; resetting\n", ifp->if_xname);
! 634: ath_reset(sc, 1);
! 635: }
! 636:
! 637: void
! 638: ath_rxorn_proc(void *arg, int pending)
! 639: {
! 640: struct ath_softc *sc = arg;
! 641: struct ieee80211com *ic = &sc->sc_ic;
! 642: struct ifnet *ifp = &ic->ic_if;
! 643:
! 644: if (ifp->if_flags & IFF_DEBUG)
! 645: printf("%s: rx FIFO overrun; resetting\n", ifp->if_xname);
! 646: ath_reset(sc, 1);
! 647: }
! 648:
! 649: void
! 650: ath_bmiss_proc(void *arg, int pending)
! 651: {
! 652: struct ath_softc *sc = arg;
! 653: struct ieee80211com *ic = &sc->sc_ic;
! 654:
! 655: DPRINTF(ATH_DEBUG_ANY, ("%s: pending %u\n", __func__, pending));
! 656: if (ic->ic_opmode != IEEE80211_M_STA)
! 657: return;
! 658: if (ic->ic_state == IEEE80211_S_RUN) {
! 659: /*
! 660: * Rather than go directly to scan state, try to
! 661: * reassociate first. If that fails then the state
! 662: * machine will drop us into scanning after timing
! 663: * out waiting for a probe response.
! 664: */
! 665: ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
! 666: }
! 667: }
! 668:
! 669: u_int
! 670: ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan)
! 671: {
! 672: enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan);
! 673:
! 674: switch (mode) {
! 675: case IEEE80211_MODE_AUTO:
! 676: return 0;
! 677: case IEEE80211_MODE_11A:
! 678: return CHANNEL_A;
! 679: case IEEE80211_MODE_11B:
! 680: return CHANNEL_B;
! 681: case IEEE80211_MODE_11G:
! 682: return CHANNEL_G;
! 683: case IEEE80211_MODE_TURBO:
! 684: return CHANNEL_T;
! 685: default:
! 686: panic("%s: unsupported mode %d", __func__, mode);
! 687: return 0;
! 688: }
! 689: }
! 690:
! 691: int
! 692: ath_init(struct ifnet *ifp)
! 693: {
! 694: return ath_init1((struct ath_softc *)ifp->if_softc);
! 695: }
! 696:
! 697: int
! 698: ath_init1(struct ath_softc *sc)
! 699: {
! 700: struct ieee80211com *ic = &sc->sc_ic;
! 701: struct ifnet *ifp = &ic->ic_if;
! 702: struct ieee80211_node *ni;
! 703: enum ieee80211_phymode mode;
! 704: struct ath_hal *ah = sc->sc_ah;
! 705: HAL_STATUS status;
! 706: HAL_CHANNEL hchan;
! 707: int error = 0, s;
! 708:
! 709: DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags 0x%x\n",
! 710: __func__, ifp->if_flags));
! 711:
! 712: if ((error = ath_enable(sc)) != 0)
! 713: return error;
! 714:
! 715: s = splnet();
! 716: /*
! 717: * Stop anything previously setup. This is safe
! 718: * whether this is the first time through or not.
! 719: */
! 720: ath_stop(ifp);
! 721:
! 722: /*
! 723: * Reset the link layer address to the latest value.
! 724: */
! 725: IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
! 726: ath_hal_set_lladdr(ah, ic->ic_myaddr);
! 727:
! 728: /*
! 729: * The basic interface to setting the hardware in a good
! 730: * state is ``reset''. On return the hardware is known to
! 731: * be powered up and with interrupts disabled. This must
! 732: * be followed by initialization of the appropriate bits
! 733: * and then setup of the interrupt mask.
! 734: */
! 735: hchan.channel = ic->ic_ibss_chan->ic_freq;
! 736: hchan.channelFlags = ath_chan2flags(ic, ic->ic_ibss_chan);
! 737: if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) {
! 738: printf("%s: unable to reset hardware; hal status %u\n",
! 739: ifp->if_xname, status);
! 740: error = EIO;
! 741: goto done;
! 742: }
! 743: ath_set_slot_time(sc);
! 744: /*
! 745: * Setup the hardware after reset: the key cache
! 746: * is filled as needed and the receive engine is
! 747: * set going. Frame transmit is handled entirely
! 748: * in the frame output path; there's nothing to do
! 749: * here except setup the interrupt mask.
! 750: */
! 751: if (ic->ic_flags & IEEE80211_F_WEPON) {
! 752: if ((error = ath_initkeytable(sc)) != 0) {
! 753: printf("%s: unable to initialize the key cache\n",
! 754: ifp->if_xname);
! 755: goto done;
! 756: }
! 757: }
! 758: if ((error = ath_startrecv(sc)) != 0) {
! 759: printf("%s: unable to start recv logic\n", ifp->if_xname);
! 760: goto done;
! 761: }
! 762:
! 763: /*
! 764: * Enable interrupts.
! 765: */
! 766: sc->sc_imask = HAL_INT_RX | HAL_INT_TX
! 767: | HAL_INT_RXEOL | HAL_INT_RXORN
! 768: | HAL_INT_FATAL | HAL_INT_GLOBAL;
! 769: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 770: sc->sc_imask |= HAL_INT_MIB;
! 771: ath_hal_set_intr(ah, sc->sc_imask);
! 772:
! 773: ifp->if_flags |= IFF_RUNNING;
! 774: ic->ic_state = IEEE80211_S_INIT;
! 775:
! 776: /*
! 777: * The hardware should be ready to go now so it's safe
! 778: * to kick the 802.11 state machine as it's likely to
! 779: * immediately call back to us to send mgmt frames.
! 780: */
! 781: ni = ic->ic_bss;
! 782: ni->ni_chan = ic->ic_ibss_chan;
! 783: mode = ieee80211_chan2mode(ic, ni->ni_chan);
! 784: if (mode != sc->sc_curmode)
! 785: ath_setcurmode(sc, mode);
! 786: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
! 787: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 788: } else {
! 789: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 790: }
! 791: done:
! 792: splx(s);
! 793: return error;
! 794: }
! 795:
! 796: void
! 797: ath_stop(struct ifnet *ifp)
! 798: {
! 799: struct ieee80211com *ic = (struct ieee80211com *) ifp;
! 800: struct ath_softc *sc = ifp->if_softc;
! 801: struct ath_hal *ah = sc->sc_ah;
! 802: int s;
! 803:
! 804: DPRINTF(ATH_DEBUG_ANY, ("%s: invalid %u if_flags 0x%x\n",
! 805: __func__, sc->sc_invalid, ifp->if_flags));
! 806:
! 807: s = splnet();
! 808: if (ifp->if_flags & IFF_RUNNING) {
! 809: /*
! 810: * Shutdown the hardware and driver:
! 811: * disable interrupts
! 812: * turn off timers
! 813: * clear transmit machinery
! 814: * clear receive machinery
! 815: * drain and release tx queues
! 816: * reclaim beacon resources
! 817: * reset 802.11 state machine
! 818: * power down hardware
! 819: *
! 820: * Note that some of this work is not possible if the
! 821: * hardware is gone (invalid).
! 822: */
! 823: ifp->if_flags &= ~IFF_RUNNING;
! 824: ifp->if_timer = 0;
! 825: if (!sc->sc_invalid)
! 826: ath_hal_set_intr(ah, 0);
! 827: ath_draintxq(sc);
! 828: if (!sc->sc_invalid) {
! 829: ath_stoprecv(sc);
! 830: } else {
! 831: sc->sc_rxlink = NULL;
! 832: }
! 833: IFQ_PURGE(&ifp->if_snd);
! 834: ath_beacon_free(sc);
! 835: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 836: if (!sc->sc_invalid) {
! 837: ath_hal_set_power(ah, HAL_PM_FULL_SLEEP, 0);
! 838: }
! 839: ath_disable(sc);
! 840: }
! 841: splx(s);
! 842: }
! 843:
! 844: /*
! 845: * Reset the hardware w/o losing operational state. This is
! 846: * basically a more efficient way of doing ath_stop, ath_init,
! 847: * followed by state transitions to the current 802.11
! 848: * operational state. Used to recover from errors rx overrun
! 849: * and to reset the hardware when rf gain settings must be reset.
! 850: */
! 851: void
! 852: ath_reset(struct ath_softc *sc, int full)
! 853: {
! 854: struct ieee80211com *ic = &sc->sc_ic;
! 855: struct ifnet *ifp = &ic->ic_if;
! 856: struct ath_hal *ah = sc->sc_ah;
! 857: struct ieee80211_channel *c;
! 858: HAL_STATUS status;
! 859: HAL_CHANNEL hchan;
! 860:
! 861: /*
! 862: * Convert to a HAL channel description with the flags
! 863: * constrained to reflect the current operating mode.
! 864: */
! 865: c = ic->ic_ibss_chan;
! 866: hchan.channel = c->ic_freq;
! 867: hchan.channelFlags = ath_chan2flags(ic, c);
! 868:
! 869: ath_hal_set_intr(ah, 0); /* disable interrupts */
! 870: ath_draintxq(sc); /* stop xmit side */
! 871: ath_stoprecv(sc); /* stop recv side */
! 872: /* NB: indicate channel change so we do a full reset */
! 873: if (!ath_hal_reset(ah, ic->ic_opmode, &hchan,
! 874: full ? AH_TRUE : AH_FALSE, &status)) {
! 875: printf("%s: %s: unable to reset hardware; hal status %u\n",
! 876: ifp->if_xname, __func__, status);
! 877: }
! 878: ath_set_slot_time(sc);
! 879: /* In case channel changed, save as a node channel */
! 880: ic->ic_bss->ni_chan = ic->ic_ibss_chan;
! 881: ath_hal_set_intr(ah, sc->sc_imask);
! 882: if (ath_startrecv(sc) != 0) /* restart recv */
! 883: printf("%s: %s: unable to start recv logic\n", ifp->if_xname,
! 884: __func__);
! 885: ath_start(ifp); /* restart xmit */
! 886: if (ic->ic_state == IEEE80211_S_RUN)
! 887: ath_beacon_config(sc); /* restart beacons */
! 888: }
! 889:
! 890: void
! 891: ath_start(struct ifnet *ifp)
! 892: {
! 893: struct ath_softc *sc = ifp->if_softc;
! 894: struct ath_hal *ah = sc->sc_ah;
! 895: struct ieee80211com *ic = &sc->sc_ic;
! 896: struct ieee80211_node *ni;
! 897: struct ath_buf *bf;
! 898: struct mbuf *m;
! 899: struct ieee80211_frame *wh;
! 900: int s;
! 901:
! 902: if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING ||
! 903: sc->sc_invalid)
! 904: return;
! 905: for (;;) {
! 906: /*
! 907: * Grab a TX buffer and associated resources.
! 908: */
! 909: s = splnet();
! 910: bf = TAILQ_FIRST(&sc->sc_txbuf);
! 911: if (bf != NULL)
! 912: TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list);
! 913: splx(s);
! 914: if (bf == NULL) {
! 915: DPRINTF(ATH_DEBUG_ANY, ("%s: out of xmit buffers\n",
! 916: __func__));
! 917: sc->sc_stats.ast_tx_qstop++;
! 918: ifp->if_flags |= IFF_OACTIVE;
! 919: break;
! 920: }
! 921: /*
! 922: * Poll the management queue for frames; they
! 923: * have priority over normal data frames.
! 924: */
! 925: IF_DEQUEUE(&ic->ic_mgtq, m);
! 926: if (m == NULL) {
! 927: /*
! 928: * No data frames go out unless we're associated.
! 929: */
! 930: if (ic->ic_state != IEEE80211_S_RUN) {
! 931: DPRINTF(ATH_DEBUG_ANY,
! 932: ("%s: ignore data packet, state %u\n",
! 933: __func__, ic->ic_state));
! 934: sc->sc_stats.ast_tx_discard++;
! 935: s = splnet();
! 936: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 937: splx(s);
! 938: break;
! 939: }
! 940: IFQ_DEQUEUE(&ifp->if_snd, m);
! 941: if (m == NULL) {
! 942: s = splnet();
! 943: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 944: splx(s);
! 945: break;
! 946: }
! 947: ifp->if_opackets++;
! 948:
! 949: #if NBPFILTER > 0
! 950: if (ifp->if_bpf)
! 951: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 952: #endif
! 953:
! 954: /*
! 955: * Encapsulate the packet in prep for transmission.
! 956: */
! 957: m = ieee80211_encap(ifp, m, &ni);
! 958: if (m == NULL) {
! 959: DPRINTF(ATH_DEBUG_ANY,
! 960: ("%s: encapsulation failure\n",
! 961: __func__));
! 962: sc->sc_stats.ast_tx_encap++;
! 963: goto bad;
! 964: }
! 965: wh = mtod(m, struct ieee80211_frame *);
! 966: } else {
! 967: /*
! 968: * Hack! The referenced node pointer is in the
! 969: * rcvif field of the packet header. This is
! 970: * placed there by ieee80211_mgmt_output because
! 971: * we need to hold the reference with the frame
! 972: * and there's no other way (other than packet
! 973: * tags which we consider too expensive to use)
! 974: * to pass it along.
! 975: */
! 976: ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
! 977: m->m_pkthdr.rcvif = NULL;
! 978:
! 979: wh = mtod(m, struct ieee80211_frame *);
! 980: if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
! 981: IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
! 982: /* fill time stamp */
! 983: u_int64_t tsf;
! 984: u_int32_t *tstamp;
! 985:
! 986: tsf = ath_hal_get_tsf64(ah);
! 987: /* XXX: adjust 100us delay to xmit */
! 988: tsf += 100;
! 989: tstamp = (u_int32_t *)&wh[1];
! 990: tstamp[0] = htole32(tsf & 0xffffffff);
! 991: tstamp[1] = htole32(tsf >> 32);
! 992: }
! 993: sc->sc_stats.ast_tx_mgmt++;
! 994: }
! 995:
! 996: if (ath_tx_start(sc, ni, bf, m)) {
! 997: bad:
! 998: s = splnet();
! 999: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 1000: splx(s);
! 1001: ifp->if_oerrors++;
! 1002: if (ni != NULL)
! 1003: ieee80211_release_node(ic, ni);
! 1004: continue;
! 1005: }
! 1006:
! 1007: sc->sc_tx_timer = 5;
! 1008: ifp->if_timer = 1;
! 1009: }
! 1010: }
! 1011:
! 1012: int
! 1013: ath_media_change(struct ifnet *ifp)
! 1014: {
! 1015: int error;
! 1016:
! 1017: error = ieee80211_media_change(ifp);
! 1018: if (error == ENETRESET) {
! 1019: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) ==
! 1020: (IFF_RUNNING|IFF_UP))
! 1021: ath_init(ifp); /* XXX lose error */
! 1022: error = 0;
! 1023: }
! 1024: return error;
! 1025: }
! 1026:
! 1027: void
! 1028: ath_watchdog(struct ifnet *ifp)
! 1029: {
! 1030: struct ath_softc *sc = ifp->if_softc;
! 1031:
! 1032: ifp->if_timer = 0;
! 1033: if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid)
! 1034: return;
! 1035: if (sc->sc_tx_timer) {
! 1036: if (--sc->sc_tx_timer == 0) {
! 1037: printf("%s: device timeout\n", ifp->if_xname);
! 1038: ath_reset(sc, 1);
! 1039: ifp->if_oerrors++;
! 1040: sc->sc_stats.ast_watchdog++;
! 1041: return;
! 1042: }
! 1043: ifp->if_timer = 1;
! 1044: }
! 1045:
! 1046: ieee80211_watchdog(ifp);
! 1047: }
! 1048:
! 1049: int
! 1050: ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1051: {
! 1052: struct ath_softc *sc = ifp->if_softc;
! 1053: struct ieee80211com *ic = &sc->sc_ic;
! 1054: struct ifreq *ifr = (struct ifreq *)data;
! 1055: struct ifaddr *ifa = (struct ifaddr *)data;
! 1056: int error = 0, s;
! 1057:
! 1058: s = splnet();
! 1059: switch (cmd) {
! 1060: case SIOCSIFADDR:
! 1061: ifp->if_flags |= IFF_UP;
! 1062: #ifdef INET
! 1063: if (ifa->ifa_addr->sa_family == AF_INET) {
! 1064: arp_ifinit(&ic->ic_ac, ifa);
! 1065: }
! 1066: #endif /* INET */
! 1067: /* FALLTHROUGH */
! 1068: case SIOCSIFFLAGS:
! 1069: if (ifp->if_flags & IFF_UP) {
! 1070: if (ifp->if_flags & IFF_RUNNING) {
! 1071: /*
! 1072: * To avoid rescanning another access point,
! 1073: * do not call ath_init() here. Instead,
! 1074: * only reflect promisc mode settings.
! 1075: */
! 1076: ath_mode_init(sc);
! 1077: } else {
! 1078: /*
! 1079: * Beware of being called during detach to
! 1080: * reset promiscuous mode. In that case we
! 1081: * will still be marked UP but not RUNNING.
! 1082: * However trying to re-init the interface
! 1083: * is the wrong thing to do as we've already
! 1084: * torn down much of our state. There's
! 1085: * probably a better way to deal with this.
! 1086: */
! 1087: if (!sc->sc_invalid)
! 1088: ath_init(ifp); /* XXX lose error */
! 1089: }
! 1090: } else
! 1091: ath_stop(ifp);
! 1092: break;
! 1093: case SIOCADDMULTI:
! 1094: case SIOCDELMULTI:
! 1095: #ifdef __FreeBSD__
! 1096: /*
! 1097: * The upper layer has already installed/removed
! 1098: * the multicast address(es), just recalculate the
! 1099: * multicast filter for the card.
! 1100: */
! 1101: if (ifp->if_flags & IFF_RUNNING)
! 1102: ath_mode_init(sc);
! 1103: #endif
! 1104: error = (cmd == SIOCADDMULTI) ?
! 1105: ether_addmulti(ifr, &sc->sc_ic.ic_ac) :
! 1106: ether_delmulti(ifr, &sc->sc_ic.ic_ac);
! 1107: if (error == ENETRESET) {
! 1108: if (ifp->if_flags & IFF_RUNNING)
! 1109: ath_mode_init(sc);
! 1110: error = 0;
! 1111: }
! 1112: break;
! 1113: case SIOCGATHSTATS:
! 1114: error = copyout(&sc->sc_stats,
! 1115: ifr->ifr_data, sizeof (sc->sc_stats));
! 1116: break;
! 1117: default:
! 1118: error = ieee80211_ioctl(ifp, cmd, data);
! 1119: if (error == ENETRESET) {
! 1120: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) ==
! 1121: (IFF_RUNNING|IFF_UP)) {
! 1122: struct ieee80211com *ic = &sc->sc_ic;
! 1123:
! 1124: if (ic->ic_opmode != IEEE80211_M_MONITOR)
! 1125: ath_init(ifp); /* XXX lose error */
! 1126: else
! 1127: ath_reset(sc, 1);
! 1128: }
! 1129: error = 0;
! 1130: }
! 1131: break;
! 1132: }
! 1133: splx(s);
! 1134: return error;
! 1135: }
! 1136:
! 1137: /*
! 1138: * Fill the hardware key cache with key entries.
! 1139: */
! 1140: int
! 1141: ath_initkeytable(struct ath_softc *sc)
! 1142: {
! 1143: struct ieee80211com *ic = &sc->sc_ic;
! 1144: struct ath_hal *ah = sc->sc_ah;
! 1145: int i;
! 1146:
! 1147: /* XXX maybe should reset all keys when !WEPON */
! 1148: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1149: struct ieee80211_key *k = &ic->ic_nw_keys[i];
! 1150: if (k->k_len == 0)
! 1151: ath_hal_reset_key(ah, i);
! 1152: else {
! 1153: HAL_KEYVAL hk;
! 1154:
! 1155: bzero(&hk, sizeof(hk));
! 1156: /*
! 1157: * Pad the key to a supported key length. It
! 1158: * is always a good idea to use full-length
! 1159: * keys without padded zeros but this seems
! 1160: * to be the default behaviour used by many
! 1161: * implementations.
! 1162: */
! 1163: if (k->k_cipher == IEEE80211_CIPHER_WEP40)
! 1164: hk.wk_len = AR5K_KEYVAL_LENGTH_40;
! 1165: else if (k->k_cipher == IEEE80211_CIPHER_WEP104)
! 1166: hk.wk_len = AR5K_KEYVAL_LENGTH_104;
! 1167: else
! 1168: return (EINVAL);
! 1169: bcopy(k->k_key, hk.wk_key, hk.wk_len);
! 1170:
! 1171: if (ath_hal_set_key(ah, i, &hk) != AH_TRUE)
! 1172: return (EINVAL);
! 1173: }
! 1174: }
! 1175:
! 1176: return (0);
! 1177: }
! 1178:
! 1179: void
! 1180: ath_mcastfilter_accum(caddr_t dl, u_int32_t (*mfilt)[2])
! 1181: {
! 1182: u_int32_t val;
! 1183: u_int8_t pos;
! 1184:
! 1185: val = LE_READ_4(dl + 0);
! 1186: pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
! 1187: val = LE_READ_4(dl + 3);
! 1188: pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
! 1189: pos &= 0x3f;
! 1190: (*mfilt)[pos / 32] |= (1 << (pos % 32));
! 1191: }
! 1192:
! 1193: void
! 1194: ath_mcastfilter_compute(struct ath_softc *sc, u_int32_t (*mfilt)[2])
! 1195: {
! 1196: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1197: struct ether_multi *enm;
! 1198: struct ether_multistep estep;
! 1199:
! 1200: ETHER_FIRST_MULTI(estep, &sc->sc_ic.ic_ac, enm);
! 1201: while (enm != NULL) {
! 1202: /* XXX Punt on ranges. */
! 1203: if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) {
! 1204: (*mfilt)[0] = (*mfilt)[1] = ~((u_int32_t)0);
! 1205: ifp->if_flags |= IFF_ALLMULTI;
! 1206: return;
! 1207: }
! 1208: ath_mcastfilter_accum(enm->enm_addrlo, mfilt);
! 1209: ETHER_NEXT_MULTI(estep, enm);
! 1210: }
! 1211: ifp->if_flags &= ~IFF_ALLMULTI;
! 1212: }
! 1213:
! 1214: /*
! 1215: * Calculate the receive filter according to the
! 1216: * operating mode and state:
! 1217: *
! 1218: * o always accept unicast, broadcast, and multicast traffic
! 1219: * o maintain current state of phy error reception
! 1220: * o probe request frames are accepted only when operating in
! 1221: * hostap, adhoc, or monitor modes
! 1222: * o enable promiscuous mode according to the interface state
! 1223: * o accept beacons:
! 1224: * - when operating in adhoc mode so the 802.11 layer creates
! 1225: * node table entries for peers,
! 1226: * - when operating in station mode for collecting rssi data when
! 1227: * the station is otherwise quiet, or
! 1228: * - when scanning
! 1229: */
! 1230: u_int32_t
! 1231: ath_calcrxfilter(struct ath_softc *sc)
! 1232: {
! 1233: struct ieee80211com *ic = &sc->sc_ic;
! 1234: struct ath_hal *ah = sc->sc_ah;
! 1235: struct ifnet *ifp = &ic->ic_if;
! 1236: u_int32_t rfilt;
! 1237:
! 1238: rfilt = (ath_hal_get_rx_filter(ah) & HAL_RX_FILTER_PHYERR)
! 1239: | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
! 1240: if (ic->ic_opmode != IEEE80211_M_STA)
! 1241: rfilt |= HAL_RX_FILTER_PROBEREQ;
! 1242: if (ic->ic_opmode != IEEE80211_M_AHDEMO)
! 1243: rfilt |= HAL_RX_FILTER_BEACON;
! 1244: if (ifp->if_flags & IFF_PROMISC)
! 1245: rfilt |= HAL_RX_FILTER_PROM;
! 1246: return rfilt;
! 1247: }
! 1248:
! 1249: void
! 1250: ath_mode_init(struct ath_softc *sc)
! 1251: {
! 1252: struct ath_hal *ah = sc->sc_ah;
! 1253: u_int32_t rfilt, mfilt[2];
! 1254:
! 1255: /* configure rx filter */
! 1256: rfilt = ath_calcrxfilter(sc);
! 1257: ath_hal_set_rx_filter(ah, rfilt);
! 1258:
! 1259: /* configure operational mode */
! 1260: ath_hal_set_opmode(ah);
! 1261:
! 1262: /* calculate and install multicast filter */
! 1263: mfilt[0] = mfilt[1] = 0;
! 1264: ath_mcastfilter_compute(sc, &mfilt);
! 1265: ath_hal_set_mcast_filter(ah, mfilt[0], mfilt[1]);
! 1266: DPRINTF(ATH_DEBUG_MODE, ("%s: RX filter 0x%x, MC filter %08x:%08x\n",
! 1267: __func__, rfilt, mfilt[0], mfilt[1]));
! 1268: }
! 1269:
! 1270: struct mbuf *
! 1271: ath_getmbuf(int flags, int type, u_int pktlen)
! 1272: {
! 1273: struct mbuf *m;
! 1274:
! 1275: KASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen));
! 1276: #ifdef __FreeBSD__
! 1277: if (pktlen <= MHLEN) {
! 1278: MGETHDR(m, flags, type);
! 1279: } else {
! 1280: m = m_getcl(flags, type, M_PKTHDR);
! 1281: }
! 1282: #else
! 1283: MGETHDR(m, flags, type);
! 1284: if (m != NULL && pktlen > MHLEN) {
! 1285: MCLGET(m, flags);
! 1286: if ((m->m_flags & M_EXT) == 0) {
! 1287: m_free(m);
! 1288: m = NULL;
! 1289: }
! 1290: }
! 1291: #endif
! 1292: return m;
! 1293: }
! 1294:
! 1295: int
! 1296: ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
! 1297: {
! 1298: struct ieee80211com *ic = &sc->sc_ic;
! 1299: struct ath_hal *ah = sc->sc_ah;
! 1300: struct ath_buf *bf;
! 1301: struct ath_desc *ds;
! 1302: struct mbuf *m;
! 1303: int error;
! 1304: u_int8_t rate;
! 1305: const HAL_RATE_TABLE *rt;
! 1306: u_int flags = 0;
! 1307:
! 1308: bf = sc->sc_bcbuf;
! 1309: if (bf->bf_m != NULL) {
! 1310: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 1311: m_freem(bf->bf_m);
! 1312: bf->bf_m = NULL;
! 1313: bf->bf_node = NULL;
! 1314: }
! 1315: /*
! 1316: * NB: the beacon data buffer must be 32-bit aligned;
! 1317: * we assume the mbuf routines will return us something
! 1318: * with this alignment (perhaps should assert).
! 1319: */
! 1320: m = ieee80211_beacon_alloc(ic, ni);
! 1321: if (m == NULL) {
! 1322: DPRINTF(ATH_DEBUG_BEACON, ("%s: cannot get mbuf/cluster\n",
! 1323: __func__));
! 1324: sc->sc_stats.ast_be_nombuf++;
! 1325: return ENOMEM;
! 1326: }
! 1327:
! 1328: DPRINTF(ATH_DEBUG_BEACON, ("%s: m %p len %u\n", __func__, m, m->m_len));
! 1329: error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m,
! 1330: BUS_DMA_NOWAIT);
! 1331: if (error != 0) {
! 1332: m_freem(m);
! 1333: return error;
! 1334: }
! 1335: KASSERT(bf->bf_nseg == 1,
! 1336: ("%s: multi-segment packet; nseg %u", __func__, bf->bf_nseg));
! 1337: bf->bf_m = m;
! 1338:
! 1339: /* setup descriptors */
! 1340: ds = bf->bf_desc;
! 1341: bzero(ds, sizeof(struct ath_desc));
! 1342:
! 1343: if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_veol) {
! 1344: ds->ds_link = bf->bf_daddr; /* link to self */
! 1345: flags |= HAL_TXDESC_VEOL;
! 1346: } else {
! 1347: ds->ds_link = 0;
! 1348: }
! 1349: ds->ds_data = bf->bf_segs[0].ds_addr;
! 1350:
! 1351: DPRINTF(ATH_DEBUG_ANY, ("%s: segaddr %p seglen %u\n", __func__,
! 1352: (caddr_t)bf->bf_segs[0].ds_addr, (u_int)bf->bf_segs[0].ds_len));
! 1353:
! 1354: /*
! 1355: * Calculate rate code.
! 1356: * XXX everything at min xmit rate
! 1357: */
! 1358: rt = sc->sc_currates;
! 1359: KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
! 1360: if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
! 1361: rate = rt->info[0].rateCode | rt->info[0].shortPreamble;
! 1362: } else {
! 1363: rate = rt->info[0].rateCode;
! 1364: }
! 1365:
! 1366: flags = HAL_TXDESC_NOACK;
! 1367: if (ic->ic_opmode == IEEE80211_M_IBSS)
! 1368: flags |= HAL_TXDESC_VEOL;
! 1369:
! 1370: if (!ath_hal_setup_tx_desc(ah, ds
! 1371: , m->m_pkthdr.len + IEEE80211_CRC_LEN /* packet length */
! 1372: , sizeof(struct ieee80211_frame) /* header length */
! 1373: , HAL_PKT_TYPE_BEACON /* Atheros packet type */
! 1374: , 60 /* txpower XXX */
! 1375: , rate, 1 /* series 0 rate/tries */
! 1376: , HAL_TXKEYIX_INVALID /* no encryption */
! 1377: , 0 /* antenna mode */
! 1378: , flags /* no ack for beacons */
! 1379: , 0 /* rts/cts rate */
! 1380: , 0 /* rts/cts duration */
! 1381: )) {
! 1382: printf("%s: ath_hal_setup_tx_desc failed\n", __func__);
! 1383: return -1;
! 1384: }
! 1385: /* NB: beacon's BufLen must be a multiple of 4 bytes */
! 1386: /* XXX verify mbuf data area covers this roundup */
! 1387: if (!ath_hal_fill_tx_desc(ah, ds
! 1388: , roundup(bf->bf_segs[0].ds_len, 4) /* buffer length */
! 1389: , AH_TRUE /* first segment */
! 1390: , AH_TRUE /* last segment */
! 1391: )) {
! 1392: printf("%s: ath_hal_fill_tx_desc failed\n", __func__);
! 1393: return -1;
! 1394: }
! 1395:
! 1396: /* XXX it is not appropriate to bus_dmamap_sync? -dcy */
! 1397:
! 1398: return 0;
! 1399: }
! 1400:
! 1401: void
! 1402: ath_beacon_proc(void *arg, int pending)
! 1403: {
! 1404: struct ath_softc *sc = arg;
! 1405: struct ieee80211com *ic = &sc->sc_ic;
! 1406: struct ath_buf *bf = sc->sc_bcbuf;
! 1407: struct ath_hal *ah = sc->sc_ah;
! 1408:
! 1409: DPRINTF(ATH_DEBUG_BEACON_PROC, ("%s: pending %u\n", __func__, pending));
! 1410: if (ic->ic_opmode == IEEE80211_M_STA ||
! 1411: bf == NULL || bf->bf_m == NULL) {
! 1412: DPRINTF(ATH_DEBUG_ANY, ("%s: ic_flags=%x bf=%p bf_m=%p\n",
! 1413: __func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL));
! 1414: return;
! 1415: }
! 1416: /* TODO: update beacon to reflect PS poll state */
! 1417: if (!ath_hal_stop_tx_dma(ah, sc->sc_bhalq)) {
! 1418: DPRINTF(ATH_DEBUG_ANY, ("%s: beacon queue %u did not stop?\n",
! 1419: __func__, sc->sc_bhalq));
! 1420: }
! 1421: bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
! 1422: bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1423:
! 1424: ath_hal_put_tx_buf(ah, sc->sc_bhalq, bf->bf_daddr);
! 1425: ath_hal_tx_start(ah, sc->sc_bhalq);
! 1426: DPRINTF(ATH_DEBUG_BEACON_PROC,
! 1427: ("%s: TXDP%u = %p (%p)\n", __func__,
! 1428: sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc));
! 1429: }
! 1430:
! 1431: void
! 1432: ath_beacon_free(struct ath_softc *sc)
! 1433: {
! 1434: struct ath_buf *bf = sc->sc_bcbuf;
! 1435:
! 1436: if (bf->bf_m != NULL) {
! 1437: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 1438: m_freem(bf->bf_m);
! 1439: bf->bf_m = NULL;
! 1440: bf->bf_node = NULL;
! 1441: }
! 1442: }
! 1443:
! 1444: /*
! 1445: * Configure the beacon and sleep timers.
! 1446: *
! 1447: * When operating as an AP this resets the TSF and sets
! 1448: * up the hardware to notify us when we need to issue beacons.
! 1449: *
! 1450: * When operating in station mode this sets up the beacon
! 1451: * timers according to the timestamp of the last received
! 1452: * beacon and the current TSF, configures PCF and DTIM
! 1453: * handling, programs the sleep registers so the hardware
! 1454: * will wakeup in time to receive beacons, and configures
! 1455: * the beacon miss handling so we'll receive a BMISS
! 1456: * interrupt when we stop seeing beacons from the AP
! 1457: * we've associated with.
! 1458: */
! 1459: void
! 1460: ath_beacon_config(struct ath_softc *sc)
! 1461: {
! 1462: #define MS_TO_TU(x) (((x) * 1000) / 1024)
! 1463: struct ath_hal *ah = sc->sc_ah;
! 1464: struct ieee80211com *ic = &sc->sc_ic;
! 1465: struct ieee80211_node *ni = ic->ic_bss;
! 1466: u_int32_t nexttbtt, intval;
! 1467:
! 1468: nexttbtt = (LE_READ_4(ni->ni_tstamp + 4) << 22) |
! 1469: (LE_READ_4(ni->ni_tstamp) >> 10);
! 1470: intval = MAX(1, ni->ni_intval) & HAL_BEACON_PERIOD;
! 1471: if (nexttbtt == 0) { /* e.g. for ap mode */
! 1472: nexttbtt = intval;
! 1473: } else if (intval) {
! 1474: nexttbtt = roundup(nexttbtt, intval);
! 1475: }
! 1476: DPRINTF(ATH_DEBUG_BEACON, ("%s: intval %u nexttbtt %u\n",
! 1477: __func__, ni->ni_intval, nexttbtt));
! 1478: if (ic->ic_opmode == IEEE80211_M_STA) {
! 1479: HAL_BEACON_STATE bs;
! 1480: u_int32_t bmisstime;
! 1481:
! 1482: /* NB: no PCF support right now */
! 1483: bzero(&bs, sizeof(bs));
! 1484: bs.bs_intval = intval;
! 1485: bs.bs_nexttbtt = nexttbtt;
! 1486: bs.bs_dtimperiod = bs.bs_intval;
! 1487: bs.bs_nextdtim = nexttbtt;
! 1488: /*
! 1489: * Calculate the number of consecutive beacons to miss
! 1490: * before taking a BMISS interrupt. The configuration
! 1491: * is specified in ms, so we need to convert that to
! 1492: * TU's and then calculate based on the beacon interval.
! 1493: * Note that we clamp the result to at most 10 beacons.
! 1494: */
! 1495: bmisstime = MAX(7, ic->ic_bmisstimeout);
! 1496: bs.bs_bmissthreshold = howmany(bmisstime, intval);
! 1497: if (bs.bs_bmissthreshold > 7) {
! 1498: bs.bs_bmissthreshold = 7;
! 1499: } else if (bs.bs_bmissthreshold <= 0) {
! 1500: bs.bs_bmissthreshold = 1;
! 1501: }
! 1502:
! 1503: /*
! 1504: * Calculate sleep duration. The configuration is
! 1505: * given in ms. We insure a multiple of the beacon
! 1506: * period is used. Also, if the sleep duration is
! 1507: * greater than the DTIM period then it makes senses
! 1508: * to make it a multiple of that.
! 1509: *
! 1510: * XXX fixed at 100ms
! 1511: */
! 1512: bs.bs_sleepduration =
! 1513: roundup(MS_TO_TU(100), bs.bs_intval);
! 1514: if (bs.bs_sleepduration > bs.bs_dtimperiod) {
! 1515: bs.bs_sleepduration =
! 1516: roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
! 1517: }
! 1518:
! 1519: DPRINTF(ATH_DEBUG_BEACON,
! 1520: ("%s: intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u"
! 1521: " sleep %u\n"
! 1522: , __func__
! 1523: , bs.bs_intval
! 1524: , bs.bs_nexttbtt
! 1525: , bs.bs_dtimperiod
! 1526: , bs.bs_nextdtim
! 1527: , bs.bs_bmissthreshold
! 1528: , bs.bs_sleepduration
! 1529: ));
! 1530: ath_hal_set_intr(ah, 0);
! 1531: ath_hal_set_beacon_timers(ah, &bs, 0/*XXX*/, 0, 0);
! 1532: sc->sc_imask |= HAL_INT_BMISS;
! 1533: ath_hal_set_intr(ah, sc->sc_imask);
! 1534: } else {
! 1535: ath_hal_set_intr(ah, 0);
! 1536: if (nexttbtt == intval)
! 1537: intval |= HAL_BEACON_RESET_TSF;
! 1538: if (ic->ic_opmode == IEEE80211_M_IBSS) {
! 1539: /*
! 1540: * In IBSS mode enable the beacon timers but ony
! 1541: * enable SWBA interrupts if we need to moanually
! 1542: * prepare beacon frames. Otherwise we use a
! 1543: * self-linked tx descriptor and let the hardware
! 1544: * deal with things.
! 1545: */
! 1546: intval |= HAL_BEACON_ENA;
! 1547: if (!sc->sc_veol)
! 1548: sc->sc_imask |= HAL_INT_SWBA;
! 1549: } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
! 1550: /*
! 1551: * In AP mode we enable the beacon timers and
! 1552: * SWBA interrupts to prepare beacon frames.
! 1553: */
! 1554: intval |= HAL_BEACON_ENA;
! 1555: sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */
! 1556: }
! 1557: ath_hal_init_beacon(ah, nexttbtt, intval);
! 1558: ath_hal_set_intr(ah, sc->sc_imask);
! 1559: /*
! 1560: * When using a self-linked beacon descriptor in IBBS
! 1561: * mode load it once here.
! 1562: */
! 1563: if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_veol)
! 1564: ath_beacon_proc(sc, 0);
! 1565: }
! 1566: }
! 1567:
! 1568: int
! 1569: ath_desc_alloc(struct ath_softc *sc)
! 1570: {
! 1571: int i, bsize, error = -1;
! 1572: struct ath_desc *ds;
! 1573: struct ath_buf *bf;
! 1574:
! 1575: /* allocate descriptors */
! 1576: sc->sc_desc_len = sizeof(struct ath_desc) *
! 1577: (ATH_TXBUF * ATH_TXDESC + ATH_RXBUF + 1);
! 1578: if ((error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_desc_len, PAGE_SIZE,
! 1579: 0, &sc->sc_dseg, 1, &sc->sc_dnseg, 0)) != 0) {
! 1580: printf("%s: unable to allocate control data, error = %d\n",
! 1581: sc->sc_dev.dv_xname, error);
! 1582: goto fail0;
! 1583: }
! 1584:
! 1585: if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dseg, sc->sc_dnseg,
! 1586: sc->sc_desc_len, (caddr_t *)&sc->sc_desc, BUS_DMA_COHERENT)) != 0) {
! 1587: printf("%s: unable to map control data, error = %d\n",
! 1588: sc->sc_dev.dv_xname, error);
! 1589: goto fail1;
! 1590: }
! 1591:
! 1592: if ((error = bus_dmamap_create(sc->sc_dmat, sc->sc_desc_len, 1,
! 1593: sc->sc_desc_len, 0, 0, &sc->sc_ddmamap)) != 0) {
! 1594: printf("%s: unable to create control data DMA map, "
! 1595: "error = %d\n", sc->sc_dev.dv_xname, error);
! 1596: goto fail2;
! 1597: }
! 1598:
! 1599: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_ddmamap, sc->sc_desc,
! 1600: sc->sc_desc_len, NULL, 0)) != 0) {
! 1601: printf("%s: unable to load control data DMA map, error = %d\n",
! 1602: sc->sc_dev.dv_xname, error);
! 1603: goto fail3;
! 1604: }
! 1605:
! 1606: ds = sc->sc_desc;
! 1607: sc->sc_desc_paddr = sc->sc_ddmamap->dm_segs[0].ds_addr;
! 1608:
! 1609: DPRINTF(ATH_DEBUG_XMIT_DESC|ATH_DEBUG_RECV_DESC,
! 1610: ("ath_desc_alloc: DMA map: %p (%lu) -> %p (%lu)\n",
! 1611: ds, (u_long)sc->sc_desc_len,
! 1612: (caddr_t) sc->sc_desc_paddr, /*XXX*/ (u_long) sc->sc_desc_len));
! 1613:
! 1614: /* allocate buffers */
! 1615: bsize = sizeof(struct ath_buf) * (ATH_TXBUF + ATH_RXBUF + 1);
! 1616: bf = malloc(bsize, M_DEVBUF, M_NOWAIT);
! 1617: if (bf == NULL) {
! 1618: printf("%s: unable to allocate Tx/Rx buffers\n",
! 1619: sc->sc_dev.dv_xname);
! 1620: error = ENOMEM;
! 1621: goto fail3;
! 1622: }
! 1623: bzero(bf, bsize);
! 1624: sc->sc_bufptr = bf;
! 1625:
! 1626: TAILQ_INIT(&sc->sc_rxbuf);
! 1627: for (i = 0; i < ATH_RXBUF; i++, bf++, ds++) {
! 1628: bf->bf_desc = ds;
! 1629: bf->bf_daddr = sc->sc_desc_paddr +
! 1630: ((caddr_t)ds - (caddr_t)sc->sc_desc);
! 1631: if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 1632: MCLBYTES, 0, 0, &bf->bf_dmamap)) != 0) {
! 1633: printf("%s: unable to create Rx dmamap, error = %d\n",
! 1634: sc->sc_dev.dv_xname, error);
! 1635: goto fail4;
! 1636: }
! 1637: TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
! 1638: }
! 1639:
! 1640: TAILQ_INIT(&sc->sc_txbuf);
! 1641: for (i = 0; i < ATH_TXBUF; i++, bf++, ds += ATH_TXDESC) {
! 1642: bf->bf_desc = ds;
! 1643: bf->bf_daddr = sc->sc_desc_paddr +
! 1644: ((caddr_t)ds - (caddr_t)sc->sc_desc);
! 1645: if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
! 1646: ATH_TXDESC, MCLBYTES, 0, 0, &bf->bf_dmamap)) != 0) {
! 1647: printf("%s: unable to create Tx dmamap, error = %d\n",
! 1648: sc->sc_dev.dv_xname, error);
! 1649: goto fail5;
! 1650: }
! 1651: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 1652: }
! 1653: TAILQ_INIT(&sc->sc_txq);
! 1654:
! 1655: /* beacon buffer */
! 1656: bf->bf_desc = ds;
! 1657: bf->bf_daddr = sc->sc_desc_paddr + ((caddr_t)ds - (caddr_t)sc->sc_desc);
! 1658: if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, 0,
! 1659: &bf->bf_dmamap)) != 0) {
! 1660: printf("%s: unable to create beacon dmamap, error = %d\n",
! 1661: sc->sc_dev.dv_xname, error);
! 1662: goto fail5;
! 1663: }
! 1664: sc->sc_bcbuf = bf;
! 1665: return 0;
! 1666:
! 1667: fail5:
! 1668: for (i = ATH_RXBUF; i < ATH_RXBUF + ATH_TXBUF; i++) {
! 1669: if (sc->sc_bufptr[i].bf_dmamap == NULL)
! 1670: continue;
! 1671: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufptr[i].bf_dmamap);
! 1672: }
! 1673: fail4:
! 1674: for (i = 0; i < ATH_RXBUF; i++) {
! 1675: if (sc->sc_bufptr[i].bf_dmamap == NULL)
! 1676: continue;
! 1677: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufptr[i].bf_dmamap);
! 1678: }
! 1679: fail3:
! 1680: bus_dmamap_unload(sc->sc_dmat, sc->sc_ddmamap);
! 1681: fail2:
! 1682: bus_dmamap_destroy(sc->sc_dmat, sc->sc_ddmamap);
! 1683: sc->sc_ddmamap = NULL;
! 1684: fail1:
! 1685: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_desc, sc->sc_desc_len);
! 1686: fail0:
! 1687: bus_dmamem_free(sc->sc_dmat, &sc->sc_dseg, sc->sc_dnseg);
! 1688: return error;
! 1689: }
! 1690:
! 1691: void
! 1692: ath_desc_free(struct ath_softc *sc)
! 1693: {
! 1694: struct ath_buf *bf;
! 1695:
! 1696: bus_dmamap_unload(sc->sc_dmat, sc->sc_ddmamap);
! 1697: bus_dmamap_destroy(sc->sc_dmat, sc->sc_ddmamap);
! 1698: bus_dmamem_free(sc->sc_dmat, &sc->sc_dseg, sc->sc_dnseg);
! 1699:
! 1700: TAILQ_FOREACH(bf, &sc->sc_txq, bf_list) {
! 1701: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 1702: bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
! 1703: m_freem(bf->bf_m);
! 1704: }
! 1705: TAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list)
! 1706: bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
! 1707: TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
! 1708: if (bf->bf_m) {
! 1709: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 1710: bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
! 1711: m_freem(bf->bf_m);
! 1712: bf->bf_m = NULL;
! 1713: }
! 1714: }
! 1715: if (sc->sc_bcbuf != NULL) {
! 1716: bus_dmamap_unload(sc->sc_dmat, sc->sc_bcbuf->bf_dmamap);
! 1717: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bcbuf->bf_dmamap);
! 1718: sc->sc_bcbuf = NULL;
! 1719: }
! 1720:
! 1721: TAILQ_INIT(&sc->sc_rxbuf);
! 1722: TAILQ_INIT(&sc->sc_txbuf);
! 1723: TAILQ_INIT(&sc->sc_txq);
! 1724: free(sc->sc_bufptr, M_DEVBUF);
! 1725: sc->sc_bufptr = NULL;
! 1726: }
! 1727:
! 1728: struct ieee80211_node *
! 1729: ath_node_alloc(struct ieee80211com *ic)
! 1730: {
! 1731: struct ath_node *an =
! 1732: malloc(sizeof(struct ath_node), M_DEVBUF, M_NOWAIT);
! 1733: if (an) {
! 1734: int i;
! 1735: bzero(an, sizeof(struct ath_node));
! 1736: for (i = 0; i < ATH_RHIST_SIZE; i++)
! 1737: an->an_rx_hist[i].arh_ticks = ATH_RHIST_NOTIME;
! 1738: an->an_rx_hist_next = ATH_RHIST_SIZE-1;
! 1739: return &an->an_node;
! 1740: } else
! 1741: return NULL;
! 1742: }
! 1743:
! 1744: void
! 1745: ath_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1746: {
! 1747: struct ath_softc *sc = ic->ic_if.if_softc;
! 1748: struct ath_buf *bf;
! 1749:
! 1750: TAILQ_FOREACH(bf, &sc->sc_txq, bf_list) {
! 1751: if (bf->bf_node == ni)
! 1752: bf->bf_node = NULL;
! 1753: }
! 1754: (*sc->sc_node_free)(ic, ni);
! 1755: }
! 1756:
! 1757: void
! 1758: ath_node_copy(struct ieee80211com *ic,
! 1759: struct ieee80211_node *dst, const struct ieee80211_node *src)
! 1760: {
! 1761: struct ath_softc *sc = ic->ic_if.if_softc;
! 1762:
! 1763: bcopy(&src[1], &dst[1],
! 1764: sizeof(struct ath_node) - sizeof(struct ieee80211_node));
! 1765: (*sc->sc_node_copy)(ic, dst, src);
! 1766: }
! 1767:
! 1768: u_int8_t
! 1769: ath_node_getrssi(struct ieee80211com *ic, const struct ieee80211_node *ni)
! 1770: {
! 1771: const struct ath_node *an = ATH_NODE(ni);
! 1772: int i, now, nsamples, rssi;
! 1773:
! 1774: /*
! 1775: * Calculate the average over the last second of sampled data.
! 1776: */
! 1777: now = ATH_TICKS();
! 1778: nsamples = 0;
! 1779: rssi = 0;
! 1780: i = an->an_rx_hist_next;
! 1781: do {
! 1782: const struct ath_recv_hist *rh = &an->an_rx_hist[i];
! 1783: if (rh->arh_ticks == ATH_RHIST_NOTIME)
! 1784: goto done;
! 1785: if (now - rh->arh_ticks > hz)
! 1786: goto done;
! 1787: rssi += rh->arh_rssi;
! 1788: nsamples++;
! 1789: if (i == 0) {
! 1790: i = ATH_RHIST_SIZE-1;
! 1791: } else {
! 1792: i--;
! 1793: }
! 1794: } while (i != an->an_rx_hist_next);
! 1795: done:
! 1796: /*
! 1797: * Return either the average or the last known
! 1798: * value if there is no recent data.
! 1799: */
! 1800: return (nsamples ? rssi / nsamples : an->an_rx_hist[i].arh_rssi);
! 1801: }
! 1802:
! 1803: int
! 1804: ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
! 1805: {
! 1806: struct ath_hal *ah = sc->sc_ah;
! 1807: struct ieee80211com *ic = &sc->sc_ic;
! 1808: int error;
! 1809: struct mbuf *m;
! 1810: struct ath_desc *ds;
! 1811:
! 1812: m = bf->bf_m;
! 1813: if (m == NULL) {
! 1814: /*
! 1815: * NB: by assigning a page to the rx dma buffer we
! 1816: * implicitly satisfy the Atheros requirement that
! 1817: * this buffer be cache-line-aligned and sized to be
! 1818: * multiple of the cache line size. Not doing this
! 1819: * causes weird stuff to happen (for the 5210 at least).
! 1820: */
! 1821: m = ath_getmbuf(M_DONTWAIT, MT_DATA, MCLBYTES);
! 1822: if (m == NULL) {
! 1823: DPRINTF(ATH_DEBUG_ANY,
! 1824: ("%s: no mbuf/cluster\n", __func__));
! 1825: sc->sc_stats.ast_rx_nombuf++;
! 1826: return ENOMEM;
! 1827: }
! 1828: bf->bf_m = m;
! 1829: m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
! 1830:
! 1831: error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m,
! 1832: BUS_DMA_NOWAIT);
! 1833: if (error != 0) {
! 1834: DPRINTF(ATH_DEBUG_ANY,
! 1835: ("%s: ath_bus_dmamap_load_mbuf failed;"
! 1836: " error %d\n", __func__, error));
! 1837: sc->sc_stats.ast_rx_busdma++;
! 1838: return error;
! 1839: }
! 1840: KASSERT(bf->bf_nseg == 1,
! 1841: ("ath_rxbuf_init: multi-segment packet; nseg %u",
! 1842: bf->bf_nseg));
! 1843: }
! 1844: bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
! 1845: bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1846:
! 1847: /*
! 1848: * Setup descriptors. For receive we always terminate
! 1849: * the descriptor list with a self-linked entry so we'll
! 1850: * not get overrun under high load (as can happen with a
! 1851: * 5212 when ANI processing enables PHY errors).
! 1852: *
! 1853: * To insure the last descriptor is self-linked we create
! 1854: * each descriptor as self-linked and add it to the end. As
! 1855: * each additional descriptor is added the previous self-linked
! 1856: * entry is ``fixed'' naturally. This should be safe even
! 1857: * if DMA is happening. When processing RX interrupts we
! 1858: * never remove/process the last, self-linked, entry on the
! 1859: * descriptor list. This insures the hardware always has
! 1860: * someplace to write a new frame.
! 1861: */
! 1862: ds = bf->bf_desc;
! 1863: bzero(ds, sizeof(struct ath_desc));
! 1864: if (ic->ic_opmode != IEEE80211_M_HOSTAP)
! 1865: ds->ds_link = bf->bf_daddr; /* link to self */
! 1866: ds->ds_data = bf->bf_segs[0].ds_addr;
! 1867: ath_hal_setup_rx_desc(ah, ds
! 1868: , m->m_len /* buffer size */
! 1869: , 0
! 1870: );
! 1871:
! 1872: if (sc->sc_rxlink != NULL)
! 1873: *sc->sc_rxlink = bf->bf_daddr;
! 1874: sc->sc_rxlink = &ds->ds_link;
! 1875: return 0;
! 1876: }
! 1877:
! 1878: void
! 1879: ath_rx_proc(void *arg, int npending)
! 1880: {
! 1881: #define PA2DESC(_sc, _pa) \
! 1882: ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
! 1883: ((_pa) - (_sc)->sc_desc_paddr)))
! 1884: struct ath_softc *sc = arg;
! 1885: struct ath_buf *bf;
! 1886: struct ieee80211com *ic = &sc->sc_ic;
! 1887: struct ifnet *ifp = &ic->ic_if;
! 1888: struct ath_hal *ah = sc->sc_ah;
! 1889: struct ath_desc *ds;
! 1890: struct mbuf *m;
! 1891: struct ieee80211_frame *wh, whbuf;
! 1892: struct ieee80211_node *ni;
! 1893: struct ath_node *an;
! 1894: struct ath_recv_hist *rh;
! 1895: int len;
! 1896: u_int phyerr;
! 1897: HAL_STATUS status;
! 1898:
! 1899: DPRINTF(ATH_DEBUG_RX_PROC, ("%s: pending %u\n", __func__, npending));
! 1900: do {
! 1901: bf = TAILQ_FIRST(&sc->sc_rxbuf);
! 1902: if (bf == NULL) { /* NB: shouldn't happen */
! 1903: printf("%s: ath_rx_proc: no buffer!\n", ifp->if_xname);
! 1904: break;
! 1905: }
! 1906: ds = bf->bf_desc;
! 1907: if (ds->ds_link == bf->bf_daddr) {
! 1908: /* NB: never process the self-linked entry at the end */
! 1909: break;
! 1910: }
! 1911: m = bf->bf_m;
! 1912: if (m == NULL) { /* NB: shouldn't happen */
! 1913: printf("%s: ath_rx_proc: no mbuf!\n", ifp->if_xname);
! 1914: continue;
! 1915: }
! 1916: /* XXX sync descriptor memory */
! 1917: /*
! 1918: * Must provide the virtual address of the current
! 1919: * descriptor, the physical address, and the virtual
! 1920: * address of the next descriptor in the h/w chain.
! 1921: * This allows the HAL to look ahead to see if the
! 1922: * hardware is done with a descriptor by checking the
! 1923: * done bit in the following descriptor and the address
! 1924: * of the current descriptor the DMA engine is working
! 1925: * on. All this is necessary because of our use of
! 1926: * a self-linked list to avoid rx overruns.
! 1927: */
! 1928: status = ath_hal_proc_rx_desc(ah, ds,
! 1929: bf->bf_daddr, PA2DESC(sc, ds->ds_link));
! 1930: #ifdef AR_DEBUG
! 1931: if (ath_debug & ATH_DEBUG_RECV_DESC)
! 1932: ath_printrxbuf(bf, status == HAL_OK);
! 1933: #endif
! 1934: if (status == HAL_EINPROGRESS)
! 1935: break;
! 1936: TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
! 1937:
! 1938: if (ds->ds_rxstat.rs_more) {
! 1939: /*
! 1940: * Frame spans multiple descriptors; this
! 1941: * cannot happen yet as we don't support
! 1942: * jumbograms. If not in monitor mode,
! 1943: * discard the frame.
! 1944: */
! 1945:
! 1946: /*
! 1947: * Enable this if you want to see error
! 1948: * frames in Monitor mode.
! 1949: */
! 1950: #ifdef ERROR_FRAMES
! 1951: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
! 1952: /* XXX statistic */
! 1953: goto rx_next;
! 1954: }
! 1955: #endif
! 1956: /* fall thru for monitor mode handling... */
! 1957:
! 1958: } else if (ds->ds_rxstat.rs_status != 0) {
! 1959: if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC)
! 1960: sc->sc_stats.ast_rx_crcerr++;
! 1961: if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO)
! 1962: sc->sc_stats.ast_rx_fifoerr++;
! 1963: if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT)
! 1964: sc->sc_stats.ast_rx_badcrypt++;
! 1965: if (ds->ds_rxstat.rs_status & HAL_RXERR_PHY) {
! 1966: sc->sc_stats.ast_rx_phyerr++;
! 1967: phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
! 1968: sc->sc_stats.ast_rx_phy[phyerr]++;
! 1969: }
! 1970:
! 1971: /*
! 1972: * reject error frames, we normally don't want
! 1973: * to see them in monitor mode.
! 1974: */
! 1975: if ((ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT ) ||
! 1976: (ds->ds_rxstat.rs_status & HAL_RXERR_PHY))
! 1977: goto rx_next;
! 1978:
! 1979: /*
! 1980: * In monitor mode, allow through packets that
! 1981: * cannot be decrypted
! 1982: */
! 1983: if ((ds->ds_rxstat.rs_status & ~HAL_RXERR_DECRYPT) ||
! 1984: sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR)
! 1985: goto rx_next;
! 1986: }
! 1987:
! 1988: len = ds->ds_rxstat.rs_datalen;
! 1989: if (len < IEEE80211_MIN_LEN) {
! 1990: DPRINTF(ATH_DEBUG_RECV, ("%s: short packet %d\n",
! 1991: __func__, len));
! 1992: sc->sc_stats.ast_rx_tooshort++;
! 1993: goto rx_next;
! 1994: }
! 1995:
! 1996: bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
! 1997: bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1998:
! 1999: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 2000: bf->bf_m = NULL;
! 2001: m->m_pkthdr.rcvif = ifp;
! 2002: m->m_pkthdr.len = m->m_len = len;
! 2003:
! 2004: #if NBPFILTER > 0
! 2005: if (sc->sc_drvbpf) {
! 2006: struct mbuf mb;
! 2007:
! 2008: sc->sc_rxtap.wr_rate =
! 2009: sc->sc_hwmap[ds->ds_rxstat.rs_rate] &
! 2010: IEEE80211_RATE_VAL;
! 2011: sc->sc_rxtap.wr_antenna = ds->ds_rxstat.rs_antenna;
! 2012: sc->sc_rxtap.wr_rssi = ds->ds_rxstat.rs_rssi;
! 2013: sc->sc_rxtap.wr_max_rssi = ic->ic_max_rssi;
! 2014:
! 2015: mb.m_data = (caddr_t)&sc->sc_rxtap;
! 2016: mb.m_len = sc->sc_rxtap_len;
! 2017: mb.m_next = m;
! 2018: mb.m_nextpkt = NULL;
! 2019: mb.m_type = 0;
! 2020: mb.m_flags = 0;
! 2021: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 2022: }
! 2023: #endif
! 2024:
! 2025: m_adj(m, -IEEE80211_CRC_LEN);
! 2026: wh = mtod(m, struct ieee80211_frame *);
! 2027: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 2028: /*
! 2029: * WEP is decrypted by hardware. Clear WEP bit
! 2030: * and trim WEP header for ieee80211_input().
! 2031: */
! 2032: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
! 2033: bcopy(wh, &whbuf, sizeof(whbuf));
! 2034: m_adj(m, IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN);
! 2035: wh = mtod(m, struct ieee80211_frame *);
! 2036: bcopy(&whbuf, wh, sizeof(whbuf));
! 2037: /*
! 2038: * Also trim WEP ICV from the tail.
! 2039: */
! 2040: m_adj(m, -IEEE80211_WEP_CRCLEN);
! 2041: /*
! 2042: * The header has probably moved.
! 2043: */
! 2044: wh = mtod(m, struct ieee80211_frame *);
! 2045: }
! 2046:
! 2047: /*
! 2048: * Locate the node for sender, track state, and
! 2049: * then pass this node (referenced) up to the 802.11
! 2050: * layer for its use.
! 2051: */
! 2052: ni = ieee80211_find_rxnode(ic, wh);
! 2053:
! 2054: /*
! 2055: * Record driver-specific state.
! 2056: */
! 2057: an = ATH_NODE(ni);
! 2058: if (++(an->an_rx_hist_next) == ATH_RHIST_SIZE)
! 2059: an->an_rx_hist_next = 0;
! 2060: rh = &an->an_rx_hist[an->an_rx_hist_next];
! 2061: rh->arh_ticks = ATH_TICKS();
! 2062: rh->arh_rssi = ds->ds_rxstat.rs_rssi;
! 2063: rh->arh_antenna = ds->ds_rxstat.rs_antenna;
! 2064:
! 2065: /*
! 2066: * Send frame up for processing.
! 2067: */
! 2068: ieee80211_input(ifp, m, ni,
! 2069: ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
! 2070:
! 2071: /* Handle the rate adaption */
! 2072: ieee80211_rssadapt_input(ic, ni, &an->an_rssadapt,
! 2073: ds->ds_rxstat.rs_rssi);
! 2074:
! 2075: /*
! 2076: * The frame may have caused the node to be marked for
! 2077: * reclamation (e.g. in response to a DEAUTH message)
! 2078: * so use release_node here instead of unref_node.
! 2079: */
! 2080: ieee80211_release_node(ic, ni);
! 2081:
! 2082: rx_next:
! 2083: TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
! 2084: } while (ath_rxbuf_init(sc, bf) == 0);
! 2085:
! 2086: ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
! 2087: ath_hal_start_rx(ah); /* in case of RXEOL */
! 2088:
! 2089: if ((ifp->if_flags & IFF_OACTIVE) == 0 && !IFQ_IS_EMPTY(&ifp->if_snd))
! 2090: ath_start(ifp);
! 2091: #undef PA2DESC
! 2092: }
! 2093:
! 2094: /*
! 2095: * XXX Size of an ACK control frame in bytes.
! 2096: */
! 2097: #define IEEE80211_ACK_SIZE (2+2+IEEE80211_ADDR_LEN+4)
! 2098:
! 2099: int
! 2100: ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni,
! 2101: struct ath_buf *bf, struct mbuf *m0)
! 2102: {
! 2103: struct ieee80211com *ic = &sc->sc_ic;
! 2104: struct ath_hal *ah = sc->sc_ah;
! 2105: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 2106: int i, error, iswep, hdrlen, pktlen, len, s;
! 2107: u_int8_t rix, cix, txrate, ctsrate;
! 2108: struct ath_desc *ds;
! 2109: struct mbuf *m;
! 2110: struct ieee80211_frame *wh;
! 2111: u_int32_t iv;
! 2112: u_int8_t *ivp;
! 2113: u_int8_t hdrbuf[sizeof(struct ieee80211_frame) +
! 2114: IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN];
! 2115: u_int subtype, flags, ctsduration, antenna;
! 2116: HAL_PKT_TYPE atype;
! 2117: const HAL_RATE_TABLE *rt;
! 2118: HAL_BOOL shortPreamble;
! 2119: struct ath_node *an;
! 2120: u_int8_t hwqueue = HAL_TX_QUEUE_ID_DATA_MIN;
! 2121:
! 2122: wh = mtod(m0, struct ieee80211_frame *);
! 2123: iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
! 2124: hdrlen = sizeof(struct ieee80211_frame);
! 2125: pktlen = m0->m_pkthdr.len;
! 2126:
! 2127: if (iswep) {
! 2128: bcopy(mtod(m0, caddr_t), hdrbuf, hdrlen);
! 2129: m_adj(m0, hdrlen);
! 2130: M_PREPEND(m0, sizeof(hdrbuf), M_DONTWAIT);
! 2131: if (m0 == NULL) {
! 2132: sc->sc_stats.ast_tx_nombuf++;
! 2133: return ENOMEM;
! 2134: }
! 2135: ivp = hdrbuf + hdrlen;
! 2136: wh = mtod(m0, struct ieee80211_frame *);
! 2137: /*
! 2138: * XXX
! 2139: * IV must not duplicate during the lifetime of the key.
! 2140: * But no mechanism to renew keys is defined in IEEE 802.11
! 2141: * for WEP. And the IV may be duplicated at other stations
! 2142: * because the session key itself is shared. So we use a
! 2143: * pseudo random IV for now, though it is not the right way.
! 2144: *
! 2145: * NB: Rather than use a strictly random IV we select a
! 2146: * random one to start and then increment the value for
! 2147: * each frame. This is an explicit tradeoff between
! 2148: * overhead and security. Given the basic insecurity of
! 2149: * WEP this seems worthwhile.
! 2150: */
! 2151:
! 2152: /*
! 2153: * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
! 2154: * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
! 2155: */
! 2156: iv = ic->ic_iv;
! 2157: if ((iv & 0xff00) == 0xff00) {
! 2158: int B = (iv & 0xff0000) >> 16;
! 2159: if (3 <= B && B < 16)
! 2160: iv = (B+1) << 16;
! 2161: }
! 2162: ic->ic_iv = iv + 1;
! 2163:
! 2164: /*
! 2165: * NB: Preserve byte order of IV for packet
! 2166: * sniffers; it doesn't matter otherwise.
! 2167: */
! 2168: #if AH_BYTE_ORDER == AH_BIG_ENDIAN
! 2169: ivp[0] = iv >> 0;
! 2170: ivp[1] = iv >> 8;
! 2171: ivp[2] = iv >> 16;
! 2172: #else
! 2173: ivp[2] = iv >> 0;
! 2174: ivp[1] = iv >> 8;
! 2175: ivp[0] = iv >> 16;
! 2176: #endif
! 2177: ivp[3] = ic->ic_wep_txkey << 6; /* Key ID and pad */
! 2178: bcopy(hdrbuf, mtod(m0, caddr_t), sizeof(hdrbuf));
! 2179: /*
! 2180: * The length of hdrlen and pktlen must be increased for WEP
! 2181: */
! 2182: len = IEEE80211_WEP_IVLEN +
! 2183: IEEE80211_WEP_KIDLEN +
! 2184: IEEE80211_WEP_CRCLEN;
! 2185: hdrlen += len;
! 2186: pktlen += len;
! 2187: }
! 2188: pktlen += IEEE80211_CRC_LEN;
! 2189:
! 2190: /*
! 2191: * Load the DMA map so any coalescing is done. This
! 2192: * also calculates the number of descriptors we need.
! 2193: */
! 2194: error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m0,
! 2195: BUS_DMA_NOWAIT);
! 2196: /*
! 2197: * Discard null packets and check for packets that
! 2198: * require too many TX descriptors. We try to convert
! 2199: * the latter to a cluster.
! 2200: */
! 2201: if (error == EFBIG) { /* too many desc's, linearize */
! 2202: sc->sc_stats.ast_tx_linear++;
! 2203: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 2204: if (m == NULL) {
! 2205: sc->sc_stats.ast_tx_nombuf++;
! 2206: m_freem(m0);
! 2207: return ENOMEM;
! 2208: }
! 2209:
! 2210: M_DUP_PKTHDR(m, m0);
! 2211: MCLGET(m, M_DONTWAIT);
! 2212: if ((m->m_flags & M_EXT) == 0) {
! 2213: sc->sc_stats.ast_tx_nomcl++;
! 2214: m_freem(m0);
! 2215: m_free(m);
! 2216: return ENOMEM;
! 2217: }
! 2218: m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
! 2219: m_freem(m0);
! 2220: m->m_len = m->m_pkthdr.len;
! 2221: m0 = m;
! 2222: error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m0,
! 2223: BUS_DMA_NOWAIT);
! 2224: if (error != 0) {
! 2225: sc->sc_stats.ast_tx_busdma++;
! 2226: m_freem(m0);
! 2227: return error;
! 2228: }
! 2229: KASSERT(bf->bf_nseg == 1,
! 2230: ("ath_tx_start: packet not one segment; nseg %u",
! 2231: bf->bf_nseg));
! 2232: } else if (error != 0) {
! 2233: sc->sc_stats.ast_tx_busdma++;
! 2234: m_freem(m0);
! 2235: return error;
! 2236: } else if (bf->bf_nseg == 0) { /* null packet, discard */
! 2237: sc->sc_stats.ast_tx_nodata++;
! 2238: m_freem(m0);
! 2239: return EIO;
! 2240: }
! 2241: DPRINTF(ATH_DEBUG_XMIT, ("%s: m %p len %u\n", __func__, m0, pktlen));
! 2242: bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
! 2243: bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 2244: bf->bf_m = m0;
! 2245: bf->bf_node = ni; /* NB: held reference */
! 2246: an = ATH_NODE(ni);
! 2247:
! 2248: /* setup descriptors */
! 2249: ds = bf->bf_desc;
! 2250: rt = sc->sc_currates;
! 2251: KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
! 2252:
! 2253: /*
! 2254: * Calculate Atheros packet type from IEEE80211 packet header
! 2255: * and setup for rate calculations.
! 2256: */
! 2257: bf->bf_id.id_node = NULL;
! 2258: atype = HAL_PKT_TYPE_NORMAL; /* default */
! 2259: switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
! 2260: case IEEE80211_FC0_TYPE_MGT:
! 2261: subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
! 2262: if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
! 2263: atype = HAL_PKT_TYPE_BEACON;
! 2264: } else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
! 2265: atype = HAL_PKT_TYPE_PROBE_RESP;
! 2266: } else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) {
! 2267: atype = HAL_PKT_TYPE_ATIM;
! 2268: }
! 2269: rix = 0; /* XXX lowest rate */
! 2270: break;
! 2271: case IEEE80211_FC0_TYPE_CTL:
! 2272: subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
! 2273: if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL)
! 2274: atype = HAL_PKT_TYPE_PSPOLL;
! 2275: rix = 0; /* XXX lowest rate */
! 2276: break;
! 2277: default:
! 2278: /* remember link conditions for rate adaptation algorithm */
! 2279: if (ic->ic_fixed_rate == -1) {
! 2280: bf->bf_id.id_len = m0->m_pkthdr.len;
! 2281: bf->bf_id.id_rateidx = ni->ni_txrate;
! 2282: bf->bf_id.id_node = ni;
! 2283: bf->bf_id.id_rssi = ath_node_getrssi(ic, ni);
! 2284: }
! 2285: ni->ni_txrate = ieee80211_rssadapt_choose(&an->an_rssadapt,
! 2286: &ni->ni_rates, wh, m0->m_pkthdr.len, ic->ic_fixed_rate,
! 2287: ifp->if_xname, 0);
! 2288: rix = sc->sc_rixmap[ni->ni_rates.rs_rates[ni->ni_txrate] &
! 2289: IEEE80211_RATE_VAL];
! 2290: if (rix == 0xff) {
! 2291: printf("%s: bogus xmit rate 0x%x (idx 0x%x)\n",
! 2292: ifp->if_xname, ni->ni_rates.rs_rates[ni->ni_txrate],
! 2293: ni->ni_txrate);
! 2294: sc->sc_stats.ast_tx_badrate++;
! 2295: m_freem(m0);
! 2296: return EIO;
! 2297: }
! 2298: break;
! 2299: }
! 2300:
! 2301: /*
! 2302: * NB: the 802.11 layer marks whether or not we should
! 2303: * use short preamble based on the current mode and
! 2304: * negotiated parameters.
! 2305: */
! 2306: if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
! 2307: (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
! 2308: txrate = rt->info[rix].rateCode | rt->info[rix].shortPreamble;
! 2309: shortPreamble = AH_TRUE;
! 2310: sc->sc_stats.ast_tx_shortpre++;
! 2311: } else {
! 2312: txrate = rt->info[rix].rateCode;
! 2313: shortPreamble = AH_FALSE;
! 2314: }
! 2315:
! 2316: /*
! 2317: * Calculate miscellaneous flags.
! 2318: */
! 2319: flags = HAL_TXDESC_CLRDMASK; /* XXX needed for wep errors */
! 2320: if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
! 2321: flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
! 2322: sc->sc_stats.ast_tx_noack++;
! 2323: } else if (pktlen > ic->ic_rtsthreshold) {
! 2324: flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
! 2325: sc->sc_stats.ast_tx_rts++;
! 2326: }
! 2327:
! 2328: /*
! 2329: * Calculate duration. This logically belongs in the 802.11
! 2330: * layer but it lacks sufficient information to calculate it.
! 2331: */
! 2332: if ((flags & HAL_TXDESC_NOACK) == 0 &&
! 2333: (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
! 2334: u_int16_t dur;
! 2335: /*
! 2336: * XXX not right with fragmentation.
! 2337: */
! 2338: dur = ath_hal_computetxtime(ah, rt, IEEE80211_ACK_SIZE,
! 2339: rix, shortPreamble);
! 2340: *((u_int16_t*) wh->i_dur) = htole16(dur);
! 2341: }
! 2342:
! 2343: /*
! 2344: * Calculate RTS/CTS rate and duration if needed.
! 2345: */
! 2346: ctsduration = 0;
! 2347: if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
! 2348: /*
! 2349: * CTS transmit rate is derived from the transmit rate
! 2350: * by looking in the h/w rate table. We must also factor
! 2351: * in whether or not a short preamble is to be used.
! 2352: */
! 2353: cix = rt->info[rix].controlRate;
! 2354: ctsrate = rt->info[cix].rateCode;
! 2355: if (shortPreamble)
! 2356: ctsrate |= rt->info[cix].shortPreamble;
! 2357: /*
! 2358: * Compute the transmit duration based on the size
! 2359: * of an ACK frame. We call into the HAL to do the
! 2360: * computation since it depends on the characteristics
! 2361: * of the actual PHY being used.
! 2362: */
! 2363: if (flags & HAL_TXDESC_RTSENA) { /* SIFS + CTS */
! 2364: ctsduration += ath_hal_computetxtime(ah,
! 2365: rt, IEEE80211_ACK_SIZE, cix, shortPreamble);
! 2366: }
! 2367: /* SIFS + data */
! 2368: ctsduration += ath_hal_computetxtime(ah,
! 2369: rt, pktlen, rix, shortPreamble);
! 2370: if ((flags & HAL_TXDESC_NOACK) == 0) { /* SIFS + ACK */
! 2371: ctsduration += ath_hal_computetxtime(ah,
! 2372: rt, IEEE80211_ACK_SIZE, cix, shortPreamble);
! 2373: }
! 2374: } else
! 2375: ctsrate = 0;
! 2376:
! 2377: /*
! 2378: * For now use the antenna on which the last good
! 2379: * frame was received on. We assume this field is
! 2380: * initialized to 0 which gives us ``auto'' or the
! 2381: * ``default'' antenna.
! 2382: */
! 2383: if (an->an_tx_antenna) {
! 2384: antenna = an->an_tx_antenna;
! 2385: } else {
! 2386: antenna = an->an_rx_hist[an->an_rx_hist_next].arh_antenna;
! 2387: }
! 2388:
! 2389: #if NBPFILTER > 0
! 2390: if (ic->ic_rawbpf)
! 2391: bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
! 2392:
! 2393: if (sc->sc_drvbpf) {
! 2394: struct mbuf mb;
! 2395:
! 2396: sc->sc_txtap.wt_flags = 0;
! 2397: if (shortPreamble)
! 2398: sc->sc_txtap.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
! 2399: if (iswep)
! 2400: sc->sc_txtap.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
! 2401: sc->sc_txtap.wt_rate = ni->ni_rates.rs_rates[ni->ni_txrate] &
! 2402: IEEE80211_RATE_VAL;
! 2403: sc->sc_txtap.wt_txpower = 30;
! 2404: sc->sc_txtap.wt_antenna = antenna;
! 2405: sc->sc_txtap.wt_hwqueue = hwqueue;
! 2406:
! 2407: mb.m_data = (caddr_t)&sc->sc_txtap;
! 2408: mb.m_len = sc->sc_txtap_len;
! 2409: mb.m_next = m0;
! 2410: mb.m_nextpkt = NULL;
! 2411: mb.m_type = 0;
! 2412: mb.m_flags = 0;
! 2413: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
! 2414: }
! 2415: #endif
! 2416:
! 2417: /*
! 2418: * Formulate first tx descriptor with tx controls.
! 2419: */
! 2420: /* XXX check return value? */
! 2421: ath_hal_setup_tx_desc(ah, ds
! 2422: , pktlen /* packet length */
! 2423: , hdrlen /* header length */
! 2424: , atype /* Atheros packet type */
! 2425: , 60 /* txpower XXX */
! 2426: , txrate, 1+10 /* series 0 rate/tries */
! 2427: , iswep ? sc->sc_ic.ic_wep_txkey : HAL_TXKEYIX_INVALID
! 2428: , antenna /* antenna mode */
! 2429: , flags /* flags */
! 2430: , ctsrate /* rts/cts rate */
! 2431: , ctsduration /* rts/cts duration */
! 2432: );
! 2433: #ifdef notyet
! 2434: ath_hal_setup_xtx_desc(ah, ds
! 2435: , AH_FALSE /* short preamble */
! 2436: , 0, 0 /* series 1 rate/tries */
! 2437: , 0, 0 /* series 2 rate/tries */
! 2438: , 0, 0 /* series 3 rate/tries */
! 2439: );
! 2440: #endif
! 2441: /*
! 2442: * Fillin the remainder of the descriptor info.
! 2443: */
! 2444: for (i = 0; i < bf->bf_nseg; i++, ds++) {
! 2445: ds->ds_data = bf->bf_segs[i].ds_addr;
! 2446: if (i == bf->bf_nseg - 1) {
! 2447: ds->ds_link = 0;
! 2448: } else {
! 2449: ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
! 2450: }
! 2451: ath_hal_fill_tx_desc(ah, ds
! 2452: , bf->bf_segs[i].ds_len /* segment length */
! 2453: , i == 0 /* first segment */
! 2454: , i == bf->bf_nseg - 1 /* last segment */
! 2455: );
! 2456: DPRINTF(ATH_DEBUG_XMIT,
! 2457: ("%s: %d: %08x %08x %08x %08x %08x %08x\n",
! 2458: __func__, i, ds->ds_link, ds->ds_data,
! 2459: ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]));
! 2460: }
! 2461:
! 2462: /*
! 2463: * Insert the frame on the outbound list and
! 2464: * pass it on to the hardware.
! 2465: */
! 2466: s = splnet();
! 2467: TAILQ_INSERT_TAIL(&sc->sc_txq, bf, bf_list);
! 2468: if (sc->sc_txlink == NULL) {
! 2469: ath_hal_put_tx_buf(ah, sc->sc_txhalq[hwqueue], bf->bf_daddr);
! 2470: DPRINTF(ATH_DEBUG_XMIT, ("%s: TXDP0 = %p (%p)\n", __func__,
! 2471: (caddr_t)bf->bf_daddr, bf->bf_desc));
! 2472: } else {
! 2473: *sc->sc_txlink = bf->bf_daddr;
! 2474: DPRINTF(ATH_DEBUG_XMIT, ("%s: link(%p)=%p (%p)\n", __func__,
! 2475: sc->sc_txlink, (caddr_t)bf->bf_daddr, bf->bf_desc));
! 2476: }
! 2477: sc->sc_txlink = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
! 2478: splx(s);
! 2479:
! 2480: ath_hal_tx_start(ah, sc->sc_txhalq[hwqueue]);
! 2481: return 0;
! 2482: }
! 2483:
! 2484: void
! 2485: ath_tx_proc(void *arg, int npending)
! 2486: {
! 2487: struct ath_softc *sc = arg;
! 2488: struct ath_hal *ah = sc->sc_ah;
! 2489: struct ath_buf *bf;
! 2490: struct ieee80211com *ic = &sc->sc_ic;
! 2491: struct ifnet *ifp = &ic->ic_if;
! 2492: struct ath_desc *ds;
! 2493: struct ieee80211_node *ni;
! 2494: struct ath_node *an;
! 2495: int sr, lr, s;
! 2496: HAL_STATUS status;
! 2497:
! 2498: for (;;) {
! 2499: s = splnet();
! 2500: bf = TAILQ_FIRST(&sc->sc_txq);
! 2501: if (bf == NULL) {
! 2502: sc->sc_txlink = NULL;
! 2503: splx(s);
! 2504: break;
! 2505: }
! 2506: /* only the last descriptor is needed */
! 2507: ds = &bf->bf_desc[bf->bf_nseg - 1];
! 2508: status = ath_hal_proc_tx_desc(ah, ds);
! 2509: #ifdef AR_DEBUG
! 2510: if (ath_debug & ATH_DEBUG_XMIT_DESC)
! 2511: ath_printtxbuf(bf, status == HAL_OK);
! 2512: #endif
! 2513: if (status == HAL_EINPROGRESS) {
! 2514: splx(s);
! 2515: break;
! 2516: }
! 2517: TAILQ_REMOVE(&sc->sc_txq, bf, bf_list);
! 2518: splx(s);
! 2519:
! 2520: ni = bf->bf_node;
! 2521: if (ni != NULL) {
! 2522: an = (struct ath_node *) ni;
! 2523: if (ds->ds_txstat.ts_status == 0) {
! 2524: if (bf->bf_id.id_node != NULL)
! 2525: ieee80211_rssadapt_raise_rate(ic,
! 2526: &an->an_rssadapt, &bf->bf_id);
! 2527: an->an_tx_antenna = ds->ds_txstat.ts_antenna;
! 2528: } else {
! 2529: if (bf->bf_id.id_node != NULL)
! 2530: ieee80211_rssadapt_lower_rate(ic, ni,
! 2531: &an->an_rssadapt, &bf->bf_id);
! 2532: ifp->if_oerrors++;
! 2533: if (ds->ds_txstat.ts_status & HAL_TXERR_XRETRY)
! 2534: sc->sc_stats.ast_tx_xretries++;
! 2535: if (ds->ds_txstat.ts_status & HAL_TXERR_FIFO)
! 2536: sc->sc_stats.ast_tx_fifoerr++;
! 2537: if (ds->ds_txstat.ts_status & HAL_TXERR_FILT)
! 2538: sc->sc_stats.ast_tx_filtered++;
! 2539: an->an_tx_antenna = 0; /* invalidate */
! 2540: }
! 2541: sr = ds->ds_txstat.ts_shortretry;
! 2542: lr = ds->ds_txstat.ts_longretry;
! 2543: sc->sc_stats.ast_tx_shortretry += sr;
! 2544: sc->sc_stats.ast_tx_longretry += lr;
! 2545: /*
! 2546: * Reclaim reference to node.
! 2547: *
! 2548: * NB: the node may be reclaimed here if, for example
! 2549: * this is a DEAUTH message that was sent and the
! 2550: * node was timed out due to inactivity.
! 2551: */
! 2552: ieee80211_release_node(ic, ni);
! 2553: }
! 2554: bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, 0,
! 2555: bf->bf_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 2556: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 2557: m_freem(bf->bf_m);
! 2558: bf->bf_m = NULL;
! 2559: bf->bf_node = NULL;
! 2560:
! 2561: s = splnet();
! 2562: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 2563: splx(s);
! 2564: }
! 2565: ifp->if_flags &= ~IFF_OACTIVE;
! 2566: sc->sc_tx_timer = 0;
! 2567:
! 2568: ath_start(ifp);
! 2569: }
! 2570:
! 2571: /*
! 2572: * Drain the transmit queue and reclaim resources.
! 2573: */
! 2574: void
! 2575: ath_draintxq(struct ath_softc *sc)
! 2576: {
! 2577: struct ath_hal *ah = sc->sc_ah;
! 2578: struct ieee80211com *ic = &sc->sc_ic;
! 2579: struct ifnet *ifp = &ic->ic_if;
! 2580: struct ieee80211_node *ni;
! 2581: struct ath_buf *bf;
! 2582: int s, i;
! 2583:
! 2584: /* XXX return value */
! 2585: if (!sc->sc_invalid) {
! 2586: for (i = 0; i <= HAL_TX_QUEUE_ID_DATA_MAX; i++) {
! 2587: /* don't touch the hardware if marked invalid */
! 2588: (void) ath_hal_stop_tx_dma(ah, sc->sc_txhalq[i]);
! 2589: DPRINTF(ATH_DEBUG_RESET,
! 2590: ("%s: tx queue %d (%p), link %p\n", __func__, i,
! 2591: (caddr_t)(u_intptr_t)ath_hal_get_tx_buf(ah,
! 2592: sc->sc_txhalq[i]), sc->sc_txlink));
! 2593: }
! 2594: (void) ath_hal_stop_tx_dma(ah, sc->sc_bhalq);
! 2595: DPRINTF(ATH_DEBUG_RESET,
! 2596: ("%s: beacon queue (%p)\n", __func__,
! 2597: (caddr_t)(u_intptr_t)ath_hal_get_tx_buf(ah, sc->sc_bhalq)));
! 2598: }
! 2599: for (;;) {
! 2600: s = splnet();
! 2601: bf = TAILQ_FIRST(&sc->sc_txq);
! 2602: if (bf == NULL) {
! 2603: sc->sc_txlink = NULL;
! 2604: splx(s);
! 2605: break;
! 2606: }
! 2607: TAILQ_REMOVE(&sc->sc_txq, bf, bf_list);
! 2608: splx(s);
! 2609: #ifdef AR_DEBUG
! 2610: if (ath_debug & ATH_DEBUG_RESET) {
! 2611: ath_printtxbuf(bf,
! 2612: ath_hal_proc_tx_desc(ah, bf->bf_desc) == HAL_OK);
! 2613: }
! 2614: #endif /* AR_DEBUG */
! 2615: bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
! 2616: m_freem(bf->bf_m);
! 2617: bf->bf_m = NULL;
! 2618: ni = bf->bf_node;
! 2619: bf->bf_node = NULL;
! 2620: s = splnet();
! 2621: if (ni != NULL) {
! 2622: /*
! 2623: * Reclaim node reference.
! 2624: */
! 2625: ieee80211_release_node(ic, ni);
! 2626: }
! 2627: TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
! 2628: splx(s);
! 2629: }
! 2630: ifp->if_flags &= ~IFF_OACTIVE;
! 2631: sc->sc_tx_timer = 0;
! 2632: }
! 2633:
! 2634: /*
! 2635: * Disable the receive h/w in preparation for a reset.
! 2636: */
! 2637: void
! 2638: ath_stoprecv(struct ath_softc *sc)
! 2639: {
! 2640: #define PA2DESC(_sc, _pa) \
! 2641: ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
! 2642: ((_pa) - (_sc)->sc_desc_paddr)))
! 2643: struct ath_hal *ah = sc->sc_ah;
! 2644:
! 2645: ath_hal_stop_pcu_recv(ah); /* disable PCU */
! 2646: ath_hal_set_rx_filter(ah, 0); /* clear recv filter */
! 2647: ath_hal_stop_rx_dma(ah); /* disable DMA engine */
! 2648: #ifdef AR_DEBUG
! 2649: if (ath_debug & ATH_DEBUG_RESET) {
! 2650: struct ath_buf *bf;
! 2651:
! 2652: printf("%s: rx queue %p, link %p\n", __func__,
! 2653: (caddr_t)(u_intptr_t)ath_hal_get_rx_buf(ah), sc->sc_rxlink);
! 2654: TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
! 2655: struct ath_desc *ds = bf->bf_desc;
! 2656: if (ath_hal_proc_rx_desc(ah, ds, bf->bf_daddr,
! 2657: PA2DESC(sc, ds->ds_link)) == HAL_OK)
! 2658: ath_printrxbuf(bf, 1);
! 2659: }
! 2660: }
! 2661: #endif
! 2662: sc->sc_rxlink = NULL; /* just in case */
! 2663: #undef PA2DESC
! 2664: }
! 2665:
! 2666: /*
! 2667: * Enable the receive h/w following a reset.
! 2668: */
! 2669: int
! 2670: ath_startrecv(struct ath_softc *sc)
! 2671: {
! 2672: struct ath_hal *ah = sc->sc_ah;
! 2673: struct ath_buf *bf;
! 2674:
! 2675: sc->sc_rxlink = NULL;
! 2676: TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
! 2677: int error = ath_rxbuf_init(sc, bf);
! 2678: if (error != 0) {
! 2679: DPRINTF(ATH_DEBUG_RECV,
! 2680: ("%s: ath_rxbuf_init failed %d\n",
! 2681: __func__, error));
! 2682: return error;
! 2683: }
! 2684: }
! 2685:
! 2686: bf = TAILQ_FIRST(&sc->sc_rxbuf);
! 2687: ath_hal_put_rx_buf(ah, bf->bf_daddr);
! 2688: ath_hal_start_rx(ah); /* enable recv descriptors */
! 2689: ath_mode_init(sc); /* set filters, etc. */
! 2690: ath_hal_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
! 2691: return 0;
! 2692: }
! 2693:
! 2694: /*
! 2695: * Set/change channels. If the channel is really being changed,
! 2696: * it's done by resetting the chip. To accomplish this we must
! 2697: * first cleanup any pending DMA, then restart stuff after a la
! 2698: * ath_init.
! 2699: */
! 2700: int
! 2701: ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
! 2702: {
! 2703: struct ath_hal *ah = sc->sc_ah;
! 2704: struct ieee80211com *ic = &sc->sc_ic;
! 2705: struct ifnet *ifp = &ic->ic_if;
! 2706:
! 2707: DPRINTF(ATH_DEBUG_ANY, ("%s: %u (%u MHz) -> %u (%u MHz)\n", __func__,
! 2708: ieee80211_chan2ieee(ic, ic->ic_ibss_chan),
! 2709: ic->ic_ibss_chan->ic_freq,
! 2710: ieee80211_chan2ieee(ic, chan), chan->ic_freq));
! 2711: if (chan != ic->ic_ibss_chan) {
! 2712: HAL_STATUS status;
! 2713: HAL_CHANNEL hchan;
! 2714: enum ieee80211_phymode mode;
! 2715:
! 2716: /*
! 2717: * To switch channels clear any pending DMA operations;
! 2718: * wait long enough for the RX fifo to drain, reset the
! 2719: * hardware at the new frequency, and then re-enable
! 2720: * the relevant bits of the h/w.
! 2721: */
! 2722: ath_hal_set_intr(ah, 0); /* disable interrupts */
! 2723: ath_draintxq(sc); /* clear pending tx frames */
! 2724: ath_stoprecv(sc); /* turn off frame recv */
! 2725: /*
! 2726: * Convert to a HAL channel description with
! 2727: * the flags constrained to reflect the current
! 2728: * operating mode.
! 2729: */
! 2730: hchan.channel = chan->ic_freq;
! 2731: hchan.channelFlags = ath_chan2flags(ic, chan);
! 2732: if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE,
! 2733: &status)) {
! 2734: printf("%s: ath_chan_set: unable to reset "
! 2735: "channel %u (%u MHz)\n", ifp->if_xname,
! 2736: ieee80211_chan2ieee(ic, chan), chan->ic_freq);
! 2737: return EIO;
! 2738: }
! 2739: ath_set_slot_time(sc);
! 2740: /*
! 2741: * Re-enable rx framework.
! 2742: */
! 2743: if (ath_startrecv(sc) != 0) {
! 2744: printf("%s: ath_chan_set: unable to restart recv "
! 2745: "logic\n", ifp->if_xname);
! 2746: return EIO;
! 2747: }
! 2748:
! 2749: #if NBPFILTER > 0
! 2750: /*
! 2751: * Update BPF state.
! 2752: */
! 2753: sc->sc_txtap.wt_chan_freq = sc->sc_rxtap.wr_chan_freq =
! 2754: htole16(chan->ic_freq);
! 2755: sc->sc_txtap.wt_chan_flags = sc->sc_rxtap.wr_chan_flags =
! 2756: htole16(chan->ic_flags);
! 2757: #endif
! 2758:
! 2759: /*
! 2760: * Change channels and update the h/w rate map
! 2761: * if we're switching; e.g. 11a to 11b/g.
! 2762: */
! 2763: ic->ic_ibss_chan = chan;
! 2764: mode = ieee80211_chan2mode(ic, chan);
! 2765: if (mode != sc->sc_curmode)
! 2766: ath_setcurmode(sc, mode);
! 2767:
! 2768: /*
! 2769: * Re-enable interrupts.
! 2770: */
! 2771: ath_hal_set_intr(ah, sc->sc_imask);
! 2772: }
! 2773: return 0;
! 2774: }
! 2775:
! 2776: void
! 2777: ath_next_scan(void *arg)
! 2778: {
! 2779: struct ath_softc *sc = arg;
! 2780: struct ieee80211com *ic = &sc->sc_ic;
! 2781: struct ifnet *ifp = &ic->ic_if;
! 2782: int s;
! 2783:
! 2784: /* don't call ath_start w/o network interrupts blocked */
! 2785: s = splnet();
! 2786:
! 2787: if (ic->ic_state == IEEE80211_S_SCAN)
! 2788: ieee80211_next_scan(ifp);
! 2789: splx(s);
! 2790: }
! 2791:
! 2792: int
! 2793: ath_set_slot_time(struct ath_softc *sc)
! 2794: {
! 2795: struct ath_hal *ah = sc->sc_ah;
! 2796: struct ieee80211com *ic = &sc->sc_ic;
! 2797:
! 2798: if (ic->ic_flags & IEEE80211_F_SHSLOT)
! 2799: return (ath_hal_set_slot_time(ah, HAL_SLOT_TIME_9));
! 2800:
! 2801: return (0);
! 2802: }
! 2803:
! 2804: /*
! 2805: * Periodically recalibrate the PHY to account
! 2806: * for temperature/environment changes.
! 2807: */
! 2808: void
! 2809: ath_calibrate(void *arg)
! 2810: {
! 2811: struct ath_softc *sc = arg;
! 2812: struct ath_hal *ah = sc->sc_ah;
! 2813: struct ieee80211com *ic = &sc->sc_ic;
! 2814: struct ieee80211_channel *c;
! 2815: HAL_CHANNEL hchan;
! 2816: int s;
! 2817:
! 2818: sc->sc_stats.ast_per_cal++;
! 2819:
! 2820: /*
! 2821: * Convert to a HAL channel description with the flags
! 2822: * constrained to reflect the current operating mode.
! 2823: */
! 2824: c = ic->ic_ibss_chan;
! 2825: hchan.channel = c->ic_freq;
! 2826: hchan.channelFlags = ath_chan2flags(ic, c);
! 2827:
! 2828: s = splnet();
! 2829: DPRINTF(ATH_DEBUG_CALIBRATE,
! 2830: ("%s: channel %u/%x\n", __func__, c->ic_freq, c->ic_flags));
! 2831:
! 2832: if (ath_hal_get_rf_gain(ah) == HAL_RFGAIN_NEED_CHANGE) {
! 2833: /*
! 2834: * Rfgain is out of bounds, reset the chip
! 2835: * to load new gain values.
! 2836: */
! 2837: sc->sc_stats.ast_per_rfgain++;
! 2838: ath_reset(sc, 1);
! 2839: }
! 2840: if (!ath_hal_calibrate(ah, &hchan)) {
! 2841: DPRINTF(ATH_DEBUG_ANY,
! 2842: ("%s: calibration of channel %u failed\n",
! 2843: __func__, c->ic_freq));
! 2844: sc->sc_stats.ast_per_calfail++;
! 2845: }
! 2846: timeout_add(&sc->sc_cal_to, hz * ath_calinterval);
! 2847: splx(s);
! 2848: }
! 2849:
! 2850: void
! 2851: ath_ledstate(struct ath_softc *sc, enum ieee80211_state state)
! 2852: {
! 2853: HAL_LED_STATE led = HAL_LED_INIT;
! 2854: u_int32_t softled = AR5K_SOFTLED_OFF;
! 2855:
! 2856: switch (state) {
! 2857: case IEEE80211_S_INIT:
! 2858: break;
! 2859: case IEEE80211_S_SCAN:
! 2860: led = HAL_LED_SCAN;
! 2861: break;
! 2862: case IEEE80211_S_AUTH:
! 2863: led = HAL_LED_AUTH;
! 2864: break;
! 2865: case IEEE80211_S_ASSOC:
! 2866: led = HAL_LED_ASSOC;
! 2867: softled = AR5K_SOFTLED_ON;
! 2868: break;
! 2869: case IEEE80211_S_RUN:
! 2870: led = HAL_LED_RUN;
! 2871: softled = AR5K_SOFTLED_ON;
! 2872: break;
! 2873: }
! 2874:
! 2875: ath_hal_set_ledstate(sc->sc_ah, led);
! 2876: if (sc->sc_softled) {
! 2877: ath_hal_set_gpio_output(sc->sc_ah, AR5K_SOFTLED_PIN);
! 2878: ath_hal_set_gpio(sc->sc_ah, AR5K_SOFTLED_PIN, softled);
! 2879: }
! 2880: }
! 2881:
! 2882: int
! 2883: ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 2884: {
! 2885: struct ifnet *ifp = &ic->ic_if;
! 2886: struct ath_softc *sc = ifp->if_softc;
! 2887: struct ath_hal *ah = sc->sc_ah;
! 2888: struct ieee80211_node *ni;
! 2889: const u_int8_t *bssid;
! 2890: int i, error;
! 2891: u_int32_t rfilt;
! 2892:
! 2893: DPRINTF(ATH_DEBUG_ANY, ("%s: %s -> %s\n", __func__,
! 2894: ieee80211_state_name[ic->ic_state],
! 2895: ieee80211_state_name[nstate]));
! 2896:
! 2897: timeout_del(&sc->sc_scan_to);
! 2898: timeout_del(&sc->sc_cal_to);
! 2899: ath_ledstate(sc, nstate);
! 2900:
! 2901: if (nstate == IEEE80211_S_INIT) {
! 2902: timeout_del(&sc->sc_rssadapt_to);
! 2903: sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
! 2904: ath_hal_set_intr(ah, sc->sc_imask);
! 2905: return (*sc->sc_newstate)(ic, nstate, arg);
! 2906: }
! 2907: ni = ic->ic_bss;
! 2908: error = ath_chan_set(sc, ni->ni_chan);
! 2909: if (error != 0)
! 2910: goto bad;
! 2911: rfilt = ath_calcrxfilter(sc);
! 2912: if (nstate == IEEE80211_S_SCAN ||
! 2913: ic->ic_opmode == IEEE80211_M_MONITOR) {
! 2914: bssid = sc->sc_broadcast_addr;
! 2915: } else {
! 2916: bssid = ni->ni_bssid;
! 2917: }
! 2918: ath_hal_set_rx_filter(ah, rfilt);
! 2919: DPRINTF(ATH_DEBUG_ANY, ("%s: RX filter 0x%x bssid %s\n",
! 2920: __func__, rfilt, ether_sprintf((u_char*)bssid)));
! 2921:
! 2922: if (nstate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA) {
! 2923: ath_hal_set_associd(ah, bssid, ni->ni_associd);
! 2924: } else {
! 2925: ath_hal_set_associd(ah, bssid, 0);
! 2926: }
! 2927:
! 2928: if (ic->ic_flags & IEEE80211_F_WEPON) {
! 2929: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 2930: if (ath_hal_is_key_valid(ah, i))
! 2931: ath_hal_set_key_lladdr(ah, i, bssid);
! 2932: }
! 2933: }
! 2934:
! 2935: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
! 2936: /* nothing to do */
! 2937: } else if (nstate == IEEE80211_S_RUN) {
! 2938: DPRINTF(ATH_DEBUG_ANY, ("%s(RUN): "
! 2939: "ic_flags=0x%08x iv=%d bssid=%s "
! 2940: "capinfo=0x%04x chan=%d\n",
! 2941: __func__,
! 2942: ic->ic_flags,
! 2943: ni->ni_intval,
! 2944: ether_sprintf(ni->ni_bssid),
! 2945: ni->ni_capinfo,
! 2946: ieee80211_chan2ieee(ic, ni->ni_chan)));
! 2947:
! 2948: /*
! 2949: * Allocate and setup the beacon frame for AP or adhoc mode.
! 2950: */
! 2951: if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
! 2952: ic->ic_opmode == IEEE80211_M_IBSS) {
! 2953: error = ath_beacon_alloc(sc, ni);
! 2954: if (error != 0)
! 2955: goto bad;
! 2956: }
! 2957:
! 2958: /*
! 2959: * Configure the beacon and sleep timers.
! 2960: */
! 2961: ath_beacon_config(sc);
! 2962: } else {
! 2963: sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
! 2964: ath_hal_set_intr(ah, sc->sc_imask);
! 2965: }
! 2966:
! 2967: /*
! 2968: * Invoke the parent method to complete the work.
! 2969: */
! 2970: error = (*sc->sc_newstate)(ic, nstate, arg);
! 2971:
! 2972: if (nstate == IEEE80211_S_RUN) {
! 2973: /* start periodic recalibration timer */
! 2974: timeout_add(&sc->sc_cal_to, hz * ath_calinterval);
! 2975:
! 2976: if (ic->ic_opmode != IEEE80211_M_MONITOR)
! 2977: timeout_add(&sc->sc_rssadapt_to, hz / 10);
! 2978: } else if (nstate == IEEE80211_S_SCAN) {
! 2979: /* start ap/neighbor scan timer */
! 2980: timeout_add(&sc->sc_scan_to, (hz * ath_dwelltime) / 1000);
! 2981: }
! 2982: bad:
! 2983: return error;
! 2984: }
! 2985:
! 2986: void
! 2987: ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
! 2988: struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp)
! 2989: {
! 2990: struct ath_softc *sc = (struct ath_softc*)ic->ic_softc;
! 2991: struct ath_hal *ah = sc->sc_ah;
! 2992:
! 2993: (*sc->sc_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
! 2994:
! 2995: switch (subtype) {
! 2996: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
! 2997: case IEEE80211_FC0_SUBTYPE_BEACON:
! 2998: if (ic->ic_opmode != IEEE80211_M_IBSS ||
! 2999: ic->ic_state != IEEE80211_S_RUN)
! 3000: break;
! 3001: if (ieee80211_ibss_merge(ic, ni, ath_hal_get_tsf64(ah)) ==
! 3002: ENETRESET)
! 3003: ath_hal_set_associd(ah, ic->ic_bss->ni_bssid, 0);
! 3004: break;
! 3005: default:
! 3006: break;
! 3007: }
! 3008: return;
! 3009: }
! 3010:
! 3011: /*
! 3012: * Setup driver-specific state for a newly associated node.
! 3013: * Note that we're called also on a re-associate, the isnew
! 3014: * param tells us if this is the first time or not.
! 3015: */
! 3016: void
! 3017: ath_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
! 3018: {
! 3019: if (ic->ic_opmode == IEEE80211_M_MONITOR)
! 3020: return;
! 3021: }
! 3022:
! 3023: int
! 3024: ath_getchannels(struct ath_softc *sc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
! 3025: {
! 3026: struct ieee80211com *ic = &sc->sc_ic;
! 3027: struct ifnet *ifp = &ic->ic_if;
! 3028: struct ath_hal *ah = sc->sc_ah;
! 3029: HAL_CHANNEL *chans;
! 3030: int i, ix, nchan;
! 3031:
! 3032: sc->sc_nchan = 0;
! 3033: chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
! 3034: M_TEMP, M_NOWAIT);
! 3035: if (chans == NULL) {
! 3036: printf("%s: unable to allocate channel table\n", ifp->if_xname);
! 3037: return ENOMEM;
! 3038: }
! 3039: if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
! 3040: HAL_MODE_ALL, outdoor, xchanmode)) {
! 3041: printf("%s: unable to collect channel list from hal\n",
! 3042: ifp->if_xname);
! 3043: free(chans, M_TEMP);
! 3044: return EINVAL;
! 3045: }
! 3046:
! 3047: /*
! 3048: * Convert HAL channels to ieee80211 ones and insert
! 3049: * them in the table according to their channel number.
! 3050: */
! 3051: for (i = 0; i < nchan; i++) {
! 3052: HAL_CHANNEL *c = &chans[i];
! 3053: ix = ieee80211_mhz2ieee(c->channel, c->channelFlags);
! 3054: if (ix > IEEE80211_CHAN_MAX) {
! 3055: printf("%s: bad hal channel %u (%u/%x) ignored\n",
! 3056: ifp->if_xname, ix, c->channel, c->channelFlags);
! 3057: continue;
! 3058: }
! 3059: DPRINTF(ATH_DEBUG_ANY,
! 3060: ("%s: HAL channel %d/%d freq %d flags %#04x idx %d\n",
! 3061: sc->sc_dev.dv_xname, i, nchan, c->channel, c->channelFlags,
! 3062: ix));
! 3063: /* NB: flags are known to be compatible */
! 3064: if (ic->ic_channels[ix].ic_freq == 0) {
! 3065: ic->ic_channels[ix].ic_freq = c->channel;
! 3066: ic->ic_channels[ix].ic_flags = c->channelFlags;
! 3067: } else {
! 3068: /* channels overlap; e.g. 11g and 11b */
! 3069: ic->ic_channels[ix].ic_flags |= c->channelFlags;
! 3070: }
! 3071: /* count valid channels */
! 3072: sc->sc_nchan++;
! 3073: }
! 3074: free(chans, M_TEMP);
! 3075:
! 3076: if (sc->sc_nchan < 1) {
! 3077: printf("%s: no valid channels for regdomain %s(%u)\n",
! 3078: ifp->if_xname, ieee80211_regdomain2name(ah->ah_regdomain),
! 3079: ah->ah_regdomain);
! 3080: return ENOENT;
! 3081: }
! 3082:
! 3083: /* set an initial channel */
! 3084: ic->ic_ibss_chan = &ic->ic_channels[0];
! 3085:
! 3086: return 0;
! 3087: }
! 3088:
! 3089: int
! 3090: ath_rate_setup(struct ath_softc *sc, u_int mode)
! 3091: {
! 3092: struct ath_hal *ah = sc->sc_ah;
! 3093: struct ieee80211com *ic = &sc->sc_ic;
! 3094: const HAL_RATE_TABLE *rt;
! 3095: struct ieee80211_rateset *rs;
! 3096: int i, maxrates;
! 3097:
! 3098: switch (mode) {
! 3099: case IEEE80211_MODE_11A:
! 3100: sc->sc_rates[mode] = ath_hal_get_rate_table(ah, HAL_MODE_11A);
! 3101: break;
! 3102: case IEEE80211_MODE_11B:
! 3103: sc->sc_rates[mode] = ath_hal_get_rate_table(ah, HAL_MODE_11B);
! 3104: break;
! 3105: case IEEE80211_MODE_11G:
! 3106: sc->sc_rates[mode] = ath_hal_get_rate_table(ah, HAL_MODE_11G);
! 3107: break;
! 3108: case IEEE80211_MODE_TURBO:
! 3109: sc->sc_rates[mode] = ath_hal_get_rate_table(ah, HAL_MODE_TURBO);
! 3110: break;
! 3111: default:
! 3112: DPRINTF(ATH_DEBUG_ANY,
! 3113: ("%s: invalid mode %u\n", __func__, mode));
! 3114: return 0;
! 3115: }
! 3116: rt = sc->sc_rates[mode];
! 3117: if (rt == NULL)
! 3118: return 0;
! 3119: if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
! 3120: DPRINTF(ATH_DEBUG_ANY,
! 3121: ("%s: rate table too small (%u > %u)\n",
! 3122: __func__, rt->rateCount, IEEE80211_RATE_MAXSIZE));
! 3123: maxrates = IEEE80211_RATE_MAXSIZE;
! 3124: } else {
! 3125: maxrates = rt->rateCount;
! 3126: }
! 3127: rs = &ic->ic_sup_rates[mode];
! 3128: for (i = 0; i < maxrates; i++)
! 3129: rs->rs_rates[i] = rt->info[i].dot11Rate;
! 3130: rs->rs_nrates = maxrates;
! 3131: return 1;
! 3132: }
! 3133:
! 3134: void
! 3135: ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
! 3136: {
! 3137: const HAL_RATE_TABLE *rt;
! 3138: int i;
! 3139:
! 3140: memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
! 3141: rt = sc->sc_rates[mode];
! 3142: KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode));
! 3143: for (i = 0; i < rt->rateCount; i++)
! 3144: sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i;
! 3145: bzero(sc->sc_hwmap, sizeof(sc->sc_hwmap));
! 3146: for (i = 0; i < 32; i++)
! 3147: sc->sc_hwmap[i] = rt->info[rt->rateCodeToIndex[i]].dot11Rate;
! 3148: sc->sc_currates = rt;
! 3149: sc->sc_curmode = mode;
! 3150: }
! 3151:
! 3152: void
! 3153: ath_rssadapt_updatenode(void *arg, struct ieee80211_node *ni)
! 3154: {
! 3155: struct ath_node *an = ATH_NODE(ni);
! 3156:
! 3157: ieee80211_rssadapt_updatestats(&an->an_rssadapt);
! 3158: }
! 3159:
! 3160: void
! 3161: ath_rssadapt_updatestats(void *arg)
! 3162: {
! 3163: struct ath_softc *sc = (struct ath_softc *)arg;
! 3164: struct ieee80211com *ic = &sc->sc_ic;
! 3165:
! 3166: if (ic->ic_opmode == IEEE80211_M_STA) {
! 3167: ath_rssadapt_updatenode(arg, ic->ic_bss);
! 3168: } else {
! 3169: ieee80211_iterate_nodes(ic, ath_rssadapt_updatenode, arg);
! 3170: }
! 3171:
! 3172: timeout_add(&sc->sc_rssadapt_to, hz / 10);
! 3173: }
! 3174:
! 3175: #ifdef AR_DEBUG
! 3176: void
! 3177: ath_printrxbuf(struct ath_buf *bf, int done)
! 3178: {
! 3179: struct ath_desc *ds;
! 3180: int i;
! 3181:
! 3182: for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
! 3183: printf("R%d (%p %p) %08x %08x %08x %08x %08x %08x %c\n",
! 3184: i, ds, (struct ath_desc *)bf->bf_daddr + i,
! 3185: ds->ds_link, ds->ds_data,
! 3186: ds->ds_ctl0, ds->ds_ctl1,
! 3187: ds->ds_hw[0], ds->ds_hw[1],
! 3188: !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
! 3189: }
! 3190: }
! 3191:
! 3192: void
! 3193: ath_printtxbuf(struct ath_buf *bf, int done)
! 3194: {
! 3195: struct ath_desc *ds;
! 3196: int i;
! 3197:
! 3198: for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
! 3199: printf("T%d (%p %p) "
! 3200: "%08x %08x %08x %08x %08x %08x %08x %08x %c\n",
! 3201: i, ds, (struct ath_desc *)bf->bf_daddr + i,
! 3202: ds->ds_link, ds->ds_data,
! 3203: ds->ds_ctl0, ds->ds_ctl1,
! 3204: ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
! 3205: !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
! 3206: }
! 3207: }
! 3208: #endif /* AR_DEBUG */
! 3209:
! 3210: int
! 3211: ath_gpio_attach(struct ath_softc *sc, u_int16_t devid)
! 3212: {
! 3213: struct ath_hal *ah = sc->sc_ah;
! 3214: struct gpiobus_attach_args gba;
! 3215: int i;
! 3216:
! 3217: if (ah->ah_gpio_npins < 1)
! 3218: return 0;
! 3219:
! 3220: /* Initialize gpio pins array */
! 3221: for (i = 0; i < ah->ah_gpio_npins && i < AR5K_MAX_GPIO; i++) {
! 3222: sc->sc_gpio_pins[i].pin_num = i;
! 3223: sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
! 3224: GPIO_PIN_OUTPUT;
! 3225:
! 3226: /* Set pin mode to input */
! 3227: ath_hal_set_gpio_input(ah, i);
! 3228: sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT;
! 3229:
! 3230: /* Get pin input */
! 3231: sc->sc_gpio_pins[i].pin_state = ath_hal_get_gpio(ah, i) ?
! 3232: GPIO_PIN_HIGH : GPIO_PIN_LOW;
! 3233: }
! 3234:
! 3235: /* Enable GPIO-controlled software LED if available */
! 3236: if ((ah->ah_version == AR5K_AR5211) ||
! 3237: (devid == PCI_PRODUCT_ATHEROS_AR5212_IBM)) {
! 3238: sc->sc_softled = 1;
! 3239: ath_hal_set_gpio_output(ah, AR5K_SOFTLED_PIN);
! 3240: ath_hal_set_gpio(ah, AR5K_SOFTLED_PIN, AR5K_SOFTLED_OFF);
! 3241: }
! 3242:
! 3243: /* Create gpio controller tag */
! 3244: sc->sc_gpio_gc.gp_cookie = sc;
! 3245: sc->sc_gpio_gc.gp_pin_read = ath_gpio_pin_read;
! 3246: sc->sc_gpio_gc.gp_pin_write = ath_gpio_pin_write;
! 3247: sc->sc_gpio_gc.gp_pin_ctl = ath_gpio_pin_ctl;
! 3248:
! 3249: gba.gba_name = "gpio";
! 3250: gba.gba_gc = &sc->sc_gpio_gc;
! 3251: gba.gba_pins = sc->sc_gpio_pins;
! 3252: gba.gba_npins = ah->ah_gpio_npins;
! 3253:
! 3254: #ifdef notyet
! 3255: #if NGPIO > 0
! 3256: if (config_found(&sc->sc_dev, &gba, gpiobus_print) == NULL)
! 3257: return (ENODEV);
! 3258: #endif
! 3259: #endif
! 3260:
! 3261: return (0);
! 3262: }
! 3263:
! 3264: int
! 3265: ath_gpio_pin_read(void *arg, int pin)
! 3266: {
! 3267: struct ath_softc *sc = arg;
! 3268: struct ath_hal *ah = sc->sc_ah;
! 3269: return (ath_hal_get_gpio(ah, pin) ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
! 3270: }
! 3271:
! 3272: void
! 3273: ath_gpio_pin_write(void *arg, int pin, int value)
! 3274: {
! 3275: struct ath_softc *sc = arg;
! 3276: struct ath_hal *ah = sc->sc_ah;
! 3277: ath_hal_set_gpio(ah, pin, value ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
! 3278: }
! 3279:
! 3280: void
! 3281: ath_gpio_pin_ctl(void *arg, int pin, int flags)
! 3282: {
! 3283: struct ath_softc *sc = arg;
! 3284: struct ath_hal *ah = sc->sc_ah;
! 3285:
! 3286: if (flags & GPIO_PIN_INPUT) {
! 3287: ath_hal_set_gpio_input(ah, pin);
! 3288: } else if (flags & GPIO_PIN_OUTPUT) {
! 3289: ath_hal_set_gpio_output(ah, pin);
! 3290: }
! 3291: }
CVSweb