📄 if_ath.c
字号:
*/ ath_hal_mibevent(ah, &sc->sc_halstats); ath_hal_intrset(ah, sc->sc_imask); } } if (needmark) mark_bh(IMMEDIATE_BH); return IRQ_HANDLED;}static voidath_radar_task(TQUEUE_ARG data){ struct net_device *dev = (struct net_device *)data; struct ath_softc *sc = dev->priv; struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_channel ichan; HAL_CHANNEL hchan; sc->sc_rtasksched = 0; if (ath_hal_procdfs(ah, &hchan)) { /* * DFS was found, initiate channel change */ ichan.ic_ieee = ath_hal_mhz2ieee(ah, hchan.channel, hchan.channelFlags); ichan.ic_freq = hchan.channel; ichan.ic_flags = hchan.channelFlags; if ((sc->sc_curchan.channel == hchan.channel) && (sc->sc_curchan.channelFlags == hchan.channel)) { if (hchan.privFlags & CHANNEL_INTERFERENCE) sc->sc_curchan.privFlags |= CHANNEL_INTERFERENCE; } ieee80211_mark_dfs(ic, &ichan); if (((ic->ic_flags_ext & IEEE80211_FEXT_MARKDFS) == 0) && (ic->ic_opmode == IEEE80211_M_HOSTAP)) { sc->sc_dfstest_ieeechan = ic->ic_curchan->ic_ieee; sc->sc_dfstesttimer.function = ath_dfs_test_return; sc->sc_dfstesttimer.expires = jiffies + (sc->sc_dfstesttime * HZ); sc->sc_dfstesttimer.data = (unsigned long)sc; if (sc->sc_dfstest == 0) { sc->sc_dfstest = 1; add_timer(&sc->sc_dfstesttimer); } } }}static voidath_dfs_test_return(unsigned long data){ struct ath_softc *sc = (struct ath_softc *)data; struct ieee80211com *ic = &sc->sc_ic; sc->sc_dfstest = 0; ieee80211_dfs_test_return(ic, sc->sc_dfstest_ieeechan);}static voidath_fatal_tasklet(TQUEUE_ARG data){ struct net_device *dev = (struct net_device *)data; printk("%s: hardware error; reseting\n", dev->name); ath_reset(dev);}static voidath_rxorn_tasklet(TQUEUE_ARG data){ struct net_device *dev = (struct net_device *)data; printk("%s: rx FIFO overrun; reseting\n", dev->name); ath_reset(dev);}static voidath_bmiss_tasklet(TQUEUE_ARG data){ struct net_device *dev = (struct net_device *)data; struct ath_softc *sc = dev->priv; DPRINTF(sc, ATH_DEBUG_ANY, "%s\n", __func__); ieee80211_beacon_miss(&sc->sc_ic);}static u_intath_chan2flags(struct ieee80211_channel *chan){ u_int flags; static const u_int modeflags[] = { 0, /* IEEE80211_MODE_AUTO */ CHANNEL_A, /* IEEE80211_MODE_11A */ CHANNEL_B, /* IEEE80211_MODE_11B */ CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 0, /* IEEE80211_MODE_FH */ CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */ CHANNEL_108G, /* IEEE80211_MODE_TURBO_G */ }; flags = modeflags[ieee80211_chan2mode(chan)]; if (IEEE80211_IS_CHAN_HALF(chan)) flags |= CHANNEL_HALF; else if (IEEE80211_IS_CHAN_QUARTER(chan)) flags |= CHANNEL_QUARTER; return flags;}/* * Context: process context */static intath_init(struct net_device *dev){ struct ath_softc *sc = dev->priv; struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; int error = 0; ATH_LOCK(sc); DPRINTF(sc, ATH_DEBUG_RESET, "%s: mode %d\n", __func__, ic->ic_opmode); /* * Stop anything previously setup. This is safe * whether this is the first time through or not. */ ath_stop_locked(dev);#ifdef ATH_CAP_TPC ath_hal_setcapability(sc->sc_ah, HAL_CAP_TPC, 0, 1, NULL);#endif /* Whether we should enable h/w TKIP MIC */ if ((ic->ic_caps & IEEE80211_C_WME) == 0) ath_hal_setcapability(sc->sc_ah, HAL_CAP_TKIP_MIC, 0, 0, NULL); else { if (((ic->ic_caps & IEEE80211_C_WME_TKIPMIC) == 0) && (ic->ic_flags & IEEE80211_F_WME)) ath_hal_setcapability(sc->sc_ah, HAL_CAP_TKIP_MIC, 0, 0, NULL); else ath_hal_setcapability(sc->sc_ah, HAL_CAP_TKIP_MIC, 0, 1, NULL); } /* * Flush the skb's allocated for receive in case the rx * buffer size changes. This could be optimized but for * now we do it each time under the assumption it does * not happen often. */ ath_flushrecv(sc); /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to * be powered up and with interrupts disabled. This must * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ sc->sc_curchan.channel = ic->ic_curchan->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan); if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { printk("%s: unable to reset hardware: '%s' (HAL status %u) " "(freq %u flags 0x%x)\n", dev->name, ath_get_hal_status_desc(status), status, sc->sc_curchan.channel, sc->sc_curchan.channelFlags); error = -EIO; goto done; } if (sc->sc_softled) ath_hal_gpioCfgOutput(ah, sc->sc_ledpin); /* * This is needed only to setup initial state * but it's best done after a reset. */ ath_update_txpow(sc); /* * Setup the hardware after reset: the key cache * is filled as needed and the receive engine is * set going. Frame transmit is handled entirely * in the frame output path; there's nothing to do * here except setup the interrupt mask. */#if 0 ath_initkeytable(sc); /* XXX still needed? */#endif if (ath_startrecv(sc) != 0) { printk("%s: unable to start recv logic\n", dev->name); error = -EIO; goto done; } /* * Enable interrupts. */ sc->sc_imask = HAL_INT_RX | HAL_INT_TX | HAL_INT_RXEOL | HAL_INT_RXORN | HAL_INT_FATAL | HAL_INT_GLOBAL; /* * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. */ if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) sc->sc_imask |= HAL_INT_MIB; ath_hal_intrset(ah, sc->sc_imask); /* * The hardware should be ready to go now so it's safe * to kick the 802.11 state machine as it's likely to * immediately call back to us to send mgmt frames. */ ath_chan_change(sc, ic->ic_curchan); ath_set_ack_bitrate(sc, sc->sc_ackrate); dev->flags |= IFF_RUNNING; /* we are ready to go */ ieee80211_start_running(ic); /* start all vap's */#ifdef ATH_TX99_DIAG if (sc->sc_tx99 != NULL) sc->sc_tx99->start(sc->sc_tx99);#endifdone: ATH_UNLOCK(sc); return error;}/* Caller must lock ATH_LOCK * * Context: softIRQ */ static intath_stop_locked(struct net_device *dev){ struct ath_softc *sc = dev->priv; struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; DPRINTF(sc, ATH_DEBUG_RESET, "%s: invalid %u flags 0x%x\n", __func__, sc->sc_invalid, dev->flags); if (dev->flags & IFF_RUNNING) { /* * Shutdown the hardware and driver: * stop output from above * reset 802.11 state machine * (sends station deassoc/deauth frames) * turn off timers * disable interrupts * clear transmit machinery * clear receive machinery * turn off the radio * reclaim beacon resources * * Note that some of this work is not possible if the * hardware is gone (invalid). */#ifdef ATH_TX99_DIAG if (sc->sc_tx99 != NULL) sc->sc_tx99->stop(sc->sc_tx99);#endif netif_stop_queue(dev); /* XXX re-enabled by ath_newstate */ dev->flags &= ~IFF_RUNNING; /* NB: avoid recursion */ ieee80211_stop_running(ic); /* stop all vap's */ if (!sc->sc_invalid) { ath_hal_intrset(ah, 0); if (sc->sc_softled) { del_timer(&sc->sc_ledtimer); ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); sc->sc_blinking = 0; sc->sc_ledstate = 1; } } ath_draintxq(sc); if (!sc->sc_invalid) { ath_stoprecv(sc); ath_hal_phydisable(ah); } else sc->sc_rxlink = NULL; ath_beacon_free(sc); /* XXX needed? */ } if (sc->sc_softled) ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); return 0;}/* * Stop the device, grabbing the top-level lock to protect * against concurrent entry through ath_init (which can happen * if another thread does a system call and the thread doing the * stop is preempted). */static intath_stop(struct net_device *dev){ struct ath_softc *sc = dev->priv; int error; ATH_LOCK(sc); if (!sc->sc_invalid) ath_hal_setpower(sc->sc_ah, HAL_PM_AWAKE); error = ath_stop_locked(dev);#if 0 if (error == 0 && !sc->sc_invalid) { /* * Set the chip in full sleep mode. Note that we are * careful to do this only when bringing the interface * completely to a stop. When the chip is in this state * it must be carefully woken up or references to * registers in the PCI clock domain may freeze the bus * (and system). This varies by chip and is mostly an * issue with newer parts that go to sleep more quickly. */ ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); }#endif ATH_UNLOCK(sc); return error;}static int ar_device(int devid){ switch (devid) { case AR5210_DEFAULT: case AR5210_PROD: case AR5210_AP: return 5210; case AR5211_DEFAULT: case AR5311_DEVID: case AR5211_LEGACY: case AR5211_FPGA11B: return 5211; case AR5212_DEFAULT: case AR5212_DEVID: case AR5212_FPGA: case AR5212_DEVID_IBM: case AR5212_AR5312_REV2: case AR5212_AR5312_REV7: case AR5212_AR2313_REV8: case AR5212_AR2315_REV6: case AR5212_AR2315_REV7: case AR5212_AR2317_REV1: case AR5212_DEVID_0014: case AR5212_DEVID_0015: case AR5212_DEVID_0016: case AR5212_DEVID_0017: case AR5212_DEVID_0018: case AR5212_DEVID_0019: case AR5212_AR2413: case AR5212_AR5413: case AR5212_AR5424: case AR5212_DEVID_FF19: return 5212; case AR5213_SREV_1_0: case AR5213_SREV_REG: case AR_SUBVENDOR_ID_NOG: case AR_SUBVENDOR_ID_NEW_A: return 5213; default: return 0; /* unknown */ }}static int ath_set_ack_bitrate(struct ath_softc *sc, int high) { struct ath_hal *ah = sc->sc_ah; if (ar_device(sc->devid) == 5212 || ar_device(sc->devid) == 5213) { /* set ack to be sent at low bit-rate */ /* registers taken from the openbsd 5212 hal */#define AR5K_AR5212_STA_ID1 0x8004#define AR5K_AR5212_STA_ID1_ACKCTS_6MB 0x01000000#define AR5K_AR5212_STA_ID1_BASE_RATE_11B 0x02000000 u_int32_t v = AR5K_AR5212_STA_ID1_BASE_RATE_11B | AR5K_AR5212_STA_ID1_ACKCTS_6MB; if (high) { OS_REG_WRITE(ah, AR5K_AR5212_STA_ID1, OS_REG_READ(ah, AR5K_AR5212_STA_ID1) & ~v); } else { OS_REG_WRITE(ah, AR5K_AR5212_STA_ID1, OS_REG_READ(ah, AR5K_AR5212_STA_ID1) | v); } return 0; } return 1;}/* * Reset the hardware w/o losing operational state. This is * basically a more efficient way of doing ath_stop, ath_init, * followed by state transitions to the current 802.11 * operational state. Used to recover from errors rx overrun * and to reset the hardware when rf gain settings must be reset. */static intath_reset(struct net_device *dev){ struct ath_softc *sc = dev->priv; struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; struct ieee80211_channel *c; HAL_STATUS status; /* * Convert to a HAL channel description with the flags * constrained to reflect the current operating mode. */ c = ic->ic_curchan; sc->sc_curchan.channel = c->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(c); ath_hal_intrset(ah, 0); /* disable interrupts */ ath_draintxq(sc); /* stop xmit s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -