diff options
Diffstat (limited to 'drivers/net/wireless/ath9k')
31 files changed, 11773 insertions, 12439 deletions
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index 1209d14613ac..1a4d4eab6fe8 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -9,8 +9,11 @@ ath9k-y += hw.o \ main.o \ recv.o \ xmit.o \ + virtual.o \ rc.o +ath9k-$(CONFIG_PCI) += pci.o +ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c new file mode 100644 index 000000000000..0e65c51ba176 --- /dev/null +++ b/drivers/net/wireless/ath9k/ahb.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/nl80211.h> +#include <linux/platform_device.h> +#include <linux/ath9k_platform.h> +#include "ath9k.h" + +/* return bus cachesize in 4B word units */ +static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz) +{ + *csz = L1_CACHE_BYTES >> 2; +} + +static void ath_ahb_cleanup(struct ath_softc *sc) +{ + iounmap(sc->mem); +} + +static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +{ + struct ath_softc *sc = ah->ah_sc; + struct platform_device *pdev = to_platform_device(sc->dev); + struct ath9k_platform_data *pdata; + + pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; + if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "%s: flash read failed, offset %08x is out of range\n", + __func__, off); + return false; + } + + *data = pdata->eeprom_data[off]; + return true; +} + +static struct ath_bus_ops ath_ahb_bus_ops = { + .read_cachesize = ath_ahb_read_cachesize, + .cleanup = ath_ahb_cleanup, + + .eeprom_read = ath_ahb_eeprom_read, +}; + +static int ath_ahb_probe(struct platform_device *pdev) +{ + void __iomem *mem; + struct ath_wiphy *aphy; + struct ath_softc *sc; + struct ieee80211_hw *hw; + struct resource *res; + int irq; + int ret = 0; + struct ath_hw *ah; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + ret = -EINVAL; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no memory resource found\n"); + ret = -ENXIO; + goto err_out; + } + + mem = ioremap_nocache(res->start, res->end - res->start + 1); + if (mem == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + ret = -ENXIO; + goto err_iounmap; + } + + irq = res->start; + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + + sizeof(struct ath_softc), &ath9k_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; + goto err_iounmap; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + platform_set_drvdata(pdev, hw); + + aphy = hw->priv; + sc = (struct ath_softc *) (aphy + 1); + aphy->sc = sc; + aphy->hw = hw; + sc->pri_wiphy = aphy; + sc->hw = hw; + sc->dev = &pdev->dev; + sc->mem = mem; + sc->bus_ops = &ath_ahb_bus_ops; + sc->irq = irq; + + ret = ath_attach(AR5416_AR9100_DEVID, sc); + if (ret != 0) { + dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); + ret = -ENODEV; + goto err_free_hw; + } + + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); + ret = -EIO; + goto err_detach; + } + + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x, " + "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n", + wiphy_name(hw->wiphy), + ath_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev, + (unsigned long)mem, irq); + + return 0; + + err_detach: + ath_detach(sc); + err_free_hw: + ieee80211_free_hw(hw); + platform_set_drvdata(pdev, NULL); + err_iounmap: + iounmap(mem); + err_out: + return ret; +} + +static int ath_ahb_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + + if (hw) { + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath_cleanup(sc); + platform_set_drvdata(pdev, NULL); + } + + return 0; +} + +static struct platform_driver ath_ahb_driver = { + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", + .owner = THIS_MODULE, + }, +}; + +int ath_ahb_init(void) +{ + return platform_driver_register(&ath_ahb_driver); +} + +void ath_ahb_exit(void) +{ + platform_driver_unregister(&ath_ahb_driver); +} diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index 251e2d9a7a4a..6c5e887d50d7 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,23 +14,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" +#include "ath9k.h" -static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, +static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - if (ahp->ah_ani[i].c.channel == chan->channel) + for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { + if (ah->ani[i].c && + ah->ani[i].c->channel == chan->channel) return i; - if (ahp->ah_ani[i].c.channel == 0) { - ahp->ah_ani[i].c.channel = chan->channel; - ahp->ah_ani[i].c.channelFlags = chan->channelFlags; + if (ah->ani[i].c == NULL) { + ah->ani[i].c = chan; return i; } } @@ -41,41 +37,40 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, return 0; } -static bool ath9k_hw_ani_control(struct ath_hal *ah, +static bool ath9k_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState = ahp->ah_curani; + struct ar5416AniState *aniState = ah->curani; - switch (cmd & ahp->ah_ani_function) { + switch (cmd & ah->ani_function) { case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { + if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "level out of range (%u > %u)\n", level, - (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)); + (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); return false; } REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_TOT_DES, - ahp->ah_totalSizeDesired[level]); + ah->totalSizeDesired[level]); REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_LOW, - ahp->ah_coarseLow[level]); + ah->coarse_low[level]); REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, AR_PHY_AGC_CTL1_COARSE_HIGH, - ahp->ah_coarseHigh[level]); + ah->coarse_high[level]); REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, - ahp->ah_firpwr[level]); + ah->firpwr[level]); if (level > aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_niup++; + ah->stats.ast_ani_niup++; else if (level < aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_nidown++; + ah->stats.ast_ani_nidown++; aniState->noiseImmunityLevel = level; break; } @@ -129,9 +124,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, if (!on != aniState->ofdmWeakSigDetectOff) { if (on) - ahp->ah_stats.ast_ani_ofdmon++; + ah->stats.ast_ani_ofdmon++; else - ahp->ah_stats.ast_ani_ofdmoff++; + ah->stats.ast_ani_ofdmoff++; aniState->ofdmWeakSigDetectOff = !on; } break; @@ -145,9 +140,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, weakSigThrCck[high]); if (high != aniState->cckWeakSigThreshold) { if (high) - ahp->ah_stats.ast_ani_cckhigh++; + ah->stats.ast_ani_cckhigh++; else - ahp->ah_stats.ast_ani_ccklow++; + ah->stats.ast_ani_ccklow++; aniState->cckWeakSigThreshold = high; } break; @@ -167,9 +162,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, AR_PHY_FIND_SIG_FIRSTEP, firstep[level]); if (level > aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepup++; + ah->stats.ast_ani_stepup++; else if (level < aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepdown++; + ah->stats.ast_ani_stepdown++; aniState->firstepLevel = level; break; } @@ -190,9 +185,9 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]); if (level > aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurup++; + ah->stats.ast_ani_spurup++; else if (level < aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurdown++; + ah->stats.ast_ani_spurdown++; aniState->spurImmunityLevel = level; break; } @@ -223,7 +218,7 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, return true; } -static void ath9k_hw_update_mibstats(struct ath_hal *ah, +static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); @@ -233,18 +228,17 @@ static void ath9k_hw_update_mibstats(struct ath_hal *ah, stats->beacons += REG_READ(ah, AR_BEACON_CNT); } -static void ath9k_ani_restart(struct ath_hal *ah) +static void ath9k_ani_restart(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; if (!DO_ANI(ah)) return; - aniState = ahp->ah_curani; + aniState = ah->curani; aniState->listenTime = 0; - if (ahp->ah_hasHwPhyCounters) { + if (ah->has_hw_phycounters) { if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; DPRINTF(ah->ah_sc, ATH_DBG_ANI, @@ -270,24 +264,22 @@ static void ath9k_ani_restart(struct ath_hal *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); } aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; } -static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; struct ar5416AniState *aniState; - enum wireless_mode mode; int32_t rssi; if (!DO_ANI(ah)) return; - aniState = ahp->ah_curani; + aniState = ah->curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, @@ -303,14 +295,14 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) } } - if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } - rssi = BEACON_RSSI(ahp); + rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrHigh) { if (!aniState->ofdmWeakSigDetectOff) { if (ath9k_hw_ani_control(ah, @@ -336,8 +328,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) aniState->firstepLevel + 1); return; } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (conf->channel->band == IEEE80211_BAND_2GHZ) { if (!aniState->ofdmWeakSigDetectOff) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, @@ -350,39 +341,36 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) } } -static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) +static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; struct ar5416AniState *aniState; - enum wireless_mode mode; int32_t rssi; if (!DO_ANI(ah)) return; - aniState = ahp->ah_curani; + aniState = ah->curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { return; } } - if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } - rssi = BEACON_RSSI(ahp); + rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrLow) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (conf->channel->band == IEEE80211_BAND_2GHZ) { if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); @@ -390,22 +378,21 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) } } -static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) +static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; int32_t rssi; - aniState = ahp->ah_curani; + aniState = ah->curani; - if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1)) return; } } else { - rssi = BEACON_RSSI(ahp); + rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrHigh) { /* XXX: Handle me */ } else if (rssi > aniState->rssiThrLow) { @@ -444,9 +431,8 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) } } -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) +static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; u32 txFrameCount, rxFrameCount, cycleCount; int32_t listenTime; @@ -455,11 +441,11 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) rxFrameCount = REG_READ(ah, AR_RFCNT); cycleCount = REG_READ(ah, AR_CCCNT); - aniState = ahp->ah_curani; + aniState = ah->curani; if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { listenTime = 0; - ahp->ah_stats.ast_ani_lzero++; + ah->stats.ast_ani_lzero++; } else { int32_t ccdelta = cycleCount - aniState->cycleCount; int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; @@ -473,25 +459,24 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) return listenTime; } -void ath9k_ani_reset(struct ath_hal *ah) +void ath9k_ani_reset(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_channel *chan = ah->curchan; int index; if (!DO_ANI(ah)) return; index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ahp->ah_ani[index]; - ahp->ah_curani = aniState; + aniState = &ah->ani[index]; + ah->curani = aniState; - if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION - && ah->ah_opmode != NL80211_IFTYPE_ADHOC) { + if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION + && ah->opmode != NL80211_IFTYPE_ADHOC) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Reset ANI state opmode %u\n", ah->ah_opmode); - ahp->ah_stats.ast_ani_reset++; + "Reset ANI state opmode %u\n", ah->opmode); + ah->stats.ast_ani_reset++; ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); @@ -504,15 +489,15 @@ void ath9k_ani_reset(struct ath_hal *ah) ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYERR); - if (ah->ah_opmode == NL80211_IFTYPE_AP) { - ahp->ah_curani->ofdmTrigHigh = - ah->ah_config.ofdm_trig_high; - ahp->ah_curani->ofdmTrigLow = - ah->ah_config.ofdm_trig_low; - ahp->ah_curani->cckTrigHigh = - ah->ah_config.cck_trig_high; - ahp->ah_curani->cckTrigLow = - ah->ah_config.cck_trig_low; + if (ah->opmode == NL80211_IFTYPE_AP) { + ah->curani->ofdmTrigHigh = + ah->config.ofdm_trig_high; + ah->curani->ofdmTrigLow = + ah->config.ofdm_trig_low; + ah->curani->cckTrigHigh = + ah->config.cck_trig_high; + ah->curani->cckTrigLow = + ah->config.cck_trig_low; } ath9k_ani_restart(ah); return; @@ -533,7 +518,7 @@ void ath9k_ani_reset(struct ath_hal *ah) if (aniState->firstepLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); - if (ahp->ah_hasHwPhyCounters) { + if (ah->has_hw_phycounters) { ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & ~ATH9K_RX_FILTER_PHYERR); ath9k_ani_restart(ah); @@ -547,31 +532,33 @@ void ath9k_ani_reset(struct ath_hal *ah) } } -void ath9k_hw_ani_monitor(struct ath_hal *ah, +void ath9k_hw_ani_monitor(struct ath_hw *ah, const struct ath9k_node_stats *stats, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416AniState *aniState; int32_t listenTime; - aniState = ahp->ah_curani; - ahp->ah_stats.ast_nodestats = *stats; + if (!DO_ANI(ah)) + return; + + aniState = ah->curani; + ah->stats.ast_nodestats = *stats; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { - ahp->ah_stats.ast_ani_lneg++; + ah->stats.ast_ani_lneg++; ath9k_ani_restart(ah); return; } aniState->listenTime += listenTime; - if (ahp->ah_hasHwPhyCounters) { + if (ah->has_hw_phycounters) { u32 phyCnt1, phyCnt2; u32 ofdmPhyErrCnt, cckPhyErrCnt; - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); @@ -604,27 +591,24 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah, } ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += + ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += + ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; } - if (!DO_ANI(ah)) - return; - - if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { + if (aniState->listenTime > 5 * ah->aniperiod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * aniState->ofdmTrigLow / 1000 && aniState->cckPhyErrCount <= aniState->listenTime * aniState->cckTrigLow / 1000) ath9k_hw_ani_lower_immunity(ah); ath9k_ani_restart(ah); - } else if (aniState->listenTime > ahp->ah_aniPeriod) { + } else if (aniState->listenTime > ah->aniperiod) { if (aniState->ofdmPhyErrCount > aniState->listenTime * aniState->ofdmTrigHigh / 1000) { ath9k_hw_ani_ofdm_err_trigger(ah); @@ -638,20 +622,16 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah, } } -bool ath9k_hw_phycounters(struct ath_hal *ah) +bool ath9k_hw_phycounters(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - - return ahp->ah_hasHwPhyCounters ? true : false; + return ah->has_hw_phycounters ? true : false; } -void ath9k_enable_mib_counters(struct ath_hal *ah) +void ath9k_enable_mib_counters(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); @@ -662,21 +642,18 @@ void ath9k_enable_mib_counters(struct ath_hal *ah) REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } -void ath9k_hw_disable_mib_counters(struct ath_hal *ah) +/* Freeze the MIB counters, get the stats and then clear them */ +void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); - - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); } -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, u32 *rxf_pcnt, u32 *txf_pcnt) @@ -721,10 +698,9 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ -void ath9k_hw_procmibevent(struct ath_hal *ah, +void ath9k_hw_procmibevent(struct ath_hw *ah, const struct ath9k_node_stats *stats) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 phyCnt1, phyCnt2; /* Reset these counters regardless */ @@ -734,8 +710,8 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - ahp->ah_stats.ast_nodestats = *stats; + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + ah->stats.ast_nodestats = *stats; if (!DO_ANI(ah)) return; @@ -745,17 +721,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ahp->ah_curani; + struct ar5416AniState *aniState = ah->curani; u32 ofdmPhyErrCnt, cckPhyErrCnt; /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += + ah->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; aniState->ofdmPhyErrCount = ofdmPhyErrCnt; cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += + ah->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; aniState->cckPhyErrCount = cckPhyErrCnt; @@ -774,9 +750,8 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, } } -void ath9k_hw_ani_setup(struct ath_hal *ah) +void ath9k_hw_ani_setup(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; @@ -785,66 +760,63 @@ void ath9k_hw_ani_setup(struct ath_hal *ah) const int firpwr[] = { -78, -78, -78, -78, -80 }; for (i = 0; i < 5; i++) { - ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; - ahp->ah_coarseHigh[i] = coarseHigh[i]; - ahp->ah_coarseLow[i] = coarseLow[i]; - ahp->ah_firpwr[i] = firpwr[i]; + ah->totalSizeDesired[i] = totalSizeDesired[i]; + ah->coarse_high[i] = coarseHigh[i]; + ah->coarse_low[i] = coarseLow[i]; + ah->firpwr[i] = firpwr[i]; } } -void ath9k_hw_ani_attach(struct ath_hal *ah) +void ath9k_hw_ani_attach(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); - ahp->ah_hasHwPhyCounters = 1; - - memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; - ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; - ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; - ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ahp->ah_ani[i].ofdmWeakSigDetectOff = + ah->has_hw_phycounters = 1; + + memset(ah->ani, 0, sizeof(ah->ani)); + for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { + ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; + ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; + ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; + ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ah->ani[i].ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ahp->ah_ani[i].cckWeakSigThreshold = + ah->ani[i].cckWeakSigThreshold = ATH9K_ANI_CCK_WEAK_SIG_THR; - ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ahp->ah_hasHwPhyCounters) { - ahp->ah_ani[i].ofdmPhyErrBase = + ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + if (ah->has_hw_phycounters) { + ah->ani[i].ofdmPhyErrBase = AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].cckPhyErrBase = + ah->ani[i].cckPhyErrBase = AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } } - if (ahp->ah_hasHwPhyCounters) { + if (ah->has_hw_phycounters) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting OfdmErrBase = 0x%08x\n", - ahp->ah_ani[0].ofdmPhyErrBase); + ah->ani[0].ofdmPhyErrBase); DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ahp->ah_ani[0].cckPhyErrBase); + ah->ani[0].cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); ath9k_enable_mib_counters(ah); } - ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; - if (ah->ah_config.enable_ani) - ahp->ah_procPhyErr |= HAL_PROCESS_ANI; + ah->aniperiod = ATH9K_ANI_PERIOD; + if (ah->config.enable_ani) + ah->proc_phyerr |= HAL_PROCESS_ANI; } -void ath9k_hw_ani_detach(struct ath_hal *ah) +void ath9k_hw_ani_detach(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); - if (ahp->ah_hasHwPhyCounters) { + if (ah->has_hw_phycounters) { ath9k_hw_disable_mib_counters(ah); REG_WRITE(ah, AR_PHY_ERR_1, 0); REG_WRITE(ah, AR_PHY_ERR_2, 0); diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath9k/ani.h new file mode 100644 index 000000000000..08b4e7ed5ff0 --- /dev/null +++ b/drivers/net/wireless/ath9k/ani.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ANI_H +#define ANI_H + +#define HAL_PROCESS_ANI 0x00000001 +#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) + +#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) + +#define HAL_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) +#define BEACON_RSSI(ahp) \ + HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ + ATH9K_RSSI_EP_MULTIPLIER) + +#define ATH9K_ANI_OFDM_TRIG_HIGH 500 +#define ATH9K_ANI_OFDM_TRIG_LOW 200 +#define ATH9K_ANI_CCK_TRIG_HIGH 200 +#define ATH9K_ANI_CCK_TRIG_LOW 100 +#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 +#define ATH9K_ANI_USE_OFDM_WEAK_SIG true +#define ATH9K_ANI_CCK_WEAK_SIG_THR false +#define ATH9K_ANI_SPUR_IMMUNE_LVL 7 +#define ATH9K_ANI_FIRSTEP_LVL 0 +#define ATH9K_ANI_RSSI_THR_HIGH 40 +#define ATH9K_ANI_RSSI_THR_LOW 7 +#define ATH9K_ANI_PERIOD 100 + +#define HAL_NOISE_IMMUNE_MAX 4 +#define HAL_SPUR_IMMUNE_MAX 7 +#define HAL_FIRST_STEP_MAX 2 + +enum ath9k_ani_cmd { + ATH9K_ANI_PRESENT = 0x1, + ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, + ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, + ATH9K_ANI_FIRSTEP_LEVEL = 0x10, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, + ATH9K_ANI_MODE = 0x40, + ATH9K_ANI_PHYERR_RESET = 0x80, + ATH9K_ANI_ALL = 0xff +}; + +struct ath9k_mib_stats { + u32 ackrcv_bad; + u32 rts_bad; + u32 rts_good; + u32 fcs_bad; + u32 beacons; +}; + +struct ath9k_node_stats { + u32 ns_avgbrssi; + u32 ns_avgrssi; + u32 ns_avgtxrssi; + u32 ns_avgtxrate; +}; + +struct ar5416AniState { + struct ath9k_channel *c; + u8 noiseImmunityLevel; + u8 spurImmunityLevel; + u8 firstepLevel; + u8 ofdmWeakSigDetectOff; + u8 cckWeakSigThreshold; + u32 listenTime; + u32 ofdmTrigHigh; + u32 ofdmTrigLow; + int32_t cckTrigHigh; + int32_t cckTrigLow; + int32_t rssiThrLow; + int32_t rssiThrHigh; + u32 noiseFloor; + u32 txFrameCount; + u32 rxFrameCount; + u32 cycleCount; + u32 ofdmPhyErrCount; + u32 cckPhyErrCount; + u32 ofdmPhyErrBase; + u32 cckPhyErrBase; + int16_t pktRssi[2]; + int16_t ofdmErrRssi[2]; + int16_t cckErrRssi[2]; +}; + +struct ar5416Stats { + u32 ast_ani_niup; + u32 ast_ani_nidown; + u32 ast_ani_spurup; + u32 ast_ani_spurdown; + u32 ast_ani_ofdmon; + u32 ast_ani_ofdmoff; + u32 ast_ani_cckhigh; + u32 ast_ani_ccklow; + u32 ast_ani_stepup; + u32 ast_ani_stepdown; + u32 ast_ani_ofdmerrs; + u32 ast_ani_cckerrs; + u32 ast_ani_reset; + u32 ast_ani_lzero; + u32 ast_ani_lneg; + struct ath9k_mib_stats ast_mibstats; + struct ath9k_node_stats ast_nodestats; +}; +#define ah_mibStats stats.ast_mibstats + +void ath9k_ani_reset(struct ath_hw *ah); +void ath9k_hw_ani_monitor(struct ath_hw *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan); +bool ath9k_hw_phycounters(struct ath_hw *ah); +void ath9k_enable_mib_counters(struct ath_hw *ah); +void ath9k_hw_disable_mib_counters(struct ath_hw *ah); +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, + u32 *rxf_pcnt, u32 *txf_pcnt); +void ath9k_hw_procmibevent(struct ath_hw *ah, + const struct ath9k_node_stats *stats); +void ath9k_hw_ani_setup(struct ath_hw *ah); +void ath9k_hw_ani_attach(struct ath_hw *ah); +void ath9k_hw_ani_detach(struct ath_hw *ah); + +#endif /* ANI_H */ diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 6650f609ece4..2689a08a2844 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,1041 +17,741 @@ #ifndef ATH9K_H #define ATH9K_H -#include <linux/io.h> - -#define ATHEROS_VENDOR_ID 0x168c - -#define AR5416_DEVID_PCI 0x0023 -#define AR5416_DEVID_PCIE 0x0024 -#define AR9160_DEVID_PCI 0x0027 -#define AR9280_DEVID_PCI 0x0029 -#define AR9280_DEVID_PCIE 0x002a -#define AR9285_DEVID_PCIE 0x002b - -#define AR5416_AR9100_DEVID 0x000b - -#define AR_SUBVENDOR_ID_NOG 0x0e11 -#define AR_SUBVENDOR_ID_NEW_A 0x7065 - -#define ATH9K_TXERR_XRETRY 0x01 -#define ATH9K_TXERR_FILT 0x02 -#define ATH9K_TXERR_FIFO 0x04 -#define ATH9K_TXERR_XTXOP 0x08 -#define ATH9K_TXERR_TIMER_EXPIRED 0x10 - -#define ATH9K_TX_BA 0x01 -#define ATH9K_TX_PWRMGMT 0x02 -#define ATH9K_TX_DESC_CFG_ERR 0x04 -#define ATH9K_TX_DATA_UNDERRUN 0x08 -#define ATH9K_TX_DELIM_UNDERRUN 0x10 -#define ATH9K_TX_SW_ABORTED 0x40 -#define ATH9K_TX_SW_FILTERED 0x80 - -#define NBBY 8 - -struct ath_tx_status { - u32 ts_tstamp; - u16 ts_seqnum; - u8 ts_status; - u8 ts_ratecode; - u8 ts_rateindex; - int8_t ts_rssi; - u8 ts_shortretry; - u8 ts_longretry; - u8 ts_virtcol; - u8 ts_antenna; - u8 ts_flags; - int8_t ts_rssi_ctl0; - int8_t ts_rssi_ctl1; - int8_t ts_rssi_ctl2; - int8_t ts_rssi_ext0; - int8_t ts_rssi_ext1; - int8_t ts_rssi_ext2; - u8 pad[3]; - u32 ba_low; - u32 ba_high; - u32 evm0; - u32 evm1; - u32 evm2; -}; +#include <linux/etherdevice.h> +#include <linux/device.h> +#include <net/mac80211.h> +#include <linux/leds.h> +#include <linux/rfkill.h> -struct ath_rx_status { - u32 rs_tstamp; - u16 rs_datalen; - u8 rs_status; - u8 rs_phyerr; - int8_t rs_rssi; - u8 rs_keyix; - u8 rs_rate; - u8 rs_antenna; - u8 rs_more; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; - u8 rs_isaggr; - u8 rs_moreaggr; - u8 rs_num_delims; - u8 rs_flags; - u32 evm0; - u32 evm1; - u32 evm2; -}; +#include "hw.h" +#include "rc.h" +#include "debug.h" -#define ATH9K_RXERR_CRC 0x01 -#define ATH9K_RXERR_PHY 0x02 -#define ATH9K_RXERR_FIFO 0x04 -#define ATH9K_RXERR_DECRYPT 0x08 -#define ATH9K_RXERR_MIC 0x10 - -#define ATH9K_RX_MORE 0x01 -#define ATH9K_RX_MORE_AGGR 0x02 -#define ATH9K_RX_GI 0x04 -#define ATH9K_RX_2040 0x08 -#define ATH9K_RX_DELIM_CRC_PRE 0x10 -#define ATH9K_RX_DELIM_CRC_POST 0x20 -#define ATH9K_RX_DECRYPT_BUSY 0x40 - -#define ATH9K_RXKEYIX_INVALID ((u8)-1) -#define ATH9K_TXKEYIX_INVALID ((u32)-1) - -struct ath_desc { - u32 ds_link; - u32 ds_data; - u32 ds_ctl0; - u32 ds_ctl1; - u32 ds_hw[20]; - union { - struct ath_tx_status tx; - struct ath_rx_status rx; - void *stats; - } ds_us; - void *ds_vdata; -} __packed; - -#define ds_txstat ds_us.tx -#define ds_rxstat ds_us.rx -#define ds_stat ds_us.stats - -#define ATH9K_TXDESC_CLRDMASK 0x0001 -#define ATH9K_TXDESC_NOACK 0x0002 -#define ATH9K_TXDESC_RTSENA 0x0004 -#define ATH9K_TXDESC_CTSENA 0x0008 -/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for - * the descriptor its marked on. We take a tx interrupt to reap - * descriptors when the h/w hits an EOL condition or - * when the descriptor is specifically marked to generate - * an interrupt with this flag. Descriptors should be - * marked periodically to insure timely replenishing of the - * supply needed for sending frames. Defering interrupts - * reduces system load and potentially allows more concurrent - * work to be done but if done to aggressively can cause - * senders to backup. When the hardware queue is left too - * large rate control information may also be too out of - * date. An Alternative for this is TX interrupt mitigation - * but this needs more testing. */ -#define ATH9K_TXDESC_INTREQ 0x0010 -#define ATH9K_TXDESC_VEOL 0x0020 -#define ATH9K_TXDESC_EXT_ONLY 0x0040 -#define ATH9K_TXDESC_EXT_AND_CTL 0x0080 -#define ATH9K_TXDESC_VMF 0x0100 -#define ATH9K_TXDESC_FRAG_IS_ON 0x0200 -#define ATH9K_TXDESC_CAB 0x0400 - -#define ATH9K_RXDESC_INTREQ 0x0020 - -enum wireless_mode { - ATH9K_MODE_11A = 0, - ATH9K_MODE_11B = 2, - ATH9K_MODE_11G = 3, - ATH9K_MODE_11NA_HT20 = 6, - ATH9K_MODE_11NG_HT20 = 7, - ATH9K_MODE_11NA_HT40PLUS = 8, - ATH9K_MODE_11NA_HT40MINUS = 9, - ATH9K_MODE_11NG_HT40PLUS = 10, - ATH9K_MODE_11NG_HT40MINUS = 11, - ATH9K_MODE_MAX -}; +struct ath_node; -enum ath9k_hw_caps { - ATH9K_HW_CAP_CHAN_SPREAD = BIT(0), - ATH9K_HW_CAP_MIC_AESCCM = BIT(1), - ATH9K_HW_CAP_MIC_CKIP = BIT(2), - ATH9K_HW_CAP_MIC_TKIP = BIT(3), - ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4), - ATH9K_HW_CAP_CIPHER_CKIP = BIT(5), - ATH9K_HW_CAP_CIPHER_TKIP = BIT(6), - ATH9K_HW_CAP_VEOL = BIT(7), - ATH9K_HW_CAP_BSSIDMASK = BIT(8), - ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9), - ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10), - ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11), - ATH9K_HW_CAP_HT = BIT(12), - ATH9K_HW_CAP_GTT = BIT(13), - ATH9K_HW_CAP_FASTCC = BIT(14), - ATH9K_HW_CAP_RFSILENT = BIT(15), - ATH9K_HW_CAP_WOW = BIT(16), - ATH9K_HW_CAP_CST = BIT(17), - ATH9K_HW_CAP_ENHANCEDPM = BIT(18), - ATH9K_HW_CAP_AUTOSLEEP = BIT(19), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20), - ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21), -}; +/* Macro to expand scalars to 64-bit objects */ -enum ath9k_capability_type { - ATH9K_CAP_CIPHER = 0, - ATH9K_CAP_TKIP_MIC, - ATH9K_CAP_TKIP_SPLIT, - ATH9K_CAP_PHYCOUNTERS, - ATH9K_CAP_DIVERSITY, - ATH9K_CAP_TXPOW, - ATH9K_CAP_PHYDIAG, - ATH9K_CAP_MCAST_KEYSRCH, - ATH9K_CAP_TSF_ADJUST, - ATH9K_CAP_WME_TKIPMIC, - ATH9K_CAP_RFSILENT, - ATH9K_CAP_ANT_CFG_2GHZ, - ATH9K_CAP_ANT_CFG_5GHZ -}; +#define ito64(x) (sizeof(x) == 8) ? \ + (((unsigned long long int)(x)) & (0xff)) : \ + (sizeof(x) == 16) ? \ + (((unsigned long long int)(x)) & 0xffff) : \ + ((sizeof(x) == 32) ? \ + (((unsigned long long int)(x)) & 0xffffffff) : \ + (unsigned long long int)(x)) -struct ath9k_hw_capabilities { - u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */ - u16 total_queues; - u16 keycache_size; - u16 low_5ghz_chan, high_5ghz_chan; - u16 low_2ghz_chan, high_2ghz_chan; - u16 num_mr_retries; - u16 rts_aggr_limit; - u8 tx_chainmask; - u8 rx_chainmask; - u16 tx_triglevel_max; - u16 reg_cap; - u8 num_gpio_pins; - u8 num_antcfg_2ghz; - u8 num_antcfg_5ghz; -}; +/* increment with wrap-around */ +#define INCR(_l, _sz) do { \ + (_l)++; \ + (_l) &= ((_sz) - 1); \ + } while (0) -struct ath9k_ops_config { - int dma_beacon_response_time; - int sw_beacon_response_time; - int additional_swba_backoff; - int ack_6mb; - int cwm_ignore_extcca; - u8 pcie_powersave_enable; - u8 pcie_l1skp_enable; - u8 pcie_clock_req; - u32 pcie_waen; - int pcie_power_reset; - u8 pcie_restore; - u8 analog_shiftreg; - u8 ht_enable; - u32 ofdm_trig_low; - u32 ofdm_trig_high; - u32 cck_trig_high; - u32 cck_trig_low; - u32 enable_ani; - u8 noise_immunity_level; - u32 ofdm_weaksignal_det; - u32 cck_weaksignal_thr; - u8 spur_immunity_level; - u8 firstep_level; - int8_t rssi_thr_high; - int8_t rssi_thr_low; - u16 diversity_control; - u16 antenna_switch_swap; - int serialize_regmode; - int intr_mitigation; -#define SPUR_DISABLE 0 -#define SPUR_ENABLE_IOCTL 1 -#define SPUR_ENABLE_EEPROM 2 -#define AR_EEPROM_MODAL_SPURS 5 -#define AR_SPUR_5413_1 1640 -#define AR_SPUR_5413_2 1200 -#define AR_NO_SPUR 0x8000 -#define AR_BASE_FREQ_2GHZ 2300 -#define AR_BASE_FREQ_5GHZ 4900 -#define AR_SPUR_FEEQ_BOUND_HT40 19 -#define AR_SPUR_FEEQ_BOUND_HT20 10 - int spurmode; - u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; -}; +/* decrement with wrap-around */ +#define DECR(_l, _sz) do { \ + (_l)--; \ + (_l) &= ((_sz) - 1); \ + } while (0) -enum ath9k_tx_queue { - ATH9K_TX_QUEUE_INACTIVE = 0, - ATH9K_TX_QUEUE_DATA, - ATH9K_TX_QUEUE_BEACON, - ATH9K_TX_QUEUE_CAB, - ATH9K_TX_QUEUE_UAPSD, - ATH9K_TX_QUEUE_PSPOLL -}; - -#define ATH9K_NUM_TX_QUEUES 10 - -enum ath9k_tx_queue_subtype { - ATH9K_WME_AC_BK = 0, - ATH9K_WME_AC_BE, - ATH9K_WME_AC_VI, - ATH9K_WME_AC_VO, - ATH9K_WME_UPSD -}; +#define A_MAX(a, b) ((a) > (b) ? (a) : (b)) -enum ath9k_tx_queue_flags { - TXQ_FLAG_TXOKINT_ENABLE = 0x0001, - TXQ_FLAG_TXERRINT_ENABLE = 0x0001, - TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, - TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, - TXQ_FLAG_TXURNINT_ENABLE = 0x0008, - TXQ_FLAG_BACKOFF_DISABLE = 0x0010, - TXQ_FLAG_COMPRESSION_ENABLE = 0x0020, - TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040, - TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080, -}; - -#define ATH9K_TXQ_USEDEFAULT ((u32) -1) +#define ASSERT(exp) do { \ + if (unlikely(!(exp))) { \ + BUG(); \ + } \ + } while (0) -#define ATH9K_DECOMP_MASK_SIZE 128 -#define ATH9K_READY_TIME_LO_BOUND 50 -#define ATH9K_READY_TIME_HI_BOUND 96 +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -enum ath9k_pkt_type { - ATH9K_PKT_TYPE_NORMAL = 0, - ATH9K_PKT_TYPE_ATIM, - ATH9K_PKT_TYPE_PSPOLL, - ATH9K_PKT_TYPE_BEACON, - ATH9K_PKT_TYPE_PROBE_RESP, - ATH9K_PKT_TYPE_CHIRP, - ATH9K_PKT_TYPE_GRP_POLL, -}; +#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) -struct ath9k_tx_queue_info { - u32 tqi_ver; - enum ath9k_tx_queue tqi_type; - enum ath9k_tx_queue_subtype tqi_subtype; - enum ath9k_tx_queue_flags tqi_qflags; - u32 tqi_priority; - u32 tqi_aifs; - u32 tqi_cwmin; - u32 tqi_cwmax; - u16 tqi_shretry; - u16 tqi_lgretry; - u32 tqi_cbrPeriod; - u32 tqi_cbrOverflowLimit; - u32 tqi_burstTime; - u32 tqi_readyTime; - u32 tqi_physCompBuf; - u32 tqi_intFlags; -}; +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -enum ath9k_rx_filter { - ATH9K_RX_FILTER_UCAST = 0x00000001, - ATH9K_RX_FILTER_MCAST = 0x00000002, - ATH9K_RX_FILTER_BCAST = 0x00000004, - ATH9K_RX_FILTER_CONTROL = 0x00000008, - ATH9K_RX_FILTER_BEACON = 0x00000010, - ATH9K_RX_FILTER_PROM = 0x00000020, - ATH9K_RX_FILTER_PROBEREQ = 0x00000080, - ATH9K_RX_FILTER_PSPOLL = 0x00004000, - ATH9K_RX_FILTER_PHYERR = 0x00000100, - ATH9K_RX_FILTER_PHYRADAR = 0x00002000, +struct ath_config { + u32 ath_aggr_prot; + u16 txpowlimit; + u8 cabqReadytime; + u8 swBeaconProcess; }; -enum ath9k_int { - ATH9K_INT_RX = 0x00000001, - ATH9K_INT_RXDESC = 0x00000002, - ATH9K_INT_RXNOFRM = 0x00000008, - ATH9K_INT_RXEOL = 0x00000010, - ATH9K_INT_RXORN = 0x00000020, - ATH9K_INT_TX = 0x00000040, - ATH9K_INT_TXDESC = 0x00000080, - ATH9K_INT_TIM_TIMER = 0x00000100, - ATH9K_INT_TXURN = 0x00000800, - ATH9K_INT_MIB = 0x00001000, - ATH9K_INT_RXPHY = 0x00004000, - ATH9K_INT_RXKCM = 0x00008000, - ATH9K_INT_SWBA = 0x00010000, - ATH9K_INT_BMISS = 0x00040000, - ATH9K_INT_BNR = 0x00100000, - ATH9K_INT_TIM = 0x00200000, - ATH9K_INT_DTIM = 0x00400000, - ATH9K_INT_DTIMSYNC = 0x00800000, - ATH9K_INT_GPIO = 0x01000000, - ATH9K_INT_CABEND = 0x02000000, - ATH9K_INT_CST = 0x10000000, - ATH9K_INT_GTT = 0x20000000, - ATH9K_INT_FATAL = 0x40000000, - ATH9K_INT_GLOBAL = 0x80000000, - ATH9K_INT_BMISC = ATH9K_INT_TIM | - ATH9K_INT_DTIM | - ATH9K_INT_DTIMSYNC | - ATH9K_INT_CABEND, - ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | - ATH9K_INT_RXDESC | - ATH9K_INT_RXEOL | - ATH9K_INT_RXORN | - ATH9K_INT_TXURN | - ATH9K_INT_TXDESC | - ATH9K_INT_MIB | - ATH9K_INT_RXPHY | - ATH9K_INT_RXKCM | - ATH9K_INT_SWBA | - ATH9K_INT_BMISS | - ATH9K_INT_GPIO, - ATH9K_INT_NOCARD = 0xffffffff -}; +/*************************/ +/* Descriptor Management */ +/*************************/ -#define ATH9K_RATESERIES_RTS_CTS 0x0001 -#define ATH9K_RATESERIES_2040 0x0002 -#define ATH9K_RATESERIES_HALFGI 0x0004 +#define ATH_TXBUF_RESET(_bf) do { \ + (_bf)->bf_status = 0; \ + (_bf)->bf_lastbf = NULL; \ + (_bf)->bf_next = NULL; \ + memset(&((_bf)->bf_state), 0, \ + sizeof(struct ath_buf_state)); \ + } while (0) -struct ath9k_11n_rate_series { - u32 Tries; - u32 Rate; - u32 PktDuration; - u32 ChSel; - u32 RateFlags; -}; +/** + * enum buffer_type - Buffer type flags + * + * @BUF_HT: Send this buffer using HT capabilities + * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) + * @BUF_AGGR: Indicates whether the buffer can be aggregated + * (used in aggregation scheduling) + * @BUF_RETRY: Indicates whether the buffer is retried + * @BUF_XRETRY: To denote excessive retries of the buffer + */ +enum buffer_type { + BUF_HT = BIT(1), + BUF_AMPDU = BIT(2), + BUF_AGGR = BIT(3), + BUF_RETRY = BIT(4), + BUF_XRETRY = BIT(5), +}; + +struct ath_buf_state { + int bfs_nframes; + u16 bfs_al; + u16 bfs_frmlen; + int bfs_seqno; + int bfs_tidno; + int bfs_retries; + u32 bf_type; + u32 bfs_keyix; + enum ath9k_key_type bfs_keytype; +}; + +#define bf_nframes bf_state.bfs_nframes +#define bf_al bf_state.bfs_al +#define bf_frmlen bf_state.bfs_frmlen +#define bf_retries bf_state.bfs_retries +#define bf_seqno bf_state.bfs_seqno +#define bf_tidno bf_state.bfs_tidno +#define bf_keyix bf_state.bfs_keyix +#define bf_keytype bf_state.bfs_keytype +#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) +#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) +#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) + +struct ath_buf { + struct list_head list; + struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or + an aggregate) */ + struct ath_buf *bf_next; /* next subframe in the aggregate */ + void *bf_mpdu; /* enclosing frame structure */ + struct ath_desc *bf_desc; /* virtual addr of desc */ + dma_addr_t bf_daddr; /* physical addr of desc */ + dma_addr_t bf_buf_addr; /* physical addr of data buffer */ + u32 bf_status; + u16 bf_flags; + struct ath_buf_state bf_state; + dma_addr_t bf_dmacontext; +}; + +#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) +#define ATH_BUFSTATUS_STALE 0x00000002 + +struct ath_descdma { + const char *dd_name; + struct ath_desc *dd_desc; + dma_addr_t dd_desc_paddr; + u32 dd_desc_len; + struct ath_buf *dd_bufptr; + dma_addr_t dd_dmacontext; +}; + +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc); +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head); + +/***********/ +/* RX / TX */ +/***********/ + +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 +#define ATH_TXBUF 512 +#define ATH_TXMAXTRY 13 +#define ATH_11N_TXMAXTRY 10 +#define ATH_MGT_TXMAXTRY 4 +#define WME_BA_BMP_SIZE 64 +#define WME_MAX_BA WME_BA_BMP_SIZE +#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + +#define TID_TO_WME_AC(_tid) \ + ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 + +#define ADDBA_EXCHANGE_ATTEMPTS 10 +#define ATH_AGGR_DELIM_SZ 4 +#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ +/* number of delimiters for encryption padding */ +#define ATH_AGGR_ENCRYPTDELIM 10 +/* minimum h/w qdepth to be sustained to maximize aggregation */ +#define ATH_AGGR_MIN_QDEPTH 2 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX + +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 +#define IEEE80211_WEP_IVLEN 3 +#define IEEE80211_WEP_KIDLEN 1 +#define IEEE80211_WEP_CRCLEN 4 +#define IEEE80211_MAX_MPDU_LEN (3840 + FCS_LEN + \ + (IEEE80211_WEP_IVLEN + \ + IEEE80211_WEP_KIDLEN + \ + IEEE80211_WEP_CRCLEN)) + +/* return whether a bit at index _n in bitmap _bm is set + * _sz is the size of the bitmap */ +#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ + ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) + +/* return block-ack bitmap index given sequence and starting sequence */ +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) + +/* returns delimiter padding required given the packet length */ +#define ATH_AGGR_GET_NDELIM(_len) \ + (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ + (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) + +#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) +#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) +#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) +#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) + +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, +}; + +struct ath_txq { + u32 axq_qnum; + u32 *axq_link; + struct list_head axq_q; + spinlock_t axq_lock; + u32 axq_depth; + u8 axq_aggr_depth; + u32 axq_totalqueued; + bool stopped; + struct ath_buf *axq_linkbuf; + + /* first desc of the last descriptor that contains CTS */ + struct ath_desc *axq_lastdsWithCTS; + + /* final desc of the gating desc that determines whether + lastdsWithCTS has been DMA'ed or not */ + struct ath_desc *axq_gatingds; + + struct list_head axq_acq; +}; + +#define AGGR_CLEANUP BIT(1) +#define AGGR_ADDBA_COMPLETE BIT(2) +#define AGGR_ADDBA_PROGRESS BIT(3) + +struct ath_atx_tid { + struct list_head list; + struct list_head buf_q; + struct ath_node *an; + struct ath_atx_ac *ac; + struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; + u16 seq_start; + u16 seq_next; + u16 baw_size; + int tidno; + int baw_head; /* first un-acked tx buffer */ + int baw_tail; /* next unused tx buffer slot */ + int sched; + int paused; + u8 state; + int addba_exchangeattempts; +}; + +struct ath_atx_ac { + int sched; + int qnum; + struct list_head list; + struct list_head tid_q; +}; + +struct ath_tx_control { + struct ath_txq *txq; + int if_id; + enum ath9k_internal_frame_type frame_type; +}; + +#define ATH_TX_ERROR 0x01 +#define ATH_TX_XRETRY 0x02 +#define ATH_TX_BAR 0x04 + +/* All RSSI values are noise floor adjusted */ +struct ath_tx_stat { + int rssi; + int rssictl[ATH_MAX_ANTENNA]; + int rssiextn[ATH_MAX_ANTENNA]; + int rateieee; + int rateKbps; + int ratecode; + int flags; + u32 airtime; /* time on air per final tx rate */ +}; + +struct aggr_rifs_param { + int param_max_frames; + int param_max_len; + int param_rl; + int param_al; + struct ath_rc_series *param_rcs; +}; + +struct ath_node { + struct ath_softc *an_sc; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; +}; + +struct ath_tx { + u16 seq_no; + u32 txqsetup; + int hwq_map[ATH9K_WME_AC_VO+1]; + spinlock_t txbuflock; + struct list_head txbuf; + struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; + struct ath_descdma txdma; +}; + +struct ath_rx { + u8 defant; + u8 rxotherant; + u32 *rxlink; + int bufsize; + unsigned int rxfilter; + spinlock_t rxflushlock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +}; + +int ath_startrecv(struct ath_softc *sc); +bool ath_stoprecv(struct ath_softc *sc); +void ath_flushrecv(struct ath_softc *sc); +u32 ath_calcrxfilter(struct ath_softc *sc); +int ath_rx_init(struct ath_softc *sc, int nbufs); +void ath_rx_cleanup(struct ath_softc *sc); +int ath_rx_tasklet(struct ath_softc *sc, int flush); +struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); +void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); +int ath_tx_setup(struct ath_softc *sc, int haltype); +void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); +void ath_draintxq(struct ath_softc *sc, + struct ath_txq *txq, bool retry_tx); +void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); +void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); +int ath_tx_init(struct ath_softc *sc, int nbufs); +int ath_tx_cleanup(struct ath_softc *sc); +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); +int ath_txq_update(struct ath_softc *sc, int qnum, + struct ath9k_tx_queue_info *q); +int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath_tx_control *txctl); +void ath_tx_tasklet(struct ath_softc *sc); +void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); + +/********/ +/* VIFs */ +/********/ + +struct ath_vif { + int av_bslot; + __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ + enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; + u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ +}; + +/*******************/ +/* Beacon Handling */ +/*******************/ -#define CHANNEL_CW_INT 0x00002 -#define CHANNEL_CCK 0x00020 -#define CHANNEL_OFDM 0x00040 -#define CHANNEL_2GHZ 0x00080 -#define CHANNEL_5GHZ 0x00100 -#define CHANNEL_PASSIVE 0x00200 -#define CHANNEL_DYN 0x00400 -#define CHANNEL_HALF 0x04000 -#define CHANNEL_QUARTER 0x08000 -#define CHANNEL_HT20 0x10000 -#define CHANNEL_HT40PLUS 0x20000 -#define CHANNEL_HT40MINUS 0x40000 - -#define CHANNEL_INTERFERENCE 0x01 -#define CHANNEL_DFS 0x02 -#define CHANNEL_4MS_LIMIT 0x04 -#define CHANNEL_DFS_CLEAR 0x08 -#define CHANNEL_DISALLOW_ADHOC 0x10 -#define CHANNEL_PER_11D_ADHOC 0x20 - -#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) -#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) -#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_ALL \ - (CHANNEL_OFDM| \ - CHANNEL_CCK| \ - CHANNEL_2GHZ | \ - CHANNEL_5GHZ | \ - CHANNEL_HT20 | \ - CHANNEL_HT40PLUS | \ - CHANNEL_HT40MINUS) - -struct ath9k_channel { - u16 channel; - u32 channelFlags; - u8 privFlags; - int8_t maxRegTxPower; - int8_t maxTxPower; - int8_t minTxPower; - u32 chanmode; - int32_t CalValid; - bool oneTimeCalsDone; - int8_t iCoff; - int8_t qCoff; - int16_t rawNoiseFloor; - int8_t antennaMax; - u32 regDmnFlags; - u32 conformanceTestLimit[3]; /* 0:11a, 1: 11b, 2:11g */ -#ifdef ATH_NF_PER_CHAN - struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; -#endif -}; +/* + * Regardless of the number of beacons we stagger, (i.e. regardless of the + * number of BSSIDs) if a given beacon does not go out even after waiting this + * number of beacon intervals, the game's up. + */ +#define BSTUCK_THRESH (9 * ATH_BCBUF) +#define ATH_BCBUF 4 +#define ATH_DEFAULT_BINTVAL 100 /* TU */ +#define ATH_DEFAULT_BMISS_LIMIT 10 +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + +struct ath_beacon_config { + u16 beacon_interval; + u16 listen_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; +}; + +struct ath_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; + u64 bc_tstamp; + struct ieee80211_vif *bslot[ATH_BCBUF]; + struct ath_wiphy *bslot_aphy[ATH_BCBUF]; + int slottime; + int slotupdate; + struct ath9k_tx_queue_info beacon_qi; + struct ath_descdma bdma; + struct ath_txq *cabq; + struct list_head bbuf; +}; + +void ath_beacon_tasklet(unsigned long data); +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); +int ath_beaconq_setup(struct ath_hw *ah); +int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); +void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); + +/*******/ +/* ANI */ +/*******/ -#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ - (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ - (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) -#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ - (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ - (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) -#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) -#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) -#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) -#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) - -/* These macros check chanmode and not channelFlags */ -#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) -#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ - ((_c)->chanmode == CHANNEL_G_HT20)) -#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) - -#define IS_CHAN_IN_PUBLIC_SAFETY_BAND(_c) ((_c) > 4940 && (_c) < 4990) -#define IS_CHAN_A_5MHZ_SPACED(_c) \ - ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ - (((_c)->channel % 20) != 0) && \ - (((_c)->channel % 10) != 0)) - -struct ath9k_keyval { - u8 kv_type; - u8 kv_pad; - u16 kv_len; - u8 kv_val[16]; - u8 kv_mic[8]; - u8 kv_txmic[8]; -}; +#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ +#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ +#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ +#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ +#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ -enum ath9k_key_type { - ATH9K_KEY_TYPE_CLEAR, - ATH9K_KEY_TYPE_WEP, - ATH9K_KEY_TYPE_AES, - ATH9K_KEY_TYPE_TKIP, +struct ath_ani { + bool caldone; + int16_t noise_floor; + unsigned int longcal_timer; + unsigned int shortcal_timer; + unsigned int resetcal_timer; + unsigned int checkani_timer; + struct timer_list timer; }; -enum ath9k_cipher { - ATH9K_CIPHER_WEP = 0, - ATH9K_CIPHER_AES_OCB = 1, - ATH9K_CIPHER_AES_CCM = 2, - ATH9K_CIPHER_CKIP = 3, - ATH9K_CIPHER_TKIP = 4, - ATH9K_CIPHER_CLR = 5, - ATH9K_CIPHER_MIC = 127 -}; +/********************/ +/* LED Control */ +/********************/ -#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001 -#define AR_EEPROM_EEPCAP_AES_DIS 0x0002 -#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004 -#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008 -#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0 -#define AR_EEPROM_EEPCAP_MAXQCU_S 4 -#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200 -#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000 -#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12 - -#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 -#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100 -#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 - -#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000 -#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000 - -#define SD_NO_CTL 0xE0 -#define NO_CTL 0xff -#define CTL_MODE_M 7 -#define CTL_11A 0 -#define CTL_11B 1 -#define CTL_11G 2 -#define CTL_2GHT20 5 -#define CTL_5GHT20 6 -#define CTL_2GHT40 7 -#define CTL_5GHT40 8 - -#define AR_EEPROM_MAC(i) (0x1d+(i)) - -#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c -#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 -#define AR_EEPROM_RFSILENT_POLARITY 0x0002 -#define AR_EEPROM_RFSILENT_POLARITY_S 1 - -#define CTRY_DEBUG 0x1ff -#define CTRY_DEFAULT 0 - -enum reg_ext_bitmap { - REG_EXT_JAPAN_MIDBAND = 1, - REG_EXT_FCC_DFS_HT40 = 2, - REG_EXT_JAPAN_NONDFS_HT40 = 3, - REG_EXT_JAPAN_DFS_HT40 = 4 -}; +#define ATH_LED_PIN 1 +#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ +#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ -struct ath9k_country_entry { - u16 countryCode; - u16 regDmnEnum; - u16 regDmn5G; - u16 regDmn2G; - u8 isMultidomain; - u8 iso[3]; +enum ath_led_type { + ATH_LED_RADIO, + ATH_LED_ASSOC, + ATH_LED_TX, + ATH_LED_RX }; -#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) -#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) - -#define SM(_v, _f) (((_v) << _f##_S) & _f) -#define MS(_v, _f) (((_v) & _f) >> _f##_S) -#define REG_RMW(_a, _r, _set, _clr) \ - REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) -#define REG_RMW_FIELD(_a, _r, _f, _v) \ - REG_WRITE(_a, _r, \ - (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) -#define REG_SET_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) -#define REG_CLR_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) - -#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 - -#define INIT_AIFS 2 -#define INIT_CWMIN 15 -#define INIT_CWMIN_11B 31 -#define INIT_CWMAX 1023 -#define INIT_SH_RETRY 10 -#define INIT_LG_RETRY 10 -#define INIT_SSH_RETRY 32 -#define INIT_SLG_RETRY 32 - -#define WLAN_CTRL_FRAME_SIZE (2+2+6+4) - -#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) -#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX - -#define IEEE80211_WEP_IVLEN 3 -#define IEEE80211_WEP_KIDLEN 1 -#define IEEE80211_WEP_CRCLEN 4 -#define IEEE80211_MAX_MPDU_LEN (3840 + FCS_LEN + \ - (IEEE80211_WEP_IVLEN + \ - IEEE80211_WEP_KIDLEN + \ - IEEE80211_WEP_CRCLEN)) -#define MAX_RATE_POWER 63 - -enum ath9k_power_mode { - ATH9K_PM_AWAKE = 0, - ATH9K_PM_FULL_SLEEP, - ATH9K_PM_NETWORK_SLEEP, - ATH9K_PM_UNDEFINED +struct ath_led { + struct ath_softc *sc; + struct led_classdev led_cdev; + enum ath_led_type led_type; + char name[32]; + bool registered; }; -struct ath9k_mib_stats { - u32 ackrcv_bad; - u32 rts_bad; - u32 rts_good; - u32 fcs_bad; - u32 beacons; -}; +/* Rfkill */ +#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ -enum ath9k_ant_setting { - ATH9K_ANT_VARIABLE = 0, - ATH9K_ANT_FIXED_A, - ATH9K_ANT_FIXED_B +struct ath_rfkill { + struct rfkill *rfkill; + struct delayed_work rfkill_poll; + char rfkill_name[32]; }; -#define ATH9K_SLOT_TIME_6 6 -#define ATH9K_SLOT_TIME_9 9 -#define ATH9K_SLOT_TIME_20 20 +/********************/ +/* Main driver core */ +/********************/ -enum ath9k_ht_macmode { - ATH9K_HT_MACMODE_20 = 0, - ATH9K_HT_MACMODE_2040 = 1, -}; - -enum ath9k_ht_extprotspacing { - ATH9K_HT_EXTPROTSPACING_20 = 0, - ATH9K_HT_EXTPROTSPACING_25 = 1, -}; +/* + * Default cache line size, in bytes. + * Used when PCI device not fully initialized by bootrom/BIOS +*/ +#define DEFAULT_CACHELINE 32 +#define ATH_DEFAULT_NOISE_FLOOR -95 +#define ATH_REGCLASSIDS_MAX 10 +#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ +#define ATH_MAX_SW_RETRIES 10 +#define ATH_CHAN_MAX 255 +#define IEEE80211_WEP_NKID 4 /* number of key ids */ -struct ath9k_ht_cwm { - enum ath9k_ht_macmode ht_macmode; +/* + * The key cache is used for h/w cipher state and also for + * tracking station state such as the current tx antenna. + * We also setup a mapping table between key cache slot indices + * and station state to short-circuit node lookups on rx. + * Different parts have different size key caches. We handle + * up to ATH_KEYMAX entries (could dynamically allocate state). + */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ + +#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RATE_DUMMY_MARKER 0 + +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_CHAINMASK_UPDATE BIT(4) +#define SC_OP_FULL_RESET BIT(5) +#define SC_OP_PREAMBLE_SHORT BIT(6) +#define SC_OP_PROTECT_ENABLE BIT(7) +#define SC_OP_RXFLUSH BIT(8) +#define SC_OP_LED_ASSOCIATED BIT(9) +#define SC_OP_RFKILL_REGISTERED BIT(10) +#define SC_OP_RFKILL_SW_BLOCKED BIT(11) +#define SC_OP_RFKILL_HW_BLOCKED BIT(12) +#define SC_OP_WAIT_FOR_BEACON BIT(13) +#define SC_OP_LED_ON BIT(14) +#define SC_OP_SCANNING BIT(15) +#define SC_OP_TSF_RESET BIT(16) + +struct ath_bus_ops { + void (*read_cachesize)(struct ath_softc *sc, int *csz); + void (*cleanup)(struct ath_softc *sc); + bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data); +}; + +struct ath_wiphy; + +struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; + + spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ + struct ath_wiphy *pri_wiphy; + struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may + * have NULL entries */ + int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ + int chan_idx; + int chan_is_ht; + struct ath_wiphy *next_wiphy; + struct work_struct chan_work; + int wiphy_select_failures; + unsigned long wiphy_select_first_fail; + struct delayed_work wiphy_work; + unsigned long wiphy_scheduler_int; + int wiphy_scheduler_index; + + struct tasklet_struct intr_tq; + struct tasklet_struct bcon_tasklet; + struct ath_hw *sc_ah; + void __iomem *mem; + int irq; + spinlock_t sc_resetlock; + spinlock_t sc_serial_rw; + struct mutex mutex; + + u8 curbssid[ETH_ALEN]; + u8 bssidmask[ETH_ALEN]; + u32 intrstatus; + u32 sc_flags; /* SC_OP_* */ + u16 curtxpow; + u16 curaid; + u16 cachelsz; + u8 nbcnvifs; + u16 nvifs; + u8 tx_chainmask; + u8 rx_chainmask; + u32 keymax; + DECLARE_BITMAP(keymap, ATH_KEYMAX); + u8 splitmic; + atomic_t ps_usecount; + enum ath9k_int imask; enum ath9k_ht_extprotspacing ht_extprotspacing; -}; - -enum ath9k_ani_cmd { - ATH9K_ANI_PRESENT = 0x1, - ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, - ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, - ATH9K_ANI_FIRSTEP_LEVEL = 0x10, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, - ATH9K_ANI_MODE = 0x40, - ATH9K_ANI_PHYERR_RESET = 0x80, - ATH9K_ANI_ALL = 0xff -}; - -enum { - WLAN_RC_PHY_OFDM, - WLAN_RC_PHY_CCK, - WLAN_RC_PHY_HT_20_SS, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_MAX -}; - -enum ath9k_tp_scale { - ATH9K_TP_SCALE_MAX = 0, - ATH9K_TP_SCALE_50, - ATH9K_TP_SCALE_25, - ATH9K_TP_SCALE_12, - ATH9K_TP_SCALE_MIN -}; - -enum ser_reg_mode { - SER_REG_MODE_OFF = 0, - SER_REG_MODE_ON = 1, - SER_REG_MODE_AUTO = 2, -}; - -#define AR_PHY_CCA_MAX_GOOD_VALUE -85 -#define AR_PHY_CCA_MAX_HIGH_VALUE -62 -#define AR_PHY_CCA_MIN_BAD_VALUE -121 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 -#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 - -#define ATH9K_NF_CAL_HIST_MAX 5 -#define NUM_NF_READINGS 6 - -struct ath9k_nfcal_hist { - int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX]; - u8 currIndex; - int16_t privNF; - u8 invalidNFcount; -}; - -struct ath9k_beacon_state { - u32 bs_nexttbtt; - u32 bs_nextdtim; - u32 bs_intval; -#define ATH9K_BEACON_PERIOD 0x0000ffff -#define ATH9K_BEACON_ENA 0x00800000 -#define ATH9K_BEACON_RESET_TSF 0x01000000 - u32 bs_dtimperiod; - u16 bs_cfpperiod; - u16 bs_cfpmaxduration; - u32 bs_cfpnext; - u16 bs_timoffset; - u16 bs_bmissthreshold; - u32 bs_sleepduration; -}; - -struct ath9k_node_stats { - u32 ns_avgbrssi; - u32 ns_avgrssi; - u32 ns_avgtxrssi; - u32 ns_avgtxrate; -}; - -#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) - -#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 - -enum { - ATH9K_RESET_POWER_ON, - ATH9K_RESET_WARM, - ATH9K_RESET_COLD, -}; - -#define AH_USE_EEPROM 0x1 - -struct ath_hal { - u32 ah_magic; - u16 ah_devid; - u16 ah_subvendorid; - u32 ah_macVersion; - u16 ah_macRev; - u16 ah_phyRev; - u16 ah_analog5GhzRev; - u16 ah_analog2GhzRev; - - void __iomem *ah_sh; - struct ath_softc *ah_sc; - - enum nl80211_iftype ah_opmode; - struct ath9k_ops_config ah_config; - struct ath9k_hw_capabilities ah_caps; - - u16 ah_countryCode; - u32 ah_flags; - int16_t ah_powerLimit; - u16 ah_maxPowerLevel; - u32 ah_tpScale; - u16 ah_currentRD; - u16 ah_currentRDExt; - u16 ah_currentRDInUse; - u16 ah_currentRD5G; - u16 ah_currentRD2G; - char ah_iso[4]; - - struct ath9k_channel ah_channels[150]; - struct ath9k_channel *ah_curchan; - u32 ah_nchan; - - bool ah_isPciExpress; - u16 ah_txTrigLevel; - u16 ah_rfsilent; - u32 ah_rfkill_gpio; - u32 ah_rfkill_polarity; - -#ifndef ATH_NF_PER_CHAN - struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + enum ath9k_ht_macmode tx_chan_width; + + struct ath_config config; + struct ath_rx rx; + struct ath_tx tx; + struct ath_beacon beacon; + struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; + struct delayed_work ath_led_blink_work; + int led_on_duration; + int led_off_duration; + int led_on_cnt; + int led_off_cnt; + + struct ath_rfkill rf_kill; + struct ath_ani ani; + struct ath9k_node_stats nodestats; +#ifdef CONFIG_ATH9K_DEBUG + struct ath9k_debug debug; +#endif + struct ath_bus_ops *bus_ops; +}; + +struct ath_wiphy { + struct ath_softc *sc; /* shared for all virtual wiphys */ + struct ieee80211_hw *hw; + enum ath_wiphy_state { + ATH_WIPHY_INACTIVE, + ATH_WIPHY_ACTIVE, + ATH_WIPHY_PAUSING, + ATH_WIPHY_PAUSED, + ATH_WIPHY_SCAN, + } state; + int chan_idx; + int chan_is_ht; +}; + +int ath_reset(struct ath_softc *sc, bool retry_tx); +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); +int ath_cabq_update(struct ath_softc *); + +static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) +{ + sc->bus_ops->read_cachesize(sc, csz); +} + +static inline void ath_bus_cleanup(struct ath_softc *sc) +{ + sc->bus_ops->cleanup(sc); +} + +extern struct ieee80211_ops ath9k_ops; + +irqreturn_t ath_isr(int irq, void *dev); +void ath_cleanup(struct ath_softc *sc); +int ath_attach(u16 devid, struct ath_softc *sc); +void ath_detach(struct ath_softc *sc); +const char *ath_mac_bb_name(u32 mac_bb_version); +const char *ath_rf_name(u16 rf_version); +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *ichan); +void ath_update_chainmask(struct ath_softc *sc, int is_ht); +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *hchan); +void ath_radio_enable(struct ath_softc *sc); +void ath_radio_disable(struct ath_softc *sc); + +#ifdef CONFIG_PCI +int ath_pci_init(void); +void ath_pci_exit(void); +#else +static inline int ath_pci_init(void) { return 0; }; +static inline void ath_pci_exit(void) {}; #endif -}; - -struct chan_centers { - u16 synth_center; - u16 ctl_center; - u16 ext_center; -}; -struct ath_rate_table; - -/* Helpers */ - -enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, - const struct ath9k_channel *chan); -bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val); -u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high); -u16 ath9k_hw_computetxtime(struct ath_hal *ah, - struct ath_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble); -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -void ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers); - -/* Attach, Detach */ - -const char *ath9k_hw_probe(u16 vendorid, u16 devid); -void ath9k_hw_detach(struct ath_hal *ah); -struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, - void __iomem *mem, int *error); -void ath9k_hw_rfdetach(struct ath_hal *ah); - - -/* HW Reset */ - -bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode, - u8 txchainmask, u8 rxchainmask, - enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, int *status); - -/* Key Cache Management */ - -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry); -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac); -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, int xorKey); -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); - -/* Power Management */ - -bool ath9k_hw_setpower(struct ath_hal *ah, - enum ath9k_power_mode mode); -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); - -/* Beacon timers */ - -void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period); -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs); -/* HW Capabilities */ - -bool ath9k_hw_fill_cap_info(struct ath_hal *ah); -bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 *result); -bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 setting, int *status); - -/* GPIO / RFKILL / Antennae */ - -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type); -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hal *ah); +#ifdef CONFIG_ATHEROS_AR71XX +int ath_ahb_init(void); +void ath_ahb_exit(void); +#else +static inline int ath_ahb_init(void) { return 0; }; +static inline void ath_ahb_exit(void) {}; #endif -int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); -u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); -bool ath9k_hw_setantennaswitch(struct ath_hal *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd); - -/* General Operation */ - -u32 ath9k_hw_getrxfilter(struct ath_hal *ah); -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); -bool ath9k_hw_phy_disable(struct ath_hal *ah); -bool ath9k_hw_disable(struct ath_hal *ah); -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); -void ath9k_hw_setopmode(struct ath_hal *ah); -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1); -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); -bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId); -u64 ath9k_hw_gettsf64(struct ath_hal *ah); -void ath9k_hw_reset_tsf(struct ath_hal *ah); -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting); -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); - -/* Regulatory */ - -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); -struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c); -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); -u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan); -bool ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, u32 *nchans, u8 *regclassids, - u32 maxregids, u32 *nregids, u16 cc, - bool enableOutdoor, bool enableExtendedChannels); -/* ANI */ +static inline void ath9k_ps_wakeup(struct ath_softc *sc) +{ + if (atomic_inc_return(&sc->ps_usecount) == 1) + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + } +} + +static inline void ath9k_ps_restore(struct ath_softc *sc) +{ + if (atomic_dec_and_test(&sc->ps_usecount)) + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + ath9k_hw_setpower(sc->sc_ah, + sc->sc_ah->restore_mode); +} + + +void ath9k_set_bssid_mask(struct ieee80211_hw *hw); +int ath9k_wiphy_add(struct ath_softc *sc); +int ath9k_wiphy_del(struct ath_wiphy *aphy); +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); +int ath9k_wiphy_pause(struct ath_wiphy *aphy); +int ath9k_wiphy_unpause(struct ath_wiphy *aphy); +int ath9k_wiphy_select(struct ath_wiphy *aphy); +void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); +void ath9k_wiphy_chan_work(struct work_struct *work); +bool ath9k_wiphy_started(struct ath_softc *sc); +void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, + struct ath_wiphy *selected); +bool ath9k_wiphy_scanning(struct ath_softc *sc); +void ath9k_wiphy_work(struct work_struct *work); -void ath9k_ani_reset(struct ath_hal *ah); -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan); -bool ath9k_hw_phycounters(struct ath_hal *ah); -void ath9k_enable_mib_counters(struct ath_hal *ah); -void ath9k_hw_disable_mib_counters(struct ath_hal *ah); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt); -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats); -void ath9k_hw_ani_setup(struct ath_hal *ah); -void ath9k_hw_ani_attach(struct ath_hal *ah); -void ath9k_hw_ani_detach(struct ath_hal *ah); - -/* Calibration */ - -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone); -void ath9k_hw_start_nfcal(struct ath_hal *ah); -void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan); -int16_t ath9k_hw_getnf(struct ath_hal *ah, - struct ath9k_channel *chan); -void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah); -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone); -bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan); - - -/* EEPROM */ - -int ath9k_hw_set_txpower(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit); -void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan); -bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u8 AntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit); -bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset); -bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, - struct ath9k_channel *chan); -int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 index, u16 *config); -u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, - enum ieee80211_band freq_band); -u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz); -int ath9k_hw_eeprom_attach(struct ath_hal *ah); - -/* Interrupt Handling */ - -bool ath9k_hw_intrpend(struct ath_hal *ah); -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); - -/* MAC (PCU/QCU) */ - -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp); -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q); -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel); -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0); -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); -int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags); -void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags); -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, - u32 burstDuration); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, - u32 vmf); -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, - const struct ath9k_tx_queue_info *qinfo); -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo); -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo); -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); -int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf); -bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 size, u32 flags); -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp); -void ath9k_hw_rxena(struct ath_hal *ah); -void ath9k_hw_startpcureceive(struct ath_hal *ah); -void ath9k_hw_stoppcurecv(struct ath_hal *ah); -bool ath9k_hw_stopdmarecv(struct ath_hal *ah); +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ -#endif +static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) +{ + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) +{ + u32 val; + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + +#endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 3ab0b43aaf93..ec995730632d 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" +#include "ath9k.h" + +#define FUDGE 2 /* * This function will modify certain transmit queue properties depending on @@ -23,11 +25,11 @@ */ static int ath_beaconq_config(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; @@ -44,46 +46,33 @@ static int ath_beaconq_config(struct ath_softc *sc) "unable to update h/w beacon queue parameters\n"); return 0; } else { - ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */ + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); return 1; } } -static void ath_bstuck_process(struct ath_softc *sc) -{ - DPRINTF(sc, ATH_DBG_BEACON, - "stuck beacon; resetting (bmiss count %u)\n", - sc->beacon.bmisscnt); - ath_reset(sc, false); -} - /* * Associates the beacon frame buffer with a transmit descriptor. Will set * up all required antenna switch parameters, rate codes, and channel flags. * Beacons are always sent out at the lowest rate, and are not retried. */ -static void ath_beacon_setup(struct ath_softc *sc, - struct ath_vap *avp, struct ath_buf *bf) +static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, + struct ath_buf *bf) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; struct ath_rate_table *rt; - int flags, antenna; - u8 rix, rate; - int ctsrate = 0; - int ctsduration = 0; - - DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len); + int flags, antenna, ctsrate = 0, ctsduration = 0; + u8 rate; - /* setup descriptors */ ds = bf->bf_desc; - flags = ATH9K_TXDESC_NOACK; - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && - (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { + if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && + (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; /* Let hardware handle antenna switching. */ @@ -92,65 +81,53 @@ static void ath_beacon_setup(struct ath_softc *sc, ds->ds_link = 0; /* * Switch antenna every beacon. - * Should only switch every beacon period, not for every - * SWBA's - * XXX assumes two antenna + * Should only switch every beacon period, not for every SWBA + * XXX assumes two antennae */ - antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); + antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); } ds->ds_data = bf->bf_buf_addr; - /* - * Calculate rate code. - * XXX everything at min xmit rate - */ - rix = 0; rt = sc->cur_rate_table; - rate = rt->info[rix].ratecode; + rate = rt->info[0].ratecode; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[rix].short_preamble; - - ath9k_hw_set11n_txdesc(ah, ds, - skb->len + FCS_LEN, /* frame length */ - ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ - MAX_RATE_POWER, /* FIXME */ - ATH9K_TXKEYIX_INVALID, /* no encryption */ - ATH9K_KEY_TYPE_CLEAR, /* no encryption */ - flags /* no ack, - veol for beacons */ - ); + rate |= rt->info[0].short_preamble; + + ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, + ATH9K_PKT_TYPE_BEACON, + MAX_RATE_POWER, + ATH9K_TXKEYIX_INVALID, + ATH9K_KEY_TYPE_CLEAR, + flags); /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds, - roundup(skb->len, 4), /* buffer length */ - true, /* first segment */ - true, /* last segment */ - ds /* first descriptor */ - ); + ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), + true, true, ds); memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); series[0].Tries = 1; series[0].Rate = rate; - series[0].ChSel = sc->sc_tx_chainmask; + series[0].ChSel = sc->tx_chainmask; series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; - ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, - ctsrate, ctsduration, series, 4, 0); + ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, + series, 4, 0); } -/* Generate beacon frame and queue cab data for a vap */ -static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) +static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ath_buf *bf; - struct ath_vap *avp; + struct ath_vif *avp; struct sk_buff *skb; struct ath_txq *cabq; - struct ieee80211_vif *vif; struct ieee80211_tx_info *info; int cabq_depth; - vif = sc->sc_vaps[if_id]; - ASSERT(vif); + if (aphy->state != ATH_WIPHY_ACTIVE) + return NULL; avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; @@ -161,19 +138,24 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) return NULL; } + /* Release the old beacon first */ + bf = avp->av_bcbuf; skb = (struct sk_buff *)bf->bf_mpdu; if (skb) { - pci_unmap_single(sc->pdev, bf->bf_dmacontext, - skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } - skb = ieee80211_beacon_get(sc->hw, vif); + /* Get a new beacon from mac80211 */ + + skb = ieee80211_beacon_get(hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; + ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = + avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -188,54 +170,42 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) } bf->bf_buf_addr = bf->bf_dmacontext = - pci_map_single(sc->pdev, skb->data, - skb->len, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "pci_dma_mapping_error() on beaconing\n"); + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); return NULL; } - skb = ieee80211_get_buffered_bc(sc->hw, vif); + skb = ieee80211_get_buffered_bc(hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. - * 1) if there is only one vap let the cab traffic continue. - * 2) if there are more than one vap and we are using staggered + * 1) if there is only one vif let the cab traffic continue. + * 2) if there are more than one vif and we are using staggered * beacons, then drain the cabq by dropping all the frames in - * the cabq so that the current vaps cab traffic can be scheduled. + * the cabq so that the current vifs cab traffic can be scheduled. */ spin_lock_bh(&cabq->axq_lock); cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); if (skb && cabq_depth) { - /* - * Unlock the cabq lock as ath_tx_draintxq acquires - * the lock again which is a common function and that - * acquires txq lock inside. - */ - if (sc->sc_nvaps > 1) { - ath_tx_draintxq(sc, cabq, false); + if (sc->nvifs > 1) { DPRINTF(sc, ATH_DBG_BEACON, - "flush previous cabq traffic\n"); + "Flushing previous cabq traffic\n"); + ath_draintxq(sc, cabq, false); } } - /* Construct tx descriptor. */ ath_beacon_setup(sc, avp, bf); - /* - * Enable the CAB queue before the beacon queue to - * insure cab frames are triggered by this beacon. - */ while (skb) { - ath_tx_cabq(sc, skb); - skb = ieee80211_get_buffered_bc(sc->hw, vif); + ath_tx_cabq(hw, skb); + skb = ieee80211_get_buffered_bc(hw, vif); } return bf; @@ -245,28 +215,22 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Startup beacon transmission for adhoc mode when they are sent entirely * by the hardware using the self-linked descriptor + veol trick. */ -static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) +static void ath_beacon_start_adhoc(struct ath_softc *sc, + struct ieee80211_vif *vif) { - struct ieee80211_vif *vif; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf; - struct ath_vap *avp; + struct ath_vif *avp; struct sk_buff *skb; - vif = sc->sc_vaps[if_id]; - ASSERT(vif); - avp = (void *)vif->drv_priv; - if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", - avp, avp != NULL ? avp->av_bcbuf : NULL); + if (avp->av_bcbuf == NULL) return; - } + bf = avp->av_bcbuf; skb = (struct sk_buff *) bf->bf_mpdu; - /* Construct tx descriptor. */ ath_beacon_setup(sc, avp, bf); /* NB: caller is known to have already stopped tx dma */ @@ -276,7 +240,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } -int ath_beaconq_setup(struct ath_hal *ah) +int ath_beaconq_setup(struct ath_hw *ah) { struct ath9k_tx_queue_info qi; @@ -288,18 +252,14 @@ int ath_beaconq_setup(struct ath_hal *ah) return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } -int ath_beacon_alloc(struct ath_softc *sc, int if_id) +int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) { - struct ieee80211_vif *vif; - struct ath_vap *avp; - struct ieee80211_hdr *hdr; + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp; struct ath_buf *bf; struct sk_buff *skb; __le64 tstamp; - vif = sc->sc_vaps[if_id]; - ASSERT(vif); - avp = (void *)vif->drv_priv; /* Allocate a beacon descriptor if we haven't done so. */ @@ -310,51 +270,46 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || - !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || + !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* - * Assign the vap to a beacon xmit slot. As + * Assign the vif to a beacon xmit slot. As * above, this cannot fail to find one. */ avp->av_bslot = 0; for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) { + if (sc->beacon.bslot[slot] == NULL) { /* * XXX hack, space out slots to better * deal with misses */ if (slot+1 < ATH_BCBUF && - sc->beacon.bslot[slot+1] == - ATH_IF_ID_ANY) { + sc->beacon.bslot[slot+1] == NULL) { avp->av_bslot = slot+1; break; } avp->av_bslot = slot; /* NB: keep looking for a double slot */ } - BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY); - sc->beacon.bslot[avp->av_bslot] = if_id; - sc->sc_nbcnvaps++; + BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); + sc->beacon.bslot[avp->av_bslot] = vif; + sc->beacon.bslot_aphy[avp->av_bslot] = aphy; + sc->nbcnvifs++; } } - /* release the previous beacon frame , if it already exists. */ + /* release the previous beacon frame, if it already exists. */ bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { skb = (struct sk_buff *)bf->bf_mpdu; - pci_unmap_single(sc->pdev, bf->bf_dmacontext, - skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } - /* - * NB: the beacon data buffer must be 32-bit aligned. - * FIXME: Fill avp->av_btxctl.txpower and - * avp->av_btxctl.shortPreamble - */ + /* NB: the beacon data buffer must be 32-bit aligned. */ skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); @@ -363,75 +318,65 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; sc->beacon.bc_tstamp = le64_to_cpu(tstamp); - - /* - * Calculate a TSF adjustment factor required for - * staggered beacons. Note that we assume the format - * of the beacon frame leaves the tstamp field immediately - * following the header. - */ + /* Calculate a TSF adjustment factor required for staggered beacons. */ if (avp->av_bslot > 0) { u64 tsfadjust; - __le64 val; int intval; intval = sc->hw->conf.beacon_int ? sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; /* - * The beacon interval is in TU's; the TSF in usecs. - * We figure out how many TU's to add to align the - * timestamp then convert to TSF units and handle - * byte swapping before writing it in the frame. - * The hardware will then add this each time a beacon - * frame is sent. Note that we align vap's 1..N - * and leave vap 0 untouched. This means vap 0 - * has a timestamp in one beacon interval while the - * others get a timestamp aligned to the next interval. + * Calculate the TSF offset for this beacon slot, i.e., the + * number of usecs that need to be added to the timestamp field + * in Beacon and Probe Response frames. Beacon slot 0 is + * processed at the correct offset, so it does not require TSF + * adjustment. Other slots are adjusted to get the timestamp + * close to the TBTT for the BSS. */ - tsfadjust = (intval * (ATH_BCBUF - avp->av_bslot)) / ATH_BCBUF; - val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */ + tsfadjust = intval * avp->av_bslot / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); DPRINTF(sc, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); - hdr = (struct ieee80211_hdr *)skb->data; - memcpy(&hdr[1], &val, sizeof(val)); - } + ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = + avp->tsf_adjust; + } else + avp->tsf_adjust = cpu_to_le64(0); bf->bf_mpdu = skb; bf->bf_buf_addr = bf->bf_dmacontext = - pci_map_single(sc->pdev, skb->data, - skb->len, - PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "pci_dma_mapping_error() on beacon alloc\n"); + DPRINTF(sc, ATH_DBG_FATAL, + "dma_mapping_error on beacon alloc\n"); return -ENOMEM; } return 0; } -void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) +void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) { if (avp->av_bcbuf != NULL) { struct ath_buf *bf; if (avp->av_bslot != -1) { - sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY; - sc->sc_nbcnvaps--; + sc->beacon.bslot[avp->av_bslot] = NULL; + sc->beacon.bslot_aphy[avp->av_bslot] = NULL; + sc->nbcnvifs--; } bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - pci_unmap_single(sc->pdev, bf->bf_dmacontext, - skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(sc->dev, bf->bf_dmacontext, + skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -441,92 +386,45 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) } } -void ath9k_beacon_tasklet(unsigned long data) +void ath_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf = NULL; - int slot, if_id; - u32 bfaddr; - u32 rx_clear = 0, rx_frame = 0, tx_frame = 0; - u32 show_cycles = 0; - u32 bc = 0; /* beacon count */ + struct ieee80211_vif *vif; + struct ath_wiphy *aphy; + int slot; + u32 bfaddr, bc = 0, tsftu; u64 tsf; - u32 tsftu; u16 intval; - if (sc->sc_flags & SC_OP_NO_RESET) { - show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, - &rx_clear, &rx_frame, &tx_frame); - } - /* * Check if the previous beacon has gone out. If * not don't try to post another, skip this period * and wait for the next. Missed beacons indicate * a problem and should not occur. If we miss too * many consecutive beacons reset the device. - * - * FIXME: Clean up this mess !! */ if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; - /* XXX: doth needs the chanchange IE countdown decremented. - * We should consider adding a mac80211 call to indicate - * a beacon miss so appropriate action could be taken - * (in that layer). - */ + if (sc->beacon.bmisscnt < BSTUCK_THRESH) { - if (sc->sc_flags & SC_OP_NO_RESET) { - DPRINTF(sc, ATH_DBG_BEACON, - "missed %u consecutive beacons\n", - sc->beacon.bmisscnt); - if (show_cycles) { - /* - * Display cycle counter stats from HW - * to aide in debug of stickiness. - */ - DPRINTF(sc, ATH_DBG_BEACON, - "busy times: rx_clear=%d, " - "rx_frame=%d, tx_frame=%d\n", - rx_clear, rx_frame, - tx_frame); - } else { - DPRINTF(sc, ATH_DBG_BEACON, - "unable to obtain " - "busy times\n"); - } - } else { - DPRINTF(sc, ATH_DBG_BEACON, - "missed %u consecutive beacons\n", - sc->beacon.bmisscnt); - } + DPRINTF(sc, ATH_DBG_BEACON, + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { - if (sc->sc_flags & SC_OP_NO_RESET) { - if (sc->beacon.bmisscnt == BSTUCK_THRESH) { - DPRINTF(sc, ATH_DBG_BEACON, - "beacon is officially " - "stuck\n"); - } - } else { - DPRINTF(sc, ATH_DBG_BEACON, - "beacon is officially stuck\n"); - ath_bstuck_process(sc); - } + DPRINTF(sc, ATH_DBG_BEACON, + "beacon is officially stuck\n"); + ath_reset(sc, false); } + return; } if (sc->beacon.bmisscnt != 0) { - if (sc->sc_flags & SC_OP_NO_RESET) { - DPRINTF(sc, ATH_DBG_BEACON, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - } else { - DPRINTF(sc, ATH_DBG_BEACON, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - } + DPRINTF(sc, ATH_DBG_BEACON, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); sc->beacon.bmisscnt = 0; } @@ -542,21 +440,30 @@ void ath9k_beacon_tasklet(unsigned long data) tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; - if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; + /* + * Reverse the slot order to get slot 0 on the TBTT offset that does + * not require TSF adjustment and other slots adding + * slot/ATH_BCBUF * beacon_int to timestamp. For example, with + * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. + * and slot 0 is at correct offset to TBTT. + */ + slot = ATH_BCBUF - slot - 1; + vif = sc->beacon.bslot[slot]; + aphy = sc->beacon.bslot_aphy[slot]; DPRINTF(sc, ATH_DBG_BEACON, - "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - slot, (unsigned long long)tsf, tsftu, - intval, if_id); + "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", + slot, tsf, tsftu, intval, vif); bfaddr = 0; - if (if_id != ATH_IF_ID_ANY) { - bf = ath_beacon_generate(sc, if_id); + if (vif) { + bf = ath_beacon_generate(aphy->hw, vif); if (bf != NULL) { bfaddr = bf->bf_daddr; bc = 1; } } + /* * Handle slot time change when a non-ERP station joins/leaves * an 11g network. The 802.11 layer notifies us via callback, @@ -573,7 +480,6 @@ void ath9k_beacon_tasklet(unsigned long data) * interval has passed. When bursting slot is always left * set to ATH_BCBUF so this check is a noop. */ - /* XXX locking */ if (sc->beacon.updateslot == UPDATE) { sc->beacon.updateslot = COMMIT; /* commit next beacon */ sc->beacon.slotupdate = slot; @@ -590,265 +496,251 @@ void ath9k_beacon_tasklet(unsigned long data) if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { DPRINTF(sc, ATH_DBG_FATAL, "beacon queue %u did not stop?\n", sc->beacon.beaconq); - /* NB: the HAL still stops DMA, so proceed */ } /* NB: cabq traffic should already be queued and primed */ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); ath9k_hw_txstart(ah, sc->beacon.beaconq); - sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */ + sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ } } /* - * Configure the beacon and sleep timers. - * - * When operating as an AP this resets the TSF and sets - * up the hardware to notify us when we need to issue beacons. - * - * When operating in station mode this sets up the beacon - * timers according to the timestamp of the last received - * beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware - * will wakeup in time to receive beacons, and configures - * the beacon miss handling so we'll receive a BMISS - * interrupt when we stop seeing beacons from the AP - * we've associated with. + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together. For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. */ -void ath_beacon_config(struct ath_softc *sc, int if_id) +static void ath_beacon_config_ap(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp) { - struct ieee80211_vif *vif; - struct ath_hal *ah = sc->sc_ah; - struct ath_beacon_config conf; - struct ath_vap *avp; - enum nl80211_iftype opmode; u32 nexttbtt, intval; - if (if_id != ATH_IF_ID_ANY) { - vif = sc->sc_vaps[if_id]; - ASSERT(vif); - avp = (void *)vif->drv_priv; - opmode = avp->av_opmode; - } else { - opmode = sc->sc_ah->ah_opmode; - } + /* Configure the timers only when the TSF has to be reset */ - memset(&conf, 0, sizeof(struct ath_beacon_config)); + if (!(sc->sc_flags & SC_OP_TSF_RESET)) + return; - conf.beacon_interval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; - conf.listen_interval = 1; - conf.dtim_period = conf.beacon_interval; - conf.dtim_count = 1; - conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; + /* NB: the beacon interval is kept internally in TU's */ + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval /= ATH_BCBUF; /* for staggered beacons */ + nexttbtt = intval; + intval |= ATH9K_BEACON_RESET_TSF; - /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); + /* + * In AP mode we enable the beacon timers and SWBA interrupts to + * prepare beacon frames. + */ + intval |= ATH9K_BEACON_ENA; + sc->imask |= ATH9K_INT_SWBA; + ath_beaconq_config(sc); - /* XXX conditionalize multi-bss support? */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { - /* - * For multi-bss ap support beacons are either staggered - * evenly over N slots or burst together. For the former - * arrange for the SWBA to be delivered for each slot. - * Slots that are not occupied will generate nothing. - */ - /* NB: the beacon interval is kept internally in TU's */ - intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; - intval /= ATH_BCBUF; /* for staggered beacons */ - } else { - intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; - } + /* Set the computed AP beacon timers */ - if (nexttbtt == 0) /* e.g. for ap mode */ - nexttbtt = intval; - else if (intval) /* NB: can be 0 for monitor mode */ - nexttbtt = roundup(nexttbtt, intval); + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", - nexttbtt, intval, conf.beacon_interval); + /* Clear the reset TSF flag, so that subsequent beacon updation + will not reset the HW TSF. */ - /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) { - struct ath9k_beacon_state bs; - u64 tsf; - u32 tsftu; - int dtimperiod, dtimcount, sleepduration; - int cfpperiod, cfpcount; + sc->sc_flags &= ~SC_OP_TSF_RESET; +} - /* - * Setup dtim and cfp parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = conf.dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = conf.dtim_count; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - cfpperiod = 1; /* NB: no PCF support yet */ - cfpcount = 0; - - sleepduration = conf.listen_interval * intval; - if (sleepduration <= 0) - sleepduration = intval; +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +static void ath_beacon_config_sta(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp) +{ + struct ath9k_beacon_state bs; + int dtimperiod, dtimcount, sleepduration; + int cfpperiod, cfpcount; + u32 nexttbtt = 0, intval, tsftu; + u64 tsf; -#define FUDGE 2 - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim+cfp state for the result. - */ - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { - nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; - } - } while (nexttbtt < tsftu); -#undef FUDGE - memset(&bs, 0, sizeof(bs)); - bs.bs_intval = intval; - bs.bs_nexttbtt = nexttbtt; - bs.bs_dtimperiod = dtimperiod*intval; - bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; - bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; - bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; - bs.bs_cfpmaxduration = 0; + memset(&bs, 0, sizeof(bs)); + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - /* - * Calculate the number of consecutive beacons to miss - * before taking a BMISS interrupt. The configuration - * is specified in TU so we only need calculate based - * on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf.listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = - DIV_ROUND_UP(conf.bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } + /* + * Setup dtim and cfp parameters according to + * last beacon we received (which may be none). + */ + dtimperiod = conf->dtim_period; + if (dtimperiod <= 0) /* NB: 0 if not known */ + dtimperiod = 1; + dtimcount = conf->dtim_count; + if (dtimcount >= dtimperiod) /* NB: sanity check */ + dtimcount = 0; + cfpperiod = 1; /* NB: no PCF support yet */ + cfpcount = 0; + + sleepduration = conf->listen_interval * intval; + if (sleepduration <= 0) + sleepduration = intval; - /* - * Calculate sleep duration. The configuration is - * given in ms. We insure a multiple of the beacon - * period is used. Also, if the sleep duration is - * greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim+cfp state for the result. + */ + tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; + do { + nexttbtt += intval; + if (--dtimcount < 0) { + dtimcount = dtimperiod - 1; + if (--cfpcount < 0) + cfpcount = cfpperiod - 1; + } + } while (nexttbtt < tsftu); - bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), - sleepduration); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; + bs.bs_intval = intval; + bs.bs_nexttbtt = nexttbtt; + bs.bs_dtimperiod = dtimperiod*intval; + bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; + bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; + bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; + bs.bs_cfpmaxduration = 0; - DPRINTF(sc, ATH_DBG_BEACON, - "tsf %llu " - "tsf:tu %u " - "intval %u " - "nexttbtt %u " - "dtim %u " - "nextdtim %u " - "bmiss %u " - "sleep %u " - "cfp:period %u " - "maxdur %u " - "next %u " - "timoffset %u\n", - (unsigned long long)tsf, tsftu, - bs.bs_intval, - bs.bs_nexttbtt, - bs.bs_dtimperiod, - bs.bs_nextdtim, - bs.bs_bmissthreshold, - bs.bs_sleepduration, - bs.bs_cfpperiod, - bs.bs_cfpmaxduration, - bs.bs_cfpnext, - bs.bs_timoffset - ); - - ath9k_hw_set_interrupts(ah, 0); - ath9k_hw_set_sta_beacon_timers(ah, &bs); - sc->sc_imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(ah, sc->sc_imask); + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + if (sleepduration > intval) { + bs.bs_bmissthreshold = conf->listen_interval * + ATH_DEFAULT_BMISS_LIMIT / 2; } else { - u64 tsf; - u32 tsftu; - ath9k_hw_set_interrupts(ah, 0); - if (nexttbtt == intval) - intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { - /* - * Pull nexttbtt forward to reflect the current - * TSF - */ -#define FUDGE 2 - if (!(intval & ATH9K_BEACON_RESET_TSF)) { - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU((u32)(tsf>>32), - (u32)tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - } -#undef FUDGE - DPRINTF(sc, ATH_DBG_BEACON, - "IBSS nexttbtt %u intval %u (%u)\n", - nexttbtt, - intval & ~ATH9K_BEACON_RESET_TSF, - conf.beacon_interval); - - /* - * In IBSS mode enable the beacon timers but only - * enable SWBA interrupts if we need to manually - * prepare beacon frames. Otherwise we use a - * self-linked tx descriptor and let the hardware - * deal with things. - */ - intval |= ATH9K_BEACON_ENA; - if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) - sc->sc_imask |= ATH9K_INT_SWBA; - ath_beaconq_config(sc); - } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { - /* - * In AP mode we enable the beacon timers and - * SWBA interrupts to prepare beacon frames. - */ - intval |= ATH9K_BEACON_ENA; - sc->sc_imask |= ATH9K_INT_SWBA; /* beacon prepare */ - ath_beaconq_config(sc); - } - ath9k_hw_beaconinit(ah, nexttbtt, intval); - sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, sc->sc_imask); - /* - * When using a self-linked beacon descriptor in - * ibss mode load it once here. - */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && - (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) - ath_beacon_start_adhoc(sc, 0); + bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); + if (bs.bs_bmissthreshold > 15) + bs.bs_bmissthreshold = 15; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; } + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); + if (bs.bs_sleepduration > bs.bs_dtimperiod) + bs.bs_sleepduration = bs.bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + DPRINTF(sc, ATH_DBG_BEACON, + "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", + bs.bs_bmissthreshold, bs.bs_sleepduration, + bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); + + /* Set the computed STA beacon timers */ + + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); + sc->imask |= ATH9K_INT_BMISS; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); } -void ath_beacon_sync(struct ath_softc *sc, int if_id) +static void ath_beacon_config_adhoc(struct ath_softc *sc, + struct ath_beacon_config *conf, + struct ath_vif *avp, + struct ieee80211_vif *vif) { + u64 tsf; + u32 tsftu, intval, nexttbtt; + + intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + + /* Pull nexttbtt forward to reflect the current TSF */ + + nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); + if (nexttbtt == 0) + nexttbtt = intval; + else if (intval) + nexttbtt = roundup(nexttbtt, intval); + + tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; + do { + nexttbtt += intval; + } while (nexttbtt < tsftu); + + DPRINTF(sc, ATH_DBG_BEACON, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf->beacon_interval); + /* - * Resync beacon timers using the tsf of the - * beacon frame we just received. + * In IBSS mode enable the beacon timers but only enable SWBA interrupts + * if we need to manually prepare beacon frames. Otherwise we use a + * self-linked tx descriptor and let the hardware deal with things. */ - ath_beacon_config(sc, if_id); - sc->sc_flags |= SC_OP_BEACONS; + intval |= ATH9K_BEACON_ENA; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) + sc->imask |= ATH9K_INT_SWBA; + + ath_beaconq_config(sc); + + /* Set the computed ADHOC beacon timers */ + + ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + ath_beacon_start_adhoc(sc, vif); +} + +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_beacon_config conf; + + /* Setup the beacon configuration parameters */ + + memset(&conf, 0, sizeof(struct ath_beacon_config)); + conf.beacon_interval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + conf.listen_interval = 1; + conf.dtim_period = conf.beacon_interval; + conf.dtim_count = 1; + conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; + + if (vif) { + struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; + + switch(avp->av_opmode) { + case NL80211_IFTYPE_AP: + ath_beacon_config_ap(sc, &conf, avp); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + ath_beacon_config_adhoc(sc, &conf, avp, vif); + break; + case NL80211_IFTYPE_STATION: + ath_beacon_config_sta(sc, &conf, avp); + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); + return; + } + + sc->sc_flags |= SC_OP_BEACONS; + } } diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index 3c7454fc51bd..e2d62e97131c 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,12 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" - -static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; +#include "ath9k.h" /* We can tune this as we go by monitoring really low values */ #define ATH9K_NF_TOO_LOW -60 @@ -28,7 +23,7 @@ static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; * is incorrect and we should use the static NF value. Later we can try to * find out why they are reporting these values */ -static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf) { if (nf > ATH9K_NF_TOO_LOW) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, @@ -91,7 +86,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, return; } -static void ath9k_hw_do_getnf(struct ath_hal *ah, +static void ath9k_hw_do_getnf(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]) { int16_t nf; @@ -107,27 +102,29 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, "NF calibrated [ctl] [chain 0] is %d\n", nf); nfarray[0] = nf; - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; + if (!AR_SREV_9285(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR_PHY_CH1_MINCCA_PWR); - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), + AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + } } if (AR_SREV_9280_10_OR_LATER(ah)) @@ -143,58 +140,52 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, "NF calibrated [ext] [chain 0] is %d\n", nf); nfarray[3] = nf; - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; + if (!AR_SREV_9285(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR_PHY_CH1_EXT_MINCCA_PWR); - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), + AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + } } } -static bool getNoiseFloorThresh(struct ath_hal *ah, - const struct ath9k_channel *chan, +static bool getNoiseFloorThresh(struct ath_hw *ah, + enum ieee80211_band band, int16_t *nft) { - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); + switch (band) { + case IEEE80211_BAND_5GHZ: + *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); break; - case CHANNEL_B: - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + case IEEE80211_BAND_2GHZ: + *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); break; default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "invalid channel flags 0x%x\n", chan->channelFlags); + BUG_ON(1); return false; } return true; } -static void ath9k_hw_setup_calibration(struct ath_hal *ah, +static void ath9k_hw_setup_calibration(struct ath_hw *ah, struct hal_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), @@ -228,10 +219,9 @@ static void ath9k_hw_setup_calibration(struct ath_hal *ah, AR_PHY_TIMING_CTRL4_DO_CAL); } -static void ath9k_hw_reset_calibration(struct ath_hal *ah, +static void ath9k_hw_reset_calibration(struct ath_hw *ah, struct hal_cal_list *currCal) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; ath9k_hw_setup_calibration(ah, currCal); @@ -239,23 +229,21 @@ static void ath9k_hw_reset_calibration(struct ath_hal *ah, currCal->calState = CAL_RUNNING; for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_Meas0.sign[i] = 0; - ahp->ah_Meas1.sign[i] = 0; - ahp->ah_Meas2.sign[i] = 0; - ahp->ah_Meas3.sign[i] = 0; + ah->meas0.sign[i] = 0; + ah->meas1.sign[i] = 0; + ah->meas2.sign[i] = 0; + ah->meas3.sign[i] = 0; } - ahp->ah_CalSamples = 0; + ah->cal_samples = 0; } -static void ath9k_hw_per_calibration(struct ath_hal *ah, +static void ath9k_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan, u8 rxchainmask, struct hal_cal_list *currCal, bool *isCalDone) { - struct ath_hal_5416 *ahp = AH5416(ah); - *isCalDone = false; if (currCal->calState == CAL_RUNNING) { @@ -263,9 +251,9 @@ static void ath9k_hw_per_calibration(struct ath_hal *ah, AR_PHY_TIMING_CTRL4_DO_CAL)) { currCal->calData->calCollect(ah); - ahp->ah_CalSamples++; + ah->cal_samples++; - if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { + if (ah->cal_samples >= currCal->calData->calNumSamples) { int i, numChains = 0; for (i = 0; i < AR5416_MAX_CHAINS; i++) { if (rxchainmask & (1 << i)) @@ -285,113 +273,105 @@ static void ath9k_hw_per_calibration(struct ath_hal *ah, } } -static bool ath9k_hw_iscal_supported(struct ath_hal *ah, - struct ath9k_channel *chan, +/* Assumes you are talking about the currently configured channel */ +static bool ath9k_hw_iscal_supported(struct ath_hw *ah, enum hal_cal_types calType) { - struct ath_hal_5416 *ahp = AH5416(ah); - bool retval = false; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - switch (calType & ahp->ah_suppCals) { - case IQ_MISMATCH_CAL: - if (!IS_CHAN_B(chan)) - retval = true; - break; + switch (calType & ah->supp_cals) { + case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ + return true; case ADC_GAIN_CAL: case ADC_DC_CAL: - if (!IS_CHAN_B(chan) - && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) - retval = true; + if (conf->channel->band == IEEE80211_BAND_5GHZ && + conf_is_ht20(conf)) + return true; break; } - - return retval; + return false; } -static void ath9k_hw_iqcal_collect(struct ath_hal *ah) +static void ath9k_hw_iqcal_collect(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalPowerMeasI[i] += + ah->totalPowerMeasI[i] += REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalPowerMeasQ[i] += + ah->totalPowerMeasQ[i] += REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalIqCorrMeas[i] += + ah->totalIqCorrMeas[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], - ahp->ah_totalPowerMeasQ[i], - ahp->ah_totalIqCorrMeas[i]); + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); } } -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) +static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcIOddPhase[i] += + ah->totalAdcIOddPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcIEvenPhase[i] += + ah->totalAdcIEvenPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcQOddPhase[i] += + ah->totalAdcQOddPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcQEvenPhase[i] += + ah->totalAdcQEvenPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcIOddPhase[i], - ahp->ah_totalAdcIEvenPhase[i], - ahp->ah_totalAdcQOddPhase[i], - ahp->ah_totalAdcQEvenPhase[i]); + ah->cal_samples, i, + ah->totalAdcIOddPhase[i], + ah->totalAdcIEvenPhase[i], + ah->totalAdcQOddPhase[i], + ah->totalAdcQEvenPhase[i]); } } -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) +static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int i; for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcDcOffsetIOddPhase[i] += + ah->totalAdcDcOffsetIOddPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcDcOffsetIEvenPhase[i] += + ah->totalAdcDcOffsetIEvenPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcDcOffsetQOddPhase[i] += + ah->totalAdcDcOffsetQOddPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcDcOffsetQEvenPhase[i] += + ah->totalAdcDcOffsetQEvenPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcDcOffsetIOddPhase[i], - ahp->ah_totalAdcDcOffsetIEvenPhase[i], - ahp->ah_totalAdcDcOffsetQOddPhase[i], - ahp->ah_totalAdcDcOffsetQEvenPhase[i]); + ah->cal_samples, i, + ah->totalAdcDcOffsetIOddPhase[i], + ah->totalAdcDcOffsetIEvenPhase[i], + ah->totalAdcDcOffsetQOddPhase[i], + ah->totalAdcDcOffsetQEvenPhase[i]); } } -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) +static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 powerMeasQ, powerMeasI, iqCorrMeas; u32 qCoffDenom, iCoffDenom; int32_t qCoff, iCoff; int iqCorrNeg, i; for (i = 0; i < numChains; i++) { - powerMeasI = ahp->ah_totalPowerMeasI[i]; - powerMeasQ = ahp->ah_totalPowerMeasQ[i]; - iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; + powerMeasI = ah->totalPowerMeasI[i]; + powerMeasQ = ah->totalPowerMeasQ[i]; + iqCorrMeas = ah->totalIqCorrMeas[i]; DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Starting IQ Cal and Correction for Chain %d\n", @@ -399,7 +379,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ahp->ah_totalIqCorrMeas[i]); + i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; @@ -457,17 +437,16 @@ static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); } -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) +static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; u32 qGainMismatch, iGainMismatch, val, i; for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; + iOddMeasOffset = ah->totalAdcIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Starting ADC Gain Cal for Chain %d\n", i); @@ -515,21 +494,20 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); } -static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) +static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 iOddMeasOffset, iEvenMeasOffset, val, i; int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; const struct hal_percal_data *calData = - ahp->ah_cal_list_curr->calData; + ah->cal_list_curr->calData; u32 numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples; for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; + iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Starting ADC DC Offset Cal for Chain %d\n", i); @@ -573,53 +551,42 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); } -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone) +/* This is done for the currently configured channel */ +bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct hal_cal_list *currCal = ah->cal_list_curr; - *isCalDone = true; + if (!ah->curchan) + return true; if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) - return; + return true; if (currCal == NULL) - return; - - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "invalid channel %u/0x%x; no mapping\n", - chan->channel, chan->channelFlags); - return; - } - + return true; if (currCal->calState != CAL_DONE) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Calibration state incorrect, %d\n", currCal->calState); - return; + return true; } - - if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) - return; + if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) + return true; DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Resetting Cal %d state for channel %u/0x%x\n", - currCal->calData->calType, chan->channel, - chan->channelFlags); + "Resetting Cal %d state for channel %u\n", + currCal->calData->calType, conf->channel->center_freq); - ichan->CalValid &= ~currCal->calData->calType; + ah->curchan->CalValid &= ~currCal->calData->calType; currCal->calState = CAL_WAITING; - *isCalDone = false; + return false; } -void ath9k_hw_start_nfcal(struct ath_hal *ah) +void ath9k_hw_start_nfcal(struct ath_hw *ah) { REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); @@ -628,7 +595,7 @@ void ath9k_hw_start_nfcal(struct ath_hal *ah) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); } -void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) +void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h; int i, j; @@ -643,16 +610,14 @@ void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) }; u8 chainmask; - if (AR_SREV_9280(ah)) + if (AR_SREV_9285(ah)) + chainmask = 0x9; + else if (AR_SREV_9280(ah)) chainmask = 0x1B; else chainmask = 0x3F; -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else h = ah->nfCalHist; -#endif for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { @@ -686,18 +651,13 @@ void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) } } -int16_t ath9k_hw_getnf(struct ath_hal *ah, +int16_t ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) { int16_t nf, nfThresh; int16_t nfarray[NUM_NF_READINGS] = { 0 }; struct ath9k_nfcal_hist *h; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; + struct ieee80211_channel *c = chan->chan; chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { @@ -709,7 +669,7 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah, } else { ath9k_hw_do_getnf(ah, nfarray); nf = nfarray[0]; - if (getNoiseFloorThresh(ah, chan, &nfThresh) + if (getNoiseFloorThresh(ah, c->band, &nfThresh) && nf > nfThresh) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "noise floor failed detected; " @@ -719,11 +679,7 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah, } } -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else h = ah->nfCalHist; -#endif ath9k_hw_update_nfcal_hist_buffer(h, nfarray); chan->rawNoiseFloor = h[0].privNF; @@ -731,7 +687,7 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah, return chan->rawNoiseFloor; } -void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) +void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) { int i, j; @@ -745,26 +701,16 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) AR_PHY_CCA_MAX_GOOD_VALUE; } } - return; } -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath9k_channel *ichan; s16 nf; - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "invalid channel %u/0x%x; no mapping\n", - chan->channel, chan->channelFlags); - return ATH_DEFAULT_NOISE_FLOOR; - } - if (ichan->rawNoiseFloor == 0) { - enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - nf = NOISE_FLOOR[mode]; - } else - nf = ichan->rawNoiseFloor; + if (chan->rawNoiseFloor == 0) + nf = -96; + else + nf = chan->rawNoiseFloor; if (!ath9k_hw_nf_in_range(ah, nf)) nf = ATH_DEFAULT_NOISE_FLOOR; @@ -772,53 +718,34 @@ s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) return nf; } -bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) +static void ath9k_olc_temp_compensation(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + u32 rddata, i; + int delta, currPDADC, regval; - *isCalDone = true; + rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "invalid channel %u/0x%x; no mapping\n", - chan->channel, chan->channelFlags); - return false; - } + currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { - ahp->ah_cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - *isCalDone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; - if (longcal) { - ath9k_hw_getnf(ah, ichan); - ath9k_hw_loadnf(ah, ah->ah_curchan); - ath9k_hw_start_nfcal(ah); + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; - if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { - chan->channelFlags |= CHANNEL_CW_INT; - ichan->channelFlags &= ~CHANNEL_CW_INT; + REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); } } - - return true; } -static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) +static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) { u32 regVal; @@ -913,59 +840,171 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) } -bool ath9k_hw_init_cal(struct ath_hal *ah, +bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone) +{ + struct hal_cal_list *currCal = ah->cal_list_curr; + + *isCalDone = true; + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal, + isCalDone); + if (*isCalDone) { + ah->cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + *isCalDone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + if (longcal) { + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + + if (OLC_FOR_AR9280_20_LATER) + ath9k_olc_temp_compensation(ah); + ath9k_hw_getnf(ah, chan); + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah); + + if (chan->channelFlags & CHANNEL_CW_INT) + chan->channelFlags &= ~CHANNEL_CW_INT; + } + + return true; +} + +static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) +{ + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + if (chan->channelFlags & CHANNEL_HT20) { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset " + "calibration failed to complete in " + "1ms; noisy ??\n"); + return false; + } + REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration " + "failed to complete in 1ms; noisy ??\n"); + return false; + } + + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + + return true; +} + +bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { + if (!ar9285_clc(ah, chan)) + return false; + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + + /* Kick off the cal */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, 0, + AH_WAIT_TIMEOUT)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + return false; + } + + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; " "noisy environment?\n"); return false; } + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } + + /* Do PA Calibration */ if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); + /* Do NF Calibration */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { - INIT_CAL(&ahp->ah_adcGainCalData); - INSERT_CAL(ahp, &ahp->ah_adcGainCalData); + if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { + INIT_CAL(&ah->adcgain_caldata); + INSERT_CAL(ah, &ah->adcgain_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); } - if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { - INIT_CAL(&ahp->ah_adcDcCalData); - INSERT_CAL(ahp, &ahp->ah_adcDcCalData); + if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { + INIT_CAL(&ah->adcdc_caldata); + INSERT_CAL(ah, &ah->adcdc_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } - if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { - INIT_CAL(&ahp->ah_iqCalData); - INSERT_CAL(ahp, &ahp->ah_iqCalData); + if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + "enabling IQ Calibration.\n"); } - ahp->ah_cal_list_curr = ahp->ah_cal_list; + ah->cal_list_curr = ah->cal_list; - if (ahp->ah_cal_list_curr) - ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); } - ichan->CalValid = 0; + chan->CalValid = 0; return true; } diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath9k/calib.h new file mode 100644 index 000000000000..1c74bd50700d --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CALIB_H +#define CALIB_H + +extern const struct hal_percal_data iq_cal_multi_sample; +extern const struct hal_percal_data iq_cal_single_sample; +extern const struct hal_percal_data adc_gain_cal_multi_sample; +extern const struct hal_percal_data adc_gain_cal_single_sample; +extern const struct hal_percal_data adc_dc_cal_multi_sample; +extern const struct hal_percal_data adc_dc_cal_single_sample; +extern const struct hal_percal_data adc_init_dc_cal; + +#define AR_PHY_CCA_MAX_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_HIGH_VALUE -62 +#define AR_PHY_CCA_MIN_BAD_VALUE -140 +#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 +#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 + +#define NUM_NF_READINGS 6 +#define ATH9K_NF_CAL_HIST_MAX 5 + +struct ar5416IniArray { + u32 *ia_array; + u32 ia_rows; + u32 ia_columns; +}; + +#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ + (iniarray)->ia_array = (u32 *)(array); \ + (iniarray)->ia_rows = (rows); \ + (iniarray)->ia_columns = (columns); \ + } while (0) + +#define INI_RA(iniarray, row, column) \ + (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) + +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = NULL; \ + } while (0) + +#define INSERT_CAL(_ahp, _perCal) \ + do { \ + if ((_ahp)->cal_list_last == NULL) { \ + (_ahp)->cal_list = \ + (_ahp)->cal_list_last = (_perCal); \ + ((_ahp)->cal_list_last)->calNext = (_perCal); \ + } else { \ + ((_ahp)->cal_list_last)->calNext = (_perCal); \ + (_ahp)->cal_list_last = (_perCal); \ + (_perCal)->calNext = (_ahp)->cal_list; \ + } \ + } while (0) + +enum hal_cal_types { + ADC_DC_INIT_CAL = 0x1, + ADC_GAIN_CAL = 0x2, + ADC_DC_CAL = 0x4, + IQ_MISMATCH_CAL = 0x8 +}; + +enum hal_cal_state { + CAL_INACTIVE, + CAL_WAITING, + CAL_RUNNING, + CAL_DONE +}; + +#define MIN_CAL_SAMPLES 1 +#define MAX_CAL_SAMPLES 64 +#define INIT_LOG_COUNT 5 +#define PER_MIN_LOG_COUNT 2 +#define PER_MAX_LOG_COUNT 10 + +struct hal_percal_data { + enum hal_cal_types calType; + u32 calNumSamples; + u32 calCountMax; + void (*calCollect) (struct ath_hw *); + void (*calPostProc) (struct ath_hw *, u8); +}; + +struct hal_cal_list { + const struct hal_percal_data *calData; + enum hal_cal_state calState; + struct hal_cal_list *calNext; +}; + +struct ath9k_nfcal_hist { + int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX]; + u8 currIndex; + int16_t privNF; + u8 invalidNFcount; +}; + +bool ath9k_hw_reset_calvalid(struct ath_hw *ah); +void ath9k_hw_start_nfcal(struct ath_hw *ah); +void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); +int16_t ath9k_hw_getnf(struct ath_hw *ah, + struct ath9k_channel *chan); +void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); +bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone); +bool ath9k_hw_init_cal(struct ath_hw *ah, + struct ath9k_channel *chan); + +#endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h deleted file mode 100644 index 139566cbbf65..000000000000 --- a/drivers/net/wireless/ath9k/core.h +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Copyright (c) 2008 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef CORE_H -#define CORE_H - -#include <linux/etherdevice.h> -#include <linux/pci.h> -#include <net/mac80211.h> -#include <linux/leds.h> -#include <linux/rfkill.h> - -#include "ath9k.h" -#include "rc.h" - -struct ath_node; - -/* Macro to expand scalars to 64-bit objects */ - -#define ito64(x) (sizeof(x) == 8) ? \ - (((unsigned long long int)(x)) & (0xff)) : \ - (sizeof(x) == 16) ? \ - (((unsigned long long int)(x)) & 0xffff) : \ - ((sizeof(x) == 32) ? \ - (((unsigned long long int)(x)) & 0xffffffff) : \ - (unsigned long long int)(x)) - -/* increment with wrap-around */ -#define INCR(_l, _sz) do { \ - (_l)++; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -/* decrement with wrap-around */ -#define DECR(_l, _sz) do { \ - (_l)--; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -#define A_MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define ASSERT(exp) do { \ - if (unlikely(!(exp))) { \ - BUG(); \ - } \ - } while (0) - -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - -#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) - -static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -enum ATH_DEBUG { - ATH_DBG_RESET = 0x00000001, - ATH_DBG_REG_IO = 0x00000002, - ATH_DBG_QUEUE = 0x00000004, - ATH_DBG_EEPROM = 0x00000008, - ATH_DBG_CALIBRATE = 0x00000010, - ATH_DBG_CHANNEL = 0x00000020, - ATH_DBG_INTERRUPT = 0x00000040, - ATH_DBG_REGULATORY = 0x00000080, - ATH_DBG_ANI = 0x00000100, - ATH_DBG_POWER_MGMT = 0x00000200, - ATH_DBG_XMIT = 0x00000400, - ATH_DBG_BEACON = 0x00001000, - ATH_DBG_CONFIG = 0x00002000, - ATH_DBG_KEYCACHE = 0x00004000, - ATH_DBG_FATAL = 0x00008000, - ATH_DBG_ANY = 0xffffffff -}; - -#define DBG_DEFAULT (ATH_DBG_FATAL) - -#ifdef CONFIG_ATH9K_DEBUG - -/** - * struct ath_interrupt_stats - Contains statistics about interrupts - * @total: Total no. of interrupts generated so far - * @rxok: RX with no errors - * @rxeol: RX with no more RXDESC available - * @rxorn: RX FIFO overrun - * @txok: TX completed at the requested rate - * @txurn: TX FIFO underrun - * @mib: MIB regs reaching its threshold - * @rxphyerr: RX with phy errors - * @rx_keycache_miss: RX with key cache misses - * @swba: Software Beacon Alert - * @bmiss: Beacon Miss - * @bnr: Beacon Not Ready - * @cst: Carrier Sense TImeout - * @gtt: Global TX Timeout - * @tim: RX beacon TIM occurrence - * @cabend: RX End of CAB traffic - * @dtimsync: DTIM sync lossage - * @dtim: RX Beacon with DTIM - */ -struct ath_interrupt_stats { - u32 total; - u32 rxok; - u32 rxeol; - u32 rxorn; - u32 txok; - u32 txeol; - u32 txurn; - u32 mib; - u32 rxphyerr; - u32 rx_keycache_miss; - u32 swba; - u32 bmiss; - u32 bnr; - u32 cst; - u32 gtt; - u32 tim; - u32 cabend; - u32 dtimsync; - u32 dtim; -}; - -struct ath_stats { - struct ath_interrupt_stats istats; -}; - -struct ath9k_debug { - int debug_mask; - struct dentry *debugfs_root; - struct dentry *debugfs_phy; - struct dentry *debugfs_dma; - struct dentry *debugfs_interrupt; - struct ath_stats stats; -}; - -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); -int ath9k_init_debug(struct ath_softc *sc); -void ath9k_exit_debug(struct ath_softc *sc); -void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); - -#else - -static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, - const char *fmt, ...) -{ -} - -static inline int ath9k_init_debug(struct ath_softc *sc) -{ - return 0; -} - -static inline void ath9k_exit_debug(struct ath_softc *sc) -{ -} - -static inline void ath_debug_stat_interrupt(struct ath_softc *sc, - enum ath9k_int status) -{ -} - -#endif /* CONFIG_ATH9K_DEBUG */ - -struct ath_config { - u32 ath_aggr_prot; - u16 txpowlimit; - u16 txpowlimit_override; - u8 cabqReadytime; - u8 swBeaconProcess; -}; - -/*************************/ -/* Descriptor Management */ -/*************************/ - -#define ATH_TXBUF_RESET(_bf) do { \ - (_bf)->bf_status = 0; \ - (_bf)->bf_lastbf = NULL; \ - (_bf)->bf_lastfrm = NULL; \ - (_bf)->bf_next = NULL; \ - memset(&((_bf)->bf_state), 0, \ - sizeof(struct ath_buf_state)); \ - } while (0) - -enum buffer_type { - BUF_DATA = BIT(0), - BUF_AGGR = BIT(1), - BUF_AMPDU = BIT(2), - BUF_HT = BIT(3), - BUF_RETRY = BIT(4), - BUF_XRETRY = BIT(5), - BUF_SHORT_PREAMBLE = BIT(6), - BUF_BAR = BIT(7), - BUF_PSPOLL = BIT(8), - BUF_AGGR_BURST = BIT(9), - BUF_CALC_AIRTIME = BIT(10), -}; - -struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ - u32 bf_type; /* BUF_* (enum buffer_type) */ - u32 bfs_keyix; - enum ath9k_key_type bfs_keytype; -}; - -#define bf_nframes bf_state.bfs_nframes -#define bf_al bf_state.bfs_al -#define bf_frmlen bf_state.bfs_frmlen -#define bf_retries bf_state.bfs_retries -#define bf_seqno bf_state.bfs_seqno -#define bf_tidno bf_state.bfs_tidno -#define bf_rcs bf_state.bfs_rcs -#define bf_keyix bf_state.bfs_keyix -#define bf_keytype bf_state.bfs_keytype -#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) -#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) -#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) -#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) -#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) -#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) -#define bf_isshpreamble(bf) (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE) -#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR) -#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL) -#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST) - -/* - * Abstraction of a contiguous buffer to transmit/receive. There is only - * a single hw descriptor encapsulated here. - */ -struct ath_buf { - struct list_head list; - struct list_head *last; - struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or - an aggregate) */ - struct ath_buf *bf_lastfrm; /* last buf of this frame */ - struct ath_buf *bf_next; /* next subframe in the aggregate */ - void *bf_mpdu; /* enclosing frame structure */ - struct ath_desc *bf_desc; /* virtual addr of desc */ - dma_addr_t bf_daddr; /* physical addr of desc */ - dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - u32 bf_status; - u16 bf_flags; /* tx descriptor flags */ - struct ath_buf_state bf_state; /* buffer state */ - dma_addr_t bf_dmacontext; -}; - -#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) - -/* hw processing complete, desc processed by hal */ -#define ATH_BUFSTATUS_DONE 0x00000001 -/* hw processing complete, desc hold for hw */ -#define ATH_BUFSTATUS_STALE 0x00000002 -/* Rx-only: OS is done with this packet and it's ok to queued it to hw */ -#define ATH_BUFSTATUS_FREE 0x00000004 - -/* DMA state for tx/rx descriptors */ - -struct ath_descdma { - const char *dd_name; - struct ath_desc *dd_desc; /* descriptors */ - dma_addr_t dd_desc_paddr; /* physical addr of dd_desc */ - u32 dd_desc_len; /* size of dd_desc */ - struct ath_buf *dd_bufptr; /* associated buffers */ - dma_addr_t dd_dmacontext; -}; - -int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head, const char *name, - int nbuf, int ndesc); -void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, - struct list_head *head); - -/***********/ -/* RX / TX */ -/***********/ - -#define ATH_MAX_ANTENNA 3 -#define ATH_RXBUF 512 -#define WME_NUM_TID 16 -#define ATH_TXBUF 512 -#define ATH_TXMAXTRY 13 -#define ATH_11N_TXMAXTRY 10 -#define ATH_MGT_TXMAXTRY 4 -#define WME_BA_BMP_SIZE 64 -#define WME_MAX_BA WME_BA_BMP_SIZE -#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) - -#define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) - -#define WME_AC_BE 0 -#define WME_AC_BK 1 -#define WME_AC_VI 2 -#define WME_AC_VO 3 -#define WME_NUM_AC 4 - -#define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 -#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ -/* number of delimiters for encryption padding */ -#define ATH_AGGR_ENCRYPTDELIM 10 -/* minimum h/w qdepth to be sustained to maximize aggregation */ -#define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define IEEE80211_SEQ_SEQ_SHIFT 4 -#define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - -/* return whether a bit at index _n in bitmap _bm is set - * _sz is the size of the bitmap */ -#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ - ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) - -/* return block-ack bitmap index given sequence and starting sequence */ -#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) - -/* returns delimiter padding required given the packet length */ -#define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 4095) < (_bawsz)) - -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, - ATH_AGGR_SHORTPKT, - ATH_AGGR_8K_LIMITED, -}; - -struct ath_txq { - u32 axq_qnum; /* hardware q number */ - u32 *axq_link; /* link ptr in last TX desc */ - struct list_head axq_q; /* transmit queue */ - spinlock_t axq_lock; - unsigned long axq_lockflags; /* intr state when must cli */ - u32 axq_depth; /* queue depth */ - u8 axq_aggr_depth; /* aggregates queued */ - u32 axq_totalqueued; /* total ever queued */ - bool stopped; /* Is mac80211 queue stopped ? */ - struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/ - - /* first desc of the last descriptor that contains CTS */ - struct ath_desc *axq_lastdsWithCTS; - - /* final desc of the gating desc that determines whether - lastdsWithCTS has been DMA'ed or not */ - struct ath_desc *axq_gatingds; - - struct list_head axq_acq; -}; - -#define AGGR_CLEANUP BIT(1) -#define AGGR_ADDBA_COMPLETE BIT(2) -#define AGGR_ADDBA_PROGRESS BIT(3) - -/* per TID aggregate tx state for a destination */ -struct ath_atx_tid { - struct list_head list; /* round-robin tid entry */ - struct list_head buf_q; /* pending buffers */ - struct ath_node *an; - struct ath_atx_ac *ac; - struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */ - u16 seq_start; - u16 seq_next; - u16 baw_size; - int tidno; - int baw_head; /* first un-acked tx buffer */ - int baw_tail; /* next unused tx buffer slot */ - int sched; - int paused; - u8 state; - int addba_exchangeattempts; -}; - -/* per access-category aggregate tx state for a destination */ -struct ath_atx_ac { - int sched; /* dest-ac is scheduled */ - int qnum; /* H/W queue number associated - with this AC */ - struct list_head list; /* round-robin txq entry */ - struct list_head tid_q; /* queue of TIDs with buffers */ -}; - -/* per-frame tx control block */ -struct ath_tx_control { - struct ath_txq *txq; - int if_id; -}; - -/* per frame tx status block */ -struct ath_xmit_status { - int retries; /* number of retries to successufully - transmit this frame */ - int flags; /* status of transmit */ -#define ATH_TX_ERROR 0x01 -#define ATH_TX_XRETRY 0x02 -#define ATH_TX_BAR 0x04 -}; - -/* All RSSI values are noise floor adjusted */ -struct ath_tx_stat { - int rssi; - int rssictl[ATH_MAX_ANTENNA]; - int rssiextn[ATH_MAX_ANTENNA]; - int rateieee; - int rateKbps; - int ratecode; - int flags; - u32 airtime; /* time on air per final tx rate */ -}; - -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; - -struct ath_node { - struct ath_softc *an_sc; - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; - u16 maxampdu; - u8 mpdudensity; -}; - -struct ath_tx { - u16 seq_no; - u32 txqsetup; - int hwq_map[ATH9K_WME_AC_VO+1]; - spinlock_t txbuflock; - struct list_head txbuf; - struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; - struct ath_descdma txdma; -}; - -struct ath_rx { - u8 defant; - u8 rxotherant; - u32 *rxlink; - int bufsize; - unsigned int rxfilter; - spinlock_t rxflushlock; - spinlock_t rxbuflock; - struct list_head rxbuf; - struct ath_descdma rxdma; -}; - -int ath_startrecv(struct ath_softc *sc); -bool ath_stoprecv(struct ath_softc *sc); -void ath_flushrecv(struct ath_softc *sc); -u32 ath_calcrxfilter(struct ath_softc *sc); -int ath_rx_init(struct ath_softc *sc, int nbufs); -void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); -struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); -void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); -int ath_tx_setup(struct ath_softc *sc, int haltype); -void ath_draintxq(struct ath_softc *sc, bool retry_tx); -void ath_tx_draintxq(struct ath_softc *sc, - struct ath_txq *txq, bool retry_tx); -void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); -void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); -void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); -int ath_tx_init(struct ath_softc *sc, int nbufs); -int ath_tx_cleanup(struct ath_softc *sc); -int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); -struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); -int ath_txq_update(struct ath_softc *sc, int qnum, - struct ath9k_tx_queue_info *q); -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, - struct ath_tx_control *txctl); -void ath_tx_tasklet(struct ath_softc *sc); -u32 ath_txq_depth(struct ath_softc *sc, int qnum); -u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); -void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); -void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid); -bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); -void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); - -/********/ -/* VAPs */ -/********/ - -/* - * Define the scheme that we select MAC address for multiple - * BSS on the same radio. The very first VAP will just use the MAC - * address from the EEPROM. For the next 3 VAPs, we set the - * U/L bit (bit 1) in MAC address, and use the next two bits as the - * index of the VAP. - */ - -#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ - ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) - -struct ath_vap { - int av_bslot; - enum nl80211_iftype av_opmode; - struct ath_buf *av_bcbuf; - struct ath_tx_control av_btxctl; -}; - -/*******************/ -/* Beacon Handling */ -/*******************/ - -/* - * Regardless of the number of beacons we stagger, (i.e. regardless of the - * number of BSSIDs) if a given beacon does not go out even after waiting this - * number of beacon intervals, the game's up. - */ -#define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 1 -#define ATH_DEFAULT_BINTVAL 100 /* TU */ -#define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) - -struct ath_beacon_config { - u16 beacon_interval; - u16 listen_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - u8 tim_offset; - union { - u64 last_tsf; - u8 last_tstamp[8]; - } u; /* last received beacon/probe response timestamp of this BSS. */ -}; - -struct ath_beacon { - enum { - OK, /* no change needed */ - UPDATE, /* update pending */ - COMMIT /* beacon sent, commit change */ - } updateslot; /* slot time update fsm */ - - u32 beaconq; - u32 bmisscnt; - u32 ast_be_xmit; - u64 bc_tstamp; - int bslot[ATH_BCBUF]; - int slottime; - int slotupdate; - struct ath9k_tx_queue_info beacon_qi; - struct ath_descdma bdma; - struct ath_txq *cabq; - struct list_head bbuf; -}; - -void ath9k_beacon_tasklet(unsigned long data); -void ath_beacon_config(struct ath_softc *sc, int if_id); -int ath_beaconq_setup(struct ath_hal *ah); -int ath_beacon_alloc(struct ath_softc *sc, int if_id); -void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); -void ath_beacon_sync(struct ath_softc *sc, int if_id); - -/*******/ -/* ANI */ -/*******/ - -/* ANI values for STA only. - FIXME: Add appropriate values for AP later */ - -#define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */ -#define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */ -#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */ -#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */ - -struct ath_ani { - bool sc_caldone; - int16_t sc_noise_floor; - unsigned int sc_longcal_timer; - unsigned int sc_shortcal_timer; - unsigned int sc_resetcal_timer; - unsigned int sc_checkani_timer; - struct timer_list timer; -}; - -/********************/ -/* LED Control */ -/********************/ - -#define ATH_LED_PIN 1 - -enum ath_led_type { - ATH_LED_RADIO, - ATH_LED_ASSOC, - ATH_LED_TX, - ATH_LED_RX -}; - -struct ath_led { - struct ath_softc *sc; - struct led_classdev led_cdev; - enum ath_led_type led_type; - char name[32]; - bool registered; -}; - -/* Rfkill */ -#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ - -struct ath_rfkill { - struct rfkill *rfkill; - struct delayed_work rfkill_poll; - char rfkill_name[32]; -}; - -/********************/ -/* Main driver core */ -/********************/ - -/* - * Default cache line size, in bytes. - * Used when PCI device not fully initialized by bootrom/BIOS -*/ -#define DEFAULT_CACHELINE 32 -#define ATH_DEFAULT_NOISE_FLOOR -95 -#define ATH_REGCLASSIDS_MAX 10 -#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES 10 -#define ATH_CHAN_MAX 255 -#define IEEE80211_WEP_NKID 4 /* number of key ids */ -#define IEEE80211_RATE_VAL 0x7f -/* - * The key cache is used for h/w cipher state and also for - * tracking station state such as the current tx antenna. - * We also setup a mapping table between key cache slot indices - * and station state to short-circuit node lookups on rx. - * Different parts have different size key caches. We handle - * up to ATH_KEYMAX entries (could dynamically allocate state). - */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ - -#define ATH_IF_ID_ANY 0xff -#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ -#define ATH_RSSI_DUMMY_MARKER 0x127 -#define ATH_RATE_DUMMY_MARKER 0 - -enum PROT_MODE { - PROT_M_NONE = 0, - PROT_M_RTSCTS, - PROT_M_CTSONLY -}; - -#define SC_OP_INVALID BIT(0) -#define SC_OP_BEACONS BIT(1) -#define SC_OP_RXAGGR BIT(2) -#define SC_OP_TXAGGR BIT(3) -#define SC_OP_CHAINMASK_UPDATE BIT(4) -#define SC_OP_FULL_RESET BIT(5) -#define SC_OP_NO_RESET BIT(6) -#define SC_OP_PREAMBLE_SHORT BIT(7) -#define SC_OP_PROTECT_ENABLE BIT(8) -#define SC_OP_RXFLUSH BIT(9) -#define SC_OP_LED_ASSOCIATED BIT(10) -#define SC_OP_RFKILL_REGISTERED BIT(11) -#define SC_OP_RFKILL_SW_BLOCKED BIT(12) -#define SC_OP_RFKILL_HW_BLOCKED BIT(13) - -struct ath_softc { - struct ieee80211_hw *hw; - struct pci_dev *pdev; - struct tasklet_struct intr_tq; - struct tasklet_struct bcon_tasklet; - struct ath_hal *sc_ah; - void __iomem *mem; - spinlock_t sc_resetlock; - spinlock_t sc_serial_rw; - struct mutex mutex; - - u8 sc_curbssid[ETH_ALEN]; - u8 sc_myaddr[ETH_ALEN]; - u8 sc_bssidmask[ETH_ALEN]; - u32 sc_intrstatus; - u32 sc_flags; /* SC_OP_* */ - u16 sc_curtxpow; - u16 sc_curaid; - u16 sc_cachelsz; - u8 sc_nbcnvaps; - u16 sc_nvaps; - u8 sc_tx_chainmask; - u8 sc_rx_chainmask; - u32 sc_keymax; - DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); - u8 sc_splitmic; - u8 sc_protrix; - enum ath9k_int sc_imask; - enum PROT_MODE sc_protmode; - enum ath9k_ht_extprotspacing sc_ht_extprotspacing; - enum ath9k_ht_macmode tx_chan_width; - - struct ath_config sc_config; - struct ath_rx rx; - struct ath_tx tx; - struct ath_beacon beacon; - struct ieee80211_vif *sc_vaps[ATH_BCBUF]; - struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - struct ath_rate_table *cur_rate_table; - struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath_led radio_led; - struct ath_led assoc_led; - struct ath_led tx_led; - struct ath_led rx_led; - struct ath_rfkill rf_kill; - struct ath_ani sc_ani; - struct ath9k_node_stats sc_halstats; -#ifdef CONFIG_ATH9K_DEBUG - struct ath9k_debug sc_debug; -#endif -}; - -int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); -int ath_cabq_update(struct ath_softc *); - -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -static inline void ath9k_iowrite32(struct ath_hal *ah, u32 reg_offset, u32 val) -{ - if (ah->ah_config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - iowrite32(val, ah->ah_sc->mem + reg_offset); -} - -static inline unsigned int ath9k_ioread32(struct ath_hal *ah, u32 reg_offset) -{ - u32 val; - if (ah->ah_config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - val = ioread32(ah->ah_sc->mem + reg_offset); - return val; -} - -#endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index a80ed576830f..fdf9528fa49b 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,19 +14,21 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "reg.h" -#include "hw.h" +#include <asm/unaligned.h> + +#include "ath9k.h" static unsigned int ath9k_debug = DBG_DEFAULT; module_param_named(debug, ath9k_debug, uint, 0); +static struct dentry *ath9k_debugfs_root; + void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) { if (!sc) return; - if (sc->sc_debug.debug_mask & dbg_mask) { + if (sc->debug.debug_mask & dbg_mask) { va_list args; va_start(args, fmt); @@ -46,7 +48,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; char buf[1024]; unsigned int len = 0; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; @@ -132,41 +134,41 @@ static const struct file_operations fops_dma = { void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { if (status) - sc->sc_debug.stats.istats.total++; + sc->debug.stats.istats.total++; if (status & ATH9K_INT_RX) - sc->sc_debug.stats.istats.rxok++; + sc->debug.stats.istats.rxok++; if (status & ATH9K_INT_RXEOL) - sc->sc_debug.stats.istats.rxeol++; + sc->debug.stats.istats.rxeol++; if (status & ATH9K_INT_RXORN) - sc->sc_debug.stats.istats.rxorn++; + sc->debug.stats.istats.rxorn++; if (status & ATH9K_INT_TX) - sc->sc_debug.stats.istats.txok++; + sc->debug.stats.istats.txok++; if (status & ATH9K_INT_TXURN) - sc->sc_debug.stats.istats.txurn++; + sc->debug.stats.istats.txurn++; if (status & ATH9K_INT_MIB) - sc->sc_debug.stats.istats.mib++; + sc->debug.stats.istats.mib++; if (status & ATH9K_INT_RXPHY) - sc->sc_debug.stats.istats.rxphyerr++; + sc->debug.stats.istats.rxphyerr++; if (status & ATH9K_INT_RXKCM) - sc->sc_debug.stats.istats.rx_keycache_miss++; + sc->debug.stats.istats.rx_keycache_miss++; if (status & ATH9K_INT_SWBA) - sc->sc_debug.stats.istats.swba++; + sc->debug.stats.istats.swba++; if (status & ATH9K_INT_BMISS) - sc->sc_debug.stats.istats.bmiss++; + sc->debug.stats.istats.bmiss++; if (status & ATH9K_INT_BNR) - sc->sc_debug.stats.istats.bnr++; + sc->debug.stats.istats.bnr++; if (status & ATH9K_INT_CST) - sc->sc_debug.stats.istats.cst++; + sc->debug.stats.istats.cst++; if (status & ATH9K_INT_GTT) - sc->sc_debug.stats.istats.gtt++; + sc->debug.stats.istats.gtt++; if (status & ATH9K_INT_TIM) - sc->sc_debug.stats.istats.tim++; + sc->debug.stats.istats.tim++; if (status & ATH9K_INT_CABEND) - sc->sc_debug.stats.istats.cabend++; + sc->debug.stats.istats.cabend++; if (status & ATH9K_INT_DTIMSYNC) - sc->sc_debug.stats.istats.dtimsync++; + sc->debug.stats.istats.dtimsync++; if (status & ATH9K_INT_DTIM) - sc->sc_debug.stats.istats.dtim++; + sc->debug.stats.istats.dtim++; } static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, @@ -177,41 +179,41 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, unsigned int len = 0; len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok); + "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol); + "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn); + "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok); + "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn); + "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib); + "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr); + "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss); + "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba); + "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss); + "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr); + "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst); + "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt); + "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim); + "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend); + "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync); + "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim); + "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total); + "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -222,29 +224,308 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -int ath9k_init_debug(struct ath_softc *sc) +static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) { - sc->sc_debug.debug_mask = ath9k_debug; + struct ath_tx_info_priv *tx_info_priv = NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->status.rates; + int final_ts_idx, idx; - sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!sc->sc_debug.debugfs_root) - goto err; + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; + idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; + + sc->debug.stats.n_rcstats[idx].success++; +} + +static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_tx_info_priv *tx_info_priv = NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->status.rates; + int final_ts_idx, idx; + + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; + idx = rates[final_ts_idx].idx; + + sc->debug.stats.legacy_rcstats[idx].success++; +} + +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) +{ + if (conf_is_ht(&sc->hw->conf)) + ath_debug_stat_11n_rc(sc, skb); + else + ath_debug_stat_legacy_rc(sc, skb); +} + +/* FIXME: legacy rates, later on .. */ +void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per) +{ + if (conf_is_ht(&sc->hw->conf)) { + int idx = sc->cur_rate_table->info[rix].dot11rate; + + sc->debug.stats.n_rcstats[idx].xretries += xretries; + sc->debug.stats.n_rcstats[idx].retries += retries; + sc->debug.stats.n_rcstats[idx].per = per; + } +} + +static ssize_t ath_read_file_stat_11n_rc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[1024]; + unsigned int len = 0; + int i = 0; + + len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); + + for (i = 0; i <= 15; i++) { + len += snprintf(buf + len, sizeof(buf) - len, + "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, + sc->debug.stats.n_rcstats[i].success, + sc->debug.stats.n_rcstats[i].retries, + sc->debug.stats.n_rcstats[i].xretries, + sc->debug.stats.n_rcstats[i].per); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath_read_file_stat_legacy_rc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + int i = 0; + + len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); - sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), - sc->sc_debug.debugfs_root); - if (!sc->sc_debug.debugfs_phy) + for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { + len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", + sc->cur_rate_table->info[i].ratekbps / 1000, + sc->debug.stats.legacy_rcstats[i].success); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + + if (sc->cur_rate_table == NULL) + return 0; + + if (conf_is_ht(&sc->hw->conf)) + return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); + else + return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); +} + +static const struct file_operations fops_rcstat = { + .read = read_file_rcstat, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static const char * ath_wiphy_state_str(enum ath_wiphy_state state) +{ + switch (state) { + case ATH_WIPHY_INACTIVE: + return "INACTIVE"; + case ATH_WIPHY_ACTIVE: + return "ACTIVE"; + case ATH_WIPHY_PAUSING: + return "PAUSING"; + case ATH_WIPHY_PAUSED: + return "PAUSED"; + case ATH_WIPHY_SCAN: + return "SCAN"; + } + return "?"; +} + +static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + int i; + u8 addr[ETH_ALEN]; + + len += snprintf(buf + len, sizeof(buf) - len, + "primary: %s (%s chan=%d ht=%d)\n", + wiphy_name(sc->pri_wiphy->hw->wiphy), + ath_wiphy_state_str(sc->pri_wiphy->state), + sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + len += snprintf(buf + len, sizeof(buf) - len, + "secondary: %s (%s chan=%d ht=%d)\n", + wiphy_name(aphy->hw->wiphy), + ath_wiphy_state_str(aphy->state), + aphy->chan_idx, aphy->chan_is_ht); + } + + put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); + put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addr: %pM\n", addr); + put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); + put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); + len += snprintf(buf + len, sizeof(buf) - len, + "addrmask: %pM\n", addr); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) +{ + int i; + if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) + return sc->pri_wiphy; + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) + return aphy; + } + return NULL; +} + +static int del_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_del(aphy); +} + +static int pause_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_pause(aphy); +} + +static int unpause_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_unpause(aphy); +} + +static int select_wiphy(struct ath_softc *sc, const char *name) +{ + struct ath_wiphy *aphy = get_wiphy(sc, name); + if (!aphy) + return -ENOENT; + return ath9k_wiphy_select(aphy); +} + +static int schedule_wiphy(struct ath_softc *sc, const char *msec) +{ + ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); + return 0; +} + +static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[50]; + size_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + if (strncmp(buf, "add", 3) == 0) { + int res = ath9k_wiphy_add(sc); + if (res < 0) + return res; + } else if (strncmp(buf, "del=", 4) == 0) { + int res = del_wiphy(sc, buf + 4); + if (res < 0) + return res; + } else if (strncmp(buf, "pause=", 6) == 0) { + int res = pause_wiphy(sc, buf + 6); + if (res < 0) + return res; + } else if (strncmp(buf, "unpause=", 8) == 0) { + int res = unpause_wiphy(sc, buf + 8); + if (res < 0) + return res; + } else if (strncmp(buf, "select=", 7) == 0) { + int res = select_wiphy(sc, buf + 7); + if (res < 0) + return res; + } else if (strncmp(buf, "schedule=", 9) == 0) { + int res = schedule_wiphy(sc, buf + 9); + if (res < 0) + return res; + } else + return -EOPNOTSUPP; + + return count; +} + +static const struct file_operations fops_wiphy = { + .read = read_file_wiphy, + .write = write_file_wiphy, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +int ath9k_init_debug(struct ath_softc *sc) +{ + sc->debug.debug_mask = ath9k_debug; + + sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + ath9k_debugfs_root); + if (!sc->debug.debugfs_phy) goto err; - sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, - sc->sc_debug.debugfs_phy, sc, &fops_dma); - if (!sc->sc_debug.debugfs_dma) + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->debug.debugfs_phy, sc, &fops_dma); + if (!sc->debug.debugfs_dma) goto err; - sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt", + sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", S_IRUGO, - sc->sc_debug.debugfs_phy, + sc->debug.debugfs_phy, sc, &fops_interrupt); - if (!sc->sc_debug.debugfs_interrupt) + if (!sc->debug.debugfs_interrupt) + goto err; + + sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", + S_IRUGO, + sc->debug.debugfs_phy, + sc, &fops_rcstat); + if (!sc->debug.debugfs_rcstat) + goto err; + + sc->debug.debugfs_wiphy = debugfs_create_file( + "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, + &fops_wiphy); + if (!sc->debug.debugfs_wiphy) goto err; return 0; @@ -255,8 +536,24 @@ err: void ath9k_exit_debug(struct ath_softc *sc) { - debugfs_remove(sc->sc_debug.debugfs_interrupt); - debugfs_remove(sc->sc_debug.debugfs_dma); - debugfs_remove(sc->sc_debug.debugfs_phy); - debugfs_remove(sc->sc_debug.debugfs_root); + debugfs_remove(sc->debug.debugfs_wiphy); + debugfs_remove(sc->debug.debugfs_rcstat); + debugfs_remove(sc->debug.debugfs_interrupt); + debugfs_remove(sc->debug.debugfs_dma); + debugfs_remove(sc->debug.debugfs_phy); +} + +int ath9k_debug_create_root(void) +{ + ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!ath9k_debugfs_root) + return -ENOENT; + + return 0; +} + +void ath9k_debug_remove_root(void) +{ + debugfs_remove(ath9k_debugfs_root); + ath9k_debugfs_root = NULL; } diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h new file mode 100644 index 000000000000..7b0e5419d2bc --- /dev/null +++ b/drivers/net/wireless/ath9k/debug.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DEBUG_H +#define DEBUG_H + +enum ATH_DEBUG { + ATH_DBG_RESET = 0x00000001, + ATH_DBG_REG_IO = 0x00000002, + ATH_DBG_QUEUE = 0x00000004, + ATH_DBG_EEPROM = 0x00000008, + ATH_DBG_CALIBRATE = 0x00000010, + ATH_DBG_CHANNEL = 0x00000020, + ATH_DBG_INTERRUPT = 0x00000040, + ATH_DBG_REGULATORY = 0x00000080, + ATH_DBG_ANI = 0x00000100, + ATH_DBG_POWER_MGMT = 0x00000200, + ATH_DBG_XMIT = 0x00000400, + ATH_DBG_BEACON = 0x00001000, + ATH_DBG_CONFIG = 0x00002000, + ATH_DBG_KEYCACHE = 0x00004000, + ATH_DBG_FATAL = 0x00008000, + ATH_DBG_ANY = 0xffffffff +}; + +#define DBG_DEFAULT (ATH_DBG_FATAL) + +#ifdef CONFIG_ATH9K_DEBUG + +/** + * struct ath_interrupt_stats - Contains statistics about interrupts + * @total: Total no. of interrupts generated so far + * @rxok: RX with no errors + * @rxeol: RX with no more RXDESC available + * @rxorn: RX FIFO overrun + * @txok: TX completed at the requested rate + * @txurn: TX FIFO underrun + * @mib: MIB regs reaching its threshold + * @rxphyerr: RX with phy errors + * @rx_keycache_miss: RX with key cache misses + * @swba: Software Beacon Alert + * @bmiss: Beacon Miss + * @bnr: Beacon Not Ready + * @cst: Carrier Sense TImeout + * @gtt: Global TX Timeout + * @tim: RX beacon TIM occurrence + * @cabend: RX End of CAB traffic + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + */ +struct ath_interrupt_stats { + u32 total; + u32 rxok; + u32 rxeol; + u32 rxorn; + u32 txok; + u32 txeol; + u32 txurn; + u32 mib; + u32 rxphyerr; + u32 rx_keycache_miss; + u32 swba; + u32 bmiss; + u32 bnr; + u32 cst; + u32 gtt; + u32 tim; + u32 cabend; + u32 dtimsync; + u32 dtim; +}; + +struct ath_legacy_rc_stats { + u32 success; +}; + +struct ath_11n_rc_stats { + u32 success; + u32 retries; + u32 xretries; + u8 per; +}; + +struct ath_stats { + struct ath_interrupt_stats istats; + struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ + struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ +}; + +struct ath9k_debug { + int debug_mask; + struct dentry *debugfs_phy; + struct dentry *debugfs_dma; + struct dentry *debugfs_interrupt; + struct dentry *debugfs_rcstat; + struct dentry *debugfs_wiphy; + struct ath_stats stats; +}; + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); +int ath9k_init_debug(struct ath_softc *sc); +void ath9k_exit_debug(struct ath_softc *sc); +int ath9k_debug_create_root(void); +void ath9k_debug_remove_root(void); +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); +void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per); + +#else + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline int ath9k_init_debug(struct ath_softc *sc) +{ + return 0; +} + +static inline void ath9k_exit_debug(struct ath_softc *sc) +{ +} + +static inline int ath9k_debug_create_root(void) +{ + return 0; +} + +static inline void ath9k_debug_remove_root(void) +{ +} + +static inline void ath_debug_stat_interrupt(struct ath_softc *sc, + enum ath9k_int status) +{ +} + +static inline void ath_debug_stat_rc(struct ath_softc *sc, + struct sk_buff *skb) +{ +} + +static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, + int xretries, int retries, u8 per) +{ +} + +#endif /* CONFIG_ATH9K_DEBUG */ + +#endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index acd6c5374d44..ffc36b0361c7 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,12 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" +#include "ath9k.h" -static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, +static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, u32 shift, u32 val) { @@ -30,7 +27,7 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, REG_WRITE(ah, reg, regVal); - if (ah->ah_config.analog_shiftreg) + if (ah->config.analog_shiftreg) udelay(100); return; @@ -91,254 +88,288 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, return false; } -static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data) +static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { - (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + struct ath_softc *sc = ah->ah_sc; - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { - return false; - } - - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); - - return true; + return sc->bus_ops->eeprom_read(ah, off, data); } -static int ath9k_hw_flash_map(struct ath_hal *ah) +static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) { - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + u16 i, k; + u8 currPwr = pwrMin; + u16 idxL = 0, idxR = 0; - if (!ahp->ah_cal_mem) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "cannot remap eeprom region \n"); - return -EIO; + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + ath9k_hw_get_lower_upper_index(currPwr, pPwrList, + numIntercepts, &(idxL), + &(idxR)); + if (idxR < 1) + idxR = 1; + if (idxL == numIntercepts - 1) + idxL = (u16) (numIntercepts - 2); + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL])); + pRetVpdList[i] = (u8) k; + currPwr += 2; } - return 0; -} - -static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - *data = ioread16(ahp->ah_cal_mem + off); - return true; } -static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) -{ - if (ath9k_hw_use_flash(ah)) - return ath9k_hw_flash_read(ah, off, data); - else - return ath9k_hw_eeprom_read(ah, off, data); -} - -static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah) +static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) { -#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; - u16 *eep_data; - int addr, eep_start_loc = 0; + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; - eep_start_loc = 64; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; } - eep_data = (u16 *)eep; + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); - for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); } - eep_data++; } - return true; -#undef SIZE_EEPROM_4K } -static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah) +static void ath9k_get_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct calDataPerFreqOpLoop *rawDatasetOpLoop, + u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) { -#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; - u16 *eep_data; - int addr, ar5416_eep_start_loc = 0x100; + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; - eep_data = (u16 *)eep; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); - for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region\n"); - return false; - } - eep_data++; - } - return true; -#undef SIZE_EEPROM_DEF -} + for (numPiers = 0; numPiers < availPiers; numPiers++) + if (calChans[numPiers] == AR5416_BCHAN_UNUSED) + break; -static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { - ath9k_hw_fill_def_eeprom, - ath9k_hw_fill_4k_eeprom -}; + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + calChans, numPiers, &idxL, &idxR); + if (match) { + pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; + *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; + *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + + rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } -static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + while (pcdac > ah->originalGain[i] && + i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) + i++; - return ath9k_fill_eeprom[ahp->ah_eep_map](ah); + *pcdacIdx = i; + return; } -static int ath9k_hw_check_def_eeprom(struct ath_hal *ah) +static void ath9k_olc_get_pdadcs(struct ath_hw *ah, + u32 initTxGain, + int txPower, + u8 *pPDADCValues) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = - (struct ar5416_eeprom_def *) &ahp->ah_eeprom.def; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; + u32 i; + u32 offset; - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading Magic # failed\n"); - return false; - } + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - if (!ath9k_hw_use_flash(ah)) { + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, + AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); + offset = txPower; + for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) + if (i < offset) + pPDADCValues[i] = 0x0; + else + pPDADCValues[i] = 0xFF; +} - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ahp->ah_eeprom); - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "0x%04X ", *eepdata); +static void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; - if (((addr + 1) % 6) == 0) - DPRINTF(ah->ah_sc, - ATH_DBG_EEPROM, "\n"); + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else + if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ahp->ah_eeprom.def.baseEepHeader.length); - else - el = ahp->ah_eeprom.def.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ahp->ah_eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer, j; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing \n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, + clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; +static u16 ath9k_hw_get_max_edge_power(u16 freq, + struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; + for (i = 0; (i < num_band_edges) && + (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = pRdEdgesPower[i].tPower; + break; + } else if ((i > 0) && + (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, + is2GHz))) { + if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, + is2GHz) < freq && + pRdEdgesPower[i - 1].flag) { + twiceMaxEdgePower = + pRdEdgesPower[i - 1].tPower; + } + break; + } + } - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; + return twiceMaxEdgePower; +} - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; +/****************************************/ +/* EEPROM Operations for 4K sized cards */ +/****************************************/ - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; +static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); +} - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; +static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); +} - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + int addr, eep_start_loc = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } + eep_start_loc = 64; - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } - if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || - ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ar5416_get_eep_ver(ahp)); - return -EINVAL; + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; } - return 0; + return true; +#undef SIZE_EEPROM_4K } -static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) +static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom_4k *eep = - (struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k; + (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; u16 *eepdata, temp, magic, magic2; u32 sum = 0, el; bool need_swap = false; @@ -346,38 +377,30 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); if (magic2 == AR5416_EEPROM_MAGIC) { need_swap = true; - eepdata = (u16 *) (&ahp->ah_eeprom); + eepdata = (u16 *) (&ah->eeprom); for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { temp = swab16(*eepdata); *eepdata = temp; eepdata++; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "0x%04X ", *eepdata); - - if (((addr + 1) % 6) == 0) - DPRINTF(ah->ah_sc, - ATH_DBG_EEPROM, "\n"); } } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid EEPROM Magic. " "endianness mismatch.\n"); return -EINVAL; @@ -389,16 +412,16 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) need_swap ? "True" : "False"); if (need_swap) - el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length); + el = swab16(ah->eeprom.map4k.baseEepHeader.length); else - el = ahp->ah_eeprom.map4k.baseEepHeader.length; + el = ah->eeprom.map4k.baseEepHeader.length; - if (el > sizeof(struct ar5416_eeprom_def)) + if (el > sizeof(struct ar5416_eeprom_4k)) el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); else el = el / sizeof(u16); - eepdata = (u16 *)(&ahp->ah_eeprom); + eepdata = (u16 *)(&ah->eeprom); for (i = 0; i < el; i++) sum ^= *eepdata++; @@ -408,7 +431,7 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) u16 word; DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing \n"); + "EEPROM Endianness is not native.. Changing\n"); word = swab16(eep->baseEepHeader.length); eep->baseEepHeader.length = word; @@ -448,11 +471,11 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) } } - if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER || - ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ar5416_get_eep4k_ver(ahp)); + sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; } @@ -460,48 +483,50 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) #undef EEPROM_4K_SIZE } -static int (*ath9k_check_eeprom[]) (struct ath_hal *) = { - ath9k_hw_check_def_eeprom, - ath9k_hw_check_4k_eeprom -}; - -static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - return ath9k_check_eeprom[ahp->ah_eep_map](ah); -} - -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, - u8 *pVpdList, u16 numIntercepts, - u8 *pRetVpdList) +static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) { - u16 i, k; - u8 currPwr = pwrMin; - u16 idxL = 0, idxR = 0; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; - for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { - ath9k_hw_get_lower_upper_index(currPwr, pPwrList, - numIntercepts, &(idxL), - &(idxR)); - if (idxR < 1) - idxR = 1; - if (idxL == numIntercepts - 1) - idxL = (u16) (numIntercepts - 2); - if (pPwrList[idxL] == pPwrList[idxR]) - k = pVpdList[idxL]; - else - k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + - (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / - (pPwrList[idxR] - pPwrList[idxL])); - pRetVpdList[i] = (u8) k; - currPwr += 2; + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_FRAC_N_5G: + return 0; + default: + return 0; } - - return true; } -static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, struct ath9k_channel *chan, struct cal_data_per_freq_4k *pRawDataSet, u8 *bChans, u16 availPiers, @@ -605,7 +630,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { minDelta = pPdGainBoundaries[0] - 23; pPdGainBoundaries[0] = 23; } else { @@ -644,7 +669,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, vpdTableI[i][sizeCurrVpdTable - 2]); vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - if (tgtIndex > maxIndex) { + if (tgtIndex >= maxIndex) { while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { tmpVal = (int16_t) TMP_VAL_VPD_TABLE; @@ -669,451 +694,20 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, #undef TMP_VAL_VPD_TABLE } -static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), - bChans, numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + - (ss - maxIndex + 1) * vpdStep)); - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -} - -static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, bool isExtTarget) -{ - struct chan_centers centers; - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) && - (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8)ath9k_hw_interpolate(freq, clo, chi, - powInfo[lowIndex].tPow2x[i], - powInfo[lowIndex + 1].tPow2x[i]); - } - } -} - -static void ath9k_hw_get_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, bool isHt40Target) -{ - struct chan_centers centers; - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) && - (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else - if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, - clo, chi, - powInfo[lowIndex].tPow2x[i], - powInfo[lowIndex + 1].tPow2x[i]); - } - } -} - -static u16 ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz, int num_band_edges) -{ - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; - - for (i = 0; (i < num_band_edges) && - (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; - break; - } else if ((i > 0) && - (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, - is2GHz))) { - if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, - is2GHz) < freq && - pRdEdgesPower[i - 1].flag) { - twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; - } - break; - } - } - - return twiceMaxEdgePower; -} - -static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah, +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, - pRawDataset, pCalBChans, - numPiers, pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "PDADC: Chain %d | PDADC %3d " - "Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d " - "Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; - - return true; -} - -static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct cal_data_per_freq_4k *pRawDataset; u8 *pCalBChans = NULL; u16 pdGainOverlap_t2; static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; u16 numPiers, i, j; int16_t tMinCalPower; u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; u32 reg32, regOffset, regChainOffset; xpdMask = pEepData->modalHeader.xpdGain; @@ -1128,16 +722,16 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, } pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; + numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; numXpdGain = 0; - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) + for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) break; xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); + (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); numXpdGain++; } } @@ -1148,12 +742,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, xpdGainValues[0]); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) { regChainOffset = (i == 1) ? 0x2000 : 0x1000; } else @@ -1168,7 +761,7 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, &tMinCalPower, gainBoundaries, pdadcValues, numXpdGain); - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) @@ -1216,298 +809,7 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, return true; } -static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ahp->ah_txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8)twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } else { - numCtlModes = ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - ; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } - return true; -} - -static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, +static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, @@ -1515,8 +817,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, u16 twiceMaxRegulatoryPower, u16 powerLimit) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; @@ -1544,7 +845,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, int tx_chainmask; u16 twiceMinEdgePower; - tx_chainmask = ahp->ah_txchainmask; + tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); @@ -1555,9 +856,9 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -1605,8 +906,8 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, else freq = centers.ctl_center; - if (ar5416_get_eep_ver(ahp) == 14 && - ar5416_get_eep_rev(ahp) <= 2) + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, @@ -1743,17 +1044,15 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, return true; } -static int ath9k_hw_def_set_txpower(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) +static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; @@ -1766,7 +1065,7 @@ static int ath9k_hw_def_set_txpower(struct ath_hal *ah, ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, @@ -1777,7 +1076,7 @@ static int ath9k_hw_def_set_txpower(struct ath_hal *ah, return -EIO; } - if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ath9k_hw_set_txpower: unable to set power table\n"); return -EIO; @@ -1856,10 +1155,6 @@ static int ath9k_hw_def_set_txpower(struct ath_hal *ah, | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); - i = rate6mb; if (IS_CHAN_HT40(chan)) @@ -1868,272 +1163,572 @@ static int ath9k_hw_def_set_txpower(struct ath_hal *ah, i = rateHt20_0; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = + ah->regulatory.max_power_level = ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; else - ah->ah_maxPowerLevel = ratesArray[i]; + ah->regulatory.max_power_level = ratesArray[i]; return 0; } -static int ath9k_hw_4k_set_txpower(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) +static void ath9k_hw_4k_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; - struct modal_eep_4k_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 biaslevel; - memset(ratesArray, 0, sizeof(ratesArray)); + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; - if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } + pModal = &eep->modalHeader; - if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ah->iniAddac, 7, 1) = + (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; } +} - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } +static void ath9k_hw_4k_set_gain(struct ath_hw *ah, + struct modal_eep_4k_header *pModal, + struct ar5416_eeprom_4k *eep, + u8 txRxAttenLocal, int regChainOffset) +{ + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); } - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); +} + +static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 txRxAttenLocal; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + pModal = &eep->modalHeader; + txRxAttenLocal = 23; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + /* Single chain for 4K EEPROM*/ + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version == 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); } - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } } - i = rate6mb; + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); - return 0; -} -static int (*ath9k_set_txpower[]) (struct ath_hal *, - struct ath9k_channel *, - u16, u8, u8, u8) = { - ath9k_hw_def_set_txpower, - ath9k_hw_4k_set_txpower -}; + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } -int ath9k_hw_set_txpower(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } +} + +static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; - return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl, - twiceAntennaReduction, twiceMaxRegulatoryPower, - powerLimit); + return pModal->antCtrlCommon & 0xFFFF; } -static void ath9k_hw_set_def_addac(struct ath_hal *ah, - struct ath9k_channel *chan) +static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) { -#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) - struct modal_eep_header *pModal; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; - u8 biaslevel; + return 1; +} - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; +static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; + u16 spur_val = AR_NO_SPUR; - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP4K_SPURCHAN; + break; + } - ath9k_hw_get_channel_centers(ah, chan, ¢ers); + return spur_val; - resetFreqBin = FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)); - freqBin = XPA_LVL_FREQ(0) & 0xff; - biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); +#undef EEP_MAP4K_SPURCHAN +} - freqCount++; +static struct eeprom_ops eep_4k_ops = { + .check_eeprom = ath9k_hw_4k_check_eeprom, + .get_eeprom = ath9k_hw_4k_get_eeprom, + .fill_eeprom = ath9k_hw_4k_fill_eeprom, + .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_4k_set_board_values, + .set_addac = ath9k_hw_4k_set_addac, + .set_txpower = ath9k_hw_4k_set_txpower, + .get_spur_channel = ath9k_hw_4k_get_spur_channel +}; - while (freqCount < 3) { - if (XPA_LVL_FREQ(freqCount) == 0x0) - break; +/************************************************/ +/* EEPROM Operations for non-4K (Default) cards */ +/************************************************/ - freqBin = XPA_LVL_FREQ(freqCount) & 0xff; - if (resetFreqBin >= freqBin) - biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); - else - break; - freqCount++; - } - } +static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); +} - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac, - 7, 1) & (~0x18)) | biaslevel << 3; - } else { - INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac, - 6, 1) & (~0xc0)) | biaslevel << 6; +static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.def; + int addr, ar5416_eep_start_loc = 0x100; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; } -#undef XPA_LVL_FREQ + return true; +#undef SIZE_EEPROM_DEF } -static void ath9k_hw_set_4k_addac(struct ath_hal *ah, - struct ath9k_channel *chan) +static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { - struct modal_eep_4k_header *pModal; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; - u8 biaslevel; + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ah->eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); + return false; + } - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); - pModal = &eep->modalHeader; + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - INI_RA(&ahp->ah_iniAddac, 7, 1) = - (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "Endianness mismatch.\n"); + return -EINVAL; + } + } } -} -static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { - ath9k_hw_set_def_addac, - ath9k_hw_set_4k_addac -}; + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.def.baseEepHeader.length); + else + el = ah->eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; -void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) { - struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; - ath9k_set_addac[ahp->ah_eep_map](ah, chan); + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return AR5416_VER_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + case EEP_OL_PWRCTRL: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->openLoopPwrCntl ? true : false; + else + return false; + case EEP_RC_CHAIN_MASK: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->rcChainMask; + else + return 0; + case EEP_DAC_HPWR_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) + return pBase->dacHiPwrMode_5G; + else + return 0; + case EEP_FRAC_N_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) + return pBase->frac_n_5g; + else + return 0; + default: + return 0; + } } +static void ath9k_hw_def_set_gain(struct ath_hw *ah, + struct modal_eep_header *pModal, + struct ar5416_eeprom_def *eep, + u8 txRxAttenLocal, int regChainOffset, int i) +{ + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[i]); + } else { + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) + | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } +} -/* XXX: Clean me up, make me more legible */ -static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_def_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) { struct modal_eep_header *pModal; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; int i, regChainOffset; u8 txRxAttenLocal; - u16 ant_config; pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); for (i = 0; i < AR5416_MAX_CHAINS; i++) { if (AR_SREV_9280(ah)) { @@ -2141,9 +1736,8 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, break; } - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) regChainOffset = (i == 1) ? 0x2000 : 0x1000; else regChainOffset = i * 0x1000; @@ -2152,9 +1746,7 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, pModal->antCtrlChain[i]); REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, - AR_PHY_TIMING_CTRL4(0) + - regChainOffset) & + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | SM(pModal->iqCalICh[i], @@ -2162,89 +1754,9 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - if ((eep->baseEepHeader.version & - AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal-> - bswMargin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal-> - bswAtten[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal-> - xatten2Margin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal-> - xatten2Db[i]); - } else { - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> - bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, - AR_PHY_RXGAIN + - regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) | - SM(txRxAttenLocal, - AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], - AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } - } + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) + ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, + regChainOffset, i); } if (AR_SREV_9280_10_OR_LATER(ah)) { @@ -2291,8 +1803,6 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, AR_AN_TOP2_LOCALBIAS, AR_AN_TOP2_LOCALBIAS_S, pModal->local_bias); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", - pModal->force_xpaon); REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, pModal->force_xpaon); } @@ -2318,6 +1828,7 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + if (AR_SREV_9280_10_OR_LATER(ah)) { REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, pModal->thresh62); @@ -2332,8 +1843,7 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, pModal->thresh62); } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); @@ -2341,296 +1851,880 @@ static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, pModal->txFrameToPaOn); } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { if (IS_CHAN_HT40(chan)) REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); } - return true; + if (AR_SREV_9280_20_OR_LATER(ah) && + AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, + AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, + pModal->miscBits); + + + if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { + if (IS_CHAN_2GHZ(chan)) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + else if (eep->baseEepHeader.dacHiPwrMode_5G) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); + else + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, + pModal->miscBits >> 2); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_DESIRED_SCALE_CCK, + eep->baseEepHeader.desiredScaleCCK); + } } -static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_def_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) { - struct modal_eep_4k_header *pModal; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; - int regChainOffset; - u8 txRxAttenLocal; - u16 ant_config = 0; - u8 ob[5], db1[5], db2[5]; - u8 ant_div_control1, ant_div_control2; - u32 regVal; +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + u8 biaslevel; + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; - pModal = &eep->modalHeader; + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; - txRxAttenLocal = 23; + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; - regChainOffset = 0; - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[0]); + ath9k_hw_get_channel_centers(ah, chan, ¢ers); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[0]; - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); - } + freqCount++; - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } - /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version == 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; } +#undef XPA_LVL_FREQ +} - if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); + ath9k_hw_get_channel_centers(ah, chan, ¢ers); - } else if (pModal->version == 1) { + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Model version is set to 1 \n"); - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } } else { - int i; - for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } } } - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); + k = 0; - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; } - return true; -} + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } -static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, - struct ath9k_channel *) = { - ath9k_hw_eeprom_set_def_board_values, - ath9k_hw_eeprom_set_4k_board_values -}; + return; +} -bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) { - struct ath_hal_5416 *ahp = AH5416(ah); +#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) +#define SM_PDGAIN_B(x, y) \ + SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[0]; + ah->initPDADC = ((struct calDataPerFreqOpLoop *) + pRawDataset)->vpdPdg[0][0]; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + + if (OLC_FOR_AR9280_20_LATER) { + u8 pcdacIdx; + u8 txPower; - return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan); + ath9k_get_txgain_index(ah, chan, + (struct calDataPerFreqOpLoop *)pRawDataset, + pCalBChans, numPiers, &txPower, &pcdacIdx); + ath9k_olc_get_pdadcs(ah, pcdacIdx, + txPower/2, pdadcValues); + } else { + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, + chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, + gainBoundaries, + pdadcValues, + numXpdGain); + } + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(0x6, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM_PD_GAIN(1) | SM_PD_GAIN(2) | + SM_PD_GAIN(3) | SM_PD_GAIN(4)); + } else { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| + SM_PDGAIN_B(0, 1) | + SM_PDGAIN_B(1, 2) | + SM_PDGAIN_B(2, 3) | + SM_PDGAIN_B(3, 4)); + } + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +#undef SM_PD_GAIN +#undef SM_PDGAIN_B } -static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 index, u16 *config) +static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - struct base_eep_header *pBase = &eep->baseEepHeader; +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - switch (index) { - case 0: - *config = pModal->antCtrlCommon & 0xFFFF; - return 0; + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { case 1: - if (pBase->version >= 0x0E0D) { - if (pModal->useAnt1) { - *config = - ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); - return 0; - } - } break; - default: + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; break; } - return -EINVAL; + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + ; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } + return true; } -static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah, +static int ath9k_hw_def_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, - u8 index, u16 *config) + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; +#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i, cck_ofdm_delta = 0; - switch (index) { - case 0: - *config = pModal->antCtrlCommon & 0xFFFF; - return 0; - default: - break; + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - return -EINVAL; -} + if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } -static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, - struct ath9k_channel *, - u8, u16 *) = { - ath9k_hw_get_def_eeprom_antenna_cfg, - ath9k_hw_get_4k_eeprom_antenna_cfg -}; + if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } -int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 index, u16 *config) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } - return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan, - index, config); -} + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } -static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, - enum ieee80211_band freq_band) -{ - return 1; + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + if (OLC_FOR_AR9280_20_LATER) { + cck_ofdm_delta = 2; + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch(ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } + + return 0; } -static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, +static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, enum ieee80211_band freq_band) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct modal_eep_header *pModal = &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); struct base_eep_header *pBase = &eep->baseEepHeader; @@ -2645,180 +2739,75 @@ static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, return num_ant_config; } -static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, - enum ieee80211_band) = { - ath9k_hw_get_def_num_ant_config, - ath9k_hw_get_4k_num_ant_config -}; - -u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, - enum ieee80211_band freq_band) +static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band); + return pModal->antCtrlCommon & 0xFFFF; } -u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) +static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { -#define EEP_MAP4K_SPURCHAN \ - (ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan) #define EEP_DEF_SPURCHAN \ - (ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) - struct ath_hal_5416 *ahp = AH5416(ah); + (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + u16 spur_val = AR_NO_SPUR; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); + i, is2GHz, ah->config.spurchans[i][is2GHz]); - switch (ah->ah_config.spurmode) { + switch (ah->config.spurmode) { case SPUR_DISABLE: break; case SPUR_ENABLE_IOCTL: - spur_val = ah->ah_config.spurchans[i][is2GHz]; + spur_val = ah->config.spurchans[i][is2GHz]; DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: - if (ahp->ah_eep_map == EEP_MAP_4KBITS) - spur_val = EEP_MAP4K_SPURCHAN; - else - spur_val = EEP_DEF_SPURCHAN; + spur_val = EEP_DEF_SPURCHAN; break; - } return spur_val; -#undef EEP_DEF_SPURCHAN -#undef EEP_MAP4K_SPURCHAN -} - -static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah, - enum eeprom_param param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - struct base_eep_header_4k *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_2: - return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_2: - return pModal->ob_01; - case EEP_DB_2: - return pModal->db1_01; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - default: - return 0; - } -} - -static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah, - enum eeprom_param param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - switch (param) { - case EEP_NFTHRESH_5: - return pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_RXGAIN_TYPE: - return pBase->rxGainType; - case EEP_TXGAIN_TYPE: - return pBase->txGainType; - - default: - return 0; - } +#undef EEP_DEF_SPURCHAN } -static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { - ath9k_hw_get_eeprom_def, - ath9k_hw_get_eeprom_4k +static struct eeprom_ops eep_def_ops = { + .check_eeprom = ath9k_hw_def_check_eeprom, + .get_eeprom = ath9k_hw_def_get_eeprom, + .fill_eeprom = ath9k_hw_def_fill_eeprom, + .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_def_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_def_set_board_values, + .set_addac = ath9k_hw_def_set_addac, + .set_txpower = ath9k_hw_def_set_txpower, + .get_spur_channel = ath9k_hw_def_get_spur_channel }; -u32 ath9k_hw_get_eeprom(struct ath_hal *ah, - enum eeprom_param param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - return ath9k_get_eeprom[ahp->ah_eep_map](ah, param); -} - -int ath9k_hw_eeprom_attach(struct ath_hal *ah) +int ath9k_hw_eeprom_attach(struct ath_hw *ah) { int status; - struct ath_hal_5416 *ahp = AH5416(ah); - if (ath9k_hw_use_flash(ah)) - ath9k_hw_flash_map(ah); - - if (AR_SREV_9285(ah)) - ahp->ah_eep_map = EEP_MAP_4KBITS; - else - ahp->ah_eep_map = EEP_MAP_DEFAULT; + if (AR_SREV_9285(ah)) { + ah->eep_map = EEP_MAP_4KBITS; + ah->eep_ops = &eep_4k_ops; + } else { + ah->eep_map = EEP_MAP_DEFAULT; + ah->eep_ops = &eep_def_ops; + } - if (!ath9k_hw_fill_eeprom(ah)) + if (!ah->eep_ops->fill_eeprom(ah)) return -EIO; - status = ath9k_hw_check_eeprom(ah); + status = ah->eep_ops->check_eeprom(ah); return status; } diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h new file mode 100644 index 000000000000..25b68c881ff1 --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.h @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef EEPROM_H +#define EEPROM_H + +#define AH_USE_EEPROM 0x1 + +#ifdef __BIG_ENDIAN +#define AR5416_EEPROM_MAGIC 0x5aa5 +#else +#define AR5416_EEPROM_MAGIC 0xa55a +#endif + +#define CTRY_DEBUG 0x1ff +#define CTRY_DEFAULT 0 + +#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001 +#define AR_EEPROM_EEPCAP_AES_DIS 0x0002 +#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004 +#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008 +#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0 +#define AR_EEPROM_EEPCAP_MAXQCU_S 4 +#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200 +#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000 +#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12 + +#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 + +#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000 +#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000 + +#define AR5416_EEPROM_MAGIC_OFFSET 0x0 +#define AR5416_EEPROM_S 2 +#define AR5416_EEPROM_OFFSET 0x2000 +#define AR5416_EEPROM_MAX 0xae0 + +#define AR5416_EEPROM_START_ADDR \ + (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 + +#define SD_NO_CTL 0xE0 +#define NO_CTL 0xff +#define CTL_MODE_M 7 +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define EXT_ADDITIVE (0x8000) +#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) +#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) +#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) + +#define SUB_NUM_CTL_MODES_AT_5G_40 2 +#define SUB_NUM_CTL_MODES_AT_2G_40 3 + +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + +/* + * For AR9285 and later chipsets, the following bits are not being programmed + * in EEPROM and so need to be enabled always. + * + * Bit 0: en_fcc_mid + * Bit 1: en_jap_mid + * Bit 2: en_fcc_dfs_ht40 + * Bit 3: en_jap_ht40 + * Bit 4: en_jap_dfs_ht40 + */ +#define AR9285_RDEXT_DEFAULT 0x1F + +#define AR_EEPROM_MAC(i) (0x1d+(i)) +#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) +#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) + +#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) +#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ + ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) + +#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c +#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 +#define AR_EEPROM_RFSILENT_POLARITY 0x0002 +#define AR_EEPROM_RFSILENT_POLARITY_S 1 + +#define EEP_RFSILENT_ENABLED 0x0001 +#define EEP_RFSILENT_ENABLED_S 0 +#define EEP_RFSILENT_POLARITY 0x0002 +#define EEP_RFSILENT_POLARITY_S 1 +#define EEP_RFSILENT_GPIO_SEL 0x001c +#define EEP_RFSILENT_GPIO_SEL_S 2 + +#define AR5416_OPFLAGS_11A 0x01 +#define AR5416_OPFLAGS_11G 0x02 +#define AR5416_OPFLAGS_N_5G_HT40 0x04 +#define AR5416_OPFLAGS_N_2G_HT40 0x08 +#define AR5416_OPFLAGS_N_5G_HT20 0x10 +#define AR5416_OPFLAGS_N_2G_HT20 0x20 + +#define AR5416_EEP_NO_BACK_VER 0x1 +#define AR5416_EEP_VER 0xE +#define AR5416_EEP_VER_MINOR_MASK 0x0FFF +#define AR5416_EEP_MINOR_VER_2 0x2 +#define AR5416_EEP_MINOR_VER_3 0x3 +#define AR5416_EEP_MINOR_VER_7 0x7 +#define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 +#define AR5416_EEP_MINOR_VER_20 0x14 +#define AR5416_EEP_MINOR_VER_22 0x16 + +#define AR5416_NUM_5G_CAL_PIERS 8 +#define AR5416_NUM_2G_CAL_PIERS 4 +#define AR5416_NUM_5G_20_TARGET_POWERS 8 +#define AR5416_NUM_5G_40_TARGET_POWERS 8 +#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_NUM_2G_20_TARGET_POWERS 4 +#define AR5416_NUM_2G_40_TARGET_POWERS 4 +#define AR5416_NUM_CTLS 24 +#define AR5416_NUM_BAND_EDGES 8 +#define AR5416_NUM_PD_GAINS 4 +#define AR5416_PD_GAINS_IN_MASK 4 +#define AR5416_PD_GAIN_ICEPTS 5 +#define AR5416_EEPROM_MODAL_SPURS 5 +#define AR5416_MAX_RATE_POWER 63 +#define AR5416_NUM_PDADC_VALUES 128 +#define AR5416_BCHAN_UNUSED 0xFF +#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR5416_MAX_CHAINS 3 +#define AR5416_PWR_TABLE_OFFSET -5 + +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIGINAL 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + +#define AR5416_EEP4K_START_LOC 64 +#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 +#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_CTLS 12 +#define AR5416_EEP4K_NUM_BAND_EDGES 4 +#define AR5416_EEP4K_NUM_PD_GAINS 2 +#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 +#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 +#define AR5416_EEP4K_MAX_CHAINS 1 + +#define AR9280_TX_GAIN_TABLE_SIZE 22 + +enum eeprom_param { + EEP_NFTHRESH_5, + EEP_NFTHRESH_2, + EEP_MAC_MSW, + EEP_MAC_MID, + EEP_MAC_LSW, + EEP_REG_0, + EEP_REG_1, + EEP_OP_CAP, + EEP_OP_MODE, + EEP_RF_SILENT, + EEP_OB_5, + EEP_DB_5, + EEP_OB_2, + EEP_DB_2, + EEP_MINOR_REV, + EEP_TX_MASK, + EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, + EEP_OL_PWRCTRL, + EEP_RC_CHAIN_MASK, + EEP_DAC_HPWR_5G, + EEP_FRAC_N_5G +}; + +enum ar5416_rates { + rate6mb, rate9mb, rate12mb, rate18mb, + rate24mb, rate36mb, rate48mb, rate54mb, + rate1l, rate2l, rate2s, rate5_5l, + rate5_5s, rate11l, rate11s, rateXr, + rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, + rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, + rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, + rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, + rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, + Ar5416RateSize +}; + +enum ath9k_hal_freq_band { + ATH9K_HAL_FREQ_BAND_5GHZ = 0, + ATH9K_HAL_FREQ_BAND_2GHZ = 1 +}; + +struct base_eep_header { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 pwdclkind; + u8 futureBase_1[2]; + u8 rxGainType; + u8 dacHiPwrMode_5G; + u8 openLoopPwrCntl; + u8 dacLpMode; + u8 txGainType; + u8 rcChainMask; + u8 desiredScaleCCK; + u8 power_table_offset; + u8 frac_n_5g; + u8 futureBase_3[21]; +} __packed; + +struct base_eep_header_4k { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 txGainType; +} __packed; + + +struct spur_chan { + u16 spurChan; + u8 spurRangeLow; + u8 spurRangeHigh; +} __packed; + +struct modal_eep_header { + u32 antCtrlChain[AR5416_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_MAX_CHAINS]; + u8 iqCalQCh[AR5416_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob; + u8 db; + u8 xpaBiasLvl; + u8 pwrDecreaseFor2Chain; + u8 pwrDecreaseFor3Chain; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_MAX_CHAINS]; + u8 bswMargin[AR5416_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_MAX_CHAINS]; + u8 xatten2Margin[AR5416_MAX_CHAINS]; + u8 ob_ch1; + u8 db_ch1; + u8 useAnt1:1, + force_xpaon:1, + local_bias:1, + femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1; + u8 miscBits; + u16 xpaBiasLvlFreq[3]; + u8 futureModal[6]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + +struct calDataPerFreqOpLoop { + u8 pwrPdg[2][5]; + u8 vpdPdg[2][5]; + u8 pcdac[2][5]; + u8 empty[2][5]; +} __packed; + +struct modal_eep_4k_header { + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + + +struct cal_data_per_freq { + u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +} __packed; + +struct cal_data_per_freq_4k { + u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; +} __packed; + +struct cal_target_power_leg { + u8 bChannel; + u8 tPow2x[4]; +} __packed; + +struct cal_target_power_ht { + u8 bChannel; + u8 tPow2x[8]; +} __packed; + + +#ifdef __BIG_ENDIAN_BITFIELD +struct cal_ctl_edges { + u8 bChannel; + u8 flag:2, tPower:6; +} __packed; +#else +struct cal_ctl_edges { + u8 bChannel; + u8 tPower:6, flag:2; +} __packed; +#endif + +struct cal_ctl_data { + struct cal_ctl_edges + ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed; + +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; +} __packed; + +struct ar5416_eeprom_def { + struct base_eep_header baseEepHeader; + u8 custData[64]; + struct modal_eep_header modalHeader[2]; + u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; + u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq + calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; + struct cal_data_per_freq + calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_NUM_CTLS]; + struct cal_ctl_data ctlData[AR5416_NUM_CTLS]; + u8 padding; +} __packed; + +struct ar5416_eeprom_4k { + struct base_eep_header_4k baseEepHeader; + u8 custData[20]; + struct modal_eep_4k_header modalHeader; + u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq_4k + calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; + struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; + u8 padding; +} __packed; + +enum reg_ext_bitmap { + REG_EXT_JAPAN_MIDBAND = 1, + REG_EXT_FCC_DFS_HT40 = 2, + REG_EXT_JAPAN_NONDFS_HT40 = 3, + REG_EXT_JAPAN_DFS_HT40 = 4 +}; + +struct ath9k_country_entry { + u16 countryCode; + u16 regDmnEnum; + u16 regDmn5G; + u16 regDmn2G; + u8 isMultidomain; + u8 iso[3]; +}; + +enum ath9k_eep_map { + EEP_MAP_DEFAULT = 0x0, + EEP_MAP_4KBITS, + EEP_MAP_MAX +}; + +struct eeprom_ops { + int (*check_eeprom)(struct ath_hw *hw); + u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); + bool (*fill_eeprom)(struct ath_hw *hw); + int (*get_eeprom_ver)(struct ath_hw *hw); + int (*get_eeprom_rev)(struct ath_hw *hw); + u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band); + u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw, + struct ath9k_channel *chan); + void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); + void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); + int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, + u16 cfgCtl, u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, u8 powerLimit); + u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); +}; + +#define ar5416_get_ntxchains(_txchainmask) \ + (((_txchainmask >> 2) & 1) + \ + ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) + +int ath9k_hw_eeprom_attach(struct ath_hw *ah); + +#endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index c38a00bbce64..b15eaf8417ff 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,88 +17,80 @@ #include <linux/io.h> #include <asm/unaligned.h> -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" +#include "ath9k.h" #include "initvals.h" -static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 }; +static int btcoex_enable; +module_param(btcoex_enable, bool, 0); +MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); -extern struct hal_percal_data iq_cal_multi_sample; -extern struct hal_percal_data iq_cal_single_sample; -extern struct hal_percal_data adc_gain_cal_multi_sample; -extern struct hal_percal_data adc_gain_cal_single_sample; -extern struct hal_percal_data adc_dc_cal_multi_sample; -extern struct hal_percal_data adc_dc_cal_single_sample; -extern struct hal_percal_data adc_init_dc_cal; +#define ATH9K_CLOCK_RATE_CCK 22 +#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 +#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type); -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode); -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, struct ar5416_eeprom_def *pEepData, u32 reg, u32 value); -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); /********************/ /* Helper Functions */ /********************/ -static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) +static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) { - if (ah->ah_curchan != NULL) - return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; - else - return clks / CLOCK_RATE[ATH9K_MODE_11B]; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (!ah->curchan) /* should really check for CCK instead */ + return clks / ATH9K_CLOCK_RATE_CCK; + if (conf->channel->band == IEEE80211_BAND_2GHZ) + return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; + + return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; } -static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) +static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) { - struct ath9k_channel *chan = ah->ah_curchan; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - if (chan && IS_CHAN_HT40(chan)) + if (conf_is_ht40(conf)) return ath9k_hw_mac_usec(ah, clks) / 2; else return ath9k_hw_mac_usec(ah, clks); } -static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) +static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) { - if (ah->ah_curchan != NULL) - return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, - ah->ah_curchan)]; - else - return usecs * CLOCK_RATE[ATH9K_MODE_11B]; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + + if (!ah->curchan) /* should really check for CCK instead */ + return usecs *ATH9K_CLOCK_RATE_CCK; + if (conf->channel->band == IEEE80211_BAND_2GHZ) + return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; + return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM; } -static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) +static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) { - struct ath9k_channel *chan = ah->ah_curchan; + struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - if (chan && IS_CHAN_HT40(chan)) + if (conf_is_ht40(conf)) return ath9k_hw_mac_clks(ah, usecs) * 2; else return ath9k_hw_mac_clks(ah, usecs); } -enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, - const struct ath9k_channel *chan) -{ - if (IS_CHAN_B(chan)) - return ATH9K_MODE_11B; - if (IS_CHAN_G(chan)) - return ATH9K_MODE_11G; - - return ATH9K_MODE_11A; -} - -bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) { int i; - for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) { + BUG_ON(timeout < AH_TIME_QUANTUM); + + for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) { if ((REG_READ(ah, reg) & mask) == val) return true; @@ -106,8 +98,8 @@ bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) } DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - reg, REG_READ(ah, reg), mask, val); + "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + timeout, reg, REG_READ(ah, reg), mask, val); return false; } @@ -124,11 +116,11 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) return retval; } -bool ath9k_get_channel_edges(struct ath_hal *ah, +bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; if (flags & CHANNEL_5GHZ) { *low = pCap->low_5ghz_chan; @@ -143,7 +135,7 @@ bool ath9k_get_channel_edges(struct ath_hal *ah, return false; } -u16 ath9k_hw_computetxtime(struct ath_hal *ah, +u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble) @@ -165,15 +157,15 @@ u16 ath9k_hw_computetxtime(struct ath_hal *ah, txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); break; case WLAN_RC_PHY_OFDM: - if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { + if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_QUARTER + OFDM_PREAMBLE_TIME_QUARTER + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); - } else if (ah->ah_curchan && - IS_CHAN_HALF_RATE(ah->ah_curchan)) { + } else if (ah->curchan && + IS_CHAN_HALF_RATE(ah->curchan)) { bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); @@ -199,52 +191,11 @@ u16 ath9k_hw_computetxtime(struct ath_hal *ah, return txTime; } -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) -{ - if (flags & CHANNEL_2GHZ) { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - else - return 15 + ((freq - 2512) / 20); - } else if (flags & CHANNEL_5GHZ) { - if (ath9k_regd_is_public_safety_sku(ah) && - IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; - } else if ((flags & CHANNEL_A) && (freq <= 5000)) { - return (freq - 4000) / 5; - } else { - return (freq - 5000) / 5; - } - } else { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - if (freq < 5000) { - if (ath9k_regd_is_public_safety_sku(ah) - && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == - 2) ? 5 : 0) - 49400) / 5; - } else if (freq > 4900) { - return (freq - 4000) / 5; - } else { - return 15 + ((freq - 2512) / 20); - } - } - return (freq - 5000) / 5; - } -} - -void ath9k_hw_get_channel_centers(struct ath_hal *ah, +void ath9k_hw_get_channel_centers(struct ath_hw *ah, struct ath9k_channel *chan, struct chan_centers *centers) { int8_t extoff; - struct ath_hal_5416 *ahp = AH5416(ah); if (!IS_CHAN_HT40(chan)) { centers->ctl_center = centers->ext_center = @@ -267,16 +218,15 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah, centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); centers->ext_center = centers->synth_center + (extoff * - ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? + ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? HT40_CHANNEL_CENTER_SHIFT : 15)); - } /******************/ /* Chip Revisions */ /******************/ -static void ath9k_hw_read_revisions(struct ath_hal *ah) +static void ath9k_hw_read_revisions(struct ath_hw *ah) { u32 val; @@ -284,21 +234,22 @@ static void ath9k_hw_read_revisions(struct ath_hal *ah) if (val == 0xFF) { val = REG_READ(ah, AR_SREV); - ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; - ah->ah_macRev = MS(val, AR_SREV_REVISION2); - ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; + ah->hw_version.macVersion = + (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; + ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); + ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; } else { if (!AR_SREV_9100(ah)) - ah->ah_macVersion = MS(val, AR_SREV_VERSION); + ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); - ah->ah_macRev = val & AR_SREV_REVISION; + ah->hw_version.macRev = val & AR_SREV_REVISION; - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) - ah->ah_isPciExpress = true; + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) + ah->is_pciexpress = true; } } -static int ath9k_hw_get_radiorev(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hw *ah) { u32 val; int i; @@ -317,9 +268,9 @@ static int ath9k_hw_get_radiorev(struct ath_hal *ah) /* HW Attach, Detach, Init Routines */ /************************************/ -static void ath9k_hw_disablepcie(struct ath_hal *ah) +static void ath9k_hw_disablepcie(struct ath_hw *ah) { - if (!AR_SREV_9100(ah)) + if (AR_SREV_9100(ah)) return; REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); @@ -335,7 +286,7 @@ static void ath9k_hw_disablepcie(struct ath_hal *ah) REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } -static bool ath9k_hw_chip_test(struct ath_hal *ah) +static bool ath9k_hw_chip_test(struct ath_hw *ah) { u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; u32 regHold[2]; @@ -377,6 +328,7 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah) REG_WRITE(ah, regAddr[i], regHold[i]); } udelay(100); + return true; } @@ -389,6 +341,8 @@ static const char *ath9k_hw_devname(u16 devid) return "Atheros 5418"; case AR9160_DEVID_PCI: return "Atheros 9160"; + case AR5416_AR9100_DEVID: + return "Atheros 9100"; case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: return "Atheros 9280"; @@ -399,44 +353,44 @@ static const char *ath9k_hw_devname(u16 devid) return NULL; } -static void ath9k_hw_set_defaults(struct ath_hal *ah) +static void ath9k_hw_set_defaults(struct ath_hw *ah) { int i; - ah->ah_config.dma_beacon_response_time = 2; - ah->ah_config.sw_beacon_response_time = 10; - ah->ah_config.additional_swba_backoff = 0; - ah->ah_config.ack_6mb = 0x0; - ah->ah_config.cwm_ignore_extcca = 0; - ah->ah_config.pcie_powersave_enable = 0; - ah->ah_config.pcie_l1skp_enable = 0; - ah->ah_config.pcie_clock_req = 0; - ah->ah_config.pcie_power_reset = 0x100; - ah->ah_config.pcie_restore = 0; - ah->ah_config.pcie_waen = 0; - ah->ah_config.analog_shiftreg = 1; - ah->ah_config.ht_enable = 1; - ah->ah_config.ofdm_trig_low = 200; - ah->ah_config.ofdm_trig_high = 500; - ah->ah_config.cck_trig_high = 200; - ah->ah_config.cck_trig_low = 100; - ah->ah_config.enable_ani = 1; - ah->ah_config.noise_immunity_level = 4; - ah->ah_config.ofdm_weaksignal_det = 1; - ah->ah_config.cck_weaksignal_thr = 0; - ah->ah_config.spur_immunity_level = 2; - ah->ah_config.firstep_level = 0; - ah->ah_config.rssi_thr_high = 40; - ah->ah_config.rssi_thr_low = 7; - ah->ah_config.diversity_control = 0; - ah->ah_config.antenna_switch_swap = 0; + ah->config.dma_beacon_response_time = 2; + ah->config.sw_beacon_response_time = 10; + ah->config.additional_swba_backoff = 0; + ah->config.ack_6mb = 0x0; + ah->config.cwm_ignore_extcca = 0; + ah->config.pcie_powersave_enable = 0; + ah->config.pcie_l1skp_enable = 0; + ah->config.pcie_clock_req = 0; + ah->config.pcie_power_reset = 0x100; + ah->config.pcie_restore = 0; + ah->config.pcie_waen = 0; + ah->config.analog_shiftreg = 1; + ah->config.ht_enable = 1; + ah->config.ofdm_trig_low = 200; + ah->config.ofdm_trig_high = 500; + ah->config.cck_trig_high = 200; + ah->config.cck_trig_low = 100; + ah->config.enable_ani = 1; + ah->config.noise_immunity_level = 4; + ah->config.ofdm_weaksignal_det = 1; + ah->config.cck_weaksignal_thr = 0; + ah->config.spur_immunity_level = 2; + ah->config.firstep_level = 0; + ah->config.rssi_thr_high = 40; + ah->config.rssi_thr_low = 7; + ah->config.diversity_control = 0; + ah->config.antenna_switch_swap = 0; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->ah_config.spurchans[i][0] = AR_NO_SPUR; - ah->ah_config.spurchans[i][1] = AR_NO_SPUR; + ah->config.spurchans[i][0] = AR_NO_SPUR; + ah->config.spurchans[i][1] = AR_NO_SPUR; } - ah->ah_config.intr_mitigation = 1; + ah->config.intr_mitigation = 1; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -455,62 +409,54 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) * devices (legacy, 802.11abg). */ if (num_possible_cpus() > 1) - ah->ah_config.serialize_regmode = SER_REG_MODE_AUTO; + ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) +static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, + int *status) { - static const u8 defbssidmask[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct ath_hal_5416 *ahp; - struct ath_hal *ah; + struct ath_hw *ah; - ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); - if (ahp == NULL) { + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, "Cannot allocate memory for state block\n"); *status = -ENOMEM; return NULL; } - ah = &ahp->ah; ah->ah_sc = sc; - ah->ah_sh = mem; - ah->ah_magic = AR5416_MAGIC; - ah->ah_countryCode = CTRY_DEFAULT; - ah->ah_devid = devid; - ah->ah_subvendorid = 0; + ah->hw_version.magic = AR5416_MAGIC; + ah->regulatory.country_code = CTRY_DEFAULT; + ah->hw_version.devid = devid; + ah->hw_version.subvendorid = 0; ah->ah_flags = 0; if ((devid == AR5416_AR9100_DEVID)) - ah->ah_macVersion = AR_SREV_VERSION_9100; + ah->hw_version.macVersion = AR_SREV_VERSION_9100; if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; - ah->ah_powerLimit = MAX_RATE_POWER; - ah->ah_tpScale = ATH9K_TP_SCALE_MAX; - ahp->ah_atimWindow = 0; - ahp->ah_diversityControl = ah->ah_config.diversity_control; - ahp->ah_antennaSwitchSwap = - ah->ah_config.antenna_switch_swap; - ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; - ahp->ah_beaconInterval = 100; - ahp->ah_enable32kHzClock = DONT_USE_32KHZ; - ahp->ah_slottime = (u32) -1; - ahp->ah_acktimeout = (u32) -1; - ahp->ah_ctstimeout = (u32) -1; - ahp->ah_globaltxtimeout = (u32) -1; - memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN); - - ahp->ah_gBeaconRate = 0; + ah->regulatory.power_limit = MAX_RATE_POWER; + ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; + ah->atim_window = 0; + ah->diversity_control = ah->config.diversity_control; + ah->antenna_switch_swap = + ah->config.antenna_switch_swap; + ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; + ah->beacon_interval = 100; + ah->enable_32kHz_clock = DONT_USE_32KHZ; + ah->slottime = (u32) -1; + ah->acktimeout = (u32) -1; + ah->ctstimeout = (u32) -1; + ah->globaltxtimeout = (u32) -1; + + ah->gbeacon_rate = 0; - return ahp; + return ah; } -static int ath9k_hw_rfattach(struct ath_hal *ah) +static int ath9k_hw_rfattach(struct ath_hw *ah) { bool rfStatus = false; int ecode = 0; @@ -525,7 +471,7 @@ static int ath9k_hw_rfattach(struct ath_hal *ah) return 0; } -static int ath9k_hw_rf_claim(struct ath_hal *ah) +static int ath9k_hw_rf_claim(struct ath_hw *ah) { u32 val; @@ -545,88 +491,87 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "5G Radio Chip Rev 0x%02X is not " "supported by this driver\n", - ah->ah_analog5GhzRev); + ah->hw_version.analog5GhzRev); return -EOPNOTSUPP; } - ah->ah_analog5GhzRev = val; + ah->hw_version.analog5GhzRev = val; return 0; } -static int ath9k_hw_init_macaddr(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hw *ah) { u32 sum; int i; u16 eeval; - struct ath_hal_5416 *ahp = AH5416(ah); sum = 0; for (i = 0; i < 3; i++) { - eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i)); + eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i)); sum += eeval; - ahp->ah_macaddr[2 * i] = eeval >> 8; - ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; + ah->macaddr[2 * i] = eeval >> 8; + ah->macaddr[2 * i + 1] = eeval & 0xff; } if (sum == 0 || sum == 0xffff * 3) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "mac address read failed: %pM\n", - ahp->ah_macaddr); + ah->macaddr); return -EADDRNOTAVAIL; } return 0; } -static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah) +static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah) { u32 rxgain_type; - struct ath_hal_5416 *ahp = AH5416(ah); - if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { - rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE); + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) - INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_backoff_13db_rxgain_9280_2, ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) - INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_backoff_23db_rxgain_9280_2, ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); else - INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_original_rxgain_9280_2, ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); - } else - INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + } else { + INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_original_rxgain_9280_2, ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } } -static void ath9k_hw_init_txgain_ini(struct ath_hal *ah) +static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) { u32 txgain_type; - struct ath_hal_5416 *ahp = AH5416(ah); - if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { - txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE); + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) - INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_high_power_tx_gain_9280_2, ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); else - INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_original_tx_gain_9280_2, ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); - } else - INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_original_tx_gain_9280_2, ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } } -static int ath9k_hw_post_attach(struct ath_hal *ah) +static int ath9k_hw_post_attach(struct ath_hw *ah) { int ecode; @@ -643,6 +588,10 @@ static int ath9k_hw_post_attach(struct ath_hal *ah) ecode = ath9k_hw_eeprom_attach(ah); if (ecode != 0) return ecode; + + DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", + ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); + ecode = ath9k_hw_rfattach(ah); if (ecode != 0) return ecode; @@ -655,238 +604,229 @@ static int ath9k_hw_post_attach(struct ath_hal *ah) return 0; } -static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, - void __iomem *mem, int *status) +static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, + int *status) { - struct ath_hal_5416 *ahp; - struct ath_hal *ah; + struct ath_hw *ah; int ecode; u32 i, j; - ahp = ath9k_hw_newstate(devid, sc, mem, status); - if (ahp == NULL) + ah = ath9k_hw_newstate(devid, sc, status); + if (ah == NULL) return NULL; - ah = &ahp->ah; - ath9k_hw_set_defaults(ah); - if (ah->ah_config.intr_mitigation != 0) - ahp->ah_intrMitigation = true; + if (ah->config.intr_mitigation != 0) + ah->intr_mitigation = true; if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n"); + DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n"); ecode = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); + DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); ecode = -EIO; goto bad; } - if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI || - (AR_SREV_9280(ah) && !ah->ah_isPciExpress)) { - ah->ah_config.serialize_regmode = + if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + (AR_SREV_9280(ah) && !ah->is_pciexpress)) { + ah->config.serialize_regmode = SER_REG_MODE_ON; } else { - ah->ah_config.serialize_regmode = + ah->config.serialize_regmode = SER_REG_MODE_OFF; } } - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "serialize_regmode is %d\n", - ah->ah_config.serialize_regmode); + DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); - if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->ah_macVersion != AR_SREV_VERSION_9160) && + if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && + (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(sc, ATH_DBG_RESET, "Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", ah->ah_macVersion, ah->ah_macRev); + "this driver\n", ah->hw_version.macVersion, + ah->hw_version.macRev); ecode = -EOPNOTSUPP; goto bad; } if (AR_SREV_9100(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_suppCals = IQ_MISMATCH_CAL; - ah->ah_isPciExpress = false; + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->supp_cals = IQ_MISMATCH_CAL; + ah->is_pciexpress = false; } - ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); if (AR_SREV_9160_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_single_sample; - ahp->ah_adcGainCalData.calData = + ah->iq_caldata.calData = &iq_cal_single_sample; + ah->adcgain_caldata.calData = &adc_gain_cal_single_sample; - ahp->ah_adcDcCalData.calData = + ah->adcdc_caldata.calData = &adc_dc_cal_single_sample; - ahp->ah_adcDcCalInitData.calData = + ah->adcdc_calinitdata.calData = &adc_init_dc_cal; } else { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_adcGainCalData.calData = + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->adcgain_caldata.calData = &adc_gain_cal_multi_sample; - ahp->ah_adcDcCalData.calData = + ah->adcdc_caldata.calData = &adc_dc_cal_multi_sample; - ahp->ah_adcDcCalInitData.calData = + ah->adcdc_calinitdata.calData = &adc_init_dc_cal; } - ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; } - if (AR_SREV_9160(ah)) { - ah->ah_config.enable_ani = 1; - ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - } else { - ahp->ah_ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - } - } + ah->ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(sc, ATH_DBG_RESET, "This Mac Chip Rev 0x%02x.%x is \n", - ah->ah_macVersion, ah->ah_macRev); + ah->hw_version.macVersion, ah->hw_version.macRev); if (AR_SREV_9285_12_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2, + + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, ARRAY_SIZE(ar9285Modes_9285_1_2), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2, + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, ARRAY_SIZE(ar9285Common_9285_1_2), 2); - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9285PciePhy_clkreq_off_L1_9285_1_2, ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9285PciePhy_clkreq_always_on_L1_9285_1_2, ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), 2); } } else if (AR_SREV_9285_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285, + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285, ARRAY_SIZE(ar9285Modes_9285), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285, + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285, ARRAY_SIZE(ar9285Common_9285), 2); - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9285PciePhy_clkreq_off_L1_9285, ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9285PciePhy_clkreq_always_on_L1_9285, ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); } } else if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, ARRAY_SIZE(ar9280Common_9280_2), 2); - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9280PciePhy_clkreq_off_L1_9280, ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + INIT_INI_ARRAY(&ah->iniPcieSerdes, ar9280PciePhy_clkreq_always_on_L1_9280, ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); } - INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesAdditional, ar9280Modes_fast_clock_9280_2, ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280, ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280, ARRAY_SIZE(ar9280Common_9280), 2); } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, ARRAY_SIZE(ar5416Bank7_9160), 2); if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniAddac, + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_91601_1, ARRAY_SIZE(ar5416Addac_91601_1), 2); } else { - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, ARRAY_SIZE(ar5416Addac_9160), 2); } } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, ARRAY_SIZE(ar5416Addac_9100), 2); } else { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, ARRAY_SIZE(ar5416Addac), 2); } - if (ah->ah_isPciExpress) + if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, 0); else ath9k_hw_disablepcie(ah); @@ -895,6 +835,22 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (ecode != 0) goto bad; + if (AR_SREV_9285_12_OR_LATER(ah)) { + u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + + /* txgain table */ + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_high_power_tx_gain_9285_1_2, + ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_original_tx_gain_9285_1_2, + ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6); + } + + } + /* rxgain table */ if (AR_SREV_9280_20(ah)) ath9k_hw_init_rxgain_ini(ah); @@ -903,53 +859,55 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_20(ah)) ath9k_hw_init_txgain_ini(ah); - if (ah->ah_devid == AR9280_DEVID_PCI) { - for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); + if (!ath9k_hw_fill_cap_info(ah)) { + DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n"); + ecode = -EINVAL; + goto bad; + } + + if ((ah->hw_version.devid == AR9280_DEVID_PCI) && + test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { + + /* EEPROM Fixup */ + for (i = 0; i < ah->iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniModes, i, 0); - for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { - u32 val = INI_RA(&ahp->ah_iniModes, i, j); + for (j = 1; j < ah->iniModes.ia_columns; j++) { + u32 val = INI_RA(&ah->iniModes, i, j); - INI_RA(&ahp->ah_iniModes, i, j) = + INI_RA(&ah->iniModes, i, j) = ath9k_hw_ini_fixup(ah, - &ahp->ah_eeprom.def, + &ah->eeprom.def, reg, val); } } } - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "failed ath9k_hw_fill_cap_info\n"); - ecode = -EINVAL; - goto bad; - } - ecode = ath9k_hw_init_macaddr(ah); if (ecode != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(sc, ATH_DBG_RESET, "failed initializing mac address\n"); goto bad; } if (AR_SREV_9285(ah)) - ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); + ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); else - ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); + ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); ath9k_init_nfcal_hist_buffer(ah); return ah; bad: - if (ahp) - ath9k_hw_detach((struct ath_hal *) ahp); + if (ah) + ath9k_hw_detach(ah); if (status) *status = ecode; return NULL; } -static void ath9k_hw_init_bb(struct ath_hal *ah, +static void ath9k_hw_init_bb(struct ath_hw *ah, struct ath9k_channel *chan) { u32 synthDelay; @@ -965,7 +923,7 @@ static void ath9k_hw_init_bb(struct ath_hal *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static void ath9k_hw_init_qos(struct ath_hal *ah) +static void ath9k_hw_init_qos(struct ath_hw *ah) { REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); @@ -982,7 +940,7 @@ static void ath9k_hw_init_qos(struct ath_hal *ah) REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } -static void ath9k_hw_init_pll(struct ath_hal *ah, +static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { u32 pll; @@ -1043,27 +1001,26 @@ static void ath9k_hw_init_pll(struct ath_hal *ah, pll |= SM(0xb, AR_RTC_PLL_DIV); } } - REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); + REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); udelay(RTC_PLL_SETTLE_DELAY); REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } -static void ath9k_hw_init_chain_masks(struct ath_hal *ah) +static void ath9k_hw_init_chain_masks(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); int rx_chainmask, tx_chainmask; - rx_chainmask = ahp->ah_rxchainmask; - tx_chainmask = ahp->ah_txchainmask; + rx_chainmask = ah->rxchainmask; + tx_chainmask = ah->txchainmask; switch (rx_chainmask) { case 0x5: REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); case 0x3: - if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) { + if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); break; @@ -1088,28 +1045,26 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, +static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_maskReg = AR_IMR_TXERR | + ah->mask_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ahp->ah_intrMitigation) - ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + if (ah->intr_mitigation) + ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else - ahp->ah_maskReg |= AR_IMR_RXOK; + ah->mask_reg |= AR_IMR_RXOK; - ahp->ah_maskReg |= AR_IMR_TXOK; + ah->mask_reg |= AR_IMR_TXOK; if (opmode == NL80211_IFTYPE_AP) - ahp->ah_maskReg |= AR_IMR_MIB; + ah->mask_reg |= AR_IMR_MIB; - REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + REG_WRITE(ah, AR_IMR, ah->mask_reg); REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); if (!AR_SREV_9100(ah)) { @@ -1119,72 +1074,64 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, } } -static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) +static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); - ahp->ah_acktimeout = (u32) -1; + ah->acktimeout = (u32) -1; return false; } else { REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_acktimeout = us; + ah->acktimeout = us; return true; } } -static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) +static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); - ahp->ah_ctstimeout = (u32) -1; + ah->ctstimeout = (u32) -1; return false; } else { REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_ctstimeout = us; + ah->ctstimeout = us; return true; } } -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) +static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (tu > 0xFFFF) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, "bad global tx timeout %u\n", tu); - ahp->ah_globaltxtimeout = (u32) -1; + ah->globaltxtimeout = (u32) -1; return false; } else { REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); - ahp->ah_globaltxtimeout = tu; + ah->globaltxtimeout = tu; return true; } } -static void ath9k_hw_init_user_settings(struct ath_hal *ah) +static void ath9k_hw_init_user_settings(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", + ah->misc_mode); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n", - ahp->ah_miscMode); - - if (ahp->ah_miscMode != 0) + if (ah->misc_mode != 0) REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); - if (ahp->ah_slottime != (u32) -1) - ath9k_hw_setslottime(ah, ahp->ah_slottime); - if (ahp->ah_acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); - if (ahp->ah_ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); - if (ahp->ah_globaltxtimeout != (u32) -1) - ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); + REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); + if (ah->slottime != (u32) -1) + ath9k_hw_setslottime(ah, ah->slottime); + if (ah->acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ah->acktimeout); + if (ah->ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); + if (ah->globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); } const char *ath9k_hw_probe(u16 vendorid, u16 devid) @@ -1193,7 +1140,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid) ath9k_hw_devname(devid) : NULL; } -void ath9k_hw_detach(struct ath_hal *ah) +void ath9k_hw_detach(struct ath_hw *ah) { if (!AR_SREV_9100(ah)) ath9k_hw_ani_detach(ah); @@ -1203,19 +1150,19 @@ void ath9k_hw_detach(struct ath_hal *ah) kfree(ah); } -struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, - void __iomem *mem, int *error) +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) { - struct ath_hal *ah = NULL; + struct ath_hw *ah = NULL; switch (devid) { case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: case AR9160_DEVID_PCI: case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: case AR9285_DEVID_PCIE: - ah = ath9k_hw_do_attach(devid, sc, mem, error); + ah = ath9k_hw_do_attach(devid, sc, error); break; default: *error = -ENXIO; @@ -1229,7 +1176,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, /* INI */ /*******/ -static void ath9k_hw_override_ini(struct ath_hal *ah, +static void ath9k_hw_override_ini(struct ath_hw *ah, struct ath9k_channel *chan) { /* @@ -1240,20 +1187,20 @@ static void ath9k_hw_override_ini(struct ath_hal *ah, REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - if (!AR_SREV_5416_V20_OR_LATER(ah) || + if (!AR_SREV_5416_20_OR_LATER(ah) || AR_SREV_9280_10_OR_LATER(ah)) return; REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah, +static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, struct ar5416_eeprom_def *pEepData, u32 reg, u32 value) { struct base_eep_header *pBase = &(pEepData->baseEepHeader); - switch (ah->ah_devid) { + switch (ah->hw_version.devid) { case AR9280_DEVID_PCI: if (reg == 0x7894) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, @@ -1281,24 +1228,33 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah, return value; } -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, +static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, struct ar5416_eeprom_def *pEepData, u32 reg, u32 value) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (ahp->ah_eep_map == EEP_MAP_4KBITS) + if (ah->eep_map == EEP_MAP_4KBITS) return value; else return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); } -static int ath9k_hw_process_ini(struct ath_hal *ah, +static void ath9k_olc_init(struct ath_hw *ah) +{ + u32 i; + + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; +} + +static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { int i, regWrites = 0; - struct ath_hal_5416 *ahp = AH5416(ah); + struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; int status; @@ -1330,40 +1286,38 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, } REG_WRITE(ah, AR_PHY(0), 0x00000007); - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); + ah->eep_ops->set_addac(ah, chan); - ath9k_hw_set_addac(ah, chan); - - if (AR_SREV_5416_V22_OR_LATER(ah)) { - REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites); + if (AR_SREV_5416_22_OR_LATER(ah)) { + REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); } else { struct ar5416IniArray temp; u32 addacSize = - sizeof(u32) * ahp->ah_iniAddac.ia_rows * - ahp->ah_iniAddac.ia_columns; + sizeof(u32) * ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns; - memcpy(ahp->ah_addac5416_21, - ahp->ah_iniAddac.ia_array, addacSize); + memcpy(ah->addac5416_21, + ah->iniAddac.ia_array, addacSize); - (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0; + (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; - temp.ia_array = ahp->ah_addac5416_21; - temp.ia_columns = ahp->ah_iniAddac.ia_columns; - temp.ia_rows = ahp->ah_iniAddac.ia_rows; + temp.ia_array = ah->addac5416_21; + temp.ia_columns = ah->iniAddac.ia_columns; + temp.ia_rows = ah->iniAddac.ia_rows; REG_WRITE_ARRAY(&temp, 1, regWrites); } REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); - for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex); + for (i = 0; i < ah->iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniModes, i, 0); + u32 val = INI_RA(&ah->iniModes, i, modesIndex); REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->ah_config.analog_shiftreg) { + && ah->config.analog_shiftreg) { udelay(100); } @@ -1371,19 +1325,20 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, } if (AR_SREV_9280(ah)) - REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); + REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280(ah)) - REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); + if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) && + AR_SREV_9285_12_OR_LATER(ah))) + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); - for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); - u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); + for (i = 0; i < ah->iniCommon.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniCommon, i, 0); + u32 val = INI_RA(&ah->iniCommon, i, 1); REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->ah_config.analog_shiftreg) { + && ah->config.analog_shiftreg) { udelay(100); } @@ -1393,7 +1348,7 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { - REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex, + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); } @@ -1401,13 +1356,15 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, ath9k_hw_set_regs(ah, chan, macmode); ath9k_hw_init_chain_masks(ah); - status = ath9k_hw_set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, - chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)); + if (OLC_FOR_AR9280_20_LATER) + ath9k_olc_init(ah); + + status = ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); if (status != 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "error init'ing transmit power\n"); @@ -1427,7 +1384,7 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, /* Reset and Channel Switching Routines */ /****************************************/ -static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) +static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) { u32 rfMode = 0; @@ -1447,12 +1404,12 @@ static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) REG_WRITE(ah, AR_PHY_MODE, rfMode); } -static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) +static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah) { REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); } -static inline void ath9k_hw_set_dma(struct ath_hal *ah) +static inline void ath9k_hw_set_dma(struct ath_hw *ah) { u32 regval; @@ -1462,7 +1419,7 @@ static inline void ath9k_hw_set_dma(struct ath_hal *ah) regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); @@ -1478,7 +1435,7 @@ static inline void ath9k_hw_set_dma(struct ath_hal *ah) } } -static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) +static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) { u32 val; @@ -1491,6 +1448,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE); REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); @@ -1502,7 +1460,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) } } -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, u32 *coef_mantissa, u32 *coef_exponent) @@ -1521,7 +1479,7 @@ static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, *coef_exponent = coef_exp - 16; } -static void ath9k_hw_set_delta_slope(struct ath_hal *ah, +static void ath9k_hw_set_delta_slope(struct ath_hw *ah, struct ath9k_channel *chan) { u32 coef_scaled, ds_coef_exp, ds_coef_man; @@ -1555,11 +1513,19 @@ static void ath9k_hw_set_delta_slope(struct ath_hal *ah, AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); } -static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) +static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) { u32 rst_flags; u32 tmpReg; + if (AR_SREV_9100(ah)) { + u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); + val &= ~AR_RTC_DERIVED_CLK_PERIOD; + val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); + REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); + (void)REG_READ(ah, AR_RTC_DERIVED_CLK); + } + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1582,11 +1548,11 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) rst_flags |= AR_RTC_RC_MAC_COLD; } - REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); + REG_WRITE(ah, AR_RTC_RC, rst_flags); udelay(50); - REG_WRITE(ah, (u16) (AR_RTC_RC), 0); - if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { + REG_WRITE(ah, AR_RTC_RC, 0); + if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC stuck in MAC reset\n"); return false; @@ -1603,18 +1569,20 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) return true; } -static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); - REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); + REG_WRITE(ah, AR_RTC_RESET, 0); + udelay(2); + REG_WRITE(ah, AR_RTC_RESET, 1); if (!ath9k_hw_wait(ah, AR_RTC_STATUS, AR_RTC_STATUS_M, - AR_RTC_STATUS_ON)) { + AR_RTC_STATUS_ON, + AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); return false; } @@ -1624,7 +1592,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); } -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type) +static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1642,12 +1610,11 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type) } } -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { u32 phymode; u32 enableDacFifo = 0; - struct ath_hal_5416 *ahp = AH5416(ah); if (AR_SREV_9285_10_OR_LATER(ah)) enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & @@ -1663,7 +1630,7 @@ static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, (chan->chanmode == CHANNEL_G_HT40PLUS)) phymode |= AR_PHY_FC_DYN2040_PRI_CH; - if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) + if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25) phymode |= AR_PHY_FC_DYN2040_EXT_CH; } REG_WRITE(ah, AR_PHY_TURBO, phymode); @@ -1674,54 +1641,30 @@ static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); } -static bool ath9k_hw_chip_reset(struct ath_hal *ah, +static bool ath9k_hw_chip_reset(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) + if (OLC_FOR_AR9280_20_LATER) { + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) + return false; + } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return false; - ahp->ah_chipFullSleep = false; - + ah->chip_fullsleep = false; ath9k_hw_init_pll(ah, chan); - ath9k_hw_set_rfmode(ah, chan); return true; } -static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "invalid channel %u/0x%x; not marked as " - "2GHz or 5GHz\n", chan->channel, chan->channelFlags); - return NULL; - } - - if (!IS_CHAN_OFDM(chan) && - !IS_CHAN_B(chan) && - !IS_CHAN_HT20(chan) && - !IS_CHAN_HT40(chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "invalid channel %u/0x%x; not marked as " - "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", - chan->channel, chan->channelFlags); - return NULL; - } - - return ath9k_regd_check_channel(ah, chan); -} - -static bool ath9k_hw_channel_change(struct ath_hal *ah, +static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { @@ -1734,7 +1677,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, - AR_PHY_RFBUS_GRANT_EN)) { + AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Could not kill baseband RX\n"); return false; @@ -1756,12 +1699,12 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, } } - if (ath9k_hw_set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)) != 0) { + if (ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "error init'ing transmit power\n"); return false; @@ -1791,7 +1734,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, return true; } -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) +static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) { int bb_spur = AR_NO_SPUR; int freq; @@ -1825,9 +1768,9 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel ath9k_hw_get_channel_centers(ah, chan, ¢ers); freq = centers.synth_center; - ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; + ah->config.spurmode = SPUR_ENABLE_EEPROM; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); if (is2GHz) cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; @@ -1938,9 +1881,9 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); + volatile int tmp_v = abs(cur_vit_mask - bin); - if (tmp < 75) + if (tmp_v < 75) mask_amt = 1; else mask_amt = 0; @@ -2041,7 +1984,7 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) +static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) { int bb_spur = AR_NO_SPUR; int bin, cur_bin; @@ -2070,7 +2013,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha memset(&mask_p, 0, sizeof(int8_t) * 123); for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); if (AR_NO_SPUR == cur_bb_spur) break; cur_bb_spur = cur_bb_spur - (chan->channel * 10); @@ -2139,9 +2082,9 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); + volatile int tmp_v = abs(cur_vit_mask - bin); - if (tmp < 75) + if (tmp_v < 75) mask_amt = 1; else mask_amt = 0; @@ -2242,58 +2185,47 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode, - u8 txchainmask, u8 rxchainmask, - enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, int *status) +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + bool bChannelChange) { u32 saveLedState; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *curchan = ah->ah_curchan; + struct ath_softc *sc = ah->ah_sc; + struct ath9k_channel *curchan = ah->curchan; u32 saveDefAntenna; u32 macStaId1; - int ecode; - int i, rx_chainmask; + int i, rx_chainmask, r; - ahp->ah_extprotspacing = extprotspacing; - ahp->ah_txchainmask = txchainmask; - ahp->ah_rxchainmask = rxchainmask; + ah->extprotspacing = sc->ht_extprotspacing; + ah->txchainmask = sc->tx_chainmask; + ah->rxchainmask = sc->rx_chainmask; - if (AR_SREV_9280(ah)) { - ahp->ah_txchainmask &= 0x3; - ahp->ah_rxchainmask &= 0x3; - } - - if (ath9k_hw_check_chan(ah, chan) == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "invalid channel %u/0x%x; no mapping\n", - chan->channel, chan->channelFlags); - ecode = -EINVAL; - goto bad; + if (AR_SREV_9285(ah)) { + ah->txchainmask &= 0x1; + ah->rxchainmask &= 0x1; + } else if (AR_SREV_9280(ah)) { + ah->txchainmask &= 0x3; + ah->rxchainmask &= 0x3; } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - ecode = -EIO; - goto bad; - } + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return -EIO; if (curchan) ath9k_hw_getnf(ah, curchan); if (bChannelChange && - (ahp->ah_chipFullSleep != true) && - (ah->ah_curchan != NULL) && - (chan->channel != ah->ah_curchan->channel) && + (ah->chip_fullsleep != true) && + (ah->curchan != NULL) && + (chan->channel != ah->curchan->channel) && ((chan->channelFlags & CHANNEL_ALL) == - (ah->ah_curchan->channelFlags & CHANNEL_ALL)) && + (ah->curchan->channelFlags & CHANNEL_ALL)) && (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && - !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) { + !IS_CHAN_A_5MHZ_SPACED(ah->curchan)))) { - if (ath9k_hw_channel_change(ah, chan, macmode)) { - ath9k_hw_loadnf(ah, ah->ah_curchan); + if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) { + ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah); - return true; + return 0; } } @@ -2311,28 +2243,32 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, if (!ath9k_hw_chip_reset(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); - ecode = -EINVAL; - goto bad; + return -EINVAL; } - if (AR_SREV_9280(ah)) { - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_JTAG_DISABLE); + if (AR_SREV_9280_10_OR_LATER(ah)) + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes)) { - if (IS_CHAN_5GHZ(chan)) - ath9k_hw_set_gpio(ah, 9, 0); - else - ath9k_hw_set_gpio(ah, 9, 1); - } - ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - } + r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); + if (r) + return r; - ecode = ath9k_hw_process_ini(ah, chan, macmode); - if (ecode != 0) { - ecode = -EINVAL; - goto bad; - } + /* Setup MFP options for CCMP */ + if (AR_SREV_9280_20_OR_LATER(ah)) { + /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt + * frames when constructing CCMP AAD. */ + REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, + 0xc7ff); + ah->sw_mgmt_crypto = false; + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + /* Disable hardware crypto for management frames */ + REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); + REG_SET_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); + ah->sw_mgmt_crypto = true; + } else + ah->sw_mgmt_crypto = true; if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); @@ -2342,61 +2278,52 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, else ath9k_hw_spur_mitigate(ah, chan); - if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "error setting board options\n"); - ecode = -EIO; - goto bad; - } + ah->eep_ops->set_board_values(ah, chan); ath9k_hw_decrease_chain_power(ah, chan); - REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ahp->ah_macaddr)); - REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ahp->ah_macaddr + 4) + REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr)); + REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF - | (ah->ah_config. + | (ah->config. ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) - | ahp->ah_staId1Defaults); - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); + | ah->sta_id1_defaults); + ath9k_hw_set_operating_mode(ah, ah->opmode); - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | - ((ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S)); + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | + ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); REG_WRITE(ah, AR_ISR, ~0); REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { - ecode = -EIO; - goto bad; - } + if (!(ath9k_hw_ar9280_set_channel(ah, chan))) + return -EIO; } else { - if (!(ath9k_hw_set_channel(ah, chan))) { - ecode = -EIO; - goto bad; - } + if (!(ath9k_hw_set_channel(ah, chan))) + return -EIO; } for (i = 0; i < AR_NUM_DCU; i++) REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); - ahp->ah_intrTxqs = 0; - for (i = 0; i < ah->ah_caps.total_queues; i++) + ah->intr_txqs = 0; + for (i = 0; i < ah->caps.total_queues; i++) ath9k_hw_resettxqueue(ah, i); - ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); + ath9k_hw_init_interrupt_masks(ah, ah->opmode); ath9k_hw_init_qos(ah); #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); #endif ath9k_hw_init_user_settings(ah); @@ -2408,7 +2335,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_OBS, 8); - if (ahp->ah_intrMitigation) { + if (ah->intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); @@ -2416,12 +2343,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, ath9k_hw_init_bb(ah, chan); - if (!ath9k_hw_init_cal(ah, chan)){ - ecode = -EIO;; - goto bad; - } + if (!ath9k_hw_init_cal(ah, chan)) + return -EIO;; - rx_chainmask = ahp->ah_rxchainmask; + rx_chainmask = ah->rxchainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); @@ -2448,22 +2373,18 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, #endif } - return true; -bad: - if (status) - *status = ecode; - return false; + return 0; } /************************/ /* Key Cache Management */ /************************/ -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) { u32 keyType; - if (entry >= ah->ah_caps.keycache_size) { + if (entry >= ah->caps.keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, "entry %u out of range\n", entry); return false; @@ -2490,17 +2411,17 @@ bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) } - if (ah->ah_curchan == NULL) + if (ah->curchan == NULL) return true; return true; } -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) { u32 macHi, macLo; - if (entry >= ah->ah_caps.keycache_size) { + if (entry >= ah->caps.keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, "entry %u out of range\n", entry); return false; @@ -2524,17 +2445,13 @@ bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) return true; } -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, const struct ath9k_keyval *k, - const u8 *mac, int xorKey) + const u8 *mac) { - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + const struct ath9k_hw_capabilities *pCap = &ah->caps; u32 key0, key1, key2, key3, key4; u32 keyType; - u32 xorMask = xorKey ? - (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 - | ATH9K_KEY_XOR) : 0; - struct ath_hal_5416 *ahp = AH5416(ah); if (entry >= pCap->keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, @@ -2550,7 +2467,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, "AES-CCM not supported by mac rev 0x%x\n", - ah->ah_macRev); + ah->hw_version.macRev); return false; } keyType = AR_KEYTABLE_TYPE_CCM; @@ -2586,26 +2503,57 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, return false; } - key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; - key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; - key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; - key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; - key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; + key0 = get_unaligned_le32(k->kv_val + 0); + key1 = get_unaligned_le16(k->kv_val + 4); + key2 = get_unaligned_le32(k->kv_val + 6); + key3 = get_unaligned_le16(k->kv_val + 10); + key4 = get_unaligned_le32(k->kv_val + 12); if (k->kv_len <= LEN_WEP104) key4 &= 0xff; + /* + * Note: Key cache registers access special memory area that requires + * two 32-bit writes to actually update the values in the internal + * memory. Consequently, the exact order and pairs used here must be + * maintained. + */ + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { u16 micentry = entry + 64; + /* + * Write inverted key[47:0] first to avoid Michael MIC errors + * on frames that could be sent or received at the same time. + * The correct key will be written in the end once everything + * else is ready. + */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + + /* Write key[95:48] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + + /* Write key[127:96] and key type */ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + + /* Write MAC address for the entry */ (void) ath9k_hw_keysetmac(ah, entry, mac); - if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { + if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { + /* + * TKIP uses two key cache entries: + * Michael MIC TX/RX keys in the same key cache entry + * (idx = main index + 64): + * key0 [31:0] = RX key [31:0] + * key1 [15:0] = TX key [31:16] + * key1 [31:16] = reserved + * key2 [31:0] = RX key [63:32] + * key3 [15:0] = TX key [15:0] + * key3 [31:16] = reserved + * key4 [31:0] = TX key [63:32] + */ u32 mic0, mic1, mic2, mic3, mic4; mic0 = get_unaligned_le32(k->kv_mic + 0); @@ -2613,51 +2561,90 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic4 = get_unaligned_le32(k->kv_txmic + 4); + + /* Write RX[31:0] and TX[31:16] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + + /* Write RX[63:32] and TX[15:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + + /* Write TX[63:32] and keyType(reserved) */ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); } else { + /* + * TKIP uses four key cache entries (two for group + * keys): + * Michael MIC TX/RX keys are in different key cache + * entries (idx = main index + 64 for TX and + * main index + 32 + 96 for RX): + * key0 [31:0] = TX/RX MIC key [31:0] + * key1 [31:0] = reserved + * key2 [31:0] = TX/RX MIC key [63:32] + * key3 [31:0] = reserved + * key4 [31:0] = reserved + * + * Upper layer code will call this function separately + * for TX and RX keys when these registers offsets are + * used. + */ u32 mic0, mic2; mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); + + /* Write MIC key[31:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + + /* Write MIC key[63:32] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + + /* Write TX[63:32] and keyType(reserved) */ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); } + + /* MAC address registers are reserved for the MIC entry */ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + + /* + * Write the correct (un-inverted) key[47:0] last to enable + * TKIP now that all other registers are set with correct + * values. + */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); } else { + /* Write key[47:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + + /* Write key[95:48] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + + /* Write key[127:96] and key type */ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + /* Write MAC address for the entry */ (void) ath9k_hw_keysetmac(ah, entry, mac); } - if (ah->ah_curchan == NULL) - return true; - return true; } -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) { - if (entry < ah->ah_caps.keycache_size) { + if (entry < ah->caps.keycache_size) { u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); if (val & AR_KEYTABLE_VALID) return true; @@ -2669,7 +2656,7 @@ bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) /* Power Management (Chipset) */ /******************************/ -static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) +static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) { REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { @@ -2678,16 +2665,16 @@ static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) if (!AR_SREV_9100(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), + REG_CLR_BIT(ah, (AR_RTC_RESET), AR_RTC_RESET_EN); } } -static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) +static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) { REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, @@ -2699,8 +2686,7 @@ static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) } } -static bool ath9k_hw_set_power_awake(struct ath_hal *ah, - int setChip) +static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) { u32 val; int i; @@ -2741,20 +2727,18 @@ static bool ath9k_hw_set_power_awake(struct ath_hal *ah, return true; } -bool ath9k_hw_setpower(struct ath_hal *ah, - enum ath9k_power_mode mode) +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) { - struct ath_hal_5416 *ahp = AH5416(ah); + int status = true, setChip = true; static const char *modes[] = { "AWAKE", "FULL-SLEEP", "NETWORK SLEEP", "UNDEFINED" }; - int status = true, setChip = true; DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", - modes[ahp->ah_powerMode], modes[mode], + modes[ah->power_mode], modes[mode], setChip ? "set chip " : ""); switch (mode) { @@ -2763,7 +2747,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah, break; case ATH9K_PM_FULL_SLEEP: ath9k_set_power_sleep(ah, setChip); - ahp->ah_chipFullSleep = true; + ah->chip_fullsleep = true; break; case ATH9K_PM_NETWORK_SLEEP: ath9k_set_power_network_sleep(ah, setChip); @@ -2773,41 +2757,57 @@ bool ath9k_hw_setpower(struct ath_hal *ah, "Unknown power mode %u\n", mode); return false; } - ahp->ah_powerMode = mode; + ah->power_mode = mode; return status; } -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) +/* + * Helper for ASPM support. + * + * Disable PLL when in L0s as well as receiver clock when in L1. + * This power saving option must be enabled through the SerDes. + * + * Programming the SerDes must go through the same 288 bit serial shift + * register as the other analog registers. Hence the 9 writes. + */ +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) { - struct ath_hal_5416 *ahp = AH5416(ah); u8 i; - if (ah->ah_isPciExpress != true) + if (ah->is_pciexpress != true) return; - if (ah->ah_config.pcie_powersave_enable == 2) + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) return; + /* Nothing to do on restore for 11N */ if (restore) return; if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), - INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); + /* + * AR9280 2.0 or later chips use SerDes values from the + * initvals.h initialized depending on chipset during + * ath9k_hw_do_attach() + */ + for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), + INI_RA(&ah->iniPcieSerdes, i, 1)); } - udelay(1000); } else if (AR_SREV_9280(ah) && - (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { + (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) { REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + /* RX shut off when elecidle is asserted */ REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - if (ah->ah_config.pcie_clock_req) + /* Shut off CLKREQ active in L1 */ + if (ah->config.pcie_clock_req) REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); else REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); @@ -2816,42 +2816,59 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + /* Load the new settings */ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - udelay(1000); } else { REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + + /* + * Ignore ah->ah_config.pcie_clock_req setting for + * pre-AR9280 11n + */ REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + + /* Load the new settings */ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } + udelay(1000); + + /* set bit 19 to allow forcing of pcie core into L1 state */ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - if (ah->ah_config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + /* Several PCIe massages to ensure proper behaviour */ + if (ah->config.pcie_waen) { + REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { if (AR_SREV_9285(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); + /* + * On AR9280 chips bit 22 of 0x4004 needs to be set to + * otherwise card may disappear. + */ else if (AR_SREV_9280(ah)) REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); else REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); } - } /**********************/ /* Interrupt Handling */ /**********************/ -bool ath9k_hw_intrpend(struct ath_hal *ah) +bool ath9k_hw_intrpend(struct ath_hw *ah) { u32 host_isr; @@ -2870,14 +2887,13 @@ bool ath9k_hw_intrpend(struct ath_hal *ah) return false; } -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) { u32 isr = 0; u32 mask2 = 0; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; u32 sync_cause = 0; bool fatal_int = false; - struct ath_hal_5416 *ahp = AH5416(ah); if (!AR_SREV_9100(ah)) { if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { @@ -2915,6 +2931,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) mask2 |= ATH9K_INT_GTT; if (isr2 & AR_ISR_S2_CST) mask2 |= ATH9K_INT_CST; + if (isr2 & AR_ISR_S2_TSFOOR) + mask2 |= ATH9K_INT_TSFOOR; } isr = REG_READ(ah, AR_ISR_RAC); @@ -2925,7 +2943,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ahp->ah_intrMitigation) { + if (ah->intr_mitigation) { if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -2940,12 +2958,12 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked |= ATH9K_INT_TX; s0_s = REG_READ(ah, AR_ISR_S0_S); - ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); - ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); s1_s = REG_READ(ah, AR_ISR_S1_S); - ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); - ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); } if (isr & AR_ISR_RXORN) { @@ -3002,17 +3020,16 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) return true; } -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah) +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah) { - return AH5416(ah)->ah_maskReg; + return ah->mask_reg; } -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { - struct ath_hal_5416 *ahp = AH5416(ah); - u32 omask = ahp->ah_maskReg; + u32 omask = ah->mask_reg; u32 mask, mask2; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); @@ -3033,18 +3050,18 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) mask2 = 0; if (ints & ATH9K_INT_TX) { - if (ahp->ah_txOkInterruptMask) + if (ah->txok_interrupt_mask) mask |= AR_IMR_TXOK; - if (ahp->ah_txDescInterruptMask) + if (ah->txdesc_interrupt_mask) mask |= AR_IMR_TXDESC; - if (ahp->ah_txErrInterruptMask) + if (ah->txerr_interrupt_mask) mask |= AR_IMR_TXERR; - if (ahp->ah_txEolInterruptMask) + if (ah->txeol_interrupt_mask) mask |= AR_IMR_TXEOL; } if (ints & ATH9K_INT_RX) { mask |= AR_IMR_RXERR; - if (ahp->ah_intrMitigation) + if (ah->intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; @@ -3061,7 +3078,9 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) if (ints & ATH9K_INT_DTIMSYNC) mask2 |= AR_IMR_S2_DTIMSYNC; if (ints & ATH9K_INT_CABEND) - mask2 |= (AR_IMR_S2_CABEND); + mask2 |= AR_IMR_S2_CABEND; + if (ints & ATH9K_INT_TSFOOR) + mask2 |= AR_IMR_S2_TSFOOR; } if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { @@ -3082,7 +3101,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); REG_WRITE(ah, AR_IMR_S2, mask | mask2); - ahp->ah_maskReg = ints; + ah->mask_reg = ints; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if (ints & ATH9K_INT_TIM_TIMER) @@ -3116,14 +3135,13 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) /* Beacon Handling */ /*******************/ -void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) { - struct ath_hal_5416 *ahp = AH5416(ah); int flags = 0; - ahp->ah_beaconInterval = beacon_period; + ah->beacon_interval = beacon_period; - switch (ah->ah_opmode) { + switch (ah->opmode) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); @@ -3132,22 +3150,23 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) flags |= AR_TBTT_TIMER_EN; break; case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); REG_WRITE(ah, AR_NEXT_NDP_TIMER, TU_TO_USEC(next_beacon + - (ahp->ah_atimWindow ? ahp-> - ah_atimWindow : 1))); + (ah->atim_window ? ah-> + atim_window : 1))); flags |= AR_NDP_TIMER_EN; case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, TU_TO_USEC(next_beacon - - ah->ah_config. + ah->config. dma_beacon_response_time)); REG_WRITE(ah, AR_NEXT_SWBA, TU_TO_USEC(next_beacon - - ah->ah_config. + ah->config. sw_beacon_response_time)); flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; @@ -3155,7 +3174,7 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) default: DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: unsupported opmode: %d\n", - __func__, ah->ah_opmode); + __func__, ah->opmode); return; break; } @@ -3174,11 +3193,11 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) REG_SET_BIT(ah, AR_TIMER_MODE, flags); } -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs) { u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); @@ -3232,43 +3251,46 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | AR_DTIM_TIMER_EN); + /* TSF Out of Range Threshold */ + REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); } /*******************/ /* HW Capabilities */ /*******************/ -bool ath9k_hw_fill_cap_info(struct ath_hal *ah) +bool ath9k_hw_fill_cap_info(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; u16 capField = 0, eeval; - eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0); + eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); + ah->regulatory.current_rd = eeval; - ah->ah_currentRD = eeval; - - eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1); - ah->ah_currentRDExt = eeval; - - capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); - - if (ah->ah_opmode != NL80211_IFTYPE_AP && - ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) - ah->ah_currentRD += 5; - else if (ah->ah_currentRD == 0x41) - ah->ah_currentRD = 0x43; + eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); + if (AR_SREV_9285_10_OR_LATER(ah)) + eeval |= AR9285_RDEXT_DEFAULT; + ah->regulatory.current_rd_ext = eeval; + + capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); + + if (ah->opmode != NL80211_IFTYPE_AP && + ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ah->regulatory.current_rd == 0x64 || + ah->regulatory.current_rd == 0x65) + ah->regulatory.current_rd += 5; + else if (ah->regulatory.current_rd == 0x41) + ah->regulatory.current_rd = 0x43; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", ah->ah_currentRD); + "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); } - eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); + eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); if (eeval & AR5416_OPFLAGS_11A) { set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { + if (ah->config.ht_enable) { if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) set_bit(ATH9K_MODE_11NA_HT20, pCap->wireless_modes); @@ -3284,7 +3306,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) if (eeval & AR5416_OPFLAGS_11G) { set_bit(ATH9K_MODE_11B, pCap->wireless_modes); set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { + if (ah->config.ht_enable) { if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) set_bit(ATH9K_MODE_11NG_HT20, pCap->wireless_modes); @@ -3297,18 +3319,15 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) } } - pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK); - if ((ah->ah_isPciExpress) - || (eeval & AR5416_OPFLAGS_11A)) { - pCap->rx_chainmask = - ath9k_hw_get_eeprom(ah, EEP_RX_MASK); - } else { - pCap->rx_chainmask = - (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; - } + pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); + if ((ah->hw_version.devid == AR5416_DEVID_PCI) && + !(eeval & AR5416_OPFLAGS_11A)) + pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; + else + pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); - if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) - ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; + if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) + ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; pCap->low_2ghz_chan = 2312; pCap->high_2ghz_chan = 2732; @@ -3326,7 +3345,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - if (ah->ah_config.ht_enable) + if (ah->config.ht_enable) pCap->hw_caps |= ATH9K_HW_CAP_HT; else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; @@ -3352,7 +3371,9 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->num_mr_retries = 4; pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9285_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR9285_NUM_GPIO; + else if (AR_SREV_9280_10_OR_LATER(ah)) pCap->num_gpio_pins = AR928X_NUM_GPIO; else pCap->num_gpio_pins = AR_NUM_GPIO; @@ -3375,22 +3396,22 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT); - if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { - ah->ah_rfkill_gpio = - MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ah->ah_rfkill_polarity = - MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); + ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); + if (ah->rfsilent & EEP_RFSILENT_ENABLED) { + ah->rfkill_gpio = + MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->rfkill_polarity = + MS(ah->rfsilent, EEP_RFSILENT_POLARITY); pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } #endif - if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || - (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || - (ah->ah_macVersion == AR_SREV_VERSION_9160) || - (ah->ah_macVersion == AR_SREV_VERSION_9100) || - (ah->ah_macVersion == AR_SREV_VERSION_9280)) + if ((ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || + (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9160) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9100) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9280)) pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; else pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; @@ -3400,7 +3421,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { + if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { pCap->reg_cap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | @@ -3415,19 +3436,22 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; pCap->num_antcfg_5ghz = - ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); + ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); pCap->num_antcfg_2ghz = - ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); + ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); + + if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { + pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; + ah->btactive_gpio = 6; + ah->wlanactive_gpio = 5; + } return true; } -bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result) { - struct ath_hal_5416 *ahp = AH5416(ah); - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - switch (type) { case ATH9K_CAP_CIPHER: switch (capability) { @@ -3446,23 +3470,17 @@ bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, case 0: return true; case 1: - return (ahp->ah_staId1Defaults & + return (ah->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE) ? true : false; } case ATH9K_CAP_TKIP_SPLIT: - return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? + return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? false : true; - case ATH9K_CAP_WME_TKIPMIC: - return 0; - case ATH9K_CAP_PHYCOUNTERS: - return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; case ATH9K_CAP_DIVERSITY: return (REG_READ(ah, AR_PHY_CCK_DETECT) & AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? true : false; - case ATH9K_CAP_PHYDIAG: - return true; case ATH9K_CAP_MCAST_KEYSRCH: switch (capability) { case 0: @@ -3471,57 +3489,48 @@ bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { return false; } else { - return (ahp->ah_staId1Defaults & + return (ah->sta_id1_defaults & AR_STA_ID1_MCAST_KSRCH) ? true : false; } } return false; - case ATH9K_CAP_TSF_ADJUST: - return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? - true : false; - case ATH9K_CAP_RFSILENT: - if (capability == 3) - return false; - case ATH9K_CAP_ANT_CFG_2GHZ: - *result = pCap->num_antcfg_2ghz; - return true; - case ATH9K_CAP_ANT_CFG_5GHZ: - *result = pCap->num_antcfg_5ghz; - return true; case ATH9K_CAP_TXPOW: switch (capability) { case 0: return 0; case 1: - *result = ah->ah_powerLimit; + *result = ah->regulatory.power_limit; return 0; case 2: - *result = ah->ah_maxPowerLevel; + *result = ah->regulatory.max_power_level; return 0; case 3: - *result = ah->ah_tpScale; + *result = ah->regulatory.tp_scale; return 0; } return false; + case ATH9K_CAP_DS: + return (AR_SREV_9280_20_OR_LATER(ah) && + (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1)) + ? false : true; default: return false; } } -bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 setting, int *status) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 v; switch (type) { case ATH9K_CAP_TKIP_MIC: if (setting) - ahp->ah_staId1Defaults |= + ah->sta_id1_defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; else - ahp->ah_staId1Defaults &= + ah->sta_id1_defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; return true; case ATH9K_CAP_DIVERSITY: @@ -3534,15 +3543,9 @@ bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, return true; case ATH9K_CAP_MCAST_KEYSRCH: if (setting) - ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; + ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH; else - ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; - return true; - case ATH9K_CAP_TSF_ADJUST: - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; - else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH; return true; default: return false; @@ -3553,7 +3556,7 @@ bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, /* GPIO / RFKILL / Antennae */ /****************************/ -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type) { int addr; @@ -3581,11 +3584,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, } } -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) { u32 gpio_shift; - ASSERT(gpio < ah->ah_caps.num_gpio_pins); + ASSERT(gpio < ah->caps.num_gpio_pins); gpio_shift = gpio << 1; @@ -3595,22 +3598,23 @@ void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) { - if (gpio >= ah->ah_caps.num_gpio_pins) +#define MS_REG_READ(x, y) \ + (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y))) + + if (gpio >= ah->caps.num_gpio_pins) return 0xffffffff; - if (AR_SREV_9280_10_OR_LATER(ah)) { - return (MS - (REG_READ(ah, AR_GPIO_IN_OUT), - AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; - } else { - return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & - AR_GPIO_BIT(gpio)) != 0; - } + if (AR_SREV_9285_10_OR_LATER(ah)) + return MS_REG_READ(AR9285, gpio) != 0; + else if (AR_SREV_9280_10_OR_LATER(ah)) + return MS_REG_READ(AR928X, gpio) != 0; + else + return MS_REG_READ(AR, gpio) != 0; } -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type) { u32 gpio_shift; @@ -3625,14 +3629,14 @@ void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) { REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); } #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hal *ah) +void ath9k_enable_rfkill(struct ath_hw *ah) { REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); @@ -3640,50 +3644,28 @@ void ath9k_enable_rfkill(struct ath_hal *ah) REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, AR_GPIO_INPUT_MUX2_RFSILENT); - ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); + ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); } #endif -int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) -{ - struct ath9k_channel *chan = ah->ah_curchan; - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 ant_config; - u32 halNumAntConfig; - - halNumAntConfig = IS_CHAN_2GHZ(chan) ? - pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz; - - if (cfg < halNumAntConfig) { - if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan, - cfg, &ant_config)) { - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); - return 0; - } - } - - return -EINVAL; -} - -u32 ath9k_hw_getdefantenna(struct ath_hal *ah) +u32 ath9k_hw_getdefantenna(struct ath_hw *ah) { return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) { REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } -bool ath9k_hw_setantennaswitch(struct ath_hal *ah, +bool ath9k_hw_setantennaswitch(struct ath_hw *ah, enum ath9k_ant_setting settings, struct ath9k_channel *chan, u8 *tx_chainmask, u8 *rx_chainmask, u8 *antenna_cfgd) { - struct ath_hal_5416 *ahp = AH5416(ah); static u8 tx_chainmask_cfg, rx_chainmask_cfg; if (AR_SREV_9280(ah)) { @@ -3700,7 +3682,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hal *ah, *antenna_cfgd = true; break; case ATH9K_ANT_FIXED_B: - if (ah->ah_caps.tx_chainmask > + if (ah->caps.tx_chainmask > ATH9K_ANTENNA1_CHAINMASK) { *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; } @@ -3716,7 +3698,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hal *ah, break; } } else { - ahp->ah_diversityControl = settings; + ah->diversity_control = settings; } return true; @@ -3726,7 +3708,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hal *ah, /* General Operation */ /*********************/ -u32 ath9k_hw_getrxfilter(struct ath_hal *ah) +u32 ath9k_hw_getrxfilter(struct ath_hw *ah) { u32 bits = REG_READ(ah, AR_RX_FILTER); u32 phybits = REG_READ(ah, AR_PHY_ERR); @@ -3739,7 +3721,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hal *ah) return bits; } -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { u32 phybits; @@ -3759,12 +3741,12 @@ void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); } -bool ath9k_hw_phy_disable(struct ath_hal *ah) +bool ath9k_hw_phy_disable(struct ath_hw *ah) { return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); } -bool ath9k_hw_disable(struct ath_hal *ah) +bool ath9k_hw_disable(struct ath_hw *ah) { if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return false; @@ -3772,82 +3754,54 @@ bool ath9k_hw_disable(struct ath_hal *ah) return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { - struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_channel *chan = ah->curchan; + struct ieee80211_channel *channel = chan->chan; - ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); + ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); - if (ath9k_hw_set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)) != 0) + if (ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)) != 0) return false; return true; } -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(mac, ahp->ah_macaddr, ETH_ALEN); -} - -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_macaddr, mac, ETH_ALEN); - - return true; + memcpy(ah->macaddr, mac, ETH_ALEN); } -void ath9k_hw_setopmode(struct ath_hal *ah) +void ath9k_hw_setopmode(struct ath_hw *ah) { - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); + ath9k_hw_set_operating_mode(ah, ah->opmode); } -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1) +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) { REG_WRITE(ah, AR_MCAST_FIL0, filter0); REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) +void ath9k_hw_setbssidmask(struct ath_softc *sc) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); + REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); + REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); } -bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) +void ath9k_hw_write_associd(struct ath_softc *sc) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); - - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); - - return true; -} - -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_bssid, bssid, ETH_ALEN); - ahp->ah_assocId = assocId; - - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | - ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); + REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); + REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | + ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); } -u64 ath9k_hw_gettsf64(struct ath_hal *ah) +u64 ath9k_hw_gettsf64(struct ath_hw *ah) { u64 tsf; @@ -3857,7 +3811,13 @@ u64 ath9k_hw_gettsf64(struct ath_hal *ah) return tsf; } -void ath9k_hw_reset_tsf(struct ath_hal *ah) +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) +{ + REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); + REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); +} + +void ath9k_hw_reset_tsf(struct ath_hw *ah) { int count; @@ -3874,42 +3834,65 @@ void ath9k_hw_reset_tsf(struct ath_hal *ah) REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); } -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + ah->misc_mode |= AR_PCU_TX_ADD_TSF; else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; return true; } -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); - ahp->ah_slottime = (u32) -1; + ah->slottime = (u32) -1; return false; } else { REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_slottime = us; + ah->slottime = us; return true; } } -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) { u32 macmode; if (mode == ATH9K_HT_MACMODE_2040 && - !ah->ah_config.cwm_ignore_extcca) + !ah->config.cwm_ignore_extcca) macmode = AR_2040_JOINED_RX_CLEAR; else macmode = 0; REG_WRITE(ah, AR_2040_MODE, macmode); } + +/***************************/ +/* Bluetooth Coexistence */ +/***************************/ + +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + ah->btactive_gpio); + + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); + + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); +} diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 91d8f594af81..0b594e0ee260 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,1062 +19,629 @@ #include <linux/if_ether.h> #include <linux/delay.h> +#include <linux/io.h> + +#include "mac.h" +#include "ani.h" +#include "eeprom.h" +#include "calib.h" +#include "regd.h" +#include "reg.h" +#include "phy.h" + +#define ATHEROS_VENDOR_ID 0x168c +#define AR5416_DEVID_PCI 0x0023 +#define AR5416_DEVID_PCIE 0x0024 +#define AR9160_DEVID_PCI 0x0027 +#define AR9280_DEVID_PCI 0x0029 +#define AR9280_DEVID_PCIE 0x002a +#define AR9285_DEVID_PCIE 0x002b +#define AR5416_AR9100_DEVID 0x000b +#define AR_SUBVENDOR_ID_NOG 0x0e11 +#define AR_SUBVENDOR_ID_NEW_A 0x7065 +#define AR5416_MAGIC 0x19641014 + +/* Register read/write primitives */ +#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) +#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) + +#define SM(_v, _f) (((_v) << _f##_S) & _f) +#define MS(_v, _f) (((_v) & _f) >> _f##_S) +#define REG_RMW(_a, _r, _set, _clr) \ + REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) +#define REG_RMW_FIELD(_a, _r, _f, _v) \ + REG_WRITE(_a, _r, \ + (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) +#define REG_SET_BIT(_a, _r, _f) \ + REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) +#define REG_CLR_BIT(_a, _r, _f) \ + REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) -struct ar5416_desc { - u32 ds_link; - u32 ds_data; - u32 ds_ctl0; - u32 ds_ctl1; - union { - struct { - u32 ctl2; - u32 ctl3; - u32 ctl4; - u32 ctl5; - u32 ctl6; - u32 ctl7; - u32 ctl8; - u32 ctl9; - u32 ctl10; - u32 ctl11; - u32 status0; - u32 status1; - u32 status2; - u32 status3; - u32 status4; - u32 status5; - u32 status6; - u32 status7; - u32 status8; - u32 status9; - } tx; - struct { - u32 status0; - u32 status1; - u32 status2; - u32 status3; - u32 status4; - u32 status5; - u32 status6; - u32 status7; - u32 status8; - } rx; - } u; -} __packed; - -#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) -#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) - -#define ds_ctl2 u.tx.ctl2 -#define ds_ctl3 u.tx.ctl3 -#define ds_ctl4 u.tx.ctl4 -#define ds_ctl5 u.tx.ctl5 -#define ds_ctl6 u.tx.ctl6 -#define ds_ctl7 u.tx.ctl7 -#define ds_ctl8 u.tx.ctl8 -#define ds_ctl9 u.tx.ctl9 -#define ds_ctl10 u.tx.ctl10 -#define ds_ctl11 u.tx.ctl11 - -#define ds_txstatus0 u.tx.status0 -#define ds_txstatus1 u.tx.status1 -#define ds_txstatus2 u.tx.status2 -#define ds_txstatus3 u.tx.status3 -#define ds_txstatus4 u.tx.status4 -#define ds_txstatus5 u.tx.status5 -#define ds_txstatus6 u.tx.status6 -#define ds_txstatus7 u.tx.status7 -#define ds_txstatus8 u.tx.status8 -#define ds_txstatus9 u.tx.status9 - -#define ds_rxstatus0 u.rx.status0 -#define ds_rxstatus1 u.rx.status1 -#define ds_rxstatus2 u.rx.status2 -#define ds_rxstatus3 u.rx.status3 -#define ds_rxstatus4 u.rx.status4 -#define ds_rxstatus5 u.rx.status5 -#define ds_rxstatus6 u.rx.status6 -#define ds_rxstatus7 u.rx.status7 -#define ds_rxstatus8 u.rx.status8 - -#define AR_FrameLen 0x00000fff -#define AR_VirtMoreFrag 0x00001000 -#define AR_TxCtlRsvd00 0x0000e000 -#define AR_XmitPower 0x003f0000 -#define AR_XmitPower_S 16 -#define AR_RTSEnable 0x00400000 -#define AR_VEOL 0x00800000 -#define AR_ClrDestMask 0x01000000 -#define AR_TxCtlRsvd01 0x1e000000 -#define AR_TxIntrReq 0x20000000 -#define AR_DestIdxValid 0x40000000 -#define AR_CTSEnable 0x80000000 - -#define AR_BufLen 0x00000fff -#define AR_TxMore 0x00001000 -#define AR_DestIdx 0x000fe000 -#define AR_DestIdx_S 13 -#define AR_FrameType 0x00f00000 -#define AR_FrameType_S 20 -#define AR_NoAck 0x01000000 -#define AR_InsertTS 0x02000000 -#define AR_CorruptFCS 0x04000000 -#define AR_ExtOnly 0x08000000 -#define AR_ExtAndCtl 0x10000000 -#define AR_MoreAggr 0x20000000 -#define AR_IsAggr 0x40000000 - -#define AR_BurstDur 0x00007fff -#define AR_BurstDur_S 0 -#define AR_DurUpdateEna 0x00008000 -#define AR_XmitDataTries0 0x000f0000 -#define AR_XmitDataTries0_S 16 -#define AR_XmitDataTries1 0x00f00000 -#define AR_XmitDataTries1_S 20 -#define AR_XmitDataTries2 0x0f000000 -#define AR_XmitDataTries2_S 24 -#define AR_XmitDataTries3 0xf0000000 -#define AR_XmitDataTries3_S 28 - -#define AR_XmitRate0 0x000000ff -#define AR_XmitRate0_S 0 -#define AR_XmitRate1 0x0000ff00 -#define AR_XmitRate1_S 8 -#define AR_XmitRate2 0x00ff0000 -#define AR_XmitRate2_S 16 -#define AR_XmitRate3 0xff000000 -#define AR_XmitRate3_S 24 - -#define AR_PacketDur0 0x00007fff -#define AR_PacketDur0_S 0 -#define AR_RTSCTSQual0 0x00008000 -#define AR_PacketDur1 0x7fff0000 -#define AR_PacketDur1_S 16 -#define AR_RTSCTSQual1 0x80000000 - -#define AR_PacketDur2 0x00007fff -#define AR_PacketDur2_S 0 -#define AR_RTSCTSQual2 0x00008000 -#define AR_PacketDur3 0x7fff0000 -#define AR_PacketDur3_S 16 -#define AR_RTSCTSQual3 0x80000000 - -#define AR_AggrLen 0x0000ffff -#define AR_AggrLen_S 0 -#define AR_TxCtlRsvd60 0x00030000 -#define AR_PadDelim 0x03fc0000 -#define AR_PadDelim_S 18 -#define AR_EncrType 0x0c000000 -#define AR_EncrType_S 26 -#define AR_TxCtlRsvd61 0xf0000000 - -#define AR_2040_0 0x00000001 -#define AR_GI0 0x00000002 -#define AR_ChainSel0 0x0000001c -#define AR_ChainSel0_S 2 -#define AR_2040_1 0x00000020 -#define AR_GI1 0x00000040 -#define AR_ChainSel1 0x00000380 -#define AR_ChainSel1_S 7 -#define AR_2040_2 0x00000400 -#define AR_GI2 0x00000800 -#define AR_ChainSel2 0x00007000 -#define AR_ChainSel2_S 12 -#define AR_2040_3 0x00008000 -#define AR_GI3 0x00010000 -#define AR_ChainSel3 0x000e0000 -#define AR_ChainSel3_S 17 -#define AR_RTSCTSRate 0x0ff00000 -#define AR_RTSCTSRate_S 20 -#define AR_TxCtlRsvd70 0xf0000000 - -#define AR_TxRSSIAnt00 0x000000ff -#define AR_TxRSSIAnt00_S 0 -#define AR_TxRSSIAnt01 0x0000ff00 -#define AR_TxRSSIAnt01_S 8 -#define AR_TxRSSIAnt02 0x00ff0000 -#define AR_TxRSSIAnt02_S 16 -#define AR_TxStatusRsvd00 0x3f000000 -#define AR_TxBaStatus 0x40000000 -#define AR_TxStatusRsvd01 0x80000000 - -#define AR_FrmXmitOK 0x00000001 -#define AR_ExcessiveRetries 0x00000002 -#define AR_FIFOUnderrun 0x00000004 -#define AR_Filtered 0x00000008 -#define AR_RTSFailCnt 0x000000f0 -#define AR_RTSFailCnt_S 4 -#define AR_DataFailCnt 0x00000f00 -#define AR_DataFailCnt_S 8 -#define AR_VirtRetryCnt 0x0000f000 -#define AR_VirtRetryCnt_S 12 -#define AR_TxDelimUnderrun 0x00010000 -#define AR_TxDataUnderrun 0x00020000 -#define AR_DescCfgErr 0x00040000 -#define AR_TxTimerExpired 0x00080000 -#define AR_TxStatusRsvd10 0xfff00000 - -#define AR_SendTimestamp ds_txstatus2 -#define AR_BaBitmapLow ds_txstatus3 -#define AR_BaBitmapHigh ds_txstatus4 - -#define AR_TxRSSIAnt10 0x000000ff -#define AR_TxRSSIAnt10_S 0 -#define AR_TxRSSIAnt11 0x0000ff00 -#define AR_TxRSSIAnt11_S 8 -#define AR_TxRSSIAnt12 0x00ff0000 -#define AR_TxRSSIAnt12_S 16 -#define AR_TxRSSICombined 0xff000000 -#define AR_TxRSSICombined_S 24 - -#define AR_TxEVM0 ds_txstatus5 -#define AR_TxEVM1 ds_txstatus6 -#define AR_TxEVM2 ds_txstatus7 - -#define AR_TxDone 0x00000001 -#define AR_SeqNum 0x00001ffe -#define AR_SeqNum_S 1 -#define AR_TxStatusRsvd80 0x0001e000 -#define AR_TxOpExceeded 0x00020000 -#define AR_TxStatusRsvd81 0x001c0000 -#define AR_FinalTxIdx 0x00600000 -#define AR_FinalTxIdx_S 21 -#define AR_TxStatusRsvd82 0x01800000 -#define AR_PowerMgmt 0x02000000 -#define AR_TxStatusRsvd83 0xfc000000 - -#define AR_RxCTLRsvd00 0xffffffff - -#define AR_BufLen 0x00000fff -#define AR_RxCtlRsvd00 0x00001000 -#define AR_RxIntrReq 0x00002000 -#define AR_RxCtlRsvd01 0xffffc000 - -#define AR_RxRSSIAnt00 0x000000ff -#define AR_RxRSSIAnt00_S 0 -#define AR_RxRSSIAnt01 0x0000ff00 -#define AR_RxRSSIAnt01_S 8 -#define AR_RxRSSIAnt02 0x00ff0000 -#define AR_RxRSSIAnt02_S 16 -#define AR_RxRate 0xff000000 -#define AR_RxRate_S 24 -#define AR_RxStatusRsvd00 0xff000000 - -#define AR_DataLen 0x00000fff -#define AR_RxMore 0x00001000 -#define AR_NumDelim 0x003fc000 -#define AR_NumDelim_S 14 -#define AR_RxStatusRsvd10 0xff800000 - -#define AR_RcvTimestamp ds_rxstatus2 - -#define AR_GI 0x00000001 -#define AR_2040 0x00000002 -#define AR_Parallel40 0x00000004 -#define AR_Parallel40_S 2 -#define AR_RxStatusRsvd30 0x000000f8 -#define AR_RxAntenna 0xffffff00 -#define AR_RxAntenna_S 8 - -#define AR_RxRSSIAnt10 0x000000ff -#define AR_RxRSSIAnt10_S 0 -#define AR_RxRSSIAnt11 0x0000ff00 -#define AR_RxRSSIAnt11_S 8 -#define AR_RxRSSIAnt12 0x00ff0000 -#define AR_RxRSSIAnt12_S 16 -#define AR_RxRSSICombined 0xff000000 -#define AR_RxRSSICombined_S 24 - -#define AR_RxEVM0 ds_rxstatus4 -#define AR_RxEVM1 ds_rxstatus5 -#define AR_RxEVM2 ds_rxstatus6 - -#define AR_RxDone 0x00000001 -#define AR_RxFrameOK 0x00000002 -#define AR_CRCErr 0x00000004 -#define AR_DecryptCRCErr 0x00000008 -#define AR_PHYErr 0x00000010 -#define AR_MichaelErr 0x00000020 -#define AR_PreDelimCRCErr 0x00000040 -#define AR_RxStatusRsvd70 0x00000080 -#define AR_RxKeyIdxValid 0x00000100 -#define AR_KeyIdx 0x0000fe00 -#define AR_KeyIdx_S 9 -#define AR_PHYErrCode 0x0000ff00 -#define AR_PHYErrCode_S 8 -#define AR_RxMoreAggr 0x00010000 -#define AR_RxAggr 0x00020000 -#define AR_PostDelimCRCErr 0x00040000 -#define AR_RxStatusRsvd71 0x3ff80000 -#define AR_DecryptBusyErr 0x40000000 -#define AR_KeyMiss 0x80000000 - -#define AR5416_MAGIC 0x19641014 - -#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus0, AR_RxRate) : \ - (ads->ds_rxstatus3 >> 2) & 0xFF) - -#define set11nTries(_series, _index) \ - (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) - -#define set11nRate(_series, _index) \ - (SM((_series)[_index].Rate, AR_XmitRate##_index)) - -#define set11nPktDurRTSCTS(_series, _index) \ - (SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \ - ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \ - AR_RTSCTSQual##_index : 0)) +#define DO_DELAY(x) do { \ + if ((++(x) % 64) == 0) \ + udelay(1); \ + } while (0) -#define set11nRateFlags(_series, _index) \ - (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ - AR_2040_##_index : 0) \ - |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ - AR_GI##_index : 0) \ - |SM((_series)[_index].ChSel, AR_ChainSel##_index)) +#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ + int r; \ + for (r = 0; r < ((iniarray)->ia_rows); r++) { \ + REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ + INI_RA((iniarray), r, (column))); \ + DO_DELAY(regWr); \ + } \ + } while (0) -#define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100) +#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 +#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 -#define INIT_CONFIG_STATUS 0x00000000 -#define INIT_RSSI_THR 0x00000700 -#define INIT_BCON_CNTRL_REG 0x00000000 +#define AR_GPIOD_MASK 0x00001FFF +#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) -#define MIN_TX_FIFO_THRESHOLD 0x1 -#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) -#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD +#define BASE_ACTIVATE_DELAY 100 +#define RTC_PLL_SETTLE_DELAY 1000 +#define COEF_SCALE_S 24 +#define HT40_CHANNEL_CENTER_SHIFT 10 -struct ar5416AniState { - struct ath9k_channel c; - u8 noiseImmunityLevel; - u8 spurImmunityLevel; - u8 firstepLevel; - u8 ofdmWeakSigDetectOff; - u8 cckWeakSigThreshold; - u32 listenTime; - u32 ofdmTrigHigh; - u32 ofdmTrigLow; - int32_t cckTrigHigh; - int32_t cckTrigLow; - int32_t rssiThrLow; - int32_t rssiThrHigh; - u32 noiseFloor; - u32 txFrameCount; - u32 rxFrameCount; - u32 cycleCount; - u32 ofdmPhyErrCount; - u32 cckPhyErrCount; - u32 ofdmPhyErrBase; - u32 cckPhyErrBase; - int16_t pktRssi[2]; - int16_t ofdmErrRssi[2]; - int16_t cckErrRssi[2]; +#define ATH9K_ANTENNA0_CHAINMASK 0x1 +#define ATH9K_ANTENNA1_CHAINMASK 0x2 + +#define ATH9K_NUM_DMA_DEBUG_REGS 8 +#define ATH9K_NUM_QUEUES 10 + +#define MAX_RATE_POWER 63 +#define AH_WAIT_TIMEOUT 100000 /* (us) */ +#define AH_TIME_QUANTUM 10 +#define AR_KEYTABLE_SIZE 128 +#define POWER_UP_TIME 200000 +#define SPUR_RSSI_THRESH 40 + +#define CAB_TIMEOUT_VAL 10 +#define BEACON_TIMEOUT_VAL 10 +#define MIN_BEACON_TIMEOUT_VAL 1 +#define SLEEP_SLOP 3 + +#define INIT_CONFIG_STATUS 0x00000000 +#define INIT_RSSI_THR 0x00000700 +#define INIT_BCON_CNTRL_REG 0x00000000 + +#define TU_TO_USEC(_tu) ((_tu) << 10) + +enum wireless_mode { + ATH9K_MODE_11A = 0, + ATH9K_MODE_11B = 2, + ATH9K_MODE_11G = 3, + ATH9K_MODE_11NA_HT20 = 6, + ATH9K_MODE_11NG_HT20 = 7, + ATH9K_MODE_11NA_HT40PLUS = 8, + ATH9K_MODE_11NA_HT40MINUS = 9, + ATH9K_MODE_11NG_HT40PLUS = 10, + ATH9K_MODE_11NG_HT40MINUS = 11, + ATH9K_MODE_MAX }; -#define HAL_PROCESS_ANI 0x00000001 -#define DO_ANI(ah) \ - ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) - -struct ar5416Stats { - u32 ast_ani_niup; - u32 ast_ani_nidown; - u32 ast_ani_spurup; - u32 ast_ani_spurdown; - u32 ast_ani_ofdmon; - u32 ast_ani_ofdmoff; - u32 ast_ani_cckhigh; - u32 ast_ani_ccklow; - u32 ast_ani_stepup; - u32 ast_ani_stepdown; - u32 ast_ani_ofdmerrs; - u32 ast_ani_cckerrs; - u32 ast_ani_reset; - u32 ast_ani_lzero; - u32 ast_ani_lneg; - struct ath9k_mib_stats ast_mibstats; - struct ath9k_node_stats ast_nodestats; +enum ath9k_hw_caps { + ATH9K_HW_CAP_CHAN_SPREAD = BIT(0), + ATH9K_HW_CAP_MIC_AESCCM = BIT(1), + ATH9K_HW_CAP_MIC_CKIP = BIT(2), + ATH9K_HW_CAP_MIC_TKIP = BIT(3), + ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4), + ATH9K_HW_CAP_CIPHER_CKIP = BIT(5), + ATH9K_HW_CAP_CIPHER_TKIP = BIT(6), + ATH9K_HW_CAP_VEOL = BIT(7), + ATH9K_HW_CAP_BSSIDMASK = BIT(8), + ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9), + ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10), + ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11), + ATH9K_HW_CAP_HT = BIT(12), + ATH9K_HW_CAP_GTT = BIT(13), + ATH9K_HW_CAP_FASTCC = BIT(14), + ATH9K_HW_CAP_RFSILENT = BIT(15), + ATH9K_HW_CAP_WOW = BIT(16), + ATH9K_HW_CAP_CST = BIT(17), + ATH9K_HW_CAP_ENHANCEDPM = BIT(18), + ATH9K_HW_CAP_AUTOSLEEP = BIT(19), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20), + ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21), + ATH9K_HW_CAP_BT_COEX = BIT(22) }; -#define AR5416_OPFLAGS_11A 0x01 -#define AR5416_OPFLAGS_11G 0x02 -#define AR5416_OPFLAGS_N_5G_HT40 0x04 -#define AR5416_OPFLAGS_N_2G_HT40 0x08 -#define AR5416_OPFLAGS_N_5G_HT20 0x10 -#define AR5416_OPFLAGS_N_2G_HT20 0x20 - -#define EEP_RFSILENT_ENABLED 0x0001 -#define EEP_RFSILENT_ENABLED_S 0 -#define EEP_RFSILENT_POLARITY 0x0002 -#define EEP_RFSILENT_POLARITY_S 1 -#define EEP_RFSILENT_GPIO_SEL 0x001c -#define EEP_RFSILENT_GPIO_SEL_S 2 - -#define AR5416_EEP_NO_BACK_VER 0x1 -#define AR5416_EEP_VER 0xE -#define AR5416_EEP_VER_MINOR_MASK 0x0FFF -#define AR5416_EEP_MINOR_VER_2 0x2 -#define AR5416_EEP_MINOR_VER_3 0x3 -#define AR5416_EEP_MINOR_VER_7 0x7 -#define AR5416_EEP_MINOR_VER_9 0x9 -#define AR5416_EEP_MINOR_VER_16 0x10 -#define AR5416_EEP_MINOR_VER_17 0x11 -#define AR5416_EEP_MINOR_VER_19 0x13 - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 -#define AR5416_NUM_5G_20_TARGET_POWERS 8 -#define AR5416_NUM_5G_40_TARGET_POWERS 8 -#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 -#define AR5416_NUM_2G_20_TARGET_POWERS 4 -#define AR5416_NUM_2G_40_TARGET_POWERS 4 -#define AR5416_NUM_CTLS 24 -#define AR5416_NUM_BAND_EDGES 8 -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAINS_IN_MASK 4 -#define AR5416_PD_GAIN_ICEPTS 5 -#define AR5416_EEPROM_MODAL_SPURS 5 -#define AR5416_MAX_RATE_POWER 63 -#define AR5416_NUM_PDADC_VALUES 128 -#define AR5416_BCHAN_UNUSED 0xFF -#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 -#define AR5416_MAX_CHAINS 3 -#define AR5416_PWR_TABLE_OFFSET -5 - -/* Rx gain type values */ -#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 -#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 -#define AR5416_EEP_RXGAIN_ORIG 2 - -/* Tx gain type values */ -#define AR5416_EEP_TXGAIN_ORIGINAL 0 -#define AR5416_EEP_TXGAIN_HIGH_POWER 1 - -#define AR5416_EEP4K_START_LOC 64 -#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 -#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 -#define AR5416_EEP4K_NUM_CTLS 12 -#define AR5416_EEP4K_NUM_BAND_EDGES 4 -#define AR5416_EEP4K_NUM_PD_GAINS 2 -#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 -#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 -#define AR5416_EEP4K_MAX_CHAINS 1 - -enum eeprom_param { - EEP_NFTHRESH_5, - EEP_NFTHRESH_2, - EEP_MAC_MSW, - EEP_MAC_MID, - EEP_MAC_LSW, - EEP_REG_0, - EEP_REG_1, - EEP_OP_CAP, - EEP_OP_MODE, - EEP_RF_SILENT, - EEP_OB_5, - EEP_DB_5, - EEP_OB_2, - EEP_DB_2, - EEP_MINOR_REV, - EEP_TX_MASK, - EEP_RX_MASK, - EEP_RXGAIN_TYPE, - EEP_TXGAIN_TYPE, +enum ath9k_capability_type { + ATH9K_CAP_CIPHER = 0, + ATH9K_CAP_TKIP_MIC, + ATH9K_CAP_TKIP_SPLIT, + ATH9K_CAP_DIVERSITY, + ATH9K_CAP_TXPOW, + ATH9K_CAP_MCAST_KEYSRCH, + ATH9K_CAP_DS }; -enum ar5416_rates { - rate6mb, rate9mb, rate12mb, rate18mb, - rate24mb, rate36mb, rate48mb, rate54mb, - rate1l, rate2l, rate2s, rate5_5l, - rate5_5s, rate11l, rate11s, rateXr, - rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, - rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, - rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, - rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, - rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, - Ar5416RateSize +struct ath9k_hw_capabilities { + u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ + DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */ + u16 total_queues; + u16 keycache_size; + u16 low_5ghz_chan, high_5ghz_chan; + u16 low_2ghz_chan, high_2ghz_chan; + u16 num_mr_retries; + u16 rts_aggr_limit; + u8 tx_chainmask; + u8 rx_chainmask; + u16 tx_triglevel_max; + u16 reg_cap; + u8 num_gpio_pins; + u8 num_antcfg_2ghz; + u8 num_antcfg_5ghz; }; -enum ath9k_hal_freq_band { - ATH9K_HAL_FREQ_BAND_5GHZ = 0, - ATH9K_HAL_FREQ_BAND_2GHZ = 1 +struct ath9k_ops_config { + int dma_beacon_response_time; + int sw_beacon_response_time; + int additional_swba_backoff; + int ack_6mb; + int cwm_ignore_extcca; + u8 pcie_powersave_enable; + u8 pcie_l1skp_enable; + u8 pcie_clock_req; + u32 pcie_waen; + int pcie_power_reset; + u8 pcie_restore; + u8 analog_shiftreg; + u8 ht_enable; + u32 ofdm_trig_low; + u32 ofdm_trig_high; + u32 cck_trig_high; + u32 cck_trig_low; + u32 enable_ani; + u8 noise_immunity_level; + u32 ofdm_weaksignal_det; + u32 cck_weaksignal_thr; + u8 spur_immunity_level; + u8 firstep_level; + int8_t rssi_thr_high; + int8_t rssi_thr_low; + u16 diversity_control; + u16 antenna_switch_swap; + int serialize_regmode; + int intr_mitigation; +#define SPUR_DISABLE 0 +#define SPUR_ENABLE_IOCTL 1 +#define SPUR_ENABLE_EEPROM 2 +#define AR_EEPROM_MODAL_SPURS 5 +#define AR_SPUR_5413_1 1640 +#define AR_SPUR_5413_2 1200 +#define AR_NO_SPUR 0x8000 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + int spurmode; + u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; }; -struct base_eep_header { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 pwdclkind; - u8 futureBase_1[2]; - u8 rxGainType; - u8 futureBase_2[3]; - u8 txGainType; - u8 futureBase_3[25]; -} __packed; - -struct base_eep_header_4k { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 futureBase[1]; -} __packed; - - -struct spur_chan { - u16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; -} __packed; - -struct modal_eep_header { - u32 antCtrlChain[AR5416_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_MAX_CHAINS]; - u8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_MAX_CHAINS]; - u8 xatten2Margin[AR5416_MAX_CHAINS]; - u8 ob_ch1; - u8 db_ch1; - u8 useAnt1:1, - force_xpaon:1, - local_bias:1, - femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1; - u8 futureModalar9280; - u16 xpaBiasLvlFreq[3]; - u8 futureModal[6]; - - struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; -} __packed; - -struct modal_eep_4k_header { - u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; - u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; - u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; - u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; - u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; - u8 futureModal[4]; - - struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; -} __packed; - - -struct cal_data_per_freq { - u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -struct cal_data_per_freq_4k { - u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; - u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; -} __packed; - -struct cal_target_power_leg { - u8 bChannel; - u8 tPow2x[4]; -} __packed; - -struct cal_target_power_ht { - u8 bChannel; - u8 tPow2x[8]; -} __packed; - - -#ifdef __BIG_ENDIAN_BITFIELD -struct cal_ctl_edges { - u8 bChannel; - u8 flag:2, tPower:6; -} __packed; -#else -struct cal_ctl_edges { - u8 bChannel; - u8 tPower:6, flag:2; -} __packed; -#endif - -struct cal_ctl_data { - struct cal_ctl_edges - ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - -struct cal_ctl_data_4k { - struct cal_ctl_edges - ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; -} __packed; - -struct ar5416_eeprom_def { - struct base_eep_header baseEepHeader; - u8 custData[64]; - struct modal_eep_header modalHeader[2]; - u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; - u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; - struct cal_data_per_freq - calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; - struct cal_data_per_freq - calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - struct cal_target_power_leg - calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; - u8 ctlIndex[AR5416_NUM_CTLS]; - struct cal_ctl_data ctlData[AR5416_NUM_CTLS]; - u8 padding; -} __packed; - -struct ar5416_eeprom_4k { - struct base_eep_header_4k baseEepHeader; - u8 custData[20]; - struct modal_eep_4k_header modalHeader; - u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; - struct cal_data_per_freq_4k - calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; - struct cal_target_power_leg - calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; - struct cal_target_power_leg - calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; - struct cal_target_power_ht - calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; - u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; - struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; - u8 padding; -} __packed; - -struct ar5416IniArray { - u32 *ia_array; - u32 ia_rows; - u32 ia_columns; +enum ath9k_int { + ATH9K_INT_RX = 0x00000001, + ATH9K_INT_RXDESC = 0x00000002, + ATH9K_INT_RXNOFRM = 0x00000008, + ATH9K_INT_RXEOL = 0x00000010, + ATH9K_INT_RXORN = 0x00000020, + ATH9K_INT_TX = 0x00000040, + ATH9K_INT_TXDESC = 0x00000080, + ATH9K_INT_TIM_TIMER = 0x00000100, + ATH9K_INT_TXURN = 0x00000800, + ATH9K_INT_MIB = 0x00001000, + ATH9K_INT_RXPHY = 0x00004000, + ATH9K_INT_RXKCM = 0x00008000, + ATH9K_INT_SWBA = 0x00010000, + ATH9K_INT_BMISS = 0x00040000, + ATH9K_INT_BNR = 0x00100000, + ATH9K_INT_TIM = 0x00200000, + ATH9K_INT_DTIM = 0x00400000, + ATH9K_INT_DTIMSYNC = 0x00800000, + ATH9K_INT_GPIO = 0x01000000, + ATH9K_INT_CABEND = 0x02000000, + ATH9K_INT_TSFOOR = 0x04000000, + ATH9K_INT_CST = 0x10000000, + ATH9K_INT_GTT = 0x20000000, + ATH9K_INT_FATAL = 0x40000000, + ATH9K_INT_GLOBAL = 0x80000000, + ATH9K_INT_BMISC = ATH9K_INT_TIM | + ATH9K_INT_DTIM | + ATH9K_INT_DTIMSYNC | + ATH9K_INT_TSFOOR | + ATH9K_INT_CABEND, + ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | + ATH9K_INT_RXDESC | + ATH9K_INT_RXEOL | + ATH9K_INT_RXORN | + ATH9K_INT_TXURN | + ATH9K_INT_TXDESC | + ATH9K_INT_MIB | + ATH9K_INT_RXPHY | + ATH9K_INT_RXKCM | + ATH9K_INT_SWBA | + ATH9K_INT_BMISS | + ATH9K_INT_GPIO, + ATH9K_INT_NOCARD = 0xffffffff }; -#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u32 *)(array); \ - (iniarray)->ia_rows = (rows); \ - (iniarray)->ia_columns = (columns); \ - } while (0) - -#define INI_RA(iniarray, row, column) \ - (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) +#define CHANNEL_CW_INT 0x00002 +#define CHANNEL_CCK 0x00020 +#define CHANNEL_OFDM 0x00040 +#define CHANNEL_2GHZ 0x00080 +#define CHANNEL_5GHZ 0x00100 +#define CHANNEL_PASSIVE 0x00200 +#define CHANNEL_DYN 0x00400 +#define CHANNEL_HALF 0x04000 +#define CHANNEL_QUARTER 0x08000 +#define CHANNEL_HT20 0x10000 +#define CHANNEL_HT40PLUS 0x20000 +#define CHANNEL_HT40MINUS 0x40000 + +#define CHANNEL_INTERFERENCE 0x01 +#define CHANNEL_DFS 0x02 +#define CHANNEL_4MS_LIMIT 0x04 +#define CHANNEL_DFS_CLEAR 0x08 +#define CHANNEL_DISALLOW_ADHOC 0x10 +#define CHANNEL_PER_11D_ADHOC 0x20 + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) +#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) +#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) +#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) +#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) +#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) +#define CHANNEL_ALL \ + (CHANNEL_OFDM| \ + CHANNEL_CCK| \ + CHANNEL_2GHZ | \ + CHANNEL_5GHZ | \ + CHANNEL_HT20 | \ + CHANNEL_HT40PLUS | \ + CHANNEL_HT40MINUS) + +struct ath9k_channel { + struct ieee80211_channel *chan; + u16 channel; + u32 channelFlags; + u32 chanmode; + int32_t CalValid; + bool oneTimeCalsDone; + int8_t iCoff; + int8_t qCoff; + int16_t rawNoiseFloor; +}; -#define INIT_CAL(_perCal) do { \ - (_perCal)->calState = CAL_WAITING; \ - (_perCal)->calNext = NULL; \ - } while (0) +#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ + (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ + (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ + (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) +#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ + (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ + (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ + (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) +#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) +#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) +#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) +#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) +#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) +#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) +#define IS_CHAN_A_5MHZ_SPACED(_c) \ + ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ + (((_c)->channel % 20) != 0) && \ + (((_c)->channel % 10) != 0)) + +/* These macros check chanmode and not channelFlags */ +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) +#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ + ((_c)->chanmode == CHANNEL_G_HT20)) +#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ + ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \ + ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \ + ((_c)->chanmode == CHANNEL_G_HT40MINUS)) +#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) + +enum ath9k_power_mode { + ATH9K_PM_AWAKE = 0, + ATH9K_PM_FULL_SLEEP, + ATH9K_PM_NETWORK_SLEEP, + ATH9K_PM_UNDEFINED +}; -#define INSERT_CAL(_ahp, _perCal) \ - do { \ - if ((_ahp)->ah_cal_list_last == NULL) { \ - (_ahp)->ah_cal_list = \ - (_ahp)->ah_cal_list_last = (_perCal); \ - ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ - } else { \ - ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ - (_ahp)->ah_cal_list_last = (_perCal); \ - (_perCal)->calNext = (_ahp)->ah_cal_list; \ - } \ - } while (0) +enum ath9k_ant_setting { + ATH9K_ANT_VARIABLE = 0, + ATH9K_ANT_FIXED_A, + ATH9K_ANT_FIXED_B +}; -enum hal_cal_types { - ADC_DC_INIT_CAL = 0x1, - ADC_GAIN_CAL = 0x2, - ADC_DC_CAL = 0x4, - IQ_MISMATCH_CAL = 0x8 +enum ath9k_tp_scale { + ATH9K_TP_SCALE_MAX = 0, + ATH9K_TP_SCALE_50, + ATH9K_TP_SCALE_25, + ATH9K_TP_SCALE_12, + ATH9K_TP_SCALE_MIN }; -enum hal_cal_state { - CAL_INACTIVE, - CAL_WAITING, - CAL_RUNNING, - CAL_DONE +enum ser_reg_mode { + SER_REG_MODE_OFF = 0, + SER_REG_MODE_ON = 1, + SER_REG_MODE_AUTO = 2, }; -#define MIN_CAL_SAMPLES 1 -#define MAX_CAL_SAMPLES 64 -#define INIT_LOG_COUNT 5 -#define PER_MIN_LOG_COUNT 2 -#define PER_MAX_LOG_COUNT 10 +struct ath9k_beacon_state { + u32 bs_nexttbtt; + u32 bs_nextdtim; + u32 bs_intval; +#define ATH9K_BEACON_PERIOD 0x0000ffff +#define ATH9K_BEACON_ENA 0x00800000 +#define ATH9K_BEACON_RESET_TSF 0x01000000 +#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ + u32 bs_dtimperiod; + u16 bs_cfpperiod; + u16 bs_cfpmaxduration; + u32 bs_cfpnext; + u16 bs_timoffset; + u16 bs_bmissthreshold; + u32 bs_sleepduration; + u32 bs_tsfoor_threshold; +}; -struct hal_percal_data { - enum hal_cal_types calType; - u32 calNumSamples; - u32 calCountMax; - void (*calCollect) (struct ath_hal *); - void (*calPostProc) (struct ath_hal *, u8); +struct chan_centers { + u16 synth_center; + u16 ctl_center; + u16 ext_center; }; -struct hal_cal_list { - const struct hal_percal_data *calData; - enum hal_cal_state calState; - struct hal_cal_list *calNext; +enum { + ATH9K_RESET_POWER_ON, + ATH9K_RESET_WARM, + ATH9K_RESET_COLD, }; -/* - * Enum to indentify the eeprom mappings - */ -enum hal_eep_map { - EEP_MAP_DEFAULT = 0x0, - EEP_MAP_4KBITS, - EEP_MAP_MAX +struct ath9k_hw_version { + u32 magic; + u16 devid; + u16 subvendorid; + u32 macVersion; + u16 macRev; + u16 phyRev; + u16 analog5GhzRev; + u16 analog2GhzRev; }; +struct ath_hw { + struct ath_softc *ah_sc; + struct ath9k_hw_version hw_version; + struct ath9k_ops_config config; + struct ath9k_hw_capabilities caps; + struct ath9k_regulatory regulatory; + struct ath9k_channel channels[38]; + struct ath9k_channel *curchan; -struct ath_hal_5416 { - struct ath_hal ah; union { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; - } ah_eeprom; - struct ar5416Stats ah_stats; - struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; - void __iomem *ah_cal_mem; - - u8 ah_macaddr[ETH_ALEN]; - u8 ah_bssid[ETH_ALEN]; - u8 ah_bssidmask[ETH_ALEN]; - u16 ah_assocId; - - int16_t ah_curchanRadIndex; - u32 ah_maskReg; - u32 ah_txOkInterruptMask; - u32 ah_txErrInterruptMask; - u32 ah_txDescInterruptMask; - u32 ah_txEolInterruptMask; - u32 ah_txUrnInterruptMask; - bool ah_chipFullSleep; - u32 ah_atimWindow; - u16 ah_antennaSwitchSwap; - enum ath9k_power_mode ah_powerMode; - enum ath9k_ant_setting ah_diversityControl; + } eeprom; + const struct eeprom_ops *eep_ops; + enum ath9k_eep_map eep_map; + + bool sw_mgmt_crypto; + bool is_pciexpress; + u8 macaddr[ETH_ALEN]; + u16 tx_trig_level; + u16 rfsilent; + u32 rfkill_gpio; + u32 rfkill_polarity; + u32 btactive_gpio; + u32 wlanactive_gpio; + u32 ah_flags; + + enum nl80211_iftype opmode; + enum ath9k_power_mode power_mode; + enum ath9k_power_mode restore_mode; + + struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + struct ar5416Stats stats; + struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; + + int16_t curchan_rad_index; + u32 mask_reg; + u32 txok_interrupt_mask; + u32 txerr_interrupt_mask; + u32 txdesc_interrupt_mask; + u32 txeol_interrupt_mask; + u32 txurn_interrupt_mask; + bool chip_fullsleep; + u32 atim_window; + u16 antenna_switch_swap; + enum ath9k_ant_setting diversity_control; /* Calibration */ - enum hal_cal_types ah_suppCals; - struct hal_cal_list ah_iqCalData; - struct hal_cal_list ah_adcGainCalData; - struct hal_cal_list ah_adcDcCalInitData; - struct hal_cal_list ah_adcDcCalData; - struct hal_cal_list *ah_cal_list; - struct hal_cal_list *ah_cal_list_last; - struct hal_cal_list *ah_cal_list_curr; -#define ah_totalPowerMeasI ah_Meas0.unsign -#define ah_totalPowerMeasQ ah_Meas1.unsign -#define ah_totalIqCorrMeas ah_Meas2.sign -#define ah_totalAdcIOddPhase ah_Meas0.unsign -#define ah_totalAdcIEvenPhase ah_Meas1.unsign -#define ah_totalAdcQOddPhase ah_Meas2.unsign -#define ah_totalAdcQEvenPhase ah_Meas3.unsign -#define ah_totalAdcDcOffsetIOddPhase ah_Meas0.sign -#define ah_totalAdcDcOffsetIEvenPhase ah_Meas1.sign -#define ah_totalAdcDcOffsetQOddPhase ah_Meas2.sign -#define ah_totalAdcDcOffsetQEvenPhase ah_Meas3.sign + enum hal_cal_types supp_cals; + struct hal_cal_list iq_caldata; + struct hal_cal_list adcgain_caldata; + struct hal_cal_list adcdc_calinitdata; + struct hal_cal_list adcdc_caldata; + struct hal_cal_list *cal_list; + struct hal_cal_list *cal_list_last; + struct hal_cal_list *cal_list_curr; +#define totalPowerMeasI meas0.unsign +#define totalPowerMeasQ meas1.unsign +#define totalIqCorrMeas meas2.sign +#define totalAdcIOddPhase meas0.unsign +#define totalAdcIEvenPhase meas1.unsign +#define totalAdcQOddPhase meas2.unsign +#define totalAdcQEvenPhase meas3.unsign +#define totalAdcDcOffsetIOddPhase meas0.sign +#define totalAdcDcOffsetIEvenPhase meas1.sign +#define totalAdcDcOffsetQOddPhase meas2.sign +#define totalAdcDcOffsetQEvenPhase meas3.sign union { u32 unsign[AR5416_MAX_CHAINS]; int32_t sign[AR5416_MAX_CHAINS]; - } ah_Meas0; + } meas0; union { u32 unsign[AR5416_MAX_CHAINS]; int32_t sign[AR5416_MAX_CHAINS]; - } ah_Meas1; + } meas1; union { u32 unsign[AR5416_MAX_CHAINS]; int32_t sign[AR5416_MAX_CHAINS]; - } ah_Meas2; + } meas2; union { u32 unsign[AR5416_MAX_CHAINS]; int32_t sign[AR5416_MAX_CHAINS]; - } ah_Meas3; - u16 ah_CalSamples; + } meas3; + u16 cal_samples; - u32 ah_staId1Defaults; - u32 ah_miscMode; + u32 sta_id1_defaults; + u32 misc_mode; enum { AUTO_32KHZ, USE_32KHZ, DONT_USE_32KHZ, - } ah_enable32kHzClock; + } enable_32kHz_clock; /* RF */ - u32 *ah_analogBank0Data; - u32 *ah_analogBank1Data; - u32 *ah_analogBank2Data; - u32 *ah_analogBank3Data; - u32 *ah_analogBank6Data; - u32 *ah_analogBank6TPCData; - u32 *ah_analogBank7Data; - u32 *ah_addac5416_21; - u32 *ah_bank6Temp; - - int16_t ah_txPowerIndexOffset; - u32 ah_beaconInterval; - u32 ah_slottime; - u32 ah_acktimeout; - u32 ah_ctstimeout; - u32 ah_globaltxtimeout; - u8 ah_gBeaconRate; - u32 ah_gpioSelect; - u32 ah_polarity; - u32 ah_gpioBit; + u32 *analogBank0Data; + u32 *analogBank1Data; + u32 *analogBank2Data; + u32 *analogBank3Data; + u32 *analogBank6Data; + u32 *analogBank6TPCData; + u32 *analogBank7Data; + u32 *addac5416_21; + u32 *bank6Temp; + + int16_t txpower_indexoffset; + u32 beacon_interval; + u32 slottime; + u32 acktimeout; + u32 ctstimeout; + u32 globaltxtimeout; + u8 gbeacon_rate; /* ANI */ - u32 ah_procPhyErr; - bool ah_hasHwPhyCounters; - u32 ah_aniPeriod; - struct ar5416AniState *ah_curani; - struct ar5416AniState ah_ani[255]; - int ah_totalSizeDesired[5]; - int ah_coarseHigh[5]; - int ah_coarseLow[5]; - int ah_firpwr[5]; - enum ath9k_ani_cmd ah_ani_function; - - u32 ah_intrTxqs; - bool ah_intrMitigation; - enum ath9k_ht_extprotspacing ah_extprotspacing; - u8 ah_txchainmask; - u8 ah_rxchainmask; - - struct ar5416IniArray ah_iniModes; - struct ar5416IniArray ah_iniCommon; - struct ar5416IniArray ah_iniBank0; - struct ar5416IniArray ah_iniBB_RfGain; - struct ar5416IniArray ah_iniBank1; - struct ar5416IniArray ah_iniBank2; - struct ar5416IniArray ah_iniBank3; - struct ar5416IniArray ah_iniBank6; - struct ar5416IniArray ah_iniBank6TPC; - struct ar5416IniArray ah_iniBank7; - struct ar5416IniArray ah_iniAddac; - struct ar5416IniArray ah_iniPcieSerdes; - struct ar5416IniArray ah_iniModesAdditional; - struct ar5416IniArray ah_iniModesRxGain; - struct ar5416IniArray ah_iniModesTxGain; - /* To indicate EEPROM mapping used */ - enum hal_eep_map ah_eep_map; + u32 proc_phyerr; + bool has_hw_phycounters; + u32 aniperiod; + struct ar5416AniState *curani; + struct ar5416AniState ani[255]; + int totalSizeDesired[5]; + int coarse_high[5]; + int coarse_low[5]; + int firpwr[5]; + enum ath9k_ani_cmd ani_function; + + u32 intr_txqs; + bool intr_mitigation; + enum ath9k_ht_extprotspacing extprotspacing; + u8 txchainmask; + u8 rxchainmask; + + u32 originalGain[22]; + int initPDADC; + int PDADCdelta; + + struct ar5416IniArray iniModes; + struct ar5416IniArray iniCommon; + struct ar5416IniArray iniBank0; + struct ar5416IniArray iniBB_RfGain; + struct ar5416IniArray iniBank1; + struct ar5416IniArray iniBank2; + struct ar5416IniArray iniBank3; + struct ar5416IniArray iniBank6; + struct ar5416IniArray iniBank6TPC; + struct ar5416IniArray iniBank7; + struct ar5416IniArray iniAddac; + struct ar5416IniArray iniPcieSerdes; + struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesRxGain; + struct ar5416IniArray iniModesTxGain; }; -#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) - -#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) - -#define ar5416RfDetach(ah) do { \ - if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \ - AH5416(ah)->ah_rfHal.rfDetach(ah); \ - } while (0) - -#define ath9k_hw_use_flash(_ah) \ - (!(_ah->ah_flags & AH_USE_EEPROM)) - - -#define DO_DELAY(x) do { \ - if ((++(x) % 64) == 0) \ - udelay(1); \ - } while (0) - -#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ - DO_DELAY(regWr); \ - } \ - } while (0) - -#define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 1000 -#define COEF_SCALE_S 24 -#define HT40_CHANNEL_CENTER_SHIFT 10 - -#define AR5416_EEPROM_MAGIC_OFFSET 0x0 - -#define AR5416_EEPROM_S 2 -#define AR5416_EEPROM_OFFSET 0x2000 -#define AR5416_EEPROM_START_ADDR \ - (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 -#define AR5416_EEPROM_MAX 0xae0 -#define ar5416_get_eep_ver(_ahp) \ - (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF) -#define ar5416_get_eep_rev(_ahp) \ - (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF) -#define ar5416_get_ntxchains(_txchainmask) \ - (((_txchainmask >> 2) & 1) + \ - ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -/* EEPROM 4K bit map definations */ -#define ar5416_get_eep4k_ver(_ahp) \ - (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF) -#define ar5416_get_eep4k_rev(_ahp) \ - (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF) - - -#ifdef __BIG_ENDIAN -#define AR5416_EEPROM_MAGIC 0x5aa5 -#else -#define AR5416_EEPROM_MAGIC 0xa55a +/* Attach, Detach, Reset */ +const char *ath9k_hw_probe(u16 vendorid, u16 devid); +void ath9k_hw_detach(struct ath_hw *ah); +struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); +void ath9k_hw_rfdetach(struct ath_hw *ah); +int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + bool bChannelChange); +bool ath9k_hw_fill_cap_info(struct ath_hw *ah); +bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 *result); +bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status); + +/* Key Cache Management */ +bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); +bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac); +bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac); +bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry); + +/* GPIO / RFKILL / Antennae */ +void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); +void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hw *ah); #endif - -#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) - -#define ATH9K_ANTENNA0_CHAINMASK 0x1 -#define ATH9K_ANTENNA1_CHAINMASK 0x2 - -#define ATH9K_NUM_DMA_DEBUG_REGS 8 -#define ATH9K_NUM_QUEUES 10 - -#define HAL_NOISE_IMMUNE_MAX 4 -#define HAL_SPUR_IMMUNE_MAX 7 -#define HAL_FIRST_STEP_MAX 2 - -#define ATH9K_ANI_OFDM_TRIG_HIGH 500 -#define ATH9K_ANI_OFDM_TRIG_LOW 200 -#define ATH9K_ANI_CCK_TRIG_HIGH 200 -#define ATH9K_ANI_CCK_TRIG_LOW 100 -#define ATH9K_ANI_NOISE_IMMUNE_LVL 4 -#define ATH9K_ANI_USE_OFDM_WEAK_SIG true -#define ATH9K_ANI_CCK_WEAK_SIG_THR false -#define ATH9K_ANI_SPUR_IMMUNE_LVL 7 -#define ATH9K_ANI_FIRSTEP_LVL 0 -#define ATH9K_ANI_RSSI_THR_HIGH 40 -#define ATH9K_ANI_RSSI_THR_LOW 7 -#define ATH9K_ANI_PERIOD 100 - -#define AR_GPIOD_MASK 0x00001FFF -#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) - -#define HAL_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define BEACON_RSSI(ahp) \ - HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ - ATH9K_RSSI_EP_MULTIPLIER) - -#define ah_mibStats ah_stats.ast_mibstats - -#define AH_TIMEOUT 100000 -#define AH_TIME_QUANTUM 10 - -#define AR_KEYTABLE_SIZE 128 -#define POWER_UP_TIME 200000 - -#define EXT_ADDITIVE (0x8000) -#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) -#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) -#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) - -#define SUB_NUM_CTL_MODES_AT_5G_40 2 -#define SUB_NUM_CTL_MODES_AT_2G_40 3 -#define SPUR_RSSI_THRESH 40 - -#define TU_TO_USEC(_tu) ((_tu) << 10) - -#define CAB_TIMEOUT_VAL 10 -#define BEACON_TIMEOUT_VAL 10 -#define MIN_BEACON_TIMEOUT_VAL 1 -#define SLEEP_SLOP 3 - -#define CCK_SIFS_TIME 10 -#define CCK_PREAMBLE_BITS 144 -#define CCK_PLCP_BITS 48 - -#define OFDM_SIFS_TIME 16 -#define OFDM_PREAMBLE_TIME 20 -#define OFDM_PLCP_BITS 22 -#define OFDM_SYMBOL_TIME 4 - -#define OFDM_SIFS_TIME_HALF 32 -#define OFDM_PREAMBLE_TIME_HALF 40 -#define OFDM_PLCP_BITS_HALF 22 -#define OFDM_SYMBOL_TIME_HALF 8 - -#define OFDM_SIFS_TIME_QUARTER 64 -#define OFDM_PREAMBLE_TIME_QUARTER 80 -#define OFDM_PLCP_BITS_QUARTER 22 -#define OFDM_SYMBOL_TIME_QUARTER 16 - -u32 ath9k_hw_get_eeprom(struct ath_hal *ah, - enum eeprom_param param); +u32 ath9k_hw_getdefantenna(struct ath_hw *ah); +void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); +bool ath9k_hw_setantennaswitch(struct ath_hw *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, u8 *rx_chainmask, + u8 *antenna_cfgd); + +/* General Operation */ +bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); +u32 ath9k_hw_reverse_bits(u32 val, u32 n); +bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); +u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, + u32 frameLen, u16 rateix, bool shortPreamble); +void ath9k_hw_get_channel_centers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct chan_centers *centers); +u32 ath9k_hw_getrxfilter(struct ath_hw *ah); +void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); +bool ath9k_hw_phy_disable(struct ath_hw *ah); +bool ath9k_hw_disable(struct ath_hw *ah); +bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); +void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); +void ath9k_hw_setopmode(struct ath_hw *ah); +void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); +void ath9k_hw_setbssidmask(struct ath_softc *sc); +void ath9k_hw_write_associd(struct ath_softc *sc); +u64 ath9k_hw_gettsf64(struct ath_hw *ah); +void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); +void ath9k_hw_reset_tsf(struct ath_hw *ah); +bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); +void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); +void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); +void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, + const struct ath9k_beacon_state *bs); +bool ath9k_hw_setpower(struct ath_hw *ah, + enum ath9k_power_mode mode); +void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore); + +/* Interrupt Handling */ +bool ath9k_hw_intrpend(struct ath_hw *ah); +bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); +enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); + +void ath9k_hw_btcoex_enable(struct ath_hw *ah); #endif diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index f3cfa16525e4..e2f0a34b79a1 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,8 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* AR5416 to Fowl ar5146.ini */ -static const u32 ar5416Modes_9100[][6] = { +static const u32 ar5416Modes[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -79,7 +78,7 @@ static const u32 ar5416Modes_9100[][6] = { { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, }; -static const u32 ar5416Common_9100[][2] = { +static const u32 ar5416Common[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020015 }, { 0x00000034, 0x00000005 }, @@ -457,12 +456,12 @@ static const u32 ar5416Common_9100[][2] = { { 0x0000a3e0, 0x000001ce }, }; -static const u32 ar5416Bank0_9100[][2] = { +static const u32 ar5416Bank0[][2] = { { 0x000098b0, 0x1e5795e5 }, { 0x000098e0, 0x02008020 }, }; -static const u32 ar5416BB_RfGain_9100[][3] = { +static const u32 ar5416BB_RfGain[][3] = { { 0x00009a00, 0x00000000, 0x00000000 }, { 0x00009a04, 0x00000040, 0x00000040 }, { 0x00009a08, 0x00000080, 0x00000080 }, @@ -529,21 +528,21 @@ static const u32 ar5416BB_RfGain_9100[][3] = { { 0x00009afc, 0x000000f9, 0x000000f9 }, }; -static const u32 ar5416Bank1_9100[][2] = { +static const u32 ar5416Bank1[][2] = { { 0x000098b0, 0x02108421 }, { 0x000098ec, 0x00000008 }, }; -static const u32 ar5416Bank2_9100[][2] = { +static const u32 ar5416Bank2[][2] = { { 0x000098b0, 0x0e73ff17 }, { 0x000098e0, 0x00000420 }, }; -static const u32 ar5416Bank3_9100[][3] = { +static const u32 ar5416Bank3[][3] = { { 0x000098f0, 0x01400018, 0x01c00018 }, }; -static const u32 ar5416Bank6_9100[][3] = { +static const u32 ar5416Bank6[][3] = { { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -580,7 +579,7 @@ static const u32 ar5416Bank6_9100[][3] = { { 0x000098d0, 0x0000000f, 0x0010000f }, }; -static const u32 ar5416Bank6TPC_9100[][3] = { +static const u32 ar5416Bank6TPC[][3] = { { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -616,13 +615,13 @@ static const u32 ar5416Bank6TPC_9100[][3] = { { 0x000098d0, 0x0000000f, 0x0010000f }, }; -static const u32 ar5416Bank7_9100[][2] = { +static const u32 ar5416Bank7[][2] = { { 0x0000989c, 0x00000500 }, { 0x0000989c, 0x00000800 }, { 0x000098cc, 0x0000000e }, }; -static const u32 ar5416Addac_9100[][2] = { +static const u32 ar5416Addac[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000003 }, {0x0000989c, 0x00000000 }, @@ -659,11 +658,10 @@ static const u32 ar5416Addac_9100[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, - {0x000098c4, 0x00000000 }, + {0x000098cc, 0x00000000 }, }; -/* ar5416 - howl ar5416_howl.ini */ -static const u32 ar5416Modes[][6] = { +static const u32 ar5416Modes_9100[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -737,7 +735,7 @@ static const u32 ar5416Modes[][6] = { { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, }; -static const u32 ar5416Common[][2] = { +static const u32 ar5416Common_9100[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020015 }, { 0x00000034, 0x00000005 }, @@ -1111,12 +1109,12 @@ static const u32 ar5416Common[][2] = { { 0x0000a3e0, 0x000001ce }, }; -static const u32 ar5416Bank0[][2] = { +static const u32 ar5416Bank0_9100[][2] = { { 0x000098b0, 0x1e5795e5 }, { 0x000098e0, 0x02008020 }, }; -static const u32 ar5416BB_RfGain[][3] = { +static const u32 ar5416BB_RfGain_9100[][3] = { { 0x00009a00, 0x00000000, 0x00000000 }, { 0x00009a04, 0x00000040, 0x00000040 }, { 0x00009a08, 0x00000080, 0x00000080 }, @@ -1183,21 +1181,21 @@ static const u32 ar5416BB_RfGain[][3] = { { 0x00009afc, 0x000000f9, 0x000000f9 }, }; -static const u32 ar5416Bank1[][2] = { +static const u32 ar5416Bank1_9100[][2] = { { 0x000098b0, 0x02108421}, { 0x000098ec, 0x00000008}, }; -static const u32 ar5416Bank2[][2] = { +static const u32 ar5416Bank2_9100[][2] = { { 0x000098b0, 0x0e73ff17}, { 0x000098e0, 0x00000420}, }; -static const u32 ar5416Bank3[][3] = { +static const u32 ar5416Bank3_9100[][3] = { { 0x000098f0, 0x01400018, 0x01c00018 }, }; -static const u32 ar5416Bank6[][3] = { +static const u32 ar5416Bank6_9100[][3] = { { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -1235,7 +1233,7 @@ static const u32 ar5416Bank6[][3] = { }; -static const u32 ar5416Bank6TPC[][3] = { +static const u32 ar5416Bank6TPC_9100[][3] = { { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -1272,13 +1270,13 @@ static const u32 ar5416Bank6TPC[][3] = { { 0x000098d0, 0x0000000f, 0x0010000f }, }; -static const u32 ar5416Bank7[][2] = { +static const u32 ar5416Bank7_9100[][2] = { { 0x0000989c, 0x00000500 }, { 0x0000989c, 0x00000800 }, { 0x000098cc, 0x0000000e }, }; -static const u32 ar5416Addac[][2] = { +static const u32 ar5416Addac_9100[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1313,7 +1311,6 @@ static const u32 ar5416Addac[][2] = { {0x000098cc, 0x00000000 }, }; -/* AR5416 9160 Sowl ar5416_sowl.ini */ static const u32 ar5416Modes_9160[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2549,6 +2546,8 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, @@ -2587,7 +2586,6 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, - { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, @@ -2719,7 +2717,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008110, 0x00000168 }, { 0x00008118, 0x000100aa }, { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, { 0x00008124, 0x00000000 }, { 0x00008128, 0x00000000 }, { 0x0000812c, 0x00000000 }, @@ -2735,7 +2732,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008178, 0x00000100 }, { 0x0000817c, 0x00000000 }, { 0x000081c0, 0x00000000 }, - { 0x000081d0, 0x00003210 }, { 0x000081ec, 0x00000000 }, { 0x000081f0, 0x00000000 }, { 0x000081f4, 0x00000000 }, @@ -2817,7 +2813,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x14750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x00009968, 0x000003ce }, + { 0x0000c968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -2909,16 +2905,12 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000780c, 0x21084210 }, { 0x00007810, 0x6d801300 }, { 0x00007818, 0x07e41000 }, - { 0x0000781c, 0x00392000 }, - { 0x00007820, 0x92592480 }, { 0x00007824, 0x00040000 }, { 0x00007828, 0xdb005012 }, { 0x0000782c, 0x04924914 }, { 0x00007830, 0x21084210 }, { 0x00007834, 0x6d801300 }, { 0x0000783c, 0x07e40000 }, - { 0x00007840, 0x00392000 }, - { 0x00007844, 0x92592480 }, { 0x00007848, 0x00100000 }, { 0x0000784c, 0x773f0567 }, { 0x00007850, 0x54214514 }, @@ -2954,7 +2946,6 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { { 0x00009844, 0x03721821, 0x03721821 }, { 0x00009914, 0x00000898, 0x00001130 }, { 0x00009918, 0x0000000b, 0x00000016 }, - { 0x00009944, 0xdfbc1210, 0xdfbc1210 }, }; static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { @@ -3366,21 +3357,26 @@ static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 }, + { 0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411 }, + { 0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413 }, + { 0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811 }, + { 0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813 }, + { 0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, + { 0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50 }, + { 0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, + { 0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, + { 0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92 }, + { 0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, + { 0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, + { 0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, + { 0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5 }, { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, + { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, + { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, + { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, + { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, }; @@ -3409,6 +3405,11 @@ static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, + { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, + { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, + { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, + { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, }; @@ -4120,6 +4121,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004044, 0x00000000 }, }; +/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -4135,11 +4137,11 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, @@ -4154,291 +4156,272 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, - { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, - { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, - { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, - { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, - { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, - { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, - { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, - { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, - { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, - { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, - { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, - { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, - { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, - { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, - { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, - { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, - { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, - { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, - { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, - { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, - { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, - { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, - { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, - { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, - { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, - { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, - { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, - { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, - { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, - { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, - { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, - { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, - { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, - { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, - { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, - { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, - { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, - { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, - { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, - { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, - { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, - { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, - { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, - { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, - { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, - { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, - { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, - { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, - { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, - { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, - { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, - { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, - { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, - { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, - { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, - { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, - { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, - { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, - { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, - { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, - { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, - { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, - { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, - { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, - { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, - { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, - { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, - { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, - { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, - { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, - { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, - { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, - { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, - { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, - { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, - { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, - { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, - { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, - { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, - { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, - { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, - { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, - { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, - { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, - { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, - { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, - { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, - { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, - { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, - { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, - { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, - { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, - { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, - { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, - { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, - { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, - { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, - { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, - { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, - { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, - { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, - { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, - { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, - { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, - { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, - { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, - { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, - { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, - { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, - { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, - { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, - { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, - { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, - { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, - { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, - { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, - { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, - { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, - { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, - { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, - { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, - { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, - { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, - { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, - { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, - { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, - { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, - { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, - { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, - { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, - { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, - { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, - { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, - { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, - { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, - { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, - { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, - { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, - { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, - { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, - { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, - { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, - { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, - { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, - { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, - { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, - { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, - { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, - { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, - { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, - { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, - { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, - { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, - { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, - { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, - { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, - { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, - { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, - { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, - { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, - { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, - { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, - { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, - { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, - { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, - { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, - { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, - { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, - { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, - { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 }, - { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 }, - { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 }, - { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, }; @@ -4568,7 +4551,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008110, 0x00000168 }, { 0x00008118, 0x000100aa }, { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, + { 0x00008120, 0x08f04810 }, { 0x00008124, 0x00000000 }, { 0x00008128, 0x00000000 }, { 0x0000812c, 0x00000000 }, @@ -4584,7 +4567,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008178, 0x00000100 }, { 0x0000817c, 0x00000000 }, { 0x000081c0, 0x00000000 }, - { 0x000081d0, 0x00003210 }, + { 0x000081d0, 0x0000320a }, { 0x000081ec, 0x00000000 }, { 0x000081f0, 0x00000000 }, { 0x000081f4, 0x00000000 }, @@ -4679,7 +4662,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x000099a0, 0x00000000 }, { 0x000099a4, 0x00000001 }, { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x2def1000 }, + { 0x000099ac, 0x2def0400 }, { 0x000099b0, 0x03051000 }, { 0x000099b4, 0x00000820 }, { 0x000099dc, 0x00000000 }, @@ -4688,7 +4671,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x000099e8, 0x3c466478 }, { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, - { 0x0000a208, 0x803e6788 }, + { 0x0000a208, 0x803e68c8 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x00206c10 }, { 0x0000a218, 0x009c4060 }, @@ -4708,8 +4691,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x0000a268, 0x00000000 }, { 0x0000a26c, 0x0ebae9e6 }, { 0x0000d270, 0x0d820820 }, - { 0x0000a278, 0x318c6318 }, - { 0x0000a27c, 0x050c0318 }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -4724,8 +4705,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x0000a388, 0x0c000000 }, { 0x0000a38c, 0x20202020 }, { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x318c6318 }, - { 0x0000a398, 0x00000318 }, { 0x0000a39c, 0x00000001 }, { 0x0000a3a0, 0x00000000 }, { 0x0000a3a4, 0x00000000 }, @@ -4740,8 +4719,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x0000a3cc, 0x20202020 }, { 0x0000a3d0, 0x20202020 }, { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x318c6318 }, - { 0x0000a3e0, 0x00000318 }, { 0x0000a3e4, 0x00000000 }, { 0x0000a3e8, 0x18c43433 }, { 0x0000a3ec, 0x00f70081 }, @@ -4752,13 +4729,11 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007810, 0x71c0d388 }, { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, - { 0x00007820, 0x00000c04 }, { 0x00007824, 0x00d86fff }, { 0x00007828, 0x26d2491b }, { 0x0000782c, 0x6e36d97b }, { 0x00007830, 0xedb6d96e }, { 0x00007834, 0x71400087 }, - { 0x00007838, 0xfac68801 }, { 0x0000783c, 0x0001fffe }, { 0x00007840, 0xffeb1a20 }, { 0x00007844, 0x000c0db6 }, @@ -4771,10 +4746,81 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007860, 0x21084210 }, { 0x00007864, 0xf7d7ffde }, { 0x00007868, 0xc2034080 }, - { 0x0000786c, 0x48609eb4 }, { 0x00007870, 0x10142c00 }, }; +static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, + { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, + { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, + { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, + { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, +}; + +static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 }, + { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, + { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c }, + { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, + { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, +}; + static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index af32d091dc38..e0a6dee45839 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,45 +14,40 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" +#include "ath9k.h" -static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, +static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) { - struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask, - ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask, - ahp->ah_txUrnInterruptMask); + ah->txok_interrupt_mask, ah->txerr_interrupt_mask, + ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, + ah->txurn_interrupt_mask); REG_WRITE(ah, AR_IMR_S0, - SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) - | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); + SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK) + | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC)); REG_WRITE(ah, AR_IMR_S1, - SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) - | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); + SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR) + | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL)); REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); + AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask); } -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) { return REG_READ(ah, AR_QTXDP(q)); } -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp) +bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) { REG_WRITE(ah, AR_QTXDP(q), txdp); return true; } -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); @@ -61,7 +56,7 @@ bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) return true; } -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) { u32 npend; @@ -75,16 +70,15 @@ u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) return npend; } -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) { - struct ath_hal_5416 *ahp = AH5416(ah); u32 txcfg, curLevel, newLevel; enum ath9k_int omask; - if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) + if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) return false; - omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); txcfg = REG_READ(ah, AR_TXCFG); curLevel = MS(txcfg, AR_FTRIG); @@ -100,21 +94,38 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) ath9k_hw_set_interrupts(ah, omask); - ah->ah_txTrigLevel = newLevel; + ah->tx_trig_level = newLevel; return newLevel != curLevel; } -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) { +#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ +#define ATH9K_TIME_QUANTUM 100 /* usec */ + + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_tx_queue_info *qi; u32 tsfLow, j, wait; + u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ah->txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + return false; + } REG_WRITE(ah, AR_Q_TXD, 1 << q); - for (wait = 1000; wait != 0; wait--) { + for (wait = wait_time; wait != 0; wait--) { if (ath9k_hw_numtxpending(ah, q) == 0) break; - udelay(100); + udelay(ATH9K_TIME_QUANTUM); } if (ath9k_hw_numtxpending(ah, q)) { @@ -144,8 +155,7 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) udelay(200); REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); - wait = 1000; - + wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, @@ -153,18 +163,20 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) "msec after killing last frame\n"); break; } - udelay(100); + udelay(ATH9K_TIME_QUANTUM); } REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); } REG_WRITE(ah, AR_Q_TXD, 0); - return wait != 0; + +#undef ATH9K_TX_STOP_DMA_TIMEOUT +#undef ATH9K_TIME_QUANTUM } -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, +bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0) { @@ -192,7 +204,7 @@ bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, return true; } -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -203,7 +215,7 @@ void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) ads->ds_txstatus8 = ads->ds_txstatus9 = 0; } -int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -273,19 +285,18 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 1; + ds->ds_txstat.ts_antenna = 0; return 0; } -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pktLen, enum ath9k_pkt_type type, u32 txPower, u32 keyIx, enum ath9k_key_type keyType, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); - struct ath_hal_5416 *ahp = AH5416(ah); - txPower += ahp->ah_txPowerIndexOffset; + txPower += ah->txpower_indexoffset; if (txPower > 63) txPower = 63; @@ -314,7 +325,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, } } -void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, struct ath_desc *lastds, u32 durUpdateEn, u32 rtsctsRate, u32 rtsctsDuration, @@ -325,9 +336,6 @@ void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, struct ar5416_desc *last_ads = AR5416DESC(lastds); u32 ds_ctl0; - (void) nseries; - (void) rtsctsDuration; - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { ds_ctl0 = ads->ds_ctl0; @@ -372,7 +380,7 @@ void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, last_ads->ds_ctl3 = ads->ds_ctl3; } -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, u32 aggrLen) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -382,7 +390,7 @@ void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); } -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, u32 numDelims) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -396,7 +404,7 @@ void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, ads->ds_ctl6 = ctl6; } -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -405,14 +413,14 @@ void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) ads->ds_ctl6 &= ~AR_PadDelim; } -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) { struct ar5416_desc *ads = AR5416DESC(ds); ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); } -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, u32 burstDuration) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -421,7 +429,7 @@ void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); } -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, +void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, u32 vmf) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -432,20 +440,17 @@ void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, ads->ds_ctl0 &= ~AR_VirtMoreFrag; } -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) { - struct ath_hal_5416 *ahp = AH5416(ah); - - *txqs &= ahp->ah_intrTxqs; - ahp->ah_intrTxqs &= ~(*txqs); + *txqs &= ah->intr_txqs; + ah->intr_txqs &= ~(*txqs); } -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, +bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) { u32 cw; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { @@ -453,7 +458,7 @@ bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, return false; } - qi = &ahp->ah_txq[q]; + qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); return false; @@ -509,11 +514,10 @@ bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, return true; } -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, +bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { @@ -521,7 +525,7 @@ bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, return false; } - qi = &ahp->ah_txq[q]; + qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); return false; @@ -545,12 +549,11 @@ bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, return true; } -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, +int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, const struct ath9k_tx_queue_info *qinfo) { - struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; int q; switch (type) { @@ -568,7 +571,7 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, break; case ATH9K_TX_QUEUE_DATA: for (q = 0; q < pCap->total_queues; q++) - if (ahp->ah_txq[q].tqi_type == + if (ah->txq[q].tqi_type == ATH9K_TX_QUEUE_INACTIVE) break; if (q == pCap->total_queues) { @@ -584,7 +587,7 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); - qi = &ahp->ah_txq[q]; + qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "tx queue %u already active\n", q); @@ -611,17 +614,16 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, return q; } -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); return false; } - qi = &ahp->ah_txq[q]; + qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); return false; @@ -630,21 +632,20 @@ bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ahp->ah_txOkInterruptMask &= ~(1 << q); - ahp->ah_txErrInterruptMask &= ~(1 << q); - ahp->ah_txDescInterruptMask &= ~(1 << q); - ahp->ah_txEolInterruptMask &= ~(1 << q); - ahp->ah_txUrnInterruptMask &= ~(1 << q); + ah->txok_interrupt_mask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; } -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; @@ -653,7 +654,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) return false; } - qi = &ahp->ah_txq[q]; + qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); return true; @@ -741,9 +742,9 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) | AR_Q_MISC_CBR_INCR_DIS1 | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - - (ah->ah_config.sw_beacon_response_time - - ah->ah_config.dma_beacon_response_time) - - ah->ah_config.additional_swba_backoff) * 1024; + (ah->config.sw_beacon_response_time - + ah->config.dma_beacon_response_time) - + ah->config.additional_swba_backoff) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) @@ -771,31 +772,31 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) } if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) - ahp->ah_txOkInterruptMask |= 1 << q; + ah->txok_interrupt_mask |= 1 << q; else - ahp->ah_txOkInterruptMask &= ~(1 << q); + ah->txok_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) - ahp->ah_txErrInterruptMask |= 1 << q; + ah->txerr_interrupt_mask |= 1 << q; else - ahp->ah_txErrInterruptMask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) - ahp->ah_txDescInterruptMask |= 1 << q; + ah->txdesc_interrupt_mask |= 1 << q; else - ahp->ah_txDescInterruptMask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) - ahp->ah_txEolInterruptMask |= 1 << q; + ah->txeol_interrupt_mask |= 1 << q; else - ahp->ah_txEolInterruptMask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) - ahp->ah_txUrnInterruptMask |= 1 << q; + ah->txurn_interrupt_mask |= 1 << q; else - ahp->ah_txUrnInterruptMask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; } -int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, +int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pa, struct ath_desc *nds, u64 tsf) { struct ar5416_desc ads; @@ -860,11 +861,11 @@ int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, return 0; } -bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, +bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_hw_capabilities *pCap = &ah->caps; ads->ds_ctl1 = size & AR_BufLen; if (flags & ATH9K_RXDESC_INTREQ) @@ -877,7 +878,7 @@ bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, return true; } -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) { u32 reg; @@ -885,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { + if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, + 0, AH_WAIT_TIMEOUT)) { REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); @@ -904,17 +906,17 @@ bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) return true; } -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp) { REG_WRITE(ah, AR_RXDP, rxdp); } -void ath9k_hw_rxena(struct ath_hal *ah) +void ath9k_hw_rxena(struct ath_hw *ah) { REG_WRITE(ah, AR_CR, AR_CR_RXE); } -void ath9k_hw_startpcureceive(struct ath_hal *ah) +void ath9k_hw_startpcureceive(struct ath_hw *ah) { ath9k_enable_mib_counters(ah); @@ -923,24 +925,41 @@ void ath9k_hw_startpcureceive(struct ath_hal *ah) REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); } -void ath9k_hw_stoppcurecv(struct ath_hal *ah) +void ath9k_hw_stoppcurecv(struct ath_hw *ah) { REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); ath9k_hw_disable_mib_counters(ah); } -bool ath9k_hw_stopdmarecv(struct ath_hal *ah) +bool ath9k_hw_stopdmarecv(struct ath_hw *ah) { +#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ +#define AH_RX_TIME_QUANTUM 100 /* usec */ + + int i; + REG_WRITE(ah, AR_CR, AR_CR_RXD); - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { + /* Wait for rx enable bit to go low */ + for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { + if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) + break; + udelay(AH_TIME_QUANTUM); + } + + if (i == 0) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "dma failed to stop in 10ms\n" - "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + "dma failed to stop in %d ms " + "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + AH_RX_STOP_DMA_TIMEOUT / 1000, + REG_READ(ah, AR_CR), + REG_READ(ah, AR_DIAG_SW)); return false; } else { return true; } + +#undef AH_RX_TIME_QUANTUM +#undef AH_RX_STOP_DMA_TIMEOUT } diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath9k/mac.h new file mode 100644 index 000000000000..1176bce8b76c --- /dev/null +++ b/drivers/net/wireless/ath9k/mac.h @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MAC_H +#define MAC_H + +#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \ + MS(ads->ds_rxstatus0, AR_RxRate) : \ + (ads->ds_rxstatus3 >> 2) & 0xFF) + +#define set11nTries(_series, _index) \ + (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) + +#define set11nRate(_series, _index) \ + (SM((_series)[_index].Rate, AR_XmitRate##_index)) + +#define set11nPktDurRTSCTS(_series, _index) \ + (SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \ + ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \ + AR_RTSCTSQual##_index : 0)) + +#define set11nRateFlags(_series, _index) \ + (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ + AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ + AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index)) + +#define CCK_SIFS_TIME 10 +#define CCK_PREAMBLE_BITS 144 +#define CCK_PLCP_BITS 48 + +#define OFDM_SIFS_TIME 16 +#define OFDM_PREAMBLE_TIME 20 +#define OFDM_PLCP_BITS 22 +#define OFDM_SYMBOL_TIME 4 + +#define OFDM_SIFS_TIME_HALF 32 +#define OFDM_PREAMBLE_TIME_HALF 40 +#define OFDM_PLCP_BITS_HALF 22 +#define OFDM_SYMBOL_TIME_HALF 8 + +#define OFDM_SIFS_TIME_QUARTER 64 +#define OFDM_PREAMBLE_TIME_QUARTER 80 +#define OFDM_PLCP_BITS_QUARTER 22 +#define OFDM_SYMBOL_TIME_QUARTER 16 + +#define INIT_AIFS 2 +#define INIT_CWMIN 15 +#define INIT_CWMIN_11B 31 +#define INIT_CWMAX 1023 +#define INIT_SH_RETRY 10 +#define INIT_LG_RETRY 10 +#define INIT_SSH_RETRY 32 +#define INIT_SLG_RETRY 32 + +#define ATH9K_SLOT_TIME_6 6 +#define ATH9K_SLOT_TIME_9 9 +#define ATH9K_SLOT_TIME_20 20 + +#define ATH9K_TXERR_XRETRY 0x01 +#define ATH9K_TXERR_FILT 0x02 +#define ATH9K_TXERR_FIFO 0x04 +#define ATH9K_TXERR_XTXOP 0x08 +#define ATH9K_TXERR_TIMER_EXPIRED 0x10 + +#define ATH9K_TX_BA 0x01 +#define ATH9K_TX_PWRMGMT 0x02 +#define ATH9K_TX_DESC_CFG_ERR 0x04 +#define ATH9K_TX_DATA_UNDERRUN 0x08 +#define ATH9K_TX_DELIM_UNDERRUN 0x10 +#define ATH9K_TX_SW_ABORTED 0x40 +#define ATH9K_TX_SW_FILTERED 0x80 + +#define MIN_TX_FIFO_THRESHOLD 0x1 +#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) +#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD + +struct ath_tx_status { + u32 ts_tstamp; + u16 ts_seqnum; + u8 ts_status; + u8 ts_ratecode; + u8 ts_rateindex; + int8_t ts_rssi; + u8 ts_shortretry; + u8 ts_longretry; + u8 ts_virtcol; + u8 ts_antenna; + u8 ts_flags; + int8_t ts_rssi_ctl0; + int8_t ts_rssi_ctl1; + int8_t ts_rssi_ctl2; + int8_t ts_rssi_ext0; + int8_t ts_rssi_ext1; + int8_t ts_rssi_ext2; + u8 pad[3]; + u32 ba_low; + u32 ba_high; + u32 evm0; + u32 evm1; + u32 evm2; +}; + +struct ath_rx_status { + u32 rs_tstamp; + u16 rs_datalen; + u8 rs_status; + u8 rs_phyerr; + int8_t rs_rssi; + u8 rs_keyix; + u8 rs_rate; + u8 rs_antenna; + u8 rs_more; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_isaggr; + u8 rs_moreaggr; + u8 rs_num_delims; + u8 rs_flags; + u32 evm0; + u32 evm1; + u32 evm2; +}; + +#define ATH9K_RXERR_CRC 0x01 +#define ATH9K_RXERR_PHY 0x02 +#define ATH9K_RXERR_FIFO 0x04 +#define ATH9K_RXERR_DECRYPT 0x08 +#define ATH9K_RXERR_MIC 0x10 + +#define ATH9K_RX_MORE 0x01 +#define ATH9K_RX_MORE_AGGR 0x02 +#define ATH9K_RX_GI 0x04 +#define ATH9K_RX_2040 0x08 +#define ATH9K_RX_DELIM_CRC_PRE 0x10 +#define ATH9K_RX_DELIM_CRC_POST 0x20 +#define ATH9K_RX_DECRYPT_BUSY 0x40 + +#define ATH9K_RXKEYIX_INVALID ((u8)-1) +#define ATH9K_TXKEYIX_INVALID ((u32)-1) + +struct ath_desc { + u32 ds_link; + u32 ds_data; + u32 ds_ctl0; + u32 ds_ctl1; + u32 ds_hw[20]; + union { + struct ath_tx_status tx; + struct ath_rx_status rx; + void *stats; + } ds_us; + void *ds_vdata; +} __packed; + +#define ds_txstat ds_us.tx +#define ds_rxstat ds_us.rx +#define ds_stat ds_us.stats + +#define ATH9K_TXDESC_CLRDMASK 0x0001 +#define ATH9K_TXDESC_NOACK 0x0002 +#define ATH9K_TXDESC_RTSENA 0x0004 +#define ATH9K_TXDESC_CTSENA 0x0008 +/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for + * the descriptor its marked on. We take a tx interrupt to reap + * descriptors when the h/w hits an EOL condition or + * when the descriptor is specifically marked to generate + * an interrupt with this flag. Descriptors should be + * marked periodically to insure timely replenishing of the + * supply needed for sending frames. Defering interrupts + * reduces system load and potentially allows more concurrent + * work to be done but if done to aggressively can cause + * senders to backup. When the hardware queue is left too + * large rate control information may also be too out of + * date. An Alternative for this is TX interrupt mitigation + * but this needs more testing. */ +#define ATH9K_TXDESC_INTREQ 0x0010 +#define ATH9K_TXDESC_VEOL 0x0020 +#define ATH9K_TXDESC_EXT_ONLY 0x0040 +#define ATH9K_TXDESC_EXT_AND_CTL 0x0080 +#define ATH9K_TXDESC_VMF 0x0100 +#define ATH9K_TXDESC_FRAG_IS_ON 0x0200 +#define ATH9K_TXDESC_CAB 0x0400 + +#define ATH9K_RXDESC_INTREQ 0x0020 + +struct ar5416_desc { + u32 ds_link; + u32 ds_data; + u32 ds_ctl0; + u32 ds_ctl1; + union { + struct { + u32 ctl2; + u32 ctl3; + u32 ctl4; + u32 ctl5; + u32 ctl6; + u32 ctl7; + u32 ctl8; + u32 ctl9; + u32 ctl10; + u32 ctl11; + u32 status0; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; + u32 status9; + } tx; + struct { + u32 status0; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; + } rx; + } u; +} __packed; + +#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) +#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) + +#define ds_ctl2 u.tx.ctl2 +#define ds_ctl3 u.tx.ctl3 +#define ds_ctl4 u.tx.ctl4 +#define ds_ctl5 u.tx.ctl5 +#define ds_ctl6 u.tx.ctl6 +#define ds_ctl7 u.tx.ctl7 +#define ds_ctl8 u.tx.ctl8 +#define ds_ctl9 u.tx.ctl9 +#define ds_ctl10 u.tx.ctl10 +#define ds_ctl11 u.tx.ctl11 + +#define ds_txstatus0 u.tx.status0 +#define ds_txstatus1 u.tx.status1 +#define ds_txstatus2 u.tx.status2 +#define ds_txstatus3 u.tx.status3 +#define ds_txstatus4 u.tx.status4 +#define ds_txstatus5 u.tx.status5 +#define ds_txstatus6 u.tx.status6 +#define ds_txstatus7 u.tx.status7 +#define ds_txstatus8 u.tx.status8 +#define ds_txstatus9 u.tx.status9 + +#define ds_rxstatus0 u.rx.status0 +#define ds_rxstatus1 u.rx.status1 +#define ds_rxstatus2 u.rx.status2 +#define ds_rxstatus3 u.rx.status3 +#define ds_rxstatus4 u.rx.status4 +#define ds_rxstatus5 u.rx.status5 +#define ds_rxstatus6 u.rx.status6 +#define ds_rxstatus7 u.rx.status7 +#define ds_rxstatus8 u.rx.status8 + +#define AR_FrameLen 0x00000fff +#define AR_VirtMoreFrag 0x00001000 +#define AR_TxCtlRsvd00 0x0000e000 +#define AR_XmitPower 0x003f0000 +#define AR_XmitPower_S 16 +#define AR_RTSEnable 0x00400000 +#define AR_VEOL 0x00800000 +#define AR_ClrDestMask 0x01000000 +#define AR_TxCtlRsvd01 0x1e000000 +#define AR_TxIntrReq 0x20000000 +#define AR_DestIdxValid 0x40000000 +#define AR_CTSEnable 0x80000000 + +#define AR_BufLen 0x00000fff +#define AR_TxMore 0x00001000 +#define AR_DestIdx 0x000fe000 +#define AR_DestIdx_S 13 +#define AR_FrameType 0x00f00000 +#define AR_FrameType_S 20 +#define AR_NoAck 0x01000000 +#define AR_InsertTS 0x02000000 +#define AR_CorruptFCS 0x04000000 +#define AR_ExtOnly 0x08000000 +#define AR_ExtAndCtl 0x10000000 +#define AR_MoreAggr 0x20000000 +#define AR_IsAggr 0x40000000 + +#define AR_BurstDur 0x00007fff +#define AR_BurstDur_S 0 +#define AR_DurUpdateEna 0x00008000 +#define AR_XmitDataTries0 0x000f0000 +#define AR_XmitDataTries0_S 16 +#define AR_XmitDataTries1 0x00f00000 +#define AR_XmitDataTries1_S 20 +#define AR_XmitDataTries2 0x0f000000 +#define AR_XmitDataTries2_S 24 +#define AR_XmitDataTries3 0xf0000000 +#define AR_XmitDataTries3_S 28 + +#define AR_XmitRate0 0x000000ff +#define AR_XmitRate0_S 0 +#define AR_XmitRate1 0x0000ff00 +#define AR_XmitRate1_S 8 +#define AR_XmitRate2 0x00ff0000 +#define AR_XmitRate2_S 16 +#define AR_XmitRate3 0xff000000 +#define AR_XmitRate3_S 24 + +#define AR_PacketDur0 0x00007fff +#define AR_PacketDur0_S 0 +#define AR_RTSCTSQual0 0x00008000 +#define AR_PacketDur1 0x7fff0000 +#define AR_PacketDur1_S 16 +#define AR_RTSCTSQual1 0x80000000 + +#define AR_PacketDur2 0x00007fff +#define AR_PacketDur2_S 0 +#define AR_RTSCTSQual2 0x00008000 +#define AR_PacketDur3 0x7fff0000 +#define AR_PacketDur3_S 16 +#define AR_RTSCTSQual3 0x80000000 + +#define AR_AggrLen 0x0000ffff +#define AR_AggrLen_S 0 +#define AR_TxCtlRsvd60 0x00030000 +#define AR_PadDelim 0x03fc0000 +#define AR_PadDelim_S 18 +#define AR_EncrType 0x0c000000 +#define AR_EncrType_S 26 +#define AR_TxCtlRsvd61 0xf0000000 + +#define AR_2040_0 0x00000001 +#define AR_GI0 0x00000002 +#define AR_ChainSel0 0x0000001c +#define AR_ChainSel0_S 2 +#define AR_2040_1 0x00000020 +#define AR_GI1 0x00000040 +#define AR_ChainSel1 0x00000380 +#define AR_ChainSel1_S 7 +#define AR_2040_2 0x00000400 +#define AR_GI2 0x00000800 +#define AR_ChainSel2 0x00007000 +#define AR_ChainSel2_S 12 +#define AR_2040_3 0x00008000 +#define AR_GI3 0x00010000 +#define AR_ChainSel3 0x000e0000 +#define AR_ChainSel3_S 17 +#define AR_RTSCTSRate 0x0ff00000 +#define AR_RTSCTSRate_S 20 +#define AR_TxCtlRsvd70 0xf0000000 + +#define AR_TxRSSIAnt00 0x000000ff +#define AR_TxRSSIAnt00_S 0 +#define AR_TxRSSIAnt01 0x0000ff00 +#define AR_TxRSSIAnt01_S 8 +#define AR_TxRSSIAnt02 0x00ff0000 +#define AR_TxRSSIAnt02_S 16 +#define AR_TxStatusRsvd00 0x3f000000 +#define AR_TxBaStatus 0x40000000 +#define AR_TxStatusRsvd01 0x80000000 + +#define AR_FrmXmitOK 0x00000001 +#define AR_ExcessiveRetries 0x00000002 +#define AR_FIFOUnderrun 0x00000004 +#define AR_Filtered 0x00000008 +#define AR_RTSFailCnt 0x000000f0 +#define AR_RTSFailCnt_S 4 +#define AR_DataFailCnt 0x00000f00 +#define AR_DataFailCnt_S 8 +#define AR_VirtRetryCnt 0x0000f000 +#define AR_VirtRetryCnt_S 12 +#define AR_TxDelimUnderrun 0x00010000 +#define AR_TxDataUnderrun 0x00020000 +#define AR_DescCfgErr 0x00040000 +#define AR_TxTimerExpired 0x00080000 +#define AR_TxStatusRsvd10 0xfff00000 + +#define AR_SendTimestamp ds_txstatus2 +#define AR_BaBitmapLow ds_txstatus3 +#define AR_BaBitmapHigh ds_txstatus4 + +#define AR_TxRSSIAnt10 0x000000ff +#define AR_TxRSSIAnt10_S 0 +#define AR_TxRSSIAnt11 0x0000ff00 +#define AR_TxRSSIAnt11_S 8 +#define AR_TxRSSIAnt12 0x00ff0000 +#define AR_TxRSSIAnt12_S 16 +#define AR_TxRSSICombined 0xff000000 +#define AR_TxRSSICombined_S 24 + +#define AR_TxEVM0 ds_txstatus5 +#define AR_TxEVM1 ds_txstatus6 +#define AR_TxEVM2 ds_txstatus7 + +#define AR_TxDone 0x00000001 +#define AR_SeqNum 0x00001ffe +#define AR_SeqNum_S 1 +#define AR_TxStatusRsvd80 0x0001e000 +#define AR_TxOpExceeded 0x00020000 +#define AR_TxStatusRsvd81 0x001c0000 +#define AR_FinalTxIdx 0x00600000 +#define AR_FinalTxIdx_S 21 +#define AR_TxStatusRsvd82 0x01800000 +#define AR_PowerMgmt 0x02000000 +#define AR_TxStatusRsvd83 0xfc000000 + +#define AR_RxCTLRsvd00 0xffffffff + +#define AR_BufLen 0x00000fff +#define AR_RxCtlRsvd00 0x00001000 +#define AR_RxIntrReq 0x00002000 +#define AR_RxCtlRsvd01 0xffffc000 + +#define AR_RxRSSIAnt00 0x000000ff +#define AR_RxRSSIAnt00_S 0 +#define AR_RxRSSIAnt01 0x0000ff00 +#define AR_RxRSSIAnt01_S 8 +#define AR_RxRSSIAnt02 0x00ff0000 +#define AR_RxRSSIAnt02_S 16 +#define AR_RxRate 0xff000000 +#define AR_RxRate_S 24 +#define AR_RxStatusRsvd00 0xff000000 + +#define AR_DataLen 0x00000fff +#define AR_RxMore 0x00001000 +#define AR_NumDelim 0x003fc000 +#define AR_NumDelim_S 14 +#define AR_RxStatusRsvd10 0xff800000 + +#define AR_RcvTimestamp ds_rxstatus2 + +#define AR_GI 0x00000001 +#define AR_2040 0x00000002 +#define AR_Parallel40 0x00000004 +#define AR_Parallel40_S 2 +#define AR_RxStatusRsvd30 0x000000f8 +#define AR_RxAntenna 0xffffff00 +#define AR_RxAntenna_S 8 + +#define AR_RxRSSIAnt10 0x000000ff +#define AR_RxRSSIAnt10_S 0 +#define AR_RxRSSIAnt11 0x0000ff00 +#define AR_RxRSSIAnt11_S 8 +#define AR_RxRSSIAnt12 0x00ff0000 +#define AR_RxRSSIAnt12_S 16 +#define AR_RxRSSICombined 0xff000000 +#define AR_RxRSSICombined_S 24 + +#define AR_RxEVM0 ds_rxstatus4 +#define AR_RxEVM1 ds_rxstatus5 +#define AR_RxEVM2 ds_rxstatus6 + +#define AR_RxDone 0x00000001 +#define AR_RxFrameOK 0x00000002 +#define AR_CRCErr 0x00000004 +#define AR_DecryptCRCErr 0x00000008 +#define AR_PHYErr 0x00000010 +#define AR_MichaelErr 0x00000020 +#define AR_PreDelimCRCErr 0x00000040 +#define AR_RxStatusRsvd70 0x00000080 +#define AR_RxKeyIdxValid 0x00000100 +#define AR_KeyIdx 0x0000fe00 +#define AR_KeyIdx_S 9 +#define AR_PHYErrCode 0x0000ff00 +#define AR_PHYErrCode_S 8 +#define AR_RxMoreAggr 0x00010000 +#define AR_RxAggr 0x00020000 +#define AR_PostDelimCRCErr 0x00040000 +#define AR_RxStatusRsvd71 0x3ff80000 +#define AR_DecryptBusyErr 0x40000000 +#define AR_KeyMiss 0x80000000 + +enum ath9k_tx_queue { + ATH9K_TX_QUEUE_INACTIVE = 0, + ATH9K_TX_QUEUE_DATA, + ATH9K_TX_QUEUE_BEACON, + ATH9K_TX_QUEUE_CAB, + ATH9K_TX_QUEUE_UAPSD, + ATH9K_TX_QUEUE_PSPOLL +}; + +#define ATH9K_NUM_TX_QUEUES 10 + +enum ath9k_tx_queue_subtype { + ATH9K_WME_AC_BK = 0, + ATH9K_WME_AC_BE, + ATH9K_WME_AC_VI, + ATH9K_WME_AC_VO, + ATH9K_WME_UPSD +}; + +enum ath9k_tx_queue_flags { + TXQ_FLAG_TXOKINT_ENABLE = 0x0001, + TXQ_FLAG_TXERRINT_ENABLE = 0x0001, + TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, + TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, + TXQ_FLAG_TXURNINT_ENABLE = 0x0008, + TXQ_FLAG_BACKOFF_DISABLE = 0x0010, + TXQ_FLAG_COMPRESSION_ENABLE = 0x0020, + TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040, + TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080, +}; + +#define ATH9K_TXQ_USEDEFAULT ((u32) -1) +#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 + +#define ATH9K_DECOMP_MASK_SIZE 128 +#define ATH9K_READY_TIME_LO_BOUND 50 +#define ATH9K_READY_TIME_HI_BOUND 96 + +enum ath9k_pkt_type { + ATH9K_PKT_TYPE_NORMAL = 0, + ATH9K_PKT_TYPE_ATIM, + ATH9K_PKT_TYPE_PSPOLL, + ATH9K_PKT_TYPE_BEACON, + ATH9K_PKT_TYPE_PROBE_RESP, + ATH9K_PKT_TYPE_CHIRP, + ATH9K_PKT_TYPE_GRP_POLL, +}; + +struct ath9k_tx_queue_info { + u32 tqi_ver; + enum ath9k_tx_queue tqi_type; + enum ath9k_tx_queue_subtype tqi_subtype; + enum ath9k_tx_queue_flags tqi_qflags; + u32 tqi_priority; + u32 tqi_aifs; + u32 tqi_cwmin; + u32 tqi_cwmax; + u16 tqi_shretry; + u16 tqi_lgretry; + u32 tqi_cbrPeriod; + u32 tqi_cbrOverflowLimit; + u32 tqi_burstTime; + u32 tqi_readyTime; + u32 tqi_physCompBuf; + u32 tqi_intFlags; +}; + +enum ath9k_rx_filter { + ATH9K_RX_FILTER_UCAST = 0x00000001, + ATH9K_RX_FILTER_MCAST = 0x00000002, + ATH9K_RX_FILTER_BCAST = 0x00000004, + ATH9K_RX_FILTER_CONTROL = 0x00000008, + ATH9K_RX_FILTER_BEACON = 0x00000010, + ATH9K_RX_FILTER_PROM = 0x00000020, + ATH9K_RX_FILTER_PROBEREQ = 0x00000080, + ATH9K_RX_FILTER_PHYERR = 0x00000100, + ATH9K_RX_FILTER_MYBEACON = 0x00000200, + ATH9K_RX_FILTER_PSPOLL = 0x00004000, + ATH9K_RX_FILTER_PHYRADAR = 0x00002000, + ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, +}; + +#define ATH9K_RATESERIES_RTS_CTS 0x0001 +#define ATH9K_RATESERIES_2040 0x0002 +#define ATH9K_RATESERIES_HALFGI 0x0004 + +struct ath9k_11n_rate_series { + u32 Tries; + u32 Rate; + u32 PktDuration; + u32 ChSel; + u32 RateFlags; +}; + +struct ath9k_keyval { + u8 kv_type; + u8 kv_pad; + u16 kv_len; + u8 kv_val[16]; /* TK */ + u8 kv_mic[8]; /* Michael MIC key */ + u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware + * supports both MIC keys in the same key cache entry; + * in that case, kv_mic is the RX key) */ +}; + +enum ath9k_key_type { + ATH9K_KEY_TYPE_CLEAR, + ATH9K_KEY_TYPE_WEP, + ATH9K_KEY_TYPE_AES, + ATH9K_KEY_TYPE_TKIP, +}; + +enum ath9k_cipher { + ATH9K_CIPHER_WEP = 0, + ATH9K_CIPHER_AES_OCB = 1, + ATH9K_CIPHER_AES_CCM = 2, + ATH9K_CIPHER_CKIP = 3, + ATH9K_CIPHER_TKIP = 4, + ATH9K_CIPHER_CLR = 5, + ATH9K_CIPHER_MIC = 127 +}; + +enum ath9k_ht_macmode { + ATH9K_HT_MACMODE_20 = 0, + ATH9K_HT_MACMODE_2040 = 1, +}; + +enum ath9k_ht_extprotspacing { + ATH9K_HT_EXTPROTSPACING_20 = 0, + ATH9K_HT_EXTPROTSPACING_25 = 1, +}; + +struct ath_hw; +struct ath9k_channel; +struct ath_rate_table; + +u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); +bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); +bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); +u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); +bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); +bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); +bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0); +void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags); +void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags); +void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, + u32 aggrLen); +void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, + u32 numDelims); +void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds); +void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, + u32 burstDuration); +void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, + u32 vmf); +void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); +bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, + struct ath9k_tx_queue_info *qinfo); +int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); +bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); +int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf); +bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 size, u32 flags); +bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); +void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); +void ath9k_hw_rxena(struct ath_hw *ah); +void ath9k_hw_startpcureceive(struct ath_hw *ah); +void ath9k_hw_stoppcurecv(struct ath_hw *ah); +bool ath9k_hw_stopdmarecv(struct ath_hw *ah); + +#endif /* MAC_H */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 3c04044a60bd..13d4e6756c99 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,9 +15,7 @@ */ #include <linux/nl80211.h> -#include "core.h" -#include "reg.h" -#include "hw.h" +#include "ath9k.h" #define ATH_PCI_VERSION "0.1" @@ -28,84 +26,129 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -static struct pci_device_id ath_pci_id_table[] __devinitdata = { - { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ - { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ - { 0 } +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +/* We use the hw_value as an index into our private channel structure */ + +#define CHAN2G(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ }; -static void ath_detach(struct ath_softc *sc); - -/* return bus cachesize in 4B word units */ - -static void bus_read_cachesize(struct ath_softc *sc, int *csz) -{ - u8 u8tmp; - - pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); - *csz = (int)u8tmp; - - /* - * This check was put in to avoid "unplesant" consequences if - * the bootrom has not fully initialized all PCI devices. - * Sometimes the cache line size register is not set - */ - - if (*csz == 0) - *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ -} - -static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) -{ - sc->cur_rate_table = sc->hw_rate_table[mode]; - /* - * All protection frames are transmited at 2Mb/s for - * 11g, otherwise at 1Mb/s. - * XXX select protection rate index from rate table. - */ - sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); -} +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; -static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) +static void ath_cache_conf_rate(struct ath_softc *sc, + struct ieee80211_conf *conf) { - if (chan->chanmode == CHANNEL_A) - return ATH9K_MODE_11A; - else if (chan->chanmode == CHANNEL_G) - return ATH9K_MODE_11G; - else if (chan->chanmode == CHANNEL_B) - return ATH9K_MODE_11B; - else if (chan->chanmode == CHANNEL_A_HT20) - return ATH9K_MODE_11NA_HT20; - else if (chan->chanmode == CHANNEL_G_HT20) - return ATH9K_MODE_11NG_HT20; - else if (chan->chanmode == CHANNEL_A_HT40PLUS) - return ATH9K_MODE_11NA_HT40PLUS; - else if (chan->chanmode == CHANNEL_A_HT40MINUS) - return ATH9K_MODE_11NA_HT40MINUS; - else if (chan->chanmode == CHANNEL_G_HT40PLUS) - return ATH9K_MODE_11NG_HT40PLUS; - else if (chan->chanmode == CHANNEL_G_HT40MINUS) - return ATH9K_MODE_11NG_HT40MINUS; - - WARN_ON(1); /* should not get here */ - - return ATH9K_MODE_11B; + switch (conf->channel->band) { + case IEEE80211_BAND_2GHZ: + if (conf_is_ht20(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; + else if (conf_is_ht40_minus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS]; + else if (conf_is_ht40_plus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS]; + else + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + if (conf_is_ht20(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + else if (conf_is_ht40_minus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS]; + else if (conf_is_ht40_plus(conf)) + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS]; + else + sc->cur_rate_table = + sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + BUG_ON(1); + break; + } } static void ath_update_txpow(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; u32 txpow; - if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); + if (sc->curtxpow != sc->config.txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); /* read back in case value is clamped */ ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); - sc->sc_curtxpow = txpow; + sc->curtxpow = txpow; } } @@ -176,150 +219,87 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) for (i = 0; i < maxrates; i++) { rate[i].bitrate = rate_table->info[i].ratekbps / 100; rate[i].hw_value = rate_table->info[i].ratecode; + if (rate_table->info[i].short_preamble) { + rate[i].hw_value_short = rate_table->info[i].ratecode | + rate_table->info[i].short_preamble; + rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE; + } sband->n_bitrates++; + DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", rate[i].bitrate / 10, rate[i].hw_value); } } -static int ath_setup_channels(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int nchan, i, a = 0, b = 0; - u8 regclassids[ATH_REGCLASSIDS_MAX]; - u32 nregclass = 0; - struct ieee80211_supported_band *band_2ghz; - struct ieee80211_supported_band *band_5ghz; - struct ieee80211_channel *chan_2ghz; - struct ieee80211_channel *chan_5ghz; - struct ath9k_channel *c; - - /* Fill in ah->ah_channels */ - if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, - regclassids, ATH_REGCLASSIDS_MAX, - &nregclass, CTRY_DEFAULT, false, 1)) { - u32 rd = ah->ah_currentRD; - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to collect channel list; " - "regdomain likely %u country code %u\n", - rd, CTRY_DEFAULT); - return -EINVAL; - } - - band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; - band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; - chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; - chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < nchan; i++) { - c = &ah->ah_channels[i]; - if (IS_CHAN_2GHZ(c)) { - chan_2ghz[a].band = IEEE80211_BAND_2GHZ; - chan_2ghz[a].center_freq = c->channel; - chan_2ghz[a].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - band_2ghz->n_channels = ++a; - - DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " - "channelFlags: 0x%x\n", - c->channel, c->channelFlags); - } else if (IS_CHAN_5GHZ(c)) { - chan_5ghz[b].band = IEEE80211_BAND_5GHZ; - chan_5ghz[b].center_freq = c->channel; - chan_5ghz[b].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - band_5ghz->n_channels = ++b; - - DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " - "channelFlags: 0x%x\n", - c->channel, c->channelFlags); - } - } - - return 0; -} - /* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending * DMA, then restart stuff. */ -static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) +int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *hchan) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; bool fastcc = true, stopped; + struct ieee80211_channel *channel = hw->conf.channel; + int r; if (sc->sc_flags & SC_OP_INVALID) return -EIO; - if (hchan->channel != sc->sc_ah->ah_curchan->channel || - hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || - (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || - (sc->sc_flags & SC_OP_FULL_RESET)) { - int status; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_set_interrupts(ah, 0); - ath_draintxq(sc, false); - stopped = ath_stoprecv(sc); - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) - fastcc = false; - - DPRINTF(sc, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", - sc->sc_ah->ah_curchan->channel, - hchan->channel, hchan->channelFlags, sc->tx_chan_width); - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, fastcc, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", - ath9k_hw_mhz2ieee(ah, hchan->channel, - hchan->channelFlags), - hchan->channel, hchan->channelFlags, status); - spin_unlock_bh(&sc->sc_resetlock); - return -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); + ath9k_ps_wakeup(sc); - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; - sc->sc_flags &= ~SC_OP_FULL_RESET; + /* + * This is only performed if the channel settings have + * actually changed. + * + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath9k_hw_set_interrupts(ah, 0); + ath_drain_all_txq(sc, false); + stopped = ath_stoprecv(sc); - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to restart recv logic\n"); - return -EIO; - } + /* XXX: do not flush receive queue here. We don't want + * to flush data frames already in queue because of + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; - ath_setcurmode(sc, ath_chan2mode(hchan)); - ath_update_txpow(sc); - ath9k_hw_set_interrupts(ah, sc->sc_imask); + DPRINTF(sc, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), chanwidth: %d\n", + sc->sc_ah->curchan->channel, + channel->center_freq, sc->tx_chan_width); + + spin_lock_bh(&sc->sc_resetlock); + + r = ath9k_hw_reset(ah, hchan, fastcc); + if (r) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel (%u Mhz) " + "reset status %u\n", + channel->center_freq, r); + spin_unlock_bh(&sc->sc_resetlock); + return r; } + spin_unlock_bh(&sc->sc_resetlock); + + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; + + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); + return -EIO; + } + + ath_cache_conf_rate(sc, &hw->conf); + ath_update_txpow(sc); + ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_ps_restore(sc); return 0; } @@ -332,123 +312,122 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) */ static void ath_ani_calibrate(unsigned long data) { - struct ath_softc *sc; - struct ath_hal *ah; + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_hw *ah = sc->sc_ah; bool longcal = false; bool shortcal = false; bool aniflag = false; unsigned int timestamp = jiffies_to_msecs(jiffies); - u32 cal_interval; + u32 cal_interval, short_cal_interval; - sc = (struct ath_softc *)data; - ah = sc->sc_ah; + short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? + ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; /* * don't calibrate when we're scanning. * we are most likely not on our home channel. */ - if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) - return; + if (sc->sc_flags & SC_OP_SCANNING) + goto set_timer; /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { + if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); - sc->sc_ani.sc_longcal_timer = timestamp; + sc->ani.longcal_timer = timestamp; } - /* Short calibration applies only while sc_caldone is false */ - if (!sc->sc_ani.sc_caldone) { - if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= - ATH_SHORT_CALINTERVAL) { + /* Short calibration applies only while caldone is false */ + if (!sc->ani.caldone) { + if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); - sc->sc_ani.sc_shortcal_timer = timestamp; - sc->sc_ani.sc_resetcal_timer = timestamp; + sc->ani.shortcal_timer = timestamp; + sc->ani.resetcal_timer = timestamp; } } else { - if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= + if ((timestamp - sc->ani.resetcal_timer) >= ATH_RESTART_CALINTERVAL) { - ath9k_hw_reset_calvalid(ah, ah->ah_curchan, - &sc->sc_ani.sc_caldone); - if (sc->sc_ani.sc_caldone) - sc->sc_ani.sc_resetcal_timer = timestamp; + sc->ani.caldone = ath9k_hw_reset_calvalid(ah); + if (sc->ani.caldone) + sc->ani.resetcal_timer = timestamp; } } /* Verify whether we must check ANI */ - if ((timestamp - sc->sc_ani.sc_checkani_timer) >= - ATH_ANI_POLLINTERVAL) { + if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { aniflag = true; - sc->sc_ani.sc_checkani_timer = timestamp; + sc->ani.checkani_timer = timestamp; } /* Skip all processing if there's nothing to do. */ if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->sc_halstats, - ah->ah_curchan); + ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan); /* Perform calibration if necessary */ if (longcal || shortcal) { bool iscaldone = false; - if (ath9k_hw_calibrate(ah, ah->ah_curchan, - sc->sc_rx_chainmask, longcal, + if (ath9k_hw_calibrate(ah, ah->curchan, + sc->rx_chainmask, longcal, &iscaldone)) { if (longcal) - sc->sc_ani.sc_noise_floor = + sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, - ah->ah_curchan); + ah->curchan); DPRINTF(sc, ATH_DBG_ANI, "calibrate chan %u/%x nf: %d\n", - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, - sc->sc_ani.sc_noise_floor); + ah->curchan->channel, + ah->curchan->channelFlags, + sc->ani.noise_floor); } else { DPRINTF(sc, ATH_DBG_ANY, "calibrate chan %u/%x failed\n", - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags); + ah->curchan->channel, + ah->curchan->channelFlags); } - sc->sc_ani.sc_caldone = iscaldone; + sc->ani.caldone = iscaldone; } } +set_timer: /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ cal_interval = ATH_LONG_CALINTERVAL; - if (sc->sc_ah->ah_config.enable_ani) + if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!sc->sc_ani.sc_caldone) - cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); + if (!sc->ani.caldone) + cal_interval = min(cal_interval, (u32)short_cal_interval); - mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); + mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } /* * Update tx/rx chainmask. For legacy association, * hard code chainmask to 1x1, for 11n association, use - * the chainmask configuration. + * the chainmask configuration, for bt coexistence, use + * the chainmask configuration even in legacy mode. */ -static void ath_update_chainmask(struct ath_softc *sc, int is_ht) +void ath_update_chainmask(struct ath_softc *sc, int is_ht) { sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; - if (is_ht) { - sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; + if (is_ht || + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { + sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; + sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { - sc->sc_tx_chainmask = 1; - sc->sc_rx_chainmask = 1; + sc->tx_chainmask = 1; + sc->rx_chainmask = 1; } DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", - sc->sc_tx_chainmask, sc->sc_rx_chainmask); + sc->tx_chainmask, sc->rx_chainmask); } static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -476,7 +455,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) static void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; - u32 status = sc->sc_intrstatus; + u32 status = sc->intrstatus; if (status & ATH9K_INT_FATAL) { /* need a chip reset */ @@ -496,13 +475,13 @@ static void ath9k_tasklet(unsigned long data) } /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); } -static irqreturn_t ath_isr(int irq, void *dev) +irqreturn_t ath_isr(int irq, void *dev) { struct ath_softc *sc = dev; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; enum ath9k_int status; bool sched = false; @@ -527,7 +506,7 @@ static irqreturn_t ath_isr(int irq, void *dev) */ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - status &= sc->sc_imask; /* discard unasked-for bits */ + status &= sc->imask; /* discard unasked-for bits */ /* * If there are no status bits set, then this interrupt was not @@ -536,7 +515,8 @@ static irqreturn_t ath_isr(int irq, void *dev) if (!status) return IRQ_NONE; - sc->sc_intrstatus = status; + sc->intrstatus = status; + ath9k_ps_wakeup(sc); if (status & ATH9K_INT_FATAL) { /* need a chip reset */ @@ -583,45 +563,39 @@ static irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ - ath9k_hw_procmibevent(ah, &sc->sc_halstats); - ath9k_hw_set_interrupts(ah, sc->sc_imask); + ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_set_interrupts(ah, sc->imask); } if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->ah_caps.hw_caps & + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { /* Clear RxAbort bit so that we can * receive frames */ + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); ath9k_hw_setrxabort(ah, 0); sched = true; + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } } + if (status & ATH9K_INT_TSFOOR) { + /* FIXME: Handle this interrupt for power save */ + sched = true; + } } + ath9k_ps_restore(sc); } while (0); ath_debug_stat_interrupt(sc, status); if (sched) { /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); + ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA)); tasklet_schedule(&sc->intr_tq); } return IRQ_HANDLED; } -static int ath_get_channel(struct ath_softc *sc, - struct ieee80211_channel *chan) -{ - int i; - - for (i = 0; i < sc->sc_ah->ah_nchan; i++) { - if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) - return i; - } - - return -1; -} - static u32 ath_get_extchanmode(struct ath_softc *sc, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) @@ -664,20 +638,9 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, return chanmode; } -static int ath_keyset(struct ath_softc *sc, u16 keyix, - struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) -{ - bool status; - - status = ath9k_hw_set_keycache_entry(sc->sc_ah, - keyix, hk, mac, false); - - return status != false; -} - static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, - struct ath9k_keyval *hk, - const u8 *addr) + struct ath9k_keyval *hk, const u8 *addr, + bool authenticator) { const u8 *key_rxmic; const u8 *key_txmic; @@ -686,26 +649,33 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; if (addr == NULL) { - /* Group key installation */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - return ath_keyset(sc, keyix, hk, addr); - } - if (!sc->sc_splitmic) { /* - * data key goes at first index, - * the hal handles the MIC keys at index+64. + * Group key installation - only two key cache entries are used + * regardless of splitmic capability since group key is only + * used either for TX or RX. */ + if (authenticator) { + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); + } else { + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); + } + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); + } + if (!sc->splitmic) { + /* TX and RX keys share the same key cache entry. */ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath_keyset(sc, keyix, hk, addr); + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); } - /* - * TX key goes at first index, RX key at +32. - * The hal handles the MIC keys at index+64. - */ + + /* Separate key cache entries for TX and RX */ + + /* TX key goes at first index, RX key at +32. */ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath_keyset(sc, keyix, hk, NULL)) { - /* Txmic entry failed. No need to proceed further */ + if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { + /* TX MIC entry failed. No need to proceed further */ DPRINTF(sc, ATH_DBG_KEYCACHE, "Setting TX MIC Key Failed\n"); return 0; @@ -713,20 +683,20 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); /* XXX delete tx key on failure? */ - return ath_keyset(sc, keyix + 32, hk, addr); + return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr); } static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) { int i; - for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { - if (test_bit(i, sc->sc_keymap) || - test_bit(i + 64, sc->sc_keymap)) + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { + if (test_bit(i, sc->keymap) || + test_bit(i + 64, sc->keymap)) continue; /* At least one part of TKIP key allocated */ - if (sc->sc_splitmic && - (test_bit(i + 32, sc->sc_keymap) || - test_bit(i + 64 + 32, sc->sc_keymap))) + if (sc->splitmic && + (test_bit(i + 32, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) continue; /* At least one part of TKIP key allocated */ /* Found a free slot for a TKIP key */ @@ -740,55 +710,55 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) int i; /* First, try to find slots that would not be available for TKIP. */ - if (sc->sc_splitmic) { - for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) { - if (!test_bit(i, sc->sc_keymap) && - (test_bit(i + 32, sc->sc_keymap) || - test_bit(i + 64, sc->sc_keymap) || - test_bit(i + 64 + 32, sc->sc_keymap))) + if (sc->splitmic) { + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) { + if (!test_bit(i, sc->keymap) && + (test_bit(i + 32, sc->keymap) || + test_bit(i + 64, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) return i; - if (!test_bit(i + 32, sc->sc_keymap) && - (test_bit(i, sc->sc_keymap) || - test_bit(i + 64, sc->sc_keymap) || - test_bit(i + 64 + 32, sc->sc_keymap))) + if (!test_bit(i + 32, sc->keymap) && + (test_bit(i, sc->keymap) || + test_bit(i + 64, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) return i + 32; - if (!test_bit(i + 64, sc->sc_keymap) && - (test_bit(i , sc->sc_keymap) || - test_bit(i + 32, sc->sc_keymap) || - test_bit(i + 64 + 32, sc->sc_keymap))) + if (!test_bit(i + 64, sc->keymap) && + (test_bit(i , sc->keymap) || + test_bit(i + 32, sc->keymap) || + test_bit(i + 64 + 32, sc->keymap))) return i + 64; - if (!test_bit(i + 64 + 32, sc->sc_keymap) && - (test_bit(i, sc->sc_keymap) || - test_bit(i + 32, sc->sc_keymap) || - test_bit(i + 64, sc->sc_keymap))) + if (!test_bit(i + 64 + 32, sc->keymap) && + (test_bit(i, sc->keymap) || + test_bit(i + 32, sc->keymap) || + test_bit(i + 64, sc->keymap))) return i + 64 + 32; } } else { - for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { - if (!test_bit(i, sc->sc_keymap) && - test_bit(i + 64, sc->sc_keymap)) + for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { + if (!test_bit(i, sc->keymap) && + test_bit(i + 64, sc->keymap)) return i; - if (test_bit(i, sc->sc_keymap) && - !test_bit(i + 64, sc->sc_keymap)) + if (test_bit(i, sc->keymap) && + !test_bit(i + 64, sc->keymap)) return i + 64; } } /* No partially used TKIP slots, pick any available slot */ - for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) { + for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) { /* Do not allow slots that could be needed for TKIP group keys * to be used. This limitation could be removed if we know that * TKIP will not be used. */ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) continue; - if (sc->sc_splitmic) { + if (sc->splitmic) { if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) continue; if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) continue; } - if (!test_bit(i, sc->sc_keymap)) + if (!test_bit(i, sc->keymap)) return i; /* Found a free slot for a key */ } @@ -797,7 +767,8 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) } static int ath_key_config(struct ath_softc *sc, - const u8 *addr, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct ath9k_keyval hk; @@ -818,7 +789,7 @@ static int ath_key_config(struct ath_softc *sc, hk.kv_type = ATH9K_CIPHER_AES_CCM; break; default: - return -EINVAL; + return -EOPNOTSUPP; } hk.kv_len = key->keylen; @@ -829,10 +800,10 @@ static int ath_key_config(struct ath_softc *sc, * need to change with virtual interfaces. */ idx = key->keyidx; } else if (key->keyidx) { - struct ieee80211_vif *vif; + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; - mac = addr; - vif = sc->sc_vaps[0]; if (vif->type != NL80211_IFTYPE_AP) { /* Only keyidx 0 should be used with unicast key, but * allow this for client mode for now. */ @@ -840,29 +811,33 @@ static int ath_key_config(struct ath_softc *sc, } else return -EIO; } else { - mac = addr; + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; + if (key->alg == ALG_TKIP) idx = ath_reserve_key_cache_slot_tkip(sc); else idx = ath_reserve_key_cache_slot(sc); if (idx < 0) - return -EIO; /* no free key cache entries */ + return -ENOSPC; /* no free key cache entries */ } if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac); + ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac, + vif->type == NL80211_IFTYPE_AP); else - ret = ath_keyset(sc, idx, &hk, mac); + ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac); if (!ret) return -EIO; - set_bit(idx, sc->sc_keymap); + set_bit(idx, sc->keymap); if (key->alg == ALG_TKIP) { - set_bit(idx + 64, sc->sc_keymap); - if (sc->sc_splitmic) { - set_bit(idx + 32, sc->sc_keymap); - set_bit(idx + 64 + 32, sc->sc_keymap); + set_bit(idx + 64, sc->keymap); + if (sc->splitmic) { + set_bit(idx + 32, sc->keymap); + set_bit(idx + 64 + 32, sc->keymap); } } @@ -875,18 +850,19 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) if (key->hw_key_idx < IEEE80211_WEP_NKID) return; - clear_bit(key->hw_key_idx, sc->sc_keymap); + clear_bit(key->hw_key_idx, sc->keymap); if (key->alg != ALG_TKIP) return; - clear_bit(key->hw_key_idx + 64, sc->sc_keymap); - if (sc->sc_splitmic) { - clear_bit(key->hw_key_idx + 32, sc->sc_keymap); - clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap); + clear_bit(key->hw_key_idx + 64, sc->keymap); + if (sc->splitmic) { + clear_bit(key->hw_key_idx + 32, sc->keymap); + clear_bit(key->hw_key_idx + 64 + 32, sc->keymap); } } -static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) +static void setup_ht_cap(struct ath_softc *sc, + struct ieee80211_sta_ht_cap *ht_info) { #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ @@ -899,10 +875,23 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->mcs.rx_mask[0] = 0xff; - ht_info->mcs.rx_mask[1] = 0xff; + + switch(sc->rx_chainmask) { + case 1: + ht_info->mcs.rx_mask[0] = 0xff; + break; + case 3: + case 5: + case 7: + default: + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + break; + } + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } @@ -910,36 +899,33 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ath_vap *avp = (void *)vif->drv_priv; + struct ath_vif *avp = (void *)vif->drv_priv; if (bss_conf->assoc) { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, sc->sc_curbssid); + bss_conf->aid, sc->curbssid); /* New association, store aid */ if (avp->av_opmode == NL80211_IFTYPE_STATION) { - sc->sc_curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); + sc->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc); } /* Configure the beacon */ - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; + ath_beacon_config(sc, vif); /* Reset rssi stats */ - sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; /* Start ANI */ - mod_timer(&sc->sc_ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); - + mod_timer(&sc->ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } else { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); - sc->sc_curaid = 0; + sc->curaid = 0; } } @@ -947,6 +933,39 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* LED functions */ /********************************/ +static void ath_led_blink_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + ath_led_blink_work.work); + + if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) + return; + + if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || + (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + else + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); + + queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); + + sc->led_on_duration = sc->led_on_cnt ? + max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : + ATH_LED_ON_DURATION_IDLE; + sc->led_off_duration = sc->led_off_cnt ? + max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : + ATH_LED_OFF_DURATION_IDLE; + sc->led_on_cnt = sc->led_off_cnt = 0; + if (sc->sc_flags & SC_OP_LED_ON) + sc->sc_flags &= ~SC_OP_LED_ON; + else + sc->sc_flags |= SC_OP_LED_ON; +} + static void ath_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -956,16 +975,27 @@ static void ath_led_brightness(struct led_classdev *led_cdev, switch (brightness) { case LED_OFF: if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) + led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO)); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, - (led->led_type == ATH_LED_RADIO) ? 1 : - !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); + if (led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ON; + } else { + sc->led_off_cnt++; + } break; case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) + if (led->led_type == ATH_LED_ASSOC) { sc->sc_flags |= SC_OP_LED_ASSOCIATED; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + queue_delayed_work(sc->hw->workqueue, + &sc->ath_led_blink_work, 0); + } else if (led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + sc->sc_flags |= SC_OP_LED_ON; + } else { + sc->led_on_cnt++; + } break; default: break; @@ -1001,6 +1031,7 @@ static void ath_unregister_led(struct ath_led *led) static void ath_deinit_leds(struct ath_softc *sc) { + cancel_delayed_work_sync(&sc->ath_led_blink_work); ath_unregister_led(&sc->assoc_led); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; ath_unregister_led(&sc->tx_led); @@ -1020,9 +1051,11 @@ static void ath_init_leds(struct ath_softc *sc) /* LED off, active low */ ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); + trigger = ieee80211_get_radio_led_name(sc->hw); snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), - "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); + "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); ret = ath_register_led(sc, &sc->radio_led, trigger); sc->radio_led.led_type = ATH_LED_RADIO; if (ret) @@ -1030,7 +1063,7 @@ static void ath_init_leds(struct ath_softc *sc) trigger = ieee80211_get_assoc_led_name(sc->hw); snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), - "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); + "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); ret = ath_register_led(sc, &sc->assoc_led, trigger); sc->assoc_led.led_type = ATH_LED_ASSOC; if (ret) @@ -1038,7 +1071,7 @@ static void ath_init_leds(struct ath_softc *sc) trigger = ieee80211_get_tx_led_name(sc->hw); snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), - "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); + "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); ret = ath_register_led(sc, &sc->tx_led, trigger); sc->tx_led.led_type = ATH_LED_TX; if (ret) @@ -1046,7 +1079,7 @@ static void ath_init_leds(struct ath_softc *sc) trigger = ieee80211_get_rx_led_name(sc->hw); snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), - "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); + "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); ret = ath_register_led(sc, &sc->rx_led, trigger); sc->rx_led.led_type = ATH_LED_RX; if (ret) @@ -1058,32 +1091,22 @@ fail: ath_deinit_leds(sc); } -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - -/*******************/ -/* Rfkill */ -/*******************/ - -static void ath_radio_enable(struct ath_softc *sc) +void ath_radio_enable(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; - int status; + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_channel *channel = sc->hw->conf.channel; + int r; + ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->tx_chan_width, - sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - false, &status)) { + + r = ath9k_hw_reset(ah, ah->curchan, false); + + if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", - ath9k_hw_mhz2ieee(ah, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags), - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, status); + "Unable to reset channel %u (%uMhz) ", + "reset status %u\n", + channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); @@ -1095,10 +1118,10 @@ static void ath_radio_enable(struct ath_softc *sc) } if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + ath_beacon_config(sc, NULL); /* restart beacons */ /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, sc->sc_imask); + ath9k_hw_set_interrupts(ah, sc->imask); /* Enable LED */ ath9k_hw_cfg_output(ah, ATH_LED_PIN, @@ -1106,14 +1129,16 @@ static void ath_radio_enable(struct ath_softc *sc) ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); ieee80211_wake_queues(sc->hw); + ath9k_ps_restore(sc); } -static void ath_radio_disable(struct ath_softc *sc) +void ath_radio_disable(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; - int status; - + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_channel *channel = sc->hw->conf.channel; + int r; + ath9k_ps_wakeup(sc); ieee80211_stop_queues(sc->hw); /* Disable LED */ @@ -1123,38 +1148,37 @@ static void ath_radio_disable(struct ath_softc *sc) /* Disable interrupts */ ath9k_hw_set_interrupts(ah, 0); - ath_draintxq(sc, false); /* clear pending tx frames */ + ath_drain_all_txq(sc, false); /* clear pending tx frames */ ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->tx_chan_width, - sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - false, &status)) { + r = ath9k_hw_reset(ah, ah->curchan, false); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", - ath9k_hw_mhz2ieee(ah, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags), - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, status); + "reset status %u\n", + channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_ps_restore(sc); } +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + +/*******************/ +/* Rfkill */ +/*******************/ + static bool ath_is_rfkill_set(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; - return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == - ah->ah_rfkill_polarity; + return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == + ah->rfkill_polarity; } /* h/w rfkill poll function */ @@ -1238,7 +1262,7 @@ static int ath_init_sw_rfkill(struct ath_softc *sc) } snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), - "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); + "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; sc->rf_kill.rfkill->data = sc; sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; @@ -1251,7 +1275,7 @@ static int ath_init_sw_rfkill(struct ath_softc *sc) /* Deinitialize rfkill */ static void ath_deinit_rfkill(struct ath_softc *sc) { - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { @@ -1263,7 +1287,7 @@ static void ath_deinit_rfkill(struct ath_softc *sc) static int ath_start_rfkill_poll(struct ath_softc *sc) { - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, 0); @@ -1274,13 +1298,7 @@ static int ath_start_rfkill_poll(struct ath_softc *sc) rfkill_free(sc->rf_kill.rfkill); /* Deinitialize the device */ - ath_detach(sc); - if (sc->pdev->irq) - free_irq(sc->pdev->irq, sc); - pci_iounmap(sc->pdev, sc->mem); - pci_release_region(sc->pdev, 0); - pci_disable_device(sc->pdev); - ieee80211_free_hw(sc->hw); + ath_cleanup(sc); return -EIO; } else { sc->sc_flags |= SC_OP_RFKILL_REGISTERED; @@ -1291,18 +1309,39 @@ static int ath_start_rfkill_poll(struct ath_softc *sc) } #endif /* CONFIG_RFKILL */ -static void ath_detach(struct ath_softc *sc) +void ath_cleanup(struct ath_softc *sc) +{ + ath_detach(sc); + free_irq(sc->irq, sc); + ath_bus_cleanup(sc); + kfree(sc->sec_wiphy); + ieee80211_free_hw(sc->hw); +} + +void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int i = 0; + ath9k_ps_wakeup(sc); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif ath_deinit_leds(sc); + cancel_work_sync(&sc->chan_work); + cancel_delayed_work_sync(&sc->wiphy_work); + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + sc->sec_wiphy[i] = NULL; + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + } ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath_tx_cleanup(sc); @@ -1320,11 +1359,12 @@ static void ath_detach(struct ath_softc *sc) ath9k_hw_detach(sc->sc_ah); ath9k_exit_debug(sc); + ath9k_ps_restore(sc); } static int ath_init(u16 devid, struct ath_softc *sc) { - struct ath_hal *ah = NULL; + struct ath_hw *ah = NULL; int status; int error = 0, i; int csz = 0; @@ -1335,55 +1375,52 @@ static int ath_init(u16 devid, struct ath_softc *sc) if (ath9k_init_debug(sc) < 0) printk(KERN_ERR "Unable to create debugfs files\n"); + spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, + tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long)sc); /* * Cache line size is used to size and align various * structures used to communicate with the hardware. */ - bus_read_cachesize(sc, &csz); + ath_read_cachesize(sc, &csz); /* XXX assert csz is non-zero */ - sc->sc_cachelsz = csz << 2; /* convert to bytes */ + sc->cachelsz = csz << 2; /* convert to bytes */ - ah = ath9k_hw_attach(devid, sc, sc->mem, &status); + ah = ath9k_hw_attach(devid, sc, &status); if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; HAL status %u\n", status); + "Unable to attach hardware; HAL status %d\n", status); error = -ENXIO; goto bad; } sc->sc_ah = ah; /* Get the hardware key cache size. */ - sc->sc_keymax = ah->ah_caps.keycache_size; - if (sc->sc_keymax > ATH_KEYMAX) { + sc->keymax = ah->caps.keycache_size; + if (sc->keymax > ATH_KEYMAX) { DPRINTF(sc, ATH_DBG_KEYCACHE, "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, sc->sc_keymax); - sc->sc_keymax = ATH_KEYMAX; + ATH_KEYMAX, sc->keymax); + sc->keymax = ATH_KEYMAX; } /* * Reset the key cache since some parts do not * reset the contents on initial power up. */ - for (i = 0; i < sc->sc_keymax; i++) + for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - /* Collect the channel list using the default country code */ - - error = ath_setup_channels(sc); - if (error) + if (ath9k_regd_init(sc->sc_ah)) goto bad; /* default to MONITOR mode */ - sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; - + sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; /* Setup rate tables */ @@ -1412,7 +1449,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) goto bad2; } - sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; + sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) @@ -1449,8 +1486,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* Initializes the noise floor to a reasonable default value. * Later on this will be updated during ANI processing. */ - sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); + sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc); if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL)) { @@ -1476,60 +1513,62 @@ static int ath_init(u16 devid, struct ath_softc *sc) ATH9K_CIPHER_MIC, NULL) && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, 0, NULL)) - sc->sc_splitmic = 1; + sc->splitmic = 1; /* turn on mcast key search if possible */ if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, 1, NULL); - sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; - sc->sc_config.txpowlimit_override = 0; + sc->config.txpowlimit = ATH_TXPOWER_MAX; /* 11n Capabilities */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { sc->sc_flags |= SC_OP_TXAGGR; sc->sc_flags |= SC_OP_RXAGGR; } - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; + sc->tx_chainmask = ah->caps.tx_chainmask; + sc->rx_chainmask = ah->caps.rx_chainmask; ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->rx.defant = ath9k_hw_getdefantenna(ah); - ath9k_hw_getmac(ah, sc->sc_myaddr); - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { - ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); - ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); - ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); - } + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) - sc->beacon.bslot[i] = ATH_IF_ID_ANY; + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } /* save MISC configurations */ - sc->sc_config.swBeaconProcess = 1; + sc->config.swBeaconProcess = 1; /* setup channels and rates */ - sc->sbands[IEEE80211_BAND_2GHZ].channels = - sc->channels[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; sc->sbands[IEEE80211_BAND_2GHZ].bitrates = sc->rates[IEEE80211_BAND_2GHZ]; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = - sc->channels[IEEE80211_BAND_5GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; sc->sbands[IEEE80211_BAND_5GHZ].bitrates = sc->rates[IEEE80211_BAND_5GHZ]; sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); } + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + ath9k_hw_btcoex_enable(sc->sc_ah); + return 0; bad2: /* cleanup tx queues */ @@ -1544,49 +1583,68 @@ bad: return error; } -static int ath_attach(u16 devid, struct ath_softc *sc) +void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { - struct ieee80211_hw *hw = sc->hw; - int error = 0, i; - - DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - - error = ath_init(devid, sc); - if (error != 0) - return error; - - /* get mac address from hardware and set in mac80211 */ - - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION; + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_SPECTRUM_MGMT; + + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->wiphy->reg_notifier = ath9k_reg_notifier; + hw->wiphy->strict_regulatory = true; hw->queues = 4; hw->max_rates = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; hw->max_rate_tries = ATH_11N_TXMAXTRY; hw->sta_data_size = sizeof(struct ath_node); - hw->vif_data_size = sizeof(struct ath_vap); + hw->vif_data_size = sizeof(struct ath_vif); hw->rate_control_algorithm = "ath9k_rate_control"; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; +} + +int ath_attach(u16 devid, struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + const struct ieee80211_regdomain *regd; + int error = 0, i; + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); + + ath_set_hw_capab(sc, hw); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } /* initialize tx/rx engine */ error = ath_tx_init(sc, ATH_TXBUF); @@ -1599,7 +1657,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc) #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* Initialze h/w Rfkill */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); /* Initialize s/w rfkill */ @@ -1608,11 +1666,39 @@ static int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #endif + if (ath9k_is_world_regd(sc->sc_ah)) { + /* Anything applied here (prior to wiphy registration) gets + * saved on the wiphy orig_* parameters */ + regd = ath9k_world_regdomain(sc->sc_ah); + hw->wiphy->custom_regulatory = true; + hw->wiphy->strict_regulatory = false; + } else { + /* This gets applied in the case of the absense of CRDA, + * it's our own custom world regulatory domain, similar to + * cfg80211's but we enable passive scanning */ + regd = ath9k_default_world_regdomain(); + } + wiphy_apply_custom_regulatory(hw->wiphy, regd); + ath9k_reg_apply_radar_flags(hw->wiphy); + ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER); + + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(500); + error = ieee80211_register_hw(hw); + if (!ath9k_is_world_regd(sc->sc_ah)) { + error = regulatory_hint(hw->wiphy, + sc->sc_ah->regulatory.alpha2); + if (error) + goto error_attach; + } + /* Initialize LED control */ ath_init_leds(sc); + return 0; error_attach: @@ -1629,24 +1715,20 @@ error_attach: int ath_reset(struct ath_softc *sc, bool retry_tx) { - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hw *hw = sc->hw; + int r; ath9k_hw_set_interrupts(ah, 0); - ath_draintxq(sc, retry_tx); + ath_drain_all_txq(sc, retry_tx); ath_stoprecv(sc); ath_flushrecv(sc); spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); + if (r) DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; hal status %u\n", status); - error = -EIO; - } + "Unable to reset hardware; reset status %u\n", r); spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) @@ -1657,14 +1739,14 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that * might change as a result. */ - ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); + ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + ath_beacon_config(sc, NULL); /* restart beacons */ - ath9k_hw_set_interrupts(ah, sc->sc_imask); + ath9k_hw_set_interrupts(ah, sc->imask); if (retry_tx) { int i; @@ -1677,7 +1759,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } } - return error; + return r; } /* @@ -1701,6 +1783,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", name, nbuf, ndesc); + INIT_LIST_HEAD(head); /* ath_desc must be a multiple of DWORDs */ if ((sizeof(struct ath_desc) % 4) != 0) { DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); @@ -1717,7 +1800,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, * descriptors that cross the 4K page boundary. Assume * one skipped descriptor per 4K page. */ - if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { u32 ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); u32 dma_len; @@ -1731,9 +1814,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } /* allocate descriptors */ - dd->dd_desc = pci_alloc_consistent(sc->pdev, - dd->dd_desc_len, - &dd->dd_desc_paddr); + dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); if (dd->dd_desc == NULL) { error = -ENOMEM; goto fail; @@ -1745,20 +1827,18 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, /* allocate buffers */ bsize = sizeof(struct ath_buf) * nbuf; - bf = kmalloc(bsize, GFP_KERNEL); + bf = kzalloc(bsize, GFP_KERNEL); if (bf == NULL) { error = -ENOMEM; goto fail2; } - memset(bf, 0, bsize); dd->dd_bufptr = bf; - INIT_LIST_HEAD(head); for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { bf->bf_desc = ds; bf->bf_daddr = DS2PHYS(dd, ds); - if (!(sc->sc_ah->ah_caps.hw_caps & + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { /* * Skip descriptor addresses which can cause 4KB @@ -1779,8 +1859,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } return 0; fail2: - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); fail: memset(dd, 0, sizeof(*dd)); return error; @@ -1793,8 +1873,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head) { - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); INIT_LIST_HEAD(head); kfree(dd->dd_bufptr); @@ -1851,33 +1931,81 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) return qnum; } +/* XXX: Remove me once we don't depend on ath9k_channel for all + * this redundant data */ +void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, + struct ath9k_channel *ichan) +{ + struct ieee80211_channel *chan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; + + ichan->channel = chan->center_freq; + ichan->chan = chan; + + if (chan->band == IEEE80211_BAND_2GHZ) { + ichan->chanmode = CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + } else { + ichan->chanmode = CHANNEL_A; + ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; + } + + sc->tx_chan_width = ATH9K_HT_MACMODE_20; + + if (conf_is_ht(conf)) { + if (conf_is_ht40(conf)) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + + ichan->chanmode = ath_get_extchanmode(sc, chan, + conf->channel_type); + } +} + /**********************/ /* mac80211 callbacks */ /**********************/ static int ath9k_start(struct ieee80211_hw *hw) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ieee80211_channel *curchan = hw->conf.channel; struct ath9k_channel *init_channel; - int error = 0, pos, status; + int r, pos; DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " "initial channel: %d MHz\n", curchan->center_freq); - /* setup initial channel */ + mutex_lock(&sc->mutex); - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); - error = -EINVAL; - goto error; + if (ath9k_wiphy_started(sc)) { + if (sc->chan_idx == curchan->hw_value) { + /* + * Already on the operational channel, the new wiphy + * can be marked active. + */ + aphy->state = ATH_WIPHY_ACTIVE; + ieee80211_wake_queues(hw); + } else { + /* + * Another wiphy is on another channel, start the new + * wiphy in paused state. + */ + aphy->state = ATH_WIPHY_PAUSED; + ieee80211_stop_queues(hw); + } + mutex_unlock(&sc->mutex); + return 0; } + aphy->state = ATH_WIPHY_ACTIVE; - sc->tx_chan_width = ATH9K_HT_MACMODE_20; - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - init_channel = &sc->sc_ah->ah_channels[pos]; + /* setup initial channel */ + + pos = curchan->hw_value; + + sc->chan_idx = pos; + init_channel = &sc->sc_ah->channels[pos]; + ath9k_update_ichannel(sc, hw, init_channel); /* Reset SERDES registers */ ath9k_hw_configpcipowersave(sc->sc_ah, 0); @@ -1890,17 +2018,14 @@ static int ath9k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(sc->sc_ah, init_channel, - sc->tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + r = ath9k_hw_reset(sc->sc_ah, init_channel, false); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; hal status %u " - "(freq %u flags 0x%x)\n", status, - init_channel->channel, init_channel->channelFlags); - error = -EIO; + "Unable to reset hardware; reset status %u " + "(freq %u MHz)\n", r, + curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); - goto error; + goto mutex_unlock; } spin_unlock_bh(&sc->sc_resetlock); @@ -1920,66 +2045,56 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); - error = -EIO; - goto error; + r = -EIO; + goto mutex_unlock; } /* Setup our intr mask. */ - sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX + sc->imask = ATH9K_INT_RX | ATH9K_INT_TX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->sc_imask |= ATH9K_INT_GTT; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT) + sc->imask |= ATH9K_INT_GTT; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - sc->sc_imask |= ATH9K_INT_CST; - - /* - * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. - */ - if (ath9k_hw_phycounters(sc->sc_ah) && - ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || - (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) - sc->sc_imask |= ATH9K_INT_MIB; - /* - * Some hardware processes the TIM IE and fires an - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && - !sc->sc_config.swBeaconProcess) - sc->sc_imask |= ATH9K_INT_TIM; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + sc->imask |= ATH9K_INT_CST; - ath_setcurmode(sc, ath_chan2mode(init_channel)); + ath_cache_conf_rate(sc, &hw->conf); sc->sc_flags &= ~SC_OP_INVALID; /* Disable BMISS interrupt when we're not associated */ - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); + sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - ieee80211_wake_queues(sc->hw); + ieee80211_wake_queues(hw); #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - error = ath_start_rfkill_poll(sc); + r = ath_start_rfkill_poll(sc); #endif -error: - return error; +mutex_unlock: + mutex_unlock(&sc->mutex); + + return r; } static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ath_tx_control txctl; int hdrlen, padsize; + if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { + printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " + "%d\n", wiphy_name(hw->wiphy), aphy->state); + goto exit; + } + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* @@ -2013,7 +2128,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); - if (ath_tx_start(sc, skb, &txctl) != 0) { + if (ath_tx_start(hw, skb, &txctl) != 0) { DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); goto exit; } @@ -2026,30 +2141,38 @@ exit: static void ath9k_stop(struct ieee80211_hw *hw) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + aphy->state = ATH_WIPHY_INACTIVE; if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); return; } - DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); + mutex_lock(&sc->mutex); - ieee80211_stop_queues(sc->hw); + ieee80211_stop_queues(hw); + + if (ath9k_wiphy_started(sc)) { + mutex_unlock(&sc->mutex); + return; /* another wiphy still in use */ + } /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ ath9k_hw_set_interrupts(sc->sc_ah, 0); if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_draintxq(sc, false); + ath_drain_all_txq(sc, false); ath_stoprecv(sc); ath9k_hw_phy_disable(sc->sc_ah); } else sc->rx.rxlink = NULL; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif /* disable HAL and put h/w to sleep */ @@ -2058,136 +2181,224 @@ static void ath9k_stop(struct ieee80211_hw *hw) sc->sc_flags |= SC_OP_INVALID; + mutex_unlock(&sc->mutex); + DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct ath_softc *sc = hw->priv; - struct ath_vap *avp = (void *)conf->vif->drv_priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp = (void *)conf->vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; + int ret = 0; - /* Support only vap for now */ + mutex_lock(&sc->mutex); - if (sc->sc_nvaps) - return -ENOBUFS; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && + sc->nvifs > 0) { + ret = -ENOBUFS; + goto out; + } switch (conf->type) { case NL80211_IFTYPE_STATION: ic_opmode = NL80211_IFTYPE_STATION; break; case NL80211_IFTYPE_ADHOC: - ic_opmode = NL80211_IFTYPE_ADHOC; - break; case NL80211_IFTYPE_AP: - ic_opmode = NL80211_IFTYPE_AP; + case NL80211_IFTYPE_MESH_POINT: + if (sc->nbcnvifs >= ATH_BCBUF) { + ret = -ENOBUFS; + goto out; + } + ic_opmode = conf->type; break; default: DPRINTF(sc, ATH_DBG_FATAL, "Interface type %d not yet supported\n", conf->type); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out; } - DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); - /* Set the VAP opmode */ + /* Set the VIF opmode */ avp->av_opmode = ic_opmode; avp->av_bslot = -1; - if (ic_opmode == NL80211_IFTYPE_AP) - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + sc->nvifs++; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath9k_set_bssid_mask(hw); - sc->sc_vaps[0] = conf->vif; - sc->sc_nvaps++; + if (sc->nvifs > 1) + goto out; /* skip global settings for secondary vif */ + + if (ic_opmode == NL80211_IFTYPE_AP) { + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + sc->sc_flags |= SC_OP_TSF_RESET; + } /* Set the device opmode */ - sc->sc_ah->ah_opmode = ic_opmode; + sc->sc_ah->opmode = ic_opmode; + + /* + * Enable MIB interrupts when there are hardware phy counters. + * Note we only do this (at the moment) for station mode. + */ + if ((conf->type == NL80211_IFTYPE_STATION) || + (conf->type == NL80211_IFTYPE_ADHOC) || + (conf->type == NL80211_IFTYPE_MESH_POINT)) { + if (ath9k_hw_phycounters(sc->sc_ah)) + sc->imask |= ATH9K_INT_MIB; + sc->imask |= ATH9K_INT_TSFOOR; + } + + /* + * Some hardware processes the TIM IE and fires an + * interrupt when the TIM bit is set. For hardware + * that does, if not overridden by configuration, + * enable the TIM interrupt when operating as station. + */ + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && + (conf->type == NL80211_IFTYPE_STATION) && + !sc->config.swBeaconProcess) + sc->imask |= ATH9K_INT_TIM; + + ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ /* Start ANI */ - mod_timer(&sc->sc_ani.timer, + mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } - return 0; +out: + mutex_unlock(&sc->mutex); + return ret; } static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct ath_softc *sc = hw->priv; - struct ath_vap *avp = (void *)conf->vif->drv_priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_vif *avp = (void *)conf->vif->drv_priv; + int i; DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); + mutex_lock(&sc->mutex); + /* Stop ANI */ - del_timer_sync(&sc->sc_ani.timer); + del_timer_sync(&sc->ani.timer); /* Reclaim beacon resources */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || - sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || + (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath_beacon_return(sc, avp); } sc->sc_flags &= ~SC_OP_BEACONS; - sc->sc_vaps[0] = NULL; - sc->sc_nvaps--; + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + if (sc->beacon.bslot[i] == conf->vif) { + printk(KERN_DEBUG "%s: vif had allocated beacon " + "slot\n", __func__); + sc->beacon.bslot[i] = NULL; + sc->beacon.bslot_aphy[i] = NULL; + } + } + + sc->nvifs--; + + mutex_unlock(&sc->mutex); } static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ieee80211_conf *conf = &hw->conf; mutex_lock(&sc->mutex); - if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | - IEEE80211_CONF_CHANGE_HT)) { - struct ieee80211_channel *curchan = hw->conf.channel; - int pos; - - DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", - curchan->center_freq); - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", - curchan->center_freq); - mutex_unlock(&sc->mutex); - return -EINVAL; + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + } else { + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_hw_setrxabort(sc->sc_ah, 0); + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->imask & ATH9K_INT_TIM_TIMER) { + sc->imask &= ~ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } } + } - sc->tx_chan_width = ATH9K_HT_MACMODE_20; - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos = curchan->hw_value; - if (conf->ht.enabled) { - if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS || - conf->ht.channel_type == NL80211_CHAN_HT40MINUS) - sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + aphy->chan_idx = pos; + aphy->chan_is_ht = conf_is_ht(conf); - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan, - conf->ht.channel_type); + if (aphy->state == ATH_WIPHY_SCAN || + aphy->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_all_forced(sc, aphy); + else { + /* + * Do not change operational channel based on a paused + * wiphy changes. + */ + goto skip_chan_change; } - ath_update_chainmask(sc, conf->ht.enabled); + DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); + + /* XXX: remove me eventualy */ + ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); + + ath_update_chainmask(sc, conf_is_ht(conf)); - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { + if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); mutex_unlock(&sc->mutex); return -EINVAL; } } +skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) - sc->sc_config.txpowlimit = 2 * conf->power_level; + sc->config.txpowlimit = 2 * conf->power_level; + + /* + * The HW TSF has to be reset when the beacon interval changes. + * We set the flag here, and ath_beacon_config_ap() would take this + * into account when it gets called through the subsequent + * config_interface() call - with IFCC_BEACON in the changed field. + */ + + if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) + sc->sc_flags |= SC_OP_TSF_RESET; mutex_unlock(&sc->mutex); + return 0; } @@ -2195,19 +2406,24 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { - struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp = (void *)vif->drv_priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_vif *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; + mutex_lock(&sc->mutex); + /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ if (vif->type == NL80211_IFTYPE_AP && - ah->ah_opmode != NL80211_IFTYPE_AP) { - ah->ah_opmode = NL80211_IFTYPE_STATION; + ah->opmode != NL80211_IFTYPE_AP) { + ah->opmode = NL80211_IFTYPE_STATION; ath9k_hw_setopmode(ah); - ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); + memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); /* Request full reset to get hw opmode changed properly */ sc->sc_flags |= SC_OP_FULL_RESET; } @@ -2217,18 +2433,19 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: /* Set BSSID */ - memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); - sc->sc_curaid = 0; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); + memcpy(sc->curbssid, conf->bssid, ETH_ALEN); + memcpy(avp->bssid, conf->bssid, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); /* Set aggregation protection mode parameters */ - sc->sc_config.ath_aggr_prot = 0; + sc->config.ath_aggr_prot = 0; DPRINTF(sc, ATH_DBG_CONFIG, "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, sc->sc_curbssid, sc->sc_curaid); + rfilt, sc->curbssid, sc->curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -2239,24 +2456,30 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } } - if ((conf->changed & IEEE80211_IFCC_BEACON) && - ((vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_AP))) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((conf->changed & IEEE80211_IFCC_BEACON) || + (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && + conf->enable_beacon)) { + /* + * Allocate and setup the beacon frame. + * + * Stop any previous beacon DMA. This may be + * necessary, for example, when an ibss merge + * causes reconfiguration; we may be called + * with beacon transmission active. + */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - error = ath_beacon_alloc(sc, 0); - if (error != 0) - return error; + error = ath_beacon_alloc(aphy, vif); + if (error != 0) { + mutex_unlock(&sc->mutex); + return error; + } - ath_beacon_sync(sc, 0); + ath_beacon_config(sc, vif); + } } /* Check for WLAN_CAPABILITY_PRIVACY ? */ @@ -2265,13 +2488,15 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, (u16)i, - sc->sc_curbssid); + sc->curbssid); } /* Only legacy IBSS for now */ if (vif->type == NL80211_IFTYPE_ADHOC) ath_update_chainmask(sc, 0); + mutex_unlock(&sc->mutex); + return 0; } @@ -2290,7 +2515,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_mc_list *mclist) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; u32 rfilt; changed_flags &= SUPPORTED_FILTERS; @@ -2300,11 +2526,6 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); - } - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } @@ -2313,7 +2534,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; switch (cmd) { case STA_NOTIFY_ADD: @@ -2327,17 +2549,19 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } } -static int ath9k_conf_tx(struct ieee80211_hw *hw, - u16 queue, +static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; struct ath9k_tx_queue_info qi; int ret = 0, qnum; if (queue >= WME_NUM_AC) return 0; + mutex_lock(&sc->mutex); + qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; @@ -2354,29 +2578,39 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, if (ret) DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); + mutex_unlock(&sc->mutex); + return ret; } static int ath9k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - const u8 *local_addr, - const u8 *addr, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; int ret = 0; + if (modparam_nohwcrypt) + return -ENOSPC; + + mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); switch (cmd) { case SET_KEY: - ret = ath_key_config(sc, addr, key); + ret = ath_key_config(sc, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->alg == ALG_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; ret = 0; } break; @@ -2387,6 +2621,9 @@ static int ath9k_set_key(struct ieee80211_hw *hw, ret = -EINVAL; } + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + return ret; } @@ -2395,7 +2632,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_ERP_PREAMBLE) { DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", @@ -2421,33 +2661,50 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->assoc); ath9k_bss_assoc_info(sc, vif, bss_conf); } + + mutex_unlock(&sc->mutex); } static u64 ath9k_get_tsf(struct ieee80211_hw *hw) { u64 tsf; - struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; - tsf = ath9k_hw_gettsf64(ah); + mutex_lock(&sc->mutex); + tsf = ath9k_hw_gettsf64(sc->sc_ah); + mutex_unlock(&sc->mutex); return tsf; } +static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + ath9k_hw_settsf64(sc->sc_ah, tsf); + mutex_unlock(&sc->mutex); +} + static void ath9k_reset_tsf(struct ieee80211_hw *hw) { - struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; - ath9k_hw_reset_tsf(ah); + mutex_lock(&sc->mutex); + ath9k_hw_reset_tsf(sc->sc_ah); + mutex_unlock(&sc->mutex); } static int ath9k_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { - struct ath_softc *sc = hw->priv; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; int ret = 0; switch (action) { @@ -2473,7 +2730,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; - case IEEE80211_AMPDU_TX_RESUME: + case IEEE80211_AMPDU_TX_OPERATIONAL: ath_tx_aggr_resume(sc, sta, tid); break; default: @@ -2483,7 +2740,41 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, return ret; } -static struct ieee80211_ops ath9k_ops = { +static void ath9k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + if (ath9k_wiphy_scanning(sc)) { + printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " + "same time\n"); + /* + * Do not allow the concurrent scanning state for now. This + * could be improved with scanning control moved into ath9k. + */ + return; + } + + aphy->state = ATH_WIPHY_SCAN; + ath9k_wiphy_pause_all_forced(sc, aphy); + + mutex_lock(&sc->mutex); + sc->sc_flags |= SC_OP_SCANNING; + mutex_unlock(&sc->mutex); +} + +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_ACTIVE; + sc->sc_flags &= ~SC_OP_SCANNING; + mutex_unlock(&sc->mutex); +} + +struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, .stop = ath9k_stop, @@ -2497,8 +2788,11 @@ static struct ieee80211_ops ath9k_ops = { .bss_info_changed = ath9k_bss_info_changed, .set_key = ath9k_set_key, .get_tsf = ath9k_get_tsf, + .set_tsf = ath9k_set_tsf, .reset_tsf = ath9k_reset_tsf, .ampdu_action = ath9k_ampdu_action, + .sw_scan_start = ath9k_sw_scan_start, + .sw_scan_complete = ath9k_sw_scan_complete, }; static struct { @@ -2527,7 +2821,7 @@ static struct { /* * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. */ -static const char * +const char * ath_mac_bb_name(u32 mac_bb_version) { int i; @@ -2544,7 +2838,7 @@ ath_mac_bb_name(u32 mac_bb_version) /* * Return the RF name. "????" is returned if the RF is unknown. */ -static const char * +const char * ath_rf_name(u16 rf_version) { int i; @@ -2558,254 +2852,62 @@ ath_rf_name(u16 rf_version) return "????"; } -static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - void __iomem *mem; - struct ath_softc *sc; - struct ieee80211_hw *hw; - u8 csz; - u32 val; - int ret = 0; - struct ath_hal *ah; - - if (pci_enable_device(pdev)) - return -EIO; - - ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - - if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); - goto bad; - } - - ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - - if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA consistent " - "DMA enable failed\n"); - goto bad; - } - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); - if (csz == 0) { - /* - * Linux 2.4.18 (at least) writes the cache line size - * register as a 16-bit wide register which is wrong. - * We must have this setup properly for rx buffer - * DMA to work so force a reasonable value here if it - * comes up zero. - */ - csz = L1_CACHE_BYTES / sizeof(u32); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); - } - /* - * The default setting of latency timer yields poor results, - * set it to the value used by other systems. It may be worth - * tweaking this setting more. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); - - pci_set_master(pdev); - - /* - * Disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state. - */ - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - ret = pci_request_region(pdev, 0, "ath9k"); - if (ret) { - dev_err(&pdev->dev, "PCI memory region reserve error\n"); - ret = -ENODEV; - goto bad; - } - - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - printk(KERN_ERR "PCI memory map error\n") ; - ret = -EIO; - goto bad1; - } - - hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); - goto bad2; - } - - SET_IEEE80211_DEV(hw, &pdev->dev); - pci_set_drvdata(pdev, hw); - - sc = hw->priv; - sc->hw = hw; - sc->pdev = pdev; - sc->mem = mem; - - if (ath_attach(id->device, sc) != 0) { - ret = -ENODEV; - goto bad3; - } - - /* setup interrupt service routine */ - - if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { - printk(KERN_ERR "%s: request_irq failed\n", - wiphy_name(hw->wiphy)); - ret = -EIO; - goto bad4; - } - - ah = sc->sc_ah; - printk(KERN_INFO - "%s: Atheros AR%s MAC/BB Rev:%x " - "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", - wiphy_name(hw->wiphy), - ath_mac_bb_name(ah->ah_macVersion), - ah->ah_macRev, - ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), - ah->ah_phyRev, - (unsigned long)mem, pdev->irq); - - return 0; -bad4: - ath_detach(sc); -bad3: - ieee80211_free_hw(hw); -bad2: - pci_iounmap(pdev, mem); -bad1: - pci_release_region(pdev, 0); -bad: - pci_disable_device(pdev); - return ret; -} - -static void ath_pci_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_softc *sc = hw->priv; - - ath_detach(sc); - if (pdev->irq) - free_irq(pdev->irq, sc); - pci_iounmap(pdev, sc->mem); - pci_release_region(pdev, 0); - pci_disable_device(pdev); - ieee80211_free_hw(hw); -} - -#ifdef CONFIG_PM - -static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_softc *sc = hw->priv; - - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, 3); - - return 0; -} - -static int ath_pci_resume(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_softc *sc = hw->priv; - u32 val; - int err; - - err = pci_enable_device(pdev); - if (err) - return err; - pci_restore_state(pdev); - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state - */ - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - /* Enable LED */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* - * check the h/w rfkill state on resume - * and start the rfkill poll timer - */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); -#endif - - return 0; -} - -#endif /* CONFIG_PM */ - -MODULE_DEVICE_TABLE(pci, ath_pci_id_table); - -static struct pci_driver ath_pci_driver = { - .name = "ath9k", - .id_table = ath_pci_id_table, - .probe = ath_pci_probe, - .remove = ath_pci_remove, -#ifdef CONFIG_PM - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, -#endif /* CONFIG_PM */ -}; - -static int __init init_ath_pci(void) +static int __init ath9k_init(void) { int error; - printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); - /* Register rate control algorithm */ error = ath_rate_control_register(); if (error != 0) { printk(KERN_ERR - "Unable to register rate control algorithm: %d\n", + "ath9k: Unable to register rate control " + "algorithm: %d\n", error); - ath_rate_control_unregister(); - return error; + goto err_out; } - if (pci_register_driver(&ath_pci_driver) < 0) { + error = ath9k_debug_create_root(); + if (error) { printk(KERN_ERR - "ath_pci: No devices found, driver not installed.\n"); - ath_rate_control_unregister(); - pci_unregister_driver(&ath_pci_driver); - return -ENODEV; + "ath9k: Unable to create debugfs root: %d\n", + error); + goto err_rate_unregister; + } + + error = ath_pci_init(); + if (error < 0) { + printk(KERN_ERR + "ath9k: No PCI devices found, driver not installed.\n"); + error = -ENODEV; + goto err_remove_root; + } + + error = ath_ahb_init(); + if (error < 0) { + error = -ENODEV; + goto err_pci_exit; } return 0; + + err_pci_exit: + ath_pci_exit(); + + err_remove_root: + ath9k_debug_remove_root(); + err_rate_unregister: + ath_rate_control_unregister(); + err_out: + return error; } -module_init(init_ath_pci); +module_init(ath9k_init); -static void __exit exit_ath_pci(void) +static void __exit ath9k_exit(void) { + ath_ahb_exit(); + ath_pci_exit(); + ath9k_debug_remove_root(); ath_rate_control_unregister(); - pci_unregister_driver(&ath_pci_driver); printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } -module_exit(exit_ath_pci); +module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c new file mode 100644 index 000000000000..6dbc58580abb --- /dev/null +++ b/drivers/net/wireless/ath9k/pci.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/nl80211.h> +#include <linux/pci.h> +#include "ath9k.h" + +static struct pci_device_id ath_pci_id_table[] __devinitdata = { + { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ + { 0 } +}; + +/* return bus cachesize in 4B word units */ +static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) +{ + u8 u8tmp; + + pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, + (u8 *)&u8tmp); + *csz = (int)u8tmp; + + /* + * This check was put in to avoid "unplesant" consequences if + * the bootrom has not fully initialized all PCI devices. + * Sometimes the cache line size register is not set + */ + + if (*csz == 0) + *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ +} + +static void ath_pci_cleanup(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + + pci_iounmap(pdev, sc->mem); + pci_disable_device(pdev); + pci_release_region(pdev, 0); +} + +static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +{ + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) { + return false; + } + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static struct ath_bus_ops ath_pci_bus_ops = { + .read_cachesize = ath_pci_read_cachesize, + .cleanup = ath_pci_cleanup, + .eeprom_read = ath_pci_eeprom_read, +}; + +static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath_wiphy *aphy; + struct ath_softc *sc; + struct ieee80211_hw *hw; + u8 csz; + int ret = 0; + struct ath_hw *ah; + + if (pci_enable_device(pdev)) + return -EIO; + + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); + goto bad; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA consistent " + "DMA enable failed\n"); + goto bad; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u32); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + pci_set_master(pdev); + + ret = pci_request_region(pdev, 0, "ath9k"); + if (ret) { + dev_err(&pdev->dev, "PCI memory region reserve error\n"); + ret = -ENODEV; + goto bad; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + printk(KERN_ERR "PCI memory map error\n") ; + ret = -EIO; + goto bad1; + } + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + + sizeof(struct ath_softc), &ath9k_ops); + if (hw == NULL) { + printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); + goto bad2; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + pci_set_drvdata(pdev, hw); + + aphy = hw->priv; + sc = (struct ath_softc *) (aphy + 1); + aphy->sc = sc; + aphy->hw = hw; + sc->pri_wiphy = aphy; + sc->hw = hw; + sc->dev = &pdev->dev; + sc->mem = mem; + sc->bus_ops = &ath_pci_bus_ops; + + if (ath_attach(id->device, sc) != 0) { + ret = -ENODEV; + goto bad3; + } + + /* setup interrupt service routine */ + + if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { + printk(KERN_ERR "%s: request_irq failed\n", + wiphy_name(hw->wiphy)); + ret = -EIO; + goto bad4; + } + + sc->irq = pdev->irq; + + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", + wiphy_name(hw->wiphy), + ath_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev, + (unsigned long)mem, pdev->irq); + + return 0; +bad4: + ath_detach(sc); +bad3: + ieee80211_free_hw(hw); +bad2: + pci_iounmap(pdev, mem); +bad1: + pci_release_region(pdev, 0); +bad: + pci_disable_device(pdev); + return ret; +} + +static void ath_pci_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath_cleanup(sc); +} + +#ifdef CONFIG_PM + +static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int ath_pci_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + pci_restore_state(pdev); + + /* Enable LED */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /* + * check the h/w rfkill state on resume + * and start the rfkill poll timer + */ + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); +#endif + + return 0; +} + +#endif /* CONFIG_PM */ + +MODULE_DEVICE_TABLE(pci, ath_pci_id_table); + +static struct pci_driver ath_pci_driver = { + .name = "ath9k", + .id_table = ath_pci_id_table, + .probe = ath_pci_probe, + .remove = ath_pci_remove, +#ifdef CONFIG_PM + .suspend = ath_pci_suspend, + .resume = ath_pci_resume, +#endif /* CONFIG_PM */ +}; + +int ath_pci_init(void) +{ + return pci_register_driver(&ath_pci_driver); +} + +void ath_pci_exit(void) +{ + pci_unregister_driver(&ath_pci_driver); +} diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index 766982a8196e..8bcba906929a 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,22 +14,17 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" -#include "hw.h" -#include "reg.h" -#include "phy.h" +#include "ath9k.h" void -ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex, +ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, int regWrites) { - struct ath_hal_5416 *ahp = AH5416(ah); - - REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites); + REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); } bool -ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) +ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { u32 channelSel = 0; u32 bModeSynth = 0; @@ -95,15 +90,14 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) REG_WRITE(ah, AR_PHY(0x37), reg32); - ah->ah_curchan = chan; - - AH5416(ah)->ah_curchanRadIndex = -1; + ah->curchan = chan; + ah->curchan_rad_index = -1; return true; } bool -ath9k_hw_ar9280_set_channel(struct ath_hal *ah, +ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { u16 bMode, fracMode, aModeRefSel = 0; @@ -138,20 +132,27 @@ ath9k_hw_ar9280_set_channel(struct ath_hal *ah, bMode = 0; fracMode = 0; - if ((freq % 20) == 0) { - aModeRefSel = 3; - } else if ((freq % 10) == 0) { - aModeRefSel = 2; - } else { + switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { + case 0: + if ((freq % 20) == 0) { + aModeRefSel = 3; + } else if ((freq % 10) == 0) { + aModeRefSel = 2; + } + if (aModeRefSel) + break; + case 1: + default: aModeRefSel = 0; - fracMode = 1; refDivA = 1; channelSel = (freq * 0x8000) / 15; REG_RMW_FIELD(ah, AR_AN_SYNTH9, AR_AN_SYNTH9_REFDIVA, refDivA); + } + if (!fracMode) { ndiv = (freq * (refDivA >> aModeRefSel)) / 60; channelSel = ndiv & 0x1ff; @@ -166,9 +167,8 @@ ath9k_hw_ar9280_set_channel(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); - ah->ah_curchan = chan; - - AH5416(ah)->ah_curchanRadIndex = -1; + ah->curchan = chan; + ah->curchan_rad_index = -1; return true; } @@ -201,11 +201,9 @@ ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, } bool -ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, +ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex) { - struct ath_hal_5416 *ahp = AH5416(ah); - u32 eepMinorRev; u32 ob5GHz = 0, db5GHz = 0; u32 ob2GHz = 0, db2GHz = 0; @@ -214,161 +212,156 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) return true; - eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV); + eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); - RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1); + RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); - RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1); + RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); - RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1); + RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); - RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3, + RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, modesIndex); { int i; - for (i = 0; i < ahp->ah_iniBank6TPC.ia_rows; i++) { - ahp->ah_analogBank6Data[i] = - INI_RA(&ahp->ah_iniBank6TPC, i, modesIndex); + for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { + ah->analogBank6Data[i] = + INI_RA(&ah->iniBank6TPC, i, modesIndex); } } if (eepMinorRev >= 2) { if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2); - db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2); - ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, + ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); + db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, ob2GHz, 3, 197, 0); - ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, db2GHz, 3, 194, 0); } else { - ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5); - db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5); - ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, + ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); + db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, ob5GHz, 3, 203, 0); - ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, db5GHz, 3, 200, 0); } } - RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1); + RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data, + REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, regWrites); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data, + REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, regWrites); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data, + REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, regWrites); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data, + REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, regWrites); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data, + REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, regWrites); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data, + REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, regWrites); return true; } void -ath9k_hw_rfdetach(struct ath_hal *ah) +ath9k_hw_rfdetach(struct ath_hw *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (ahp->ah_analogBank0Data != NULL) { - kfree(ahp->ah_analogBank0Data); - ahp->ah_analogBank0Data = NULL; + if (ah->analogBank0Data != NULL) { + kfree(ah->analogBank0Data); + ah->analogBank0Data = NULL; } - if (ahp->ah_analogBank1Data != NULL) { - kfree(ahp->ah_analogBank1Data); - ahp->ah_analogBank1Data = NULL; + if (ah->analogBank1Data != NULL) { + kfree(ah->analogBank1Data); + ah->analogBank1Data = NULL; } - if (ahp->ah_analogBank2Data != NULL) { - kfree(ahp->ah_analogBank2Data); - ahp->ah_analogBank2Data = NULL; + if (ah->analogBank2Data != NULL) { + kfree(ah->analogBank2Data); + ah->analogBank2Data = NULL; } - if (ahp->ah_analogBank3Data != NULL) { - kfree(ahp->ah_analogBank3Data); - ahp->ah_analogBank3Data = NULL; + if (ah->analogBank3Data != NULL) { + kfree(ah->analogBank3Data); + ah->analogBank3Data = NULL; } - if (ahp->ah_analogBank6Data != NULL) { - kfree(ahp->ah_analogBank6Data); - ahp->ah_analogBank6Data = NULL; + if (ah->analogBank6Data != NULL) { + kfree(ah->analogBank6Data); + ah->analogBank6Data = NULL; } - if (ahp->ah_analogBank6TPCData != NULL) { - kfree(ahp->ah_analogBank6TPCData); - ahp->ah_analogBank6TPCData = NULL; + if (ah->analogBank6TPCData != NULL) { + kfree(ah->analogBank6TPCData); + ah->analogBank6TPCData = NULL; } - if (ahp->ah_analogBank7Data != NULL) { - kfree(ahp->ah_analogBank7Data); - ahp->ah_analogBank7Data = NULL; + if (ah->analogBank7Data != NULL) { + kfree(ah->analogBank7Data); + ah->analogBank7Data = NULL; } - if (ahp->ah_addac5416_21 != NULL) { - kfree(ahp->ah_addac5416_21); - ahp->ah_addac5416_21 = NULL; + if (ah->addac5416_21 != NULL) { + kfree(ah->addac5416_21); + ah->addac5416_21 = NULL; } - if (ahp->ah_bank6Temp != NULL) { - kfree(ahp->ah_bank6Temp); - ahp->ah_bank6Temp = NULL; + if (ah->bank6Temp != NULL) { + kfree(ah->bank6Temp); + ah->bank6Temp = NULL; } } -bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) +bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (!AR_SREV_9280_10_OR_LATER(ah)) { - - ahp->ah_analogBank0Data = + ah->analogBank0Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank0.ia_rows), GFP_KERNEL); - ahp->ah_analogBank1Data = + ah->iniBank0.ia_rows), GFP_KERNEL); + ah->analogBank1Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank1.ia_rows), GFP_KERNEL); - ahp->ah_analogBank2Data = + ah->iniBank1.ia_rows), GFP_KERNEL); + ah->analogBank2Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank2.ia_rows), GFP_KERNEL); - ahp->ah_analogBank3Data = + ah->iniBank2.ia_rows), GFP_KERNEL); + ah->analogBank3Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank3.ia_rows), GFP_KERNEL); - ahp->ah_analogBank6Data = + ah->iniBank3.ia_rows), GFP_KERNEL); + ah->analogBank6Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank6.ia_rows), GFP_KERNEL); - ahp->ah_analogBank6TPCData = + ah->iniBank6.ia_rows), GFP_KERNEL); + ah->analogBank6TPCData = kzalloc((sizeof(u32) * - ahp->ah_iniBank6TPC.ia_rows), GFP_KERNEL); - ahp->ah_analogBank7Data = + ah->iniBank6TPC.ia_rows), GFP_KERNEL); + ah->analogBank7Data = kzalloc((sizeof(u32) * - ahp->ah_iniBank7.ia_rows), GFP_KERNEL); - - if (ahp->ah_analogBank0Data == NULL - || ahp->ah_analogBank1Data == NULL - || ahp->ah_analogBank2Data == NULL - || ahp->ah_analogBank3Data == NULL - || ahp->ah_analogBank6Data == NULL - || ahp->ah_analogBank6TPCData == NULL - || ahp->ah_analogBank7Data == NULL) { + ah->iniBank7.ia_rows), GFP_KERNEL); + + if (ah->analogBank0Data == NULL + || ah->analogBank1Data == NULL + || ah->analogBank2Data == NULL + || ah->analogBank3Data == NULL + || ah->analogBank6Data == NULL + || ah->analogBank6TPCData == NULL + || ah->analogBank7Data == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; } - ahp->ah_addac5416_21 = + ah->addac5416_21 = kzalloc((sizeof(u32) * - ahp->ah_iniAddac.ia_rows * - ahp->ah_iniAddac.ia_columns), GFP_KERNEL); - if (ahp->ah_addac5416_21 == NULL) { + ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns), GFP_KERNEL); + if (ah->addac5416_21 == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Cannot allocate ah_addac5416_21\n"); + "Cannot allocate addac5416_21\n"); *status = -ENOMEM; return false; } - ahp->ah_bank6Temp = + ah->bank6Temp = kzalloc((sizeof(u32) * - ahp->ah_iniBank6.ia_rows), GFP_KERNEL); - if (ahp->ah_bank6Temp == NULL) { + ah->iniBank6.ia_rows), GFP_KERNEL); + if (ah->bank6Temp == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Cannot allocate ah_bank6Temp\n"); + "Cannot allocate bank6Temp\n"); *status = -ENOMEM; return false; } @@ -378,24 +371,23 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) } void -ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan) +ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) { int i, regWrites = 0; - struct ath_hal_5416 *ahp = AH5416(ah); u32 bank6SelMask; - u32 *bank6Temp = ahp->ah_bank6Temp; + u32 *bank6Temp = ah->bank6Temp; - switch (ahp->ah_diversityControl) { + switch (ah->diversity_control) { case ATH9K_ANT_FIXED_A: bank6SelMask = - (ahp-> - ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : + (ah-> + antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : REDUCE_CHAIN_1; break; case ATH9K_ANT_FIXED_B: bank6SelMask = - (ahp-> - ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : + (ah-> + antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : REDUCE_CHAIN_0; break; case ATH9K_ANT_VARIABLE: @@ -406,8 +398,8 @@ ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan) break; } - for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++) - bank6Temp[i] = ahp->ah_analogBank6Data[i]; + for (i = 0; i < ah->iniBank6.ia_rows; i++) + bank6Temp[i] = ah->analogBank6Data[i]; REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); @@ -421,7 +413,7 @@ ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan) ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); - REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6, bank6Temp, regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); #ifdef ALTER_SWITCH diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 3a406a5c0593..0f7f8e0c9c95 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,19 +17,19 @@ #ifndef PHY_H #define PHY_H -bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah, +bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -bool ath9k_hw_set_channel(struct ath_hal *ah, +bool ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, +void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, int regWrites); -bool ath9k_hw_set_rf_regs(struct ath_hal *ah, +bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex); -void ath9k_hw_decrease_chain_power(struct ath_hal *ah, +void ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan); -bool ath9k_hw_init_rf(struct ath_hal *ah, +bool ath9k_hw_init_rf(struct ath_hw *ah, int *status); #define AR_PHY_BASE 0x9800 @@ -387,6 +387,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_CCK_TX_CTRL 0xA204 #define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 #define AR_PHY_CCK_DETECT 0xA208 #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F @@ -444,6 +446,32 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 #define AR_PHY_TPCRG1_PD_GAIN_3_S 20 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 + +#define AR_PHY_TX_PWRCTRL4 0xa264 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 + +#define AR_PHY_TX_PWRCTRL6_0 0xa270 +#define AR_PHY_TX_PWRCTRL6_1 0xb270 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 + +#define AR_PHY_TX_PWRCTRL7 0xa274 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 + +#define AR_PHY_TX_PWRCTRL9 0xa27C +#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 +#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 + +#define AR_PHY_TX_GAIN_TBL1 0xa300 +#define AR_PHY_TX_GAIN 0x0007F000 +#define AR_PHY_TX_GAIN_S 12 + #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 #define AR_PHY_MASK2_M_31_45 0xa3a4 #define AR_PHY_MASK2_M_16_30 0xa3a8 @@ -485,6 +513,11 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 +/* Carrier leak calibration control, do it after AGC calibration */ +#define AR_PHY_CL_CAL_CTL 0xA358 +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 + #define AR_PHY_POWER_TX_RATE5 0xA38C #define AR_PHY_POWER_TX_RATE6 0xA390 @@ -530,10 +563,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, } \ } while (0) -#define ATH9K_KEY_XOR 0xaa - #define ATH9K_IS_MIC_ENABLED(ah) \ - (AH5416(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE) + ((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE) #define ANTSWAP_AB 0x0001 #define REDUCE_CHAIN_0 0x00000050 diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1b71b934bb5e..824ccbb8b7b8 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2008 Atheros Communications, Inc. + * Copyright (c) 2004-2009 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,16 +15,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" +#include "ath9k.h" static struct ath_rate_table ar5416_11na_ratetable = { 42, - {0}, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 0, 2, 1, 0, 0, 0, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 1, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ @@ -158,7 +157,6 @@ static struct ath_rate_table ar5416_11na_ratetable = { static struct ath_rate_table ar5416_11ng_ratetable = { 46, - {0}, { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, @@ -306,7 +304,6 @@ static struct ath_rate_table ar5416_11ng_ratetable = { static struct ath_rate_table ar5416_11a_ratetable = { 8, - {0}, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), @@ -340,7 +337,6 @@ static struct ath_rate_table ar5416_11a_ratetable = { static struct ath_rate_table ar5416_11g_ratetable = { 12, - {0}, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, @@ -386,7 +382,6 @@ static struct ath_rate_table ar5416_11g_ratetable = { static struct ath_rate_table ar5416_11b_ratetable = { 4, - {0}, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, (0x80|2), @@ -636,8 +631,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_ratefind_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, - int probe_allowed, int *is_probing, - int is_retry) + int *is_probing) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -719,13 +713,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, } rate = best_rate; - - /* if we are retrying for more than half the number - * of max retries, use the min rate for the next retry - */ - if (is_retry) - rate = ath_rc_priv->valid_rate_index[minindex]; - ath_rc_priv->rssi_last_lookup = rssi_last; /* @@ -733,13 +720,12 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * non-monoticity of 11g's rate table */ - if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) { + if (rate >= ath_rc_priv->rate_max_phy) { rate = ath_rc_priv->rate_max_phy; /* Probe the next allowed phy state */ - /* FIXME:XXXX Check to make sure ratMax is checked properly */ if (ath_rc_get_nextvalid_txrate(rate_table, - ath_rc_priv, rate, &next_rate) && + ath_rc_priv, rate, &next_rate) && (now_msec - ath_rc_priv->probe_time > rate_table->probe_interval) && (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { @@ -761,14 +747,17 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, return rate; } -static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate, + struct ieee80211_tx_rate_control *txrc, u8 tries, u8 rix, int rtsctsenable) { rate->count = tries; rate->idx = rix; - if (rtsctsenable) + if (txrc->short_preamble) + rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + if (txrc->rts || rtsctsenable) rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; @@ -778,6 +767,43 @@ static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , rate->flags |= IEEE80211_TX_RC_MCS; } +static void ath_rc_rate_set_rtscts(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_tx_rate *rates = tx_info->control.rates; + int i = 0, rix = 0, cix, enable_g_protection = 0; + + /* get the cix for the lowest valid rix */ + for (i = 3; i >= 0; i--) { + if (rates[i].count && (rates[i].idx >= 0)) { + rix = rates[i].idx; + break; + } + } + cix = rate_table->info[rix].ctrl_rate; + + /* All protection frames are transmited at 2Mb/s for 802.11g, + * otherwise we transmit them at 1Mb/s */ + if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ && + !conf_is_ht(&sc->hw->conf)) + enable_g_protection = 1; + + /* + * If 802.11g protection is enabled, determine whether to use RTS/CTS or + * just CTS. Note that this is only done for OFDM/HT unicast frames. + */ + if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && + !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && + (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || + WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { + rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; + cix = rate_table->info[enable_g_protection].ctrl_rate; + } + + tx_info->control.rts_cts_rate_idx = cix; +} + static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, @@ -809,54 +835,58 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - int num_tries, int num_rates, - struct ieee80211_tx_info *tx_info, int *is_probe, - int is_retry) + struct ieee80211_tx_rate_control *txrc) { - u8 try_per_rate = 0, i = 0, rix, nrix; struct ath_rate_table *rate_table; + struct sk_buff *skb = txrc->skb; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + __le16 fc = hdr->frame_control; + u8 try_per_rate = 0, i = 0, rix, nrix; + int is_probe = 0; rate_table = sc->cur_rate_table; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1, - is_probe, is_retry); + rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); nrix = rix; - if (*is_probe) { + if (is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ - ath_rc_rate_set_series(rate_table, - &rates[i++], 1, nrix, 0); + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + 1, nrix, 0); - try_per_rate = (num_tries/num_rates); + try_per_rate = (ATH_11N_TXMAXTRY/4); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - nrix = ath_rc_rate_getidx(sc, - ath_rc_priv, rate_table, nrix, 1, 0); - ath_rc_rate_set_series(rate_table, - &rates[i++], try_per_rate, nrix, 0); + nrix = ath_rc_rate_getidx(sc, ath_rc_priv, + rate_table, nrix, 1, 0); + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + try_per_rate, nrix, 0); + + tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { - try_per_rate = (num_tries/num_rates); + try_per_rate = (ATH_11N_TXMAXTRY/4); /* Set the choosen rate. No RTS for first series entry. */ - ath_rc_rate_set_series(rate_table, - &rates[i++], try_per_rate, nrix, 0); + ath_rc_rate_set_series(rate_table, &rates[i++], txrc, + try_per_rate, nrix, 0); } /* Fill in the other rates for multirate retry */ - for ( ; i < num_rates; i++) { + for ( ; i < 4; i++) { u8 try_num; u8 min_rate; - try_num = ((i + 1) == num_rates) ? - num_tries - (try_per_rate * i) : try_per_rate ; - min_rate = (((i + 1) == num_rates) && 0); + try_num = ((i + 1) == 4) ? + ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ; + min_rate = (((i + 1) == 4) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ - ath_rc_rate_set_series(rate_table, - &rates[i], try_num, nrix, 1); + ath_rc_rate_set_series(rate_table, &rates[i], txrc, + try_num, nrix, 1); } /* @@ -875,7 +905,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, * above conditions. */ if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && - (sc->hw->conf.ht.enabled)) { + (conf_is_ht(&sc->hw->conf))) { u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && @@ -885,6 +915,24 @@ static void ath_rc_ratefind(struct ath_softc *sc, rates[3].flags = rates[2].flags; } } + + /* + * Force hardware to use computed duration for next + * fragment by disabling multi-rate retry, which + * updates duration based on the multi-rate duration table. + * + * FIXME: Fix duration + */ + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && + (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) { + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; + rates[0].count = ATH_TXMAXTRY; + } + + /* Setup RTS/CTS */ + ath_rc_rate_set_rtscts(sc, rate_table, tx_info); } static bool ath_rc_update_per(struct ath_softc *sc, @@ -1221,6 +1269,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->per_down_time = now_msec; } + ath_debug_stat_retries(sc, tx_rate, xretries, retries, + ath_rc_priv->state[tx_rate].per); + #undef CHK_RSSI } @@ -1338,36 +1389,18 @@ static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, static void ath_rc_init(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, + struct ath_rate_table *rate_table) { - struct ath_rate_table *rate_table = NULL; struct ath_rateset *rateset = &ath_rc_priv->neg_rates; u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - /* FIXME: Adhoc */ - if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || - (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) { - bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; - rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, - is_cw_40); - } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { - /* cur_rate_table would be set on init through config() */ - rate_table = sc->cur_rate_table; - } - if (!rate_table) { DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); return; } - if (sta->ht_cap.ht_supported) { - ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) - ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; - } - /* Initial rate table size. Will change depending * on the working rate set */ ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; @@ -1387,7 +1420,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } - ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); + ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG; /* Set stream capability */ ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; @@ -1395,16 +1428,16 @@ static void ath_rc_init(struct ath_softc *sc, if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ hi = ath_rc_init_validrates(ath_rc_priv, rate_table, - ath_rc_priv->ht_cap); + ath_rc_priv->ht_cap); } else { /* Use intersection of working rates and valid rates */ hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, - rateset, ath_rc_priv->ht_cap); + rateset, ath_rc_priv->ht_cap); if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { hthi = ath_rc_setvalid_htrates(ath_rc_priv, - rate_table, - ht_mcs, - ath_rc_priv->ht_cap); + rate_table, + ht_mcs, + ath_rc_priv->ht_cap); } hi = A_MAX(hi, hthi); } @@ -1432,9 +1465,36 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_sort_validrates(rate_table, ath_rc_priv); ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; sc->cur_rate_table = rate_table; + + DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", + ath_rc_priv->ht_cap); +} + +static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, + bool is_cw40, bool is_sgi40) +{ + u8 caps = 0; + + if (sta->ht_cap.ht_supported) { + caps = WLAN_RC_HT_FLAG; + if (sc->sc_ah->caps.tx_chainmask != 1 && + ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) { + if (sta->ht_cap.mcs.rx_mask[1]) + caps |= WLAN_RC_DS_FLAG; + } + if (is_cw40) + caps |= WLAN_RC_40_FLAG; + if (is_sgi40) + caps |= WLAN_RC_SGI_FLAG; + } + + return caps; } -/* Rate Control callbacks */ +/***********************************/ +/* mac80211 Rate Control callbacks */ +/***********************************/ + static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) @@ -1467,7 +1527,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, */ if (tx_info_priv->tx.ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) { + ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) { tx_status = 1; is_underrun = 1; } @@ -1480,6 +1540,23 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, (is_underrun) ? ATH_11N_TXMAXTRY : tx_info_priv->tx.ts_longretry); + /* Check if aggregation has to be enabled for this tid */ + if (conf_is_ht(&sc->hw->conf) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath_node *an; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + an = (struct ath_node *)sta->drv_priv; + + if(ath_tx_aggr_check(sc, an, tid)) + ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); + } + } + + ath_debug_stat_rc(sc, skb); exit: kfree(tx_info_priv); } @@ -1490,11 +1567,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_supported_band *sband = txrc->sband; struct sk_buff *skb = txrc->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = priv; - struct ieee80211_hw *hw = sc->hw; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe = 0; __le16 fc = hdr->frame_control; /* lowest rate for management and multicast/broadcast frames */ @@ -1507,23 +1582,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, } /* Find tx rate for unicast frames */ - ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, - tx_info, &is_probe, false); - - /* Check if aggregation has to be enabled for this tid */ - if (hw->conf.ht.enabled) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - struct ath_node *an; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - an = (struct ath_node *)sta->drv_priv; - - if(ath_tx_aggr_check(sc, an, tid)) - ieee80211_start_tx_ba_session(hw, hdr->addr1, tid); - } - } + ath_rc_ratefind(sc, ath_rc_priv, txrc); } static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, @@ -1531,6 +1590,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_rate_table *rate_table = NULL; + bool is_cw40, is_sgi40; int i, j = 0; for (i = 0; i < sband->n_bitrates; i++) { @@ -1552,12 +1613,71 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_init(sc, priv_sta, sband, sta); + is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + + /* Choose rate table first */ + + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || + (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + is_cw40); + } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; + } + + ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40); + ath_rc_init(sc, priv_sta, sband, sta, rate_table); +} + +static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + u32 changed) +{ + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_rate_table *rate_table = NULL; + bool oper_cw40 = false, oper_sgi40; + bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? + true : false; + bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? + true : false; + + /* FIXME: Handle AP mode later when we support CWM */ + + if (changed & IEEE80211_RC_HT_CHANGED) { + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + return; + + if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || + sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) + oper_cw40 = true; + + oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + true : false; + + if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + oper_cw40); + ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, + oper_cw40, oper_sgi40); + ath_rc_init(sc, priv_sta, sband, sta, rate_table); + + DPRINTF(sc, ATH_DBG_CONFIG, + "Operating HT Bandwidth changed to: %d\n", + sc->hw->conf.channel_type); + } + } } static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return hw->priv; + struct ath_wiphy *aphy = hw->priv; + return aphy->sc; } static void ath_rate_free(void *priv) @@ -1578,7 +1698,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp } rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); - rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; + rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; return rate_priv; } @@ -1596,41 +1716,13 @@ static struct rate_control_ops ath_rate_ops = { .tx_status = ath_tx_status, .get_rate = ath_get_rate, .rate_init = ath_rate_init, + .rate_update = ath_rate_update, .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, }; -static void ath_setup_rate_table(struct ath_softc *sc, - struct ath_rate_table *rate_table) -{ - int i; - - for (i = 0; i < 256; i++) - rate_table->rateCodeToIndex[i] = (u8)-1; - - for (i = 0; i < rate_table->rate_cnt; i++) { - u8 code = rate_table->info[i].ratecode; - u8 cix = rate_table->info[i].ctrl_rate; - u8 sh = rate_table->info[i].short_preamble; - - rate_table->rateCodeToIndex[code] = i; - rate_table->rateCodeToIndex[code | sh] = i; - - rate_table->info[i].lpAckDuration = - ath9k_hw_computetxtime(sc->sc_ah, rate_table, - WLAN_CTRL_FRAME_SIZE, - cix, - false); - rate_table->info[i].spAckDuration = - ath9k_hw_computetxtime(sc->sc_ah, rate_table, - WLAN_CTRL_FRAME_SIZE, - cix, - true); - } -} - void ath_rate_attach(struct ath_softc *sc) { sc->hw_rate_table[ATH9K_MODE_11B] = @@ -1651,12 +1743,6 @@ void ath_rate_attach(struct ath_softc *sc) &ar5416_11ng_ratetable; sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable; - - ath_setup_rate_table(sc, &ar5416_11b_ratetable); - ath_setup_rate_table(sc, &ar5416_11a_ratetable); - ath_setup_rate_table(sc, &ar5416_11g_ratetable); - ath_setup_rate_table(sc, &ar5416_11na_ratetable); - ath_setup_rate_table(sc, &ar5416_11ng_ratetable); } int ath_rate_control_register(void) diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 97c60d12e8aa..199a3ce57d64 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 Sam Leffler, Errno Consulting * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,13 +19,12 @@ #ifndef RC_H #define RC_H -#include "ath9k.h" - struct ath_softc; #define ATH_RATE_MAX 30 #define RATE_TABLE_SIZE 64 #define MAX_TX_RATE_PHY 48 +#define WLAN_CTRL_FRAME_SIZE (2+2+6+4) /* VALID_ALL - valid for 20/40/Legacy, * VALID - Legacy only, @@ -39,6 +38,20 @@ struct ath_softc; #define VALID_2040 (VALID_20|VALID_40) #define VALID_ALL (VALID_2040|VALID) +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, + WLAN_RC_PHY_HT_20_SS, + WLAN_RC_PHY_HT_20_DS, + WLAN_RC_PHY_HT_40_SS, + WLAN_RC_PHY_HT_40_DS, + WLAN_RC_PHY_HT_20_SS_HGI, + WLAN_RC_PHY_HT_20_DS_HGI, + WLAN_RC_PHY_HT_40_SS_HGI, + WLAN_RC_PHY_HT_40_DS_HGI, + WLAN_RC_PHY_MAX +}; + #define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ @@ -90,7 +103,6 @@ struct ath_softc; */ struct ath_rate_table { int rate_cnt; - u8 rateCodeToIndex[256]; struct { int valid; int valid_single_stream; @@ -108,8 +120,6 @@ struct ath_rate_table { u8 sgi_index; u8 ht_index; u32 max_4ms_framelen; - u16 lpAckDuration; - u16 spAckDuration; } info[RATE_TABLE_SIZE]; u32 probe_interval; u32 rssi_reduce_interval; @@ -184,11 +194,19 @@ struct ath_rate_priv { struct ath_rate_softc *asc; }; +enum ath9k_internal_frame_type { + ATH9K_NOT_INTERNAL, + ATH9K_INT_PAUSE, + ATH9K_INT_UNPAUSE +}; + struct ath_tx_info_priv { + struct ath_wiphy *aphy; struct ath_tx_status tx; int n_frames; int n_bad_frames; bool update_rc; + enum ath9k_internal_frame_type frame_type; }; #define ATH_TX_INFO_PRIV(tx_info) \ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 462e08c3d09d..71cb18d6757d 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,28 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" +#include "ath9k.h" + +static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, + struct ieee80211_hdr *hdr) +{ + struct ieee80211_hw *hw = sc->pri_wiphy->hw; + int i; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (aphy == NULL) + continue; + if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) + == 0) { + hw = aphy->hw; + break; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return hw; +} /* * Setup and link descriptors. @@ -26,7 +47,7 @@ */ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath_desc *ds; struct sk_buff *skb; @@ -79,7 +100,7 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) return (tsf & ~0x7fff) | rstamp; } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) { struct sk_buff *skb; u32 off; @@ -97,11 +118,11 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) * Unfortunately this means we may get 8 KB here from the * kernel... and that is actually what is observed on some * systems :( */ - skb = dev_alloc_skb(len + sc->sc_cachelsz - 1); + skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); if (skb != NULL) { - off = ((unsigned long) skb->data) % sc->sc_cachelsz; + off = ((unsigned long) skb->data) % sc->cachelsz; if (off != 0) - skb_reserve(skb, sc->sc_cachelsz - off); + skb_reserve(skb, sc->cachelsz - off); } else { DPRINTF(sc, ATH_DBG_FATAL, "skbuff alloc of size %u failed\n", len); @@ -123,10 +144,12 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, struct ieee80211_hdr *hdr; u8 ratecode; __le16 fc; + struct ieee80211_hw *hw; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + hw = ath_get_virt_hw(sc, hdr); if (ds->ds_rxstat.rs_more) { /* @@ -135,7 +158,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, * discard the frame. Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR) + if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) goto rx_next; } else if (ds->ds_rxstat.rs_status != 0) { if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) @@ -161,7 +184,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { if (ds->ds_rxstat.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) @@ -186,7 +209,6 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, rx_status->rate_idx = ratecode & 0x7f; } else { int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; cur_band = hw->conf.channel->band; n_rates = sc->sbands[cur_band].n_bitrates; @@ -208,9 +230,9 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); - rx_status->band = sc->hw->conf.channel->band; - rx_status->freq = sc->hw->conf.channel->center_freq; - rx_status->noise = sc->sc_ani.sc_noise_floor; + rx_status->band = hw->conf.channel->band; + rx_status->freq = hw->conf.channel->center_freq; + rx_status->noise = sc->ani.noise_floor; rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; @@ -233,7 +255,7 @@ rx_next: static void ath_opmode_init(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; u32 rfilt, mfilt[2]; /* configure rx filter */ @@ -241,14 +263,14 @@ static void ath_opmode_init(struct ath_softc *sc) ath9k_hw_setrxfilter(ah, rfilt); /* configure bssid mask */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath9k_hw_setbssidmask(sc); /* configure operational mode */ ath9k_hw_setopmode(ah); /* Handle any link-level address change. */ - ath9k_hw_setmac(ah, sc->sc_myaddr); + ath9k_hw_setmac(ah, sc->sc_ah->macaddr); /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; @@ -267,11 +289,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) spin_lock_init(&sc->rx.rxbuflock); sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->sc_cachelsz, + min(sc->cachelsz, (u16)64)); DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->sc_cachelsz, sc->rx.bufsize); + sc->cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ @@ -284,22 +306,22 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; break; } bf->bf_mpdu = skb; - bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, sc->rx.bufsize, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; DPRINTF(sc, ATH_DBG_CONFIG, - "pci_dma_mapping_error() on RX init\n"); + "dma_mapping_error() on RX init\n"); error = -ENOMEM; break; } @@ -322,8 +344,13 @@ void ath_rx_cleanup(struct ath_softc *sc) list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; - if (skb) + if (skb) { + dma_unmap_single(sc->dev, + bf->bf_buf_addr, + sc->rx.bufsize, + DMA_FROM_DEVICE); dev_kfree_skb(skb); + } } if (sc->rx.rxdma.dd_desc_len != 0) @@ -360,26 +387,39 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION) + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) rfilt |= ATH9K_RX_FILTER_PROBEREQ; - /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && + /* + * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station + * mode interface or when in monitor mode. AP mode does not need this + * since it receives all in-BSS frames anyway. + */ + if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) && (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) { + (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) rfilt |= ATH9K_RX_FILTER_PROM; - /* ??? To prevent from sending ACK */ - rfilt &= ~ATH9K_RX_FILTER_UCAST; - } - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION || - sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) + if (sc->rx.rxfilter & FIF_CONTROL) + rfilt |= ATH9K_RX_FILTER_CONTROL; + + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) + rfilt |= ATH9K_RX_FILTER_MYBEACON; + else rfilt |= ATH9K_RX_FILTER_BEACON; - /* If in HOSTAP mode, want to enable reception of PSPOLL frames - & beacon frames */ - if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) - rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); + /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) + rfilt |= ATH9K_RX_FILTER_PSPOLL; + + if (sc->sec_wiphy) { + /* TODO: only needed if more than one BSSID is in use in + * station/adhoc mode */ + /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM + */ + rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; + } return rfilt; @@ -388,7 +428,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) int ath_startrecv(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf, *tbf; spin_lock_bh(&sc->rx.rxbuflock); @@ -418,13 +458,12 @@ start_recv: bool ath_stoprecv(struct ath_softc *sc) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; bool stopped; ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); - mdelay(3); /* 3ms is long enough for 1 frame */ sc->rx.rxlink = NULL; return stopped; @@ -449,7 +488,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_desc *ds; struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status rx_status; - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ieee80211_hdr *hdr; int hdrlen, padsize, retval; bool decrypt_error = false; @@ -524,9 +563,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * 1. accessing the frame * 2. requeueing the same buffer to h/w */ - pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, sc->rx.bufsize, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* * If we're asked to flush receive queue, directly @@ -547,7 +586,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ - requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); + requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); /* If there is no memory we ignore the current RX'd frame, * tell hardware it can give us a new frame using the old @@ -557,9 +596,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) goto requeue; /* Unmap the frame */ - pci_unmap_single(sc->pdev, bf->bf_buf_addr, + dma_unmap_single(sc->dev, bf->bf_buf_addr, sc->rx.bufsize, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); skb_put(skb, ds->ds_rxstat.rs_datalen); skb->protocol = cpu_to_be16(ETH_P_CONTROL); @@ -590,24 +629,52 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; - if (test_bit(keyix, sc->sc_keymap)) + if (test_bit(keyix, sc->keymap)) rx_status.flag |= RX_FLAG_DECRYPTED; } + if (ah->sw_mgmt_crypto && + (rx_status.flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(hdr->frame_control)) { + /* Use software decrypt for management frames. */ + rx_status.flag &= ~RX_FLAG_DECRYPTED; + } /* Send the frame to mac80211 */ - __ieee80211_rx(sc->hw, skb, &rx_status); + if (hdr->addr1[5] & 0x01) { + int i; + /* + * Deliver broadcast/multicast frames to all suitable + * virtual wiphys. + */ + /* TODO: filter based on channel configuration */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + struct sk_buff *nskb; + if (aphy == NULL) + continue; + nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb) + __ieee80211_rx(aphy->hw, nskb, + &rx_status); + } + __ieee80211_rx(sc->hw, skb, &rx_status); + } else { + /* Deliver unicast frames based on receiver address */ + __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, + &rx_status); + } /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; - bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, + bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, sc->rx.bufsize, - PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; DPRINTF(sc, ATH_DBG_CONFIG, - "pci_dma_mapping_error() on RX\n"); + "dma_mapping_error() on RX\n"); break; } bf->bf_dmacontext = bf->bf_buf_addr; @@ -622,6 +689,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) } else { sc->rx.rxotherant = 0; } + + if (ieee80211_is_beacon(hdr->frame_control) && + (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + } requeue: list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 9fedb4911bc3..52605246679f 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -67,7 +67,7 @@ #define AR_DMASIZE_512B 0x00000007 #define AR_TXCFG 0x0030 -#define AR_TXCFG_DMASZ_MASK 0x00000003 +#define AR_TXCFG_DMASZ_MASK 0x00000007 #define AR_TXCFG_DMASZ_4B 0 #define AR_TXCFG_DMASZ_8B 1 #define AR_TXCFG_DMASZ_16B 2 @@ -158,13 +158,6 @@ #define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 #define AR_CST_TIMEOUT_LIMIT_S 16 -#define AR_SREV_VERSION_9100 0x014 - -#define AR_SREV_5416_V20_OR_LATER(_ah) \ - (AR_SREV_9100((_ah)) || AR_SREV_5416_20_OR_LATER(_ah)) -#define AR_SREV_5416_V22_OR_LATER(_ah) \ - (AR_SREV_9100((_ah)) || AR_SREV_5416_22_OR_LATER(_ah)) - #define AR_ISR 0x0080 #define AR_ISR_RXOK 0x00000001 #define AR_ISR_RXDESC 0x00000002 @@ -733,6 +726,7 @@ #define AR_SREV_REVISION_5416_10 0 #define AR_SREV_REVISION_5416_20 1 #define AR_SREV_REVISION_5416_22 2 +#define AR_SREV_VERSION_9100 0x14 #define AR_SREV_VERSION_9160 0x40 #define AR_SREV_REVISION_9160_10 0 #define AR_SREV_REVISION_9160_11 1 @@ -745,45 +739,60 @@ #define AR_SREV_REVISION_9285_11 1 #define AR_SREV_REVISION_9285_12 2 -#define AR_SREV_9100_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE)) +#define AR_SREV_5416(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ + ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)) #define AR_SREV_5416_20_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \ - ((_ah)->ah_macRev >= AR_SREV_REVISION_5416_20)) + (((AR_SREV_5416(_ah)) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \ + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) #define AR_SREV_5416_22_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \ - ((_ah)->ah_macRev >= AR_SREV_REVISION_5416_22)) + (((AR_SREV_5416(_ah)) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \ + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) + +#define AR_SREV_9100(ah) \ + ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100) +#define AR_SREV_9100_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) + #define AR_SREV_9160(_ah) \ - (((_ah)->ah_macVersion == AR_SREV_VERSION_9160)) + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160)) #define AR_SREV_9160_10_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160)) + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160)) #define AR_SREV_9160_11(_ah) \ - (AR_SREV_9160(_ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9160_11)) + (AR_SREV_9160(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11)) #define AR_SREV_9280(_ah) \ - (((_ah)->ah_macVersion == AR_SREV_VERSION_9280)) + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280)) #define AR_SREV_9280_10_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_9280)) + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280)) #define AR_SREV_9280_20(_ah) \ - (((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20)) + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20)) #define AR_SREV_9280_20_OR_LATER(_ah) \ - (((_ah)->ah_macVersion > AR_SREV_VERSION_9280) || \ - (((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \ - ((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20))) + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9280) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9280_20))) -#define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285)) +#define AR_SREV_9285(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285)) #define AR_SREV_9285_10_OR_LATER(_ah) \ - (((_ah)->ah_macVersion >= AR_SREV_VERSION_9285)) + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285)) #define AR_SREV_9285_11(_ah) \ - (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11)) + (AR_SREV_9285(ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11)) #define AR_SREV_9285_11_OR_LATER(_ah) \ - (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11))) + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ + AR_SREV_REVISION_9285_11))) #define AR_SREV_9285_12(_ah) \ - (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12)) + (AR_SREV_9285(ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12)) #define AR_SREV_9285_12_OR_LATER(_ah) \ - (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ - (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12))) + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ + AR_SREV_REVISION_9285_12))) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -875,12 +884,15 @@ enum { #define AR_NUM_GPIO 14 #define AR928X_NUM_GPIO 10 +#define AR9285_NUM_GPIO 12 #define AR_GPIO_IN_OUT 0x4048 #define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL_S 14 #define AR928X_GPIO_IN_VAL 0x000FFC00 #define AR928X_GPIO_IN_VAL_S 10 +#define AR9285_GPIO_IN_VAL 0x00FFF000 +#define AR9285_GPIO_IN_VAL_S 12 #define AR_GPIO_OE_OUT 0x404c #define AR_GPIO_OE_OUT_DRV 0x3 @@ -894,14 +906,24 @@ enum { #define AR_GPIO_INTR_POL_VAL_S 0 #define AR_GPIO_INPUT_EN_VAL 0x4054 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 +#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 +#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_S 3 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_DEF 0x00000010 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 +#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 #define AR_GPIO_INPUT_MUX1 0x4058 +#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 +#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX2 0x405c #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f @@ -940,7 +962,7 @@ enum { #define AR_RTC_BASE 0x00020000 #define AR_RTC_RC \ - (AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000 + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000) #define AR_RTC_RC_M 0x00000003 #define AR_RTC_RC_MAC_WARM 0x00000001 #define AR_RTC_RC_MAC_COLD 0x00000002 @@ -948,7 +970,7 @@ enum { #define AR_RTC_RC_WARM_RESET 0x00000008 #define AR_RTC_PLL_CONTROL \ - (AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014 + ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) #define AR_RTC_PLL_DIV 0x0000001f #define AR_RTC_PLL_DIV_S 0 @@ -957,8 +979,6 @@ enum { #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 - - #define AR_RTC_RESET \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) #define AR_RTC_RESET_EN (0x00000001) @@ -995,6 +1015,12 @@ enum { #define AR_RTC_INTR_MASK \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) +/* RTC_DERIVED_* - only for AR9100 */ + +#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) +#define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe +#define AR_RTC_DERIVED_CLK_PERIOD_S 1 + #define AR_SEQ_MASK 0x8060 #define AR_AN_RF2G1_CH0 0x7810 @@ -1021,6 +1047,10 @@ enum { #define AR_AN_RF5G1_CH1_DB5 0x00380000 #define AR_AN_RF5G1_CH1_DB5_S 19 +#define AR_AN_TOP1 0x7890 +#define AR_AN_TOP1_DACIPMODE 0x00040000 +#define AR_AN_TOP1_DACIPMODE_S 18 + #define AR_AN_TOP2 0x7894 #define AR_AN_TOP2_XPABIAS_LVL 0xC0000000 #define AR_AN_TOP2_XPABIAS_LVL_S 30 @@ -1181,18 +1211,7 @@ enum { #define AR_CFP_VAL 0x0000FFFF #define AR_RX_FILTER 0x803C -#define AR_RX_FILTER_ALL 0x00000000 -#define AR_RX_UCAST 0x00000001 -#define AR_RX_MCAST 0x00000002 -#define AR_RX_BCAST 0x00000004 -#define AR_RX_CONTROL 0x00000008 -#define AR_RX_BEACON 0x00000010 -#define AR_RX_PROM 0x00000020 -#define AR_RX_PROBE_REQ 0x00000080 -#define AR_RX_MY_BEACON 0x00000200 #define AR_RX_COMPR_BAR 0x00000400 -#define AR_RX_COMPR_BA 0x00000800 -#define AR_RX_UNCOM_BA_BAR 0x00001000 #define AR_MCAST_FIL0 0x8040 #define AR_MCAST_FIL1 0x8044 @@ -1236,6 +1255,8 @@ enum { #define AR_AES_MUTE_MASK1 0x8060 #define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF +#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000 +#define AR_AES_MUTE_MASK1_FC_MGMT_S 16 #define AR_GATED_CLKS 0x8064 #define AR_GATED_CLKS_TX 0x00000002 @@ -1370,8 +1391,8 @@ enum { #define AR_PHY_COUNTMAX (3 << 22) #define AR_MIBCNT_INTRMASK (3 << 22) -#define AR_TSF_THRESHOLD 0x813c -#define AR_TSF_THRESHOLD_VAL 0x0000FFFF +#define AR_TSFOOR_THRESHOLD 0x813c +#define AR_TSFOOR_THRESHOLD_VAL 0x0000FFFF #define AR_PHY_ERR_EIFS_MASK 8144 @@ -1460,6 +1481,10 @@ enum { #define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 #define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380 +#define AR_PCU_MISC_MODE2 0x8344 +#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 +#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 + #define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEY_CACHE_SIZE 128 diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 64043e99facf..4ca625102291 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,998 +16,504 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include "core.h" -#include "hw.h" -#include "regd.h" +#include "ath9k.h" #include "regd_common.h" -static int ath9k_regd_chansort(const void *a, const void *b) -{ - const struct ath9k_channel *ca = a; - const struct ath9k_channel *cb = b; +/* + * This is a set of common rules used by our world regulatory domains. + * We have 12 world regulatory domains. To save space we consolidate + * the regulatory domains in 5 structures by frequency and change + * the flags on our reg_notifier() on a case by case basis. + */ - return (ca->channel == cb->channel) ? - (ca->channelFlags & CHAN_FLAGS) - - (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel; +/* Only these channels all allow active scan on all world regulatory domains */ +#define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +/* We enable active scan on these a case by case basis by regulatory domain */ +#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN) +#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) + +/* We allow IBSS on these on a case by case basis by regulatory domain */ +#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 40, 0, 30,\ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ + ATH9K_2GHZ_CH12_13, \ + ATH9K_2GHZ_CH14 + +#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5470_5850 +/* This one skips what we call "mid band" */ +#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5725_5850 + +/* Can be used for: + * 0x60, 0x61, 0x62 */ +static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = { + .n_reg_rules = 5, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_ALL, + ATH9K_5GHZ_ALL, + } +}; + +/* Can be used by 0x63 and 0x65 */ +static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_NO_MIDBAND, + } +}; + +/* Can be used by 0x64 only */ +static const struct ieee80211_regdomain ath9k_world_regdom_64 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_NO_MIDBAND, + } +}; + +/* Can be used by 0x66 and 0x69 */ +static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_ALL, + } +}; + +/* Can be used by 0x67, 0x6A and 0x68 */ +static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_ALL, + } +}; + +static inline bool is_wwr_sku(u16 regd) +{ + return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || + (regd == WORLD); } -static void -ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) +static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah) { - u8 *aa = a; - u8 *ai, *t; - - for (ai = aa + size; --n >= 1; ai += size) - for (t = ai; t > aa; t -= size) { - u8 *u = t - size; - if (cmp(u, t) <= 0) - break; - swap_array(u, t, size); - } + return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG; } -static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah) +bool ath9k_is_world_regd(struct ath_hw *ah) { - return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG; + return is_wwr_sku(ath9k_regd_get_eepromRD(ah)); } -static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask) +const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) { - int i; - - for (i = 0; i < BMLEN; i++) { - if (bitmask[i] != 0) - return false; - } - return true; + /* this is the most restrictive */ + return &ath9k_world_regdom_64; } -static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) +const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah) { - u16 rd = ath9k_regd_get_eepromRD(ah); - int i; - - if (rd & COUNTRY_ERD_FLAG) { - u16 cc = rd & ~COUNTRY_ERD_FLAG; - for (i = 0; i < ARRAY_SIZE(allCountries); i++) - if (allCountries[i].countryCode == cc) - return true; - } else { - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) - return true; + switch (ah->regulatory.regpair->regDmnEnum) { + case 0x60: + case 0x61: + case 0x62: + return &ath9k_world_regdom_60_61_62; + case 0x63: + case 0x65: + return &ath9k_world_regdom_63_65; + case 0x64: + return &ath9k_world_regdom_64; + case 0x66: + case 0x69: + return &ath9k_world_regdom_66_69; + case 0x67: + case 0x68: + case 0x6A: + return &ath9k_world_regdom_67_68_6A; + default: + WARN_ON(1); + return ath9k_default_world_regdomain(); } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "invalid regulatory domain/country code 0x%x\n", rd); - return false; } -static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah) +/* Frequency is one where radar detection is required */ +static bool ath9k_is_radar_freq(u16 center_freq) { - u32 regcap; - - regcap = ah->ah_caps.reg_cap; - - if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND) - return true; - else - return false; + return (center_freq >= 5260 && center_freq <= 5700); } -static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, - u16 cc) +/* + * N.B: These exception rules do not apply radar freqs. + * + * - We enable adhoc (or beaconing) if allowed by 11d + * - We enable active scan if the channel is allowed by 11d + * - If no country IE has been processed and a we determine we have + * received a beacon on a channel we can enable active scan and + * adhoc (or beaconing). + */ +static void ath9k_reg_apply_beaconing_flags( + struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { - u16 rd; - int i; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + const struct ieee80211_reg_rule *reg_rule; + struct ieee80211_channel *ch; + unsigned int i; + u32 bandwidth = 0; + int r; - if (cc == CTRY_DEFAULT) - return true; - if (cc == CTRY_DEBUG) - return true; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - rd = ath9k_regd_get_eepromRD(ah); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd); - - if (rd & COUNTRY_ERD_FLAG) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "EEPROM setting is country code %u\n", - rd & ~COUNTRY_ERD_FLAG); - return cc == (rd & ~COUNTRY_ERD_FLAG); - } + if (!wiphy->bands[band]) + continue; - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (cc == allCountries[i].countryCode) { -#ifdef AH_SUPPORT_11D - if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) - return true; -#endif - if (allCountries[i].regDmnEnum == rd || - rd == DEBUG_REG_DMN || rd == NO_ENUMRD) - return true; + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) { + + ch = &sband->channels[i]; + + if (ath9k_is_radar_freq(ch->center_freq) || + (ch->flags & IEEE80211_CHAN_RADAR)) + continue; + + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + r = freq_reg_info(wiphy, ch->center_freq, + &bandwidth, ®_rule); + if (r) + continue; + /* + * If 11d had a rule for this channel ensure + * we enable adhoc/beaconing if it allows us to + * use it. Note that we would have disabled it + * by applying our static world regdomain by + * default during init, prior to calling our + * regulatory_hint(). + */ + if (!(reg_rule->flags & + NL80211_RRF_NO_IBSS)) + ch->flags &= + ~IEEE80211_CHAN_NO_IBSS; + if (!(reg_rule->flags & + NL80211_RRF_PASSIVE_SCAN)) + ch->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } else { + if (ch->beacon_found) + ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN); + } } } - return false; -} - -static void -ath9k_regd_get_wmodes_nreg(struct ath_hal *ah, - struct country_code_to_enum_rd *country, - struct regDomain *rd5GHz, - unsigned long *modes_allowed) -{ - bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX); - - if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) && - (!country->allow11g)) - clear_bit(ATH9K_MODE_11G, modes_allowed); - if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) && - (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a))) - clear_bit(ATH9K_MODE_11A, modes_allowed); - - if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes) - && (!country->allow11ng20)) - clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed); - - if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes) - && (!country->allow11na20)) - clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed); - - if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) && - (!country->allow11ng40)) - clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed); - - if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) && - (!country->allow11ng40)) - clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed); - - if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) && - (!country->allow11na40)) - clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed); - - if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) && - (!country->allow11na40)) - clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed); } -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah) +/* Allows active scan scan on Ch 12 and 13 */ +static void ath9k_reg_apply_active_scan_flags( + struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { - u16 rd; - - rd = ath9k_regd_get_eepromRD(ah); - - switch (rd) { - case FCC4_FCCA: - case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG): - return true; - case DEBUG_REG_DMN: - case NO_ENUMRD: - if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49) - return true; - break; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + const struct ieee80211_reg_rule *reg_rule; + u32 bandwidth = 0; + int r; + + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + + /* + * If no country IE has been received always enable active scan + * on these channels. This is only done for specific regulatory SKUs + */ + if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ch = &sband->channels[11]; /* CH 12 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + ch = &sband->channels[12]; /* CH 13 */ + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + return; } - return false; -} -static struct country_code_to_enum_rd* -ath9k_regd_find_country(u16 countryCode) -{ - int i; + /* + * If a country IE has been recieved check its rule for this + * channel first before enabling active scan. The passive scan + * would have been enforced by the initial processing of our + * custom regulatory domain. + */ - for (i = 0; i < ARRAY_SIZE(allCountries); i++) { - if (allCountries[i].countryCode == countryCode) - return &allCountries[i]; + ch = &sband->channels[11]; /* CH 12 */ + r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + if (!r) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; } - return NULL; -} - -static u16 ath9k_regd_get_default_country(struct ath_hal *ah) -{ - u16 rd; - int i; - - rd = ath9k_regd_get_eepromRD(ah); - if (rd & COUNTRY_ERD_FLAG) { - struct country_code_to_enum_rd *country = NULL; - u16 cc = rd & ~COUNTRY_ERD_FLAG; - country = ath9k_regd_find_country(cc); - if (country != NULL) - return cc; + ch = &sband->channels[12]; /* CH 13 */ + r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + if (!r) { + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) + if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; } - - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) { - if (regDomainPairs[i].singleCC != 0) - return regDomainPairs[i].singleCC; - else - i = ARRAY_SIZE(regDomainPairs); - } - return CTRY_DEFAULT; } -static bool ath9k_regd_is_valid_reg_domain(int regDmn, - struct regDomain *rd) +/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ +void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) { - int i; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(regDomains); i++) { - if (regDomains[i].regDmnEnum == regDmn) { - if (rd != NULL) { - memcpy(rd, ®Domains[i], - sizeof(struct regDomain)); - } - return true; - } - } - return false; -} + if (!wiphy->bands[IEEE80211_BAND_5GHZ]) + return; -static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair) -{ - int i; + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; - if (regDmnPair == NO_ENUMRD) - return false; - for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regDmnPair) - return true; + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (!ath9k_is_radar_freq(ch->center_freq)) + continue; + /* We always enable radar detection/DFS on this + * frequency range. Additionally we also apply on + * this frequency range: + * - If STA mode does not yet have DFS supports disable + * active scanning + * - If adhoc mode does not support DFS yet then + * disable adhoc in the frequency. + * - If AP mode does not yet support radar detection/DFS + * do not allow AP mode + */ + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch->flags |= IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; } - return false; } -static bool -ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, - u16 channelFlag, struct regDomain *rd) +void ath9k_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { - int i, found; - u64 flags = NO_REQ; - struct reg_dmn_pair_mapping *regPair = NULL; - int regOrg; - - regOrg = regDmn; - if (regDmn == CTRY_DEFAULT) { - u16 rdnum; - rdnum = ath9k_regd_get_eepromRD(ah); - - if (!(rdnum & COUNTRY_ERD_FLAG)) { - if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) || - ath9k_regd_is_valid_reg_domainPair(rdnum)) { - regDmn = rdnum; - } - } + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + + switch (ah->regulatory.regpair->regDmnEnum) { + case 0x60: + case 0x63: + case 0x66: + case 0x67: + ath9k_reg_apply_beaconing_flags(wiphy, initiator); + break; + case 0x68: + ath9k_reg_apply_beaconing_flags(wiphy, initiator); + ath9k_reg_apply_active_scan_flags(wiphy, initiator); + break; } + return; +} - if ((regDmn & MULTI_DOMAIN_MASK) == 0) { - for (i = 0, found = 0; - (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) { - if (regDomainPairs[i].regDmnEnum == regDmn) { - regPair = ®DomainPairs[i]; - found = 1; - } - } - if (!found) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Failed to find reg domain pair %u\n", regDmn); - return false; - } - if (!(channelFlag & CHANNEL_2GHZ)) { - regDmn = regPair->regDmn5GHz; - flags = regPair->flags5GHz; - } - if (channelFlag & CHANNEL_2GHZ) { - regDmn = regPair->regDmn2GHz; - flags = regPair->flags2GHz; - } - } +int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; - found = ath9k_regd_is_valid_reg_domain(regDmn, rd); - if (!found) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Failed to find unitary reg domain %u\n", regDmn); - return false; - } else { - rd->pscan &= regPair->pscanMask; - if (((regOrg & MULTI_DOMAIN_MASK) == 0) && - (flags != NO_REQ)) { - rd->flags = flags; - } + /* We always apply this */ + ath9k_reg_apply_radar_flags(wiphy); - rd->flags &= (channelFlag & CHANNEL_2GHZ) ? - REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK; - return true; + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + if (ath9k_is_world_regd(sc->sc_ah)) + ath9k_reg_apply_world_flags(wiphy, request->initiator); + break; } -} -static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask) -{ - int byteOffset, bitnum; - u64 val; - - byteOffset = bit / 64; - bitnum = bit - byteOffset * 64; - val = ((u64) 1) << bitnum; - if (bitmask[byteOffset] & val) - return true; - else - return false; + return 0; } -static void -ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids, - u32 *nregids, u8 regclassid) +bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah) { + u16 rd = ath9k_regd_get_eepromRD(ah); int i; - if (regclassid == 0) - return; - - for (i = 0; i < maxregids; i++) { - if (regclassids[i] == regclassid) - return; - if (regclassids[i] == 0) - break; - } - - if (i == maxregids) - return; - else { - regclassids[i] = regclassid; - *nregids += 1; + if (rd & COUNTRY_ERD_FLAG) { + /* EEPROM value is a country code */ + u16 cc = rd & ~COUNTRY_ERD_FLAG; + for (i = 0; i < ARRAY_SIZE(allCountries); i++) + if (allCountries[i].countryCode == cc) + return true; + } else { + /* EEPROM value is a regpair value */ + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) + if (regDomainPairs[i].regDmnEnum == rd) + return true; } - - return; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "invalid regulatory domain/country code 0x%x\n", rd); + return false; } -static bool -ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah, - enum reg_ext_bitmap bit) +/* EEPROM country code to regpair mapping */ +static struct country_code_to_enum_rd* +ath9k_regd_find_country(u16 countryCode) { - return (ah->ah_currentRDExt & (1 << bit)) ? true : false; -} - -#ifdef ATH_NF_PER_CHAN + int i; -static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans, - int nchans) -{ - int i, j, next; - - for (next = 0; next < nchans; next++) { - for (i = 0; i < NUM_NF_READINGS; i++) { - ichans[next].nfCalHist[i].currIndex = 0; - ichans[next].nfCalHist[i].privNF = - AR_PHY_CCA_MAX_GOOD_VALUE; - ichans[next].nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ichans[next].nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].countryCode == countryCode) + return &allCountries[i]; } + return NULL; } -#endif -static int ath9k_regd_is_chan_present(struct ath_hal *ah, - u16 c) +/* EEPROM rd code to regpair mapping */ +static struct country_code_to_enum_rd* +ath9k_regd_find_country_by_rd(int regdmn) { int i; - for (i = 0; i < 150; i++) { - if (!ah->ah_channels[i].channel) - return -1; - else if (ah->ah_channels[i].channel == c) - return i; + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].regDmnEnum == regdmn) + return &allCountries[i]; } - - return -1; + return NULL; } -static bool -ath9k_regd_add_channel(struct ath_hal *ah, - u16 c, - u16 c_lo, - u16 c_hi, - u16 maxChan, - u8 ctl, - int pos, - struct regDomain rd5GHz, - struct RegDmnFreqBand *fband, - struct regDomain *rd, - const struct cmode *cm, - struct ath9k_channel *ichans, - bool enableExtendedChannels) +/* Returns the map of the EEPROM set RD to a country code */ +static u16 ath9k_regd_get_default_country(u16 rd) { - struct ath9k_channel *chan; - int ret; - u32 channelFlags = 0; - u8 privFlags = 0; - - if (!(c_lo <= c && c <= c_hi)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "c %u out of range [%u..%u]\n", - c, c_lo, c_hi); - return false; - } - if ((fband->channelBW == CHANNEL_HALF_BW) && - !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping %u half rate channel\n", c); - return false; - } - - if ((fband->channelBW == CHANNEL_QUARTER_BW) && - !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping %u quarter rate channel\n", c); - return false; - } - - if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "c %u > maxChan %u\n", c, maxChan); - return false; - } - - if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping ecm channel\n"); - return false; - } - - if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HOSTAP channel\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) && - (fband->useDfs) && - (rd->conformanceTestLimit != MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, - REG_EXT_JAPAN_NONDFS_HT40)) && - !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_jap_ht40 = 0)\n"); - return false; - } - - if (IS_HT40_MODE(cm->mode) && - !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) && - (fband->useDfs) && - (rd->conformanceTestLimit == MKK)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n"); - return false; - } - - /* Calculate channel flags */ - - channelFlags = cm->flags; - - switch (fband->channelBW) { - case CHANNEL_HALF_BW: - channelFlags |= CHANNEL_HALF; - break; - case CHANNEL_QUARTER_BW: - channelFlags |= CHANNEL_QUARTER; - break; - } - - if (fband->usePassScan & rd->pscan) - channelFlags |= CHANNEL_PASSIVE; - else - channelFlags &= ~CHANNEL_PASSIVE; - if (fband->useDfs & rd->dfsMask) - privFlags = CHANNEL_DFS; - else - privFlags = 0; - if (rd->flags & LIMIT_FRAME_4MS) - privFlags |= CHANNEL_4MS_LIMIT; - if (privFlags & CHANNEL_DFS) - privFlags |= CHANNEL_DISALLOW_ADHOC; - if (rd->flags & ADHOC_PER_11D) - privFlags |= CHANNEL_PER_11D_ADHOC; - - if (channelFlags & CHANNEL_PASSIVE) { - if ((c < 2412) || (c > 2462)) { - if (rd5GHz.regDmnEnum == MKK1 || - rd5GHz.regDmnEnum == MKK2) { - u32 regcap = ah->ah_caps.reg_cap; - if (!(regcap & - (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) && - isUNII1OddChan(c)) { - channelFlags &= ~CHANNEL_PASSIVE; - } else { - privFlags |= CHANNEL_DISALLOW_ADHOC; - } - } else { - privFlags |= CHANNEL_DISALLOW_ADHOC; - } - } - } - - if ((cm->mode == ATH9K_MODE_11A) || - (cm->mode == ATH9K_MODE_11NA_HT20) || - (cm->mode == ATH9K_MODE_11NA_HT40PLUS) || - (cm->mode == ATH9K_MODE_11NA_HT40MINUS)) { - if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A)) - privFlags |= CHANNEL_DISALLOW_ADHOC; - } + if (rd & COUNTRY_ERD_FLAG) { + struct country_code_to_enum_rd *country = NULL; + u16 cc = rd & ~COUNTRY_ERD_FLAG; - /* Fill in channel details */ - - ret = ath9k_regd_is_chan_present(ah, c); - if (ret == -1) { - chan = &ah->ah_channels[pos]; - chan->channel = c; - chan->maxRegTxPower = fband->powerDfs; - chan->antennaMax = fband->antennaMax; - chan->regDmnFlags = rd->flags; - chan->maxTxPower = AR5416_MAX_RATE_POWER; - chan->minTxPower = AR5416_MAX_RATE_POWER; - chan->channelFlags = channelFlags; - chan->privFlags = privFlags; - } else { - chan = &ah->ah_channels[ret]; - chan->channelFlags |= channelFlags; - chan->privFlags |= privFlags; + country = ath9k_regd_find_country(cc); + if (country != NULL) + return cc; } - /* Set CTLs */ - - if ((cm->flags & CHANNEL_ALL) == CHANNEL_A) - chan->conformanceTestLimit[0] = ctl; - else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B) - chan->conformanceTestLimit[1] = ctl; - else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G) - chan->conformanceTestLimit[2] = ctl; - - return (ret == -1) ? true : false; + return CTRY_DEFAULT; } -static bool ath9k_regd_japan_check(struct ath_hal *ah, - int b, - struct regDomain *rd5GHz) +static struct reg_dmn_pair_mapping* +ath9k_get_regpair(int regdmn) { - bool skipband = false; int i; - u32 regcap; - - for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) { - if (j_bandcheck[i].freqbandbit == b) { - regcap = ah->ah_caps.reg_cap; - if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) { - skipband = true; - } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) || - (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) { - rd5GHz->dfsMask |= DFS_MKK4; - rd5GHz->pscan |= PSCAN_MKK3; - } - break; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Skipping %d freq band\n", j_bandcheck[i].freqbandbit); - - return skipband; + if (regdmn == NO_ENUMRD) + return NULL; + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regdmn) + return ®DomainPairs[i]; + } + return NULL; } -bool -ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, - u32 *nchans, u8 *regclassids, - u32 maxregids, u32 *nregids, u16 cc, - bool enableOutdoor, - bool enableExtendedChannels) +int ath9k_regd_init(struct ath_hw *ah) { - u16 maxChan = 7000; struct country_code_to_enum_rd *country = NULL; - struct regDomain rd5GHz, rd2GHz; - const struct cmode *cm; - struct ath9k_channel *ichans = &ah->ah_channels[0]; - int next = 0, b; - u8 ctl; - int regdmn; - u16 chanSep; - unsigned long *modes_avail; - DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX); - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc, - enableOutdoor ? "Enable outdoor" : "", - enableExtendedChannels ? "Enable ecm" : ""); - - if (!ath9k_regd_is_ccode_valid(ah, cc)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Invalid country code %d\n", cc); - return false; - } + u16 regdmn; if (!ath9k_regd_is_eeprom_valid(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Invalid EEPROM contents\n"); - return false; + return -EINVAL; } - ah->ah_countryCode = ath9k_regd_get_default_country(ah); + regdmn = ath9k_regd_get_eepromRD(ah); + ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn); - if (ah->ah_countryCode == CTRY_DEFAULT) { - ah->ah_countryCode = cc & COUNTRY_CODE_MASK; - if ((ah->ah_countryCode == CTRY_DEFAULT) && - (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) { - ah->ah_countryCode = CTRY_UNITED_STATES; - } - } + if (ah->regulatory.country_code == CTRY_DEFAULT && + regdmn == CTRY_DEFAULT) + ah->regulatory.country_code = CTRY_UNITED_STATES; -#ifdef AH_SUPPORT_11D - if (ah->ah_countryCode == CTRY_DEFAULT) { - regdmn = ath9k_regd_get_eepromRD(ah); + if (ah->regulatory.country_code == CTRY_DEFAULT) { country = NULL; } else { -#endif - country = ath9k_regd_find_country(ah->ah_countryCode); + country = ath9k_regd_find_country(ah->regulatory.country_code); if (country == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Country is NULL!!!!, cc= %d\n", - ah->ah_countryCode); - return false; - } else { + ah->regulatory.country_code); + return -EINVAL; + } else regdmn = country->regDmnEnum; -#ifdef AH_SUPPORT_11D - if (((ath9k_regd_get_eepromRD(ah) & - WORLD_SKU_MASK) == WORLD_SKU_PREFIX) && - (cc == CTRY_UNITED_STATES)) { - if (!isWwrSKU_NoMidband(ah) - && ath9k_regd_is_fcc_midband_supported(ah)) - regdmn = FCC3_FCCA; - else - regdmn = FCC1_FCCA; - } -#endif - } -#ifdef AH_SUPPORT_11D - } -#endif - if (!ath9k_regd_get_wmode_regdomain(ah, - regdmn, - ~CHANNEL_2GHZ, - &rd5GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Couldn't find unitary " - "5GHz reg domain for country %u\n", - ah->ah_countryCode); - return false; - } - if (!ath9k_regd_get_wmode_regdomain(ah, - regdmn, - CHANNEL_2GHZ, - &rd2GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Couldn't find unitary 2GHz " - "reg domain for country %u\n", - ah->ah_countryCode); - return false; - } - - if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) || - (rd5GHz.regDmnEnum == FCC2))) { - if (ath9k_regd_is_fcc_midband_supported(ah)) { - if (!ath9k_regd_get_wmode_regdomain(ah, - FCC3_FCCA, - ~CHANNEL_2GHZ, - &rd5GHz)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Couldn't find unitary 5GHz " - "reg domain for country %u\n", - ah->ah_countryCode); - return false; - } - } - } - - if (country == NULL) { - modes_avail = ah->ah_caps.wireless_modes; - } else { - ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed); - modes_avail = modes_allowed; - - if (!enableOutdoor) - maxChan = country->outdoorChanStart; - } - - next = 0; - - if (maxchans > ARRAY_SIZE(ah->ah_channels)) - maxchans = ARRAY_SIZE(ah->ah_channels); - - for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) { - u16 c, c_hi, c_lo; - u64 *channelBM = NULL; - struct regDomain *rd = NULL; - struct RegDmnFreqBand *fband = NULL, *freqs; - int8_t low_adj = 0, hi_adj = 0; - - if (!test_bit(cm->mode, modes_avail)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "!avail mode %d flags 0x%x\n", - cm->mode, cm->flags); - continue; - } - if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "channels 0x%x not supported " - "by hardware\n", cm->flags); - continue; - } - - switch (cm->mode) { - case ATH9K_MODE_11A: - case ATH9K_MODE_11NA_HT20: - case ATH9K_MODE_11NA_HT40PLUS: - case ATH9K_MODE_11NA_HT40MINUS: - rd = &rd5GHz; - channelBM = rd->chan11a; - freqs = ®Dmn5GhzFreq[0]; - ctl = rd->conformanceTestLimit; - break; - case ATH9K_MODE_11B: - rd = &rd2GHz; - channelBM = rd->chan11b; - freqs = ®Dmn2GhzFreq[0]; - ctl = rd->conformanceTestLimit | CTL_11B; - break; - case ATH9K_MODE_11G: - case ATH9K_MODE_11NG_HT20: - case ATH9K_MODE_11NG_HT40PLUS: - case ATH9K_MODE_11NG_HT40MINUS: - rd = &rd2GHz; - channelBM = rd->chan11g; - freqs = ®Dmn2Ghz11gFreq[0]; - ctl = rd->conformanceTestLimit | CTL_11G; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Unknown HAL mode 0x%x\n", cm->mode); - continue; - } - - if (ath9k_regd_is_chan_bm_zero(channelBM)) - continue; - - if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) || - (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) { - hi_adj = -20; - } - - if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) || - (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) { - low_adj = 20; - } - - /* XXX: Add a helper here instead */ - for (b = 0; b < 64 * BMLEN; b++) { - if (ath9k_regd_is_bit_set(b, channelBM)) { - fband = &freqs[b]; - if (rd5GHz.regDmnEnum == MKK1 - || rd5GHz.regDmnEnum == MKK2) { - if (ath9k_regd_japan_check(ah, - b, - &rd5GHz)) - continue; - } - - ath9k_regd_add_reg_classid(regclassids, - maxregids, - nregids, - fband-> - regClassId); - - if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) { - chanSep = 40; - if (fband->lowChannel == 5280) - low_adj += 20; - - if (fband->lowChannel == 5170) - continue; - } else - chanSep = fband->channelSep; - - for (c = fband->lowChannel + low_adj; - ((c <= (fband->highChannel + hi_adj)) && - (c >= (fband->lowChannel + low_adj))); - c += chanSep) { - if (next >= maxchans) { - DPRINTF(ah->ah_sc, - ATH_DBG_REGULATORY, - "too many channels " - "for channel table\n"); - goto done; - } - if (ath9k_regd_add_channel(ah, - c, c_lo, c_hi, - maxChan, ctl, - next, - rd5GHz, - fband, rd, cm, - ichans, - enableExtendedChannels)) - next++; - } - if (IS_HT40_MODE(cm->mode) && - (fband->lowChannel == 5280)) { - low_adj -= 20; - } - } - } } -done: - if (next != 0) { - int i; - if (next > ARRAY_SIZE(ah->ah_channels)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "too many channels %u; truncating to %u\n", - next, (int) ARRAY_SIZE(ah->ah_channels)); - next = ARRAY_SIZE(ah->ah_channels); - } -#ifdef ATH_NF_PER_CHAN - ath9k_regd_init_rf_buffer(ichans, next); -#endif - ath9k_regd_sort(ichans, next, - sizeof(struct ath9k_channel), - ath9k_regd_chansort); + ah->regulatory.regpair = ath9k_get_regpair(regdmn); - ah->ah_nchan = next; - - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n"); - for (i = 0; i < next; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "chan: %d flags: 0x%x\n", - ah->ah_channels[i].channel, - ah->ah_channels[i].channelFlags); - } + if (!ah->regulatory.regpair) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "No regulatory domain pair found, cannot continue\n"); + return -EINVAL; } - *nchans = next; - ah->ah_countryCode = ah->ah_countryCode; + if (!country) + country = ath9k_regd_find_country_by_rd(regdmn); - ah->ah_currentRDInUse = regdmn; - ah->ah_currentRD5G = rd5GHz.regDmnEnum; - ah->ah_currentRD2G = rd2GHz.regDmnEnum; - if (country == NULL) { - ah->ah_iso[0] = 0; - ah->ah_iso[1] = 0; + if (country) { + ah->regulatory.alpha2[0] = country->isoName[0]; + ah->regulatory.alpha2[1] = country->isoName[1]; } else { - ah->ah_iso[0] = country->isoName[0]; - ah->ah_iso[1] = country->isoName[1]; + ah->regulatory.alpha2[0] = '0'; + ah->regulatory.alpha2[1] = '0'; } - return next != 0; -} - -struct ath9k_channel* -ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c) -{ - struct ath9k_channel *base, *cc; - - int flags = c->channelFlags & CHAN_FLAGS; - int n, lim; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "channel %u/0x%x (0x%x) requested\n", - c->channel, c->channelFlags, flags); - - cc = ah->ah_curchan; - if (cc != NULL && cc->channel == c->channel && - (cc->channelFlags & CHAN_FLAGS) == flags) { - if ((cc->privFlags & CHANNEL_INTERFERENCE) && - (cc->privFlags & CHANNEL_DFS)) - return NULL; - else - return cc; - } + "Country alpha2 being used: %c%c\n" + "Regulatory.Regpair detected: 0x%0x\n", + ah->regulatory.alpha2[0], ah->regulatory.alpha2[1], + ah->regulatory.regpair->regDmnEnum); - base = ah->ah_channels; - n = ah->ah_nchan; - - for (lim = n; lim != 0; lim >>= 1) { - int d; - cc = &base[lim >> 1]; - d = c->channel - cc->channel; - if (d == 0) { - if ((cc->channelFlags & CHAN_FLAGS) == flags) { - if ((cc->privFlags & CHANNEL_INTERFERENCE) && - (cc->privFlags & CHANNEL_DFS)) - return NULL; - else - return cc; - } - d = flags - (cc->channelFlags & CHAN_FLAGS); - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "channel %u/0x%x d %d\n", - cc->channel, cc->channelFlags, d); - if (d > 0) { - base = cc + 1; - lim--; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n", - c->channel, c->channelFlags); - return NULL; -} - -u32 -ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath9k_channel *ichan = NULL; - - ichan = ath9k_regd_check_channel(ah, chan); - if (!ichan) - return 0; - - return ichan->antennaMax; + return 0; } -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan) +u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) { u32 ctl = NO_CTL; - struct ath9k_channel *ichan; - if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) { + if (!ah->regulatory.regpair || + (ah->regulatory.country_code == CTRY_DEFAULT && + is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) { if (IS_CHAN_B(chan)) ctl = SD_NO_CTL | CTL_11B; else if (IS_CHAN_G(chan)) ctl = SD_NO_CTL | CTL_11G; else ctl = SD_NO_CTL | CTL_11A; - } else { - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan != NULL) { - /* FIXME */ - if (IS_CHAN_A(ichan)) - ctl = ichan->conformanceTestLimit[0]; - else if (IS_CHAN_B(ichan)) - ctl = ichan->conformanceTestLimit[1]; - else if (IS_CHAN_G(ichan)) - ctl = ichan->conformanceTestLimit[2]; - - if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B) - ctl = (ctl & ~0xf) | CTL_11G; - } + return ctl; } - return ctl; -} -void ath9k_regd_get_current_country(struct ath_hal *ah, - struct ath9k_country_entry *ctry) -{ - u16 rd = ath9k_regd_get_eepromRD(ah); + if (IS_CHAN_B(chan)) + ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B; + else if (IS_CHAN_G(chan)) + ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G; + else + ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A; - ctry->isMultidomain = false; - if (rd == CTRY_DEFAULT) - ctry->isMultidomain = true; - else if (!(rd & COUNTRY_ERD_FLAG)) - ctry->isMultidomain = isWwrSKU(ah); - - ctry->countryCode = ah->ah_countryCode; - ctry->regDmnEnum = ah->ah_currentRD; - ctry->regDmn5G = ah->ah_currentRD5G; - ctry->regDmn2G = ah->ah_currentRD2G; - ctry->iso[0] = ah->ah_iso[0]; - ctry->iso[1] = ah->ah_iso[1]; - ctry->iso[2] = ah->ah_iso[2]; + return ctl; } diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 512d990aa7ea..9f5fbd4eea7a 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,127 +17,8 @@ #ifndef REGD_H #define REGD_H -#include "ath9k.h" - -#define BMLEN 2 -#define BMZERO {(u64) 0, (u64) 0} - -#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \ - {((((_fa >= 0) && (_fa < 64)) ? \ - (((u64) 1) << _fa) : (u64) 0) | \ - (((_fb >= 0) && (_fb < 64)) ? \ - (((u64) 1) << _fb) : (u64) 0) | \ - (((_fc >= 0) && (_fc < 64)) ? \ - (((u64) 1) << _fc) : (u64) 0) | \ - (((_fd >= 0) && (_fd < 64)) ? \ - (((u64) 1) << _fd) : (u64) 0) | \ - (((_fe >= 0) && (_fe < 64)) ? \ - (((u64) 1) << _fe) : (u64) 0) | \ - (((_ff >= 0) && (_ff < 64)) ? \ - (((u64) 1) << _ff) : (u64) 0) | \ - (((_fg >= 0) && (_fg < 64)) ? \ - (((u64) 1) << _fg) : (u64) 0) | \ - (((_fh >= 0) && (_fh < 64)) ? \ - (((u64) 1) << _fh) : (u64) 0) | \ - (((_fi >= 0) && (_fi < 64)) ? \ - (((u64) 1) << _fi) : (u64) 0) | \ - (((_fj >= 0) && (_fj < 64)) ? \ - (((u64) 1) << _fj) : (u64) 0) | \ - (((_fk >= 0) && (_fk < 64)) ? \ - (((u64) 1) << _fk) : (u64) 0) | \ - (((_fl >= 0) && (_fl < 64)) ? \ - (((u64) 1) << _fl) : (u64) 0) | \ - ((((_fa > 63) && (_fa < 128)) ? \ - (((u64) 1) << (_fa - 64)) : (u64) 0) | \ - (((_fb > 63) && (_fb < 128)) ? \ - (((u64) 1) << (_fb - 64)) : (u64) 0) | \ - (((_fc > 63) && (_fc < 128)) ? \ - (((u64) 1) << (_fc - 64)) : (u64) 0) | \ - (((_fd > 63) && (_fd < 128)) ? \ - (((u64) 1) << (_fd - 64)) : (u64) 0) | \ - (((_fe > 63) && (_fe < 128)) ? \ - (((u64) 1) << (_fe - 64)) : (u64) 0) | \ - (((_ff > 63) && (_ff < 128)) ? \ - (((u64) 1) << (_ff - 64)) : (u64) 0) | \ - (((_fg > 63) && (_fg < 128)) ? \ - (((u64) 1) << (_fg - 64)) : (u64) 0) | \ - (((_fh > 63) && (_fh < 128)) ? \ - (((u64) 1) << (_fh - 64)) : (u64) 0) | \ - (((_fi > 63) && (_fi < 128)) ? \ - (((u64) 1) << (_fi - 64)) : (u64) 0) | \ - (((_fj > 63) && (_fj < 128)) ? \ - (((u64) 1) << (_fj - 64)) : (u64) 0) | \ - (((_fk > 63) && (_fk < 128)) ? \ - (((u64) 1) << (_fk - 64)) : (u64) 0) | \ - (((_fl > 63) && (_fl < 128)) ? \ - (((u64) 1) << (_fl - 64)) : (u64) 0)))} - -#define DEF_REGDMN FCC1_FCCA -#define DEF_DMN_5 FCC1 -#define DEF_DMN_2 FCCA #define COUNTRY_ERD_FLAG 0x8000 #define WORLDWIDE_ROAMING_FLAG 0x4000 -#define SUPER_DOMAIN_MASK 0x0fff -#define COUNTRY_CODE_MASK 0x3fff -#define CF_INTERFERENCE (CHANNEL_CW_INT | CHANNEL_RADAR_INT) -#define CHANNEL_14 (2484) -#define IS_11G_CH14(_ch,_cf) \ - (((_ch) == CHANNEL_14) && ((_cf) == CHANNEL_G)) - -#define NO_PSCAN 0x0ULL -#define PSCAN_FCC 0x0000000000000001ULL -#define PSCAN_FCC_T 0x0000000000000002ULL -#define PSCAN_ETSI 0x0000000000000004ULL -#define PSCAN_MKK1 0x0000000000000008ULL -#define PSCAN_MKK2 0x0000000000000010ULL -#define PSCAN_MKKA 0x0000000000000020ULL -#define PSCAN_MKKA_G 0x0000000000000040ULL -#define PSCAN_ETSIA 0x0000000000000080ULL -#define PSCAN_ETSIB 0x0000000000000100ULL -#define PSCAN_ETSIC 0x0000000000000200ULL -#define PSCAN_WWR 0x0000000000000400ULL -#define PSCAN_MKKA1 0x0000000000000800ULL -#define PSCAN_MKKA1_G 0x0000000000001000ULL -#define PSCAN_MKKA2 0x0000000000002000ULL -#define PSCAN_MKKA2_G 0x0000000000004000ULL -#define PSCAN_MKK3 0x0000000000008000ULL -#define PSCAN_DEFER 0x7FFFFFFFFFFFFFFFULL -#define IS_ECM_CHAN 0x8000000000000000ULL - -#define isWwrSKU(_ah) \ - (((ath9k_regd_get_eepromRD((_ah)) & WORLD_SKU_MASK) == \ - WORLD_SKU_PREFIX) || \ - (ath9k_regd_get_eepromRD(_ah) == WORLD)) - -#define isWwrSKU_NoMidband(_ah) \ - ((ath9k_regd_get_eepromRD((_ah)) == WOR3_WORLD) || \ - (ath9k_regd_get_eepromRD(_ah) == WOR4_WORLD) || \ - (ath9k_regd_get_eepromRD(_ah) == WOR5_ETSIC)) - -#define isUNII1OddChan(ch) \ - ((ch == 5170) || (ch == 5190) || (ch == 5210) || (ch == 5230)) - -#define IS_HT40_MODE(_mode) \ - (((_mode == ATH9K_MODE_11NA_HT40PLUS || \ - _mode == ATH9K_MODE_11NG_HT40PLUS || \ - _mode == ATH9K_MODE_11NA_HT40MINUS || \ - _mode == ATH9K_MODE_11NG_HT40MINUS) ? true : false)) - -#define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) - -#define swap_array(_a, _b, _size) { \ - u8 *s = _b; \ - int i = _size; \ - do { \ - u8 tmp = *_a; \ - *_a++ = *s; \ - *s++ = tmp; \ - } while (--i); \ - _a -= _size; \ -} - - -#define HALF_MAXCHANBW 10 #define MULTI_DOMAIN_MASK 0xFF00 @@ -147,81 +28,27 @@ #define CHANNEL_HALF_BW 10 #define CHANNEL_QUARTER_BW 5 -typedef int ath_hal_cmp_t(const void *, const void *); - struct reg_dmn_pair_mapping { u16 regDmnEnum; - u16 regDmn5GHz; - u16 regDmn2GHz; - u32 flags5GHz; - u32 flags2GHz; - u64 pscanMask; - u16 singleCC; -}; - -struct ccmap { - char isoName[3]; - u16 countryCode; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; }; struct country_code_to_enum_rd { u16 countryCode; u16 regDmnEnum; const char *isoName; - const char *name; - bool allow11g; - bool allow11aTurbo; - bool allow11gTurbo; - bool allow11ng20; - bool allow11ng40; - bool allow11na20; - bool allow11na40; - u16 outdoorChanStart; -}; - -struct RegDmnFreqBand { - u16 lowChannel; - u16 highChannel; - u8 powerDfs; - u8 antennaMax; - u8 channelBW; - u8 channelSep; - u64 useDfs; - u64 usePassScan; - u8 regClassId; -}; - -struct regDomain { - u16 regDmnEnum; - u8 conformanceTestLimit; - u64 dfsMask; - u64 pscan; - u32 flags; - u64 chan11a[BMLEN]; - u64 chan11a_turbo[BMLEN]; - u64 chan11a_dyn_turbo[BMLEN]; - u64 chan11b[BMLEN]; - u64 chan11g[BMLEN]; - u64 chan11g_turbo[BMLEN]; -}; - -struct cmode { - u32 mode; - u32 flags; -}; - -#define YES true -#define NO false - -struct japan_bandcheck { - u16 freqbandbit; - u32 eepromflagtocheck; }; -struct common_mode_power { - u16 lchan; - u16 hchan; - u8 pwrlvl; +struct ath9k_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; }; enum CountryCode { @@ -406,7 +233,15 @@ enum CountryCode { CTRY_BELGIUM2 = 5002 }; -void ath9k_regd_get_current_country(struct ath_hal *ah, - struct ath9k_country_entry *ctry); +bool ath9k_is_world_regd(struct ath_hw *ah); +const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah); +const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); +void ath9k_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator); +void ath9k_reg_apply_radar_flags(struct wiphy *wiphy); +int ath9k_regd_init(struct ath_hw *ah); +bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah); +u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan); +int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); #endif diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath9k/regd_common.h index 6df1b3b77c25..4d0e298cd1c7 100644 --- a/drivers/net/wireless/ath9k/regd_common.h +++ b/drivers/net/wireless/ath9k/regd_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -150,1766 +150,324 @@ enum EnumRd { MKK9_MKKC = 0xFE, MKK9_MKKA2 = 0xFF, - APL1 = 0x0150, - APL2 = 0x0250, - APL3 = 0x0350, - APL4 = 0x0450, - APL5 = 0x0550, - APL6 = 0x0650, - APL7 = 0x0750, - APL8 = 0x0850, - APL9 = 0x0950, - APL10 = 0x1050, - - ETSI1 = 0x0130, - ETSI2 = 0x0230, - ETSI3 = 0x0330, - ETSI4 = 0x0430, - ETSI5 = 0x0530, - ETSI6 = 0x0630, - ETSIA = 0x0A30, - ETSIB = 0x0B30, - ETSIC = 0x0C30, - - FCC1 = 0x0110, - FCC2 = 0x0120, - FCC3 = 0x0160, - FCC4 = 0x0165, - FCC5 = 0x0510, - FCC6 = 0x0610, - FCCA = 0x0A10, - - APLD = 0x0D50, - - MKK1 = 0x0140, - MKK2 = 0x0240, - MKK3 = 0x0340, - MKK4 = 0x0440, - MKK5 = 0x0540, - MKK6 = 0x0640, - MKK7 = 0x0740, - MKK8 = 0x0840, - MKK9 = 0x0940, - MKK10 = 0x0B40, - MKK11 = 0x1140, - MKK12 = 0x1240, - MKK13 = 0x0C40, - MKK14 = 0x1440, - MKK15 = 0x1540, - MKKA = 0x0A40, - MKKC = 0x0A50, - - NULL1 = 0x0198, WORLD = 0x0199, DEBUG_REG_DMN = 0x01ff, }; -enum { - FCC = 0x10, - MKK = 0x40, - ETSI = 0x30, -}; - -enum { - NO_REQ = 0x00000000, - DISALLOW_ADHOC_11A = 0x00000001, - DISALLOW_ADHOC_11A_TURB = 0x00000002, - NEED_NFC = 0x00000004, - - ADHOC_PER_11D = 0x00000008, - ADHOC_NO_11A = 0x00000010, - - PUBLIC_SAFETY_DOMAIN = 0x00000020, - LIMIT_FRAME_4MS = 0x00000040, - - NO_HOSTAP = 0x00000080, - - REQ_MASK = 0x000000FF, +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, }; -#define REG_DOMAIN_2GHZ_MASK (REQ_MASK & \ - (~(ADHOC_NO_11A | DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB))) -#define REG_DOMAIN_5GHZ_MASK REQ_MASK - +/* Regpair to CTL band mapping */ static struct reg_dmn_pair_mapping regDomainPairs[] = { - {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN, NO_REQ, NO_REQ, - PSCAN_DEFER, 0}, - {NULL1_WORLD, NULL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {NULL1_ETSIB, NULL1, ETSIB, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {NULL1_ETSIC, NULL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - - {FCC2_FCCA, FCC2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC2_WORLD, FCC2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC2_ETSIC, FCC2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC3_FCCA, FCC3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC4_FCCA, FCC4, FCCA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {FCC5_FCCA, FCC5, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC6_FCCA, FCC6, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC6_WORLD, FCC6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - - {ETSI1_WORLD, ETSI1, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {ETSI2_WORLD, ETSI2, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {ETSI3_WORLD, ETSI3, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {ETSI4_WORLD, ETSI4, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {ETSI5_WORLD, ETSI5, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {ETSI6_WORLD, ETSI6, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - - {ETSI3_ETSIA, ETSI3, WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {FRANCE_RES, ETSI3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - - {FCC1_WORLD, FCC1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {FCC1_FCCA, FCC1, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL1_WORLD, APL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL2_WORLD, APL2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL3_WORLD, APL3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL4_WORLD, APL4, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL5_WORLD, APL5, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL6_WORLD, APL6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL8_WORLD, APL8, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL9_WORLD, APL9, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - - {APL3_FCCA, APL3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL1_ETSIC, APL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL2_ETSIC, APL2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {APL2_APLD, APL2, APLD, NO_REQ, NO_REQ, PSCAN_DEFER,}, - - {MKK1_MKKA, MKK1, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA, CTRY_JAPAN}, - {MKK1_MKKB, MKK1, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN1}, - {MKK1_FCCA, MKK1, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1, CTRY_JAPAN2}, - {MKK1_MKKA1, MKK1, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN4}, - {MKK1_MKKA2, MKK1, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN5}, - {MKK1_MKKC, MKK1, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1, CTRY_JAPAN6}, - - {MKK2_MKKA, MKK2, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN3}, - - {MKK3_MKKA, MKK3, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA, CTRY_JAPAN25}, - {MKK3_MKKB, MKK3, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN7}, - {MKK3_MKKA1, MKK3, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN26}, - {MKK3_MKKA2, MKK3, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN8}, - {MKK3_MKKC, MKK3, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN9}, - {MKK3_FCCA, MKK3, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN27}, - - {MKK4_MKKA, MKK4, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN36}, - {MKK4_MKKB, MKK4, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN10}, - {MKK4_MKKA1, MKK4, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN28}, - {MKK4_MKKA2, MKK4, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN11}, - {MKK4_MKKC, MKK4, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN12}, - {MKK4_FCCA, MKK4, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN29}, - - {MKK5_MKKB, MKK5, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN13}, - {MKK5_MKKA2, MKK5, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN14}, - {MKK5_MKKC, MKK5, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN15}, - - {MKK6_MKKB, MKK6, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN16}, - {MKK6_MKKA1, MKK6, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN30}, - {MKK6_MKKA2, MKK6, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN17}, - {MKK6_MKKC, MKK6, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1, CTRY_JAPAN18}, - {MKK6_FCCA, MKK6, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN31}, - - {MKK7_MKKB, MKK7, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN19}, - {MKK7_MKKA1, MKK7, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN32}, - {MKK7_MKKA2, MKK7, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, - CTRY_JAPAN20}, - {MKK7_MKKC, MKK7, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN21}, - {MKK7_FCCA, MKK7, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN33}, - - {MKK8_MKKB, MKK8, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN22}, - {MKK8_MKKA2, MKK8, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, - CTRY_JAPAN23}, - {MKK8_MKKC, MKK8, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN24}, - - {MKK9_MKKA, MKK9, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK2 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN34}, - {MKK9_FCCA, MKK9, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN37}, - {MKK9_MKKA1, MKK9, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN38}, - {MKK9_MKKA2, MKK9, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN40}, - {MKK9_MKKC, MKK9, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN39}, - - {MKK10_MKKA, MKK10, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKK3, CTRY_JAPAN35}, - {MKK10_FCCA, MKK10, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN41}, - {MKK10_MKKA1, MKK10, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN42}, - {MKK10_MKKA2, MKK10, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN44}, - {MKK10_MKKC, MKK10, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - NO_PSCAN, CTRY_JAPAN43}, - - {MKK11_MKKA, MKK11, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN45}, - {MKK11_FCCA, MKK11, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN46}, - {MKK11_MKKA1, MKK11, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN47}, - {MKK11_MKKA2, MKK11, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN49}, - {MKK11_MKKC, MKK11, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK3, CTRY_JAPAN48}, - - {MKK12_MKKA, MKK12, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN50}, - {MKK12_FCCA, MKK12, FCCA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN51}, - {MKK12_MKKA1, MKK12, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, - CTRY_JAPAN52}, - {MKK12_MKKA2, MKK12, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, - CTRY_JAPAN54}, - {MKK12_MKKC, MKK12, MKKC, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN53}, - - {MKK13_MKKB, MKK13, MKKA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | - LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, - CTRY_JAPAN57}, - - {MKK14_MKKA1, MKK14, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN58}, - {MKK15_MKKA1, MKK15, MKKA, - DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, - PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN59}, - - {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, - 0}, - {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, DISALLOW_ADHOC_11A_TURB, - NO_REQ, PSCAN_DEFER, 0}, - {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, - 0}, - {WOR4_WORLD, WOR4_WORLD, WOR4_WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, NO_REQ, NO_REQ, - PSCAN_DEFER, 0}, - {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, NO_REQ, NO_REQ, - PSCAN_DEFER, 0}, - {EU1_WORLD, EU1_WORLD, EU1_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, - {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {WORA_WORLD, WORA_WORLD, WORA_WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, - {WORB_WORLD, WORB_WORLD, WORB_WORLD, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, - 0}, + /* regpair, 5 GHz CTL, 2 GHz CTL */ + {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN}, + {NULL1_WORLD, NO_CTL, CTL_ETSI}, + {NULL1_ETSIB, NO_CTL, CTL_ETSI}, + {NULL1_ETSIC, NO_CTL, CTL_ETSI}, + + {FCC2_FCCA, CTL_FCC, CTL_FCC}, + {FCC2_WORLD, CTL_FCC, CTL_ETSI}, + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, + {FCC5_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_WORLD, CTL_FCC, CTL_ETSI}, + + {ETSI1_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI2_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI3_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + + /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ + {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, + {FRANCE_RES, CTL_ETSI, CTL_ETSI}, + + {FCC1_WORLD, CTL_FCC, CTL_ETSI}, + {FCC1_FCCA, CTL_FCC, CTL_FCC}, + {APL1_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL3_WORLD, CTL_FCC, CTL_ETSI}, + {APL4_WORLD, CTL_FCC, CTL_ETSI}, + {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL6_WORLD, CTL_ETSI, CTL_ETSI}, + {APL8_WORLD, CTL_ETSI, CTL_ETSI}, + {APL9_WORLD, CTL_ETSI, CTL_ETSI}, + + {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL1_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_ETSIC, CTL_FCC, CTL_ETSI}, + {APL2_APLD, CTL_FCC, NO_CTL}, + + {MKK1_MKKA, CTL_MKK, CTL_MKK}, + {MKK1_MKKB, CTL_MKK, CTL_MKK}, + {MKK1_FCCA, CTL_MKK, CTL_FCC}, + {MKK1_MKKA1, CTL_MKK, CTL_MKK}, + {MKK1_MKKA2, CTL_MKK, CTL_MKK}, + {MKK1_MKKC, CTL_MKK, CTL_MKK}, + + {MKK2_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKA, CTL_MKK, CTL_MKK}, + {MKK3_MKKB, CTL_MKK, CTL_MKK}, + {MKK3_MKKA1, CTL_MKK, CTL_MKK}, + {MKK3_MKKA2, CTL_MKK, CTL_MKK}, + {MKK3_MKKC, CTL_MKK, CTL_MKK}, + {MKK3_FCCA, CTL_MKK, CTL_FCC}, + + {MKK4_MKKA, CTL_MKK, CTL_MKK}, + {MKK4_MKKB, CTL_MKK, CTL_MKK}, + {MKK4_MKKA1, CTL_MKK, CTL_MKK}, + {MKK4_MKKA2, CTL_MKK, CTL_MKK}, + {MKK4_MKKC, CTL_MKK, CTL_MKK}, + {MKK4_FCCA, CTL_MKK, CTL_FCC}, + + {MKK5_MKKB, CTL_MKK, CTL_MKK}, + {MKK5_MKKA2, CTL_MKK, CTL_MKK}, + {MKK5_MKKC, CTL_MKK, CTL_MKK}, + + {MKK6_MKKB, CTL_MKK, CTL_MKK}, + {MKK6_MKKA1, CTL_MKK, CTL_MKK}, + {MKK6_MKKA2, CTL_MKK, CTL_MKK}, + {MKK6_MKKC, CTL_MKK, CTL_MKK}, + {MKK6_FCCA, CTL_MKK, CTL_FCC}, + + {MKK7_MKKB, CTL_MKK, CTL_MKK}, + {MKK7_MKKA1, CTL_MKK, CTL_MKK}, + {MKK7_MKKA2, CTL_MKK, CTL_MKK}, + {MKK7_MKKC, CTL_MKK, CTL_MKK}, + {MKK7_FCCA, CTL_MKK, CTL_FCC}, + + {MKK8_MKKB, CTL_MKK, CTL_MKK}, + {MKK8_MKKA2, CTL_MKK, CTL_MKK}, + {MKK8_MKKC, CTL_MKK, CTL_MKK}, + + {MKK9_MKKA, CTL_MKK, CTL_MKK}, + {MKK9_FCCA, CTL_MKK, CTL_FCC}, + {MKK9_MKKA1, CTL_MKK, CTL_MKK}, + {MKK9_MKKA2, CTL_MKK, CTL_MKK}, + {MKK9_MKKC, CTL_MKK, CTL_MKK}, + + {MKK10_MKKA, CTL_MKK, CTL_MKK}, + {MKK10_FCCA, CTL_MKK, CTL_FCC}, + {MKK10_MKKA1, CTL_MKK, CTL_MKK}, + {MKK10_MKKA2, CTL_MKK, CTL_MKK}, + {MKK10_MKKC, CTL_MKK, CTL_MKK}, + + {MKK11_MKKA, CTL_MKK, CTL_MKK}, + {MKK11_FCCA, CTL_MKK, CTL_FCC}, + {MKK11_MKKA1, CTL_MKK, CTL_MKK}, + {MKK11_MKKA2, CTL_MKK, CTL_MKK}, + {MKK11_MKKC, CTL_MKK, CTL_MKK}, + + {MKK12_MKKA, CTL_MKK, CTL_MKK}, + {MKK12_FCCA, CTL_MKK, CTL_FCC}, + {MKK12_MKKA1, CTL_MKK, CTL_MKK}, + {MKK12_MKKA2, CTL_MKK, CTL_MKK}, + {MKK12_MKKC, CTL_MKK, CTL_MKK}, + + {MKK13_MKKB, CTL_MKK, CTL_MKK}, + {MKK14_MKKA1, CTL_MKK, CTL_MKK}, + {MKK15_MKKA1, CTL_MKK, CTL_MKK}, + + {WOR0_WORLD, NO_CTL, NO_CTL}, + {WOR1_WORLD, NO_CTL, NO_CTL}, + {WOR2_WORLD, NO_CTL, NO_CTL}, + {WOR3_WORLD, NO_CTL, NO_CTL}, + {WOR4_WORLD, NO_CTL, NO_CTL}, + {WOR5_ETSIC, NO_CTL, NO_CTL}, + {WOR01_WORLD, NO_CTL, NO_CTL}, + {WOR02_WORLD, NO_CTL, NO_CTL}, + {EU1_WORLD, NO_CTL, NO_CTL}, + {WOR9_WORLD, NO_CTL, NO_CTL}, + {WORA_WORLD, NO_CTL, NO_CTL}, + {WORB_WORLD, NO_CTL, NO_CTL}, }; -#define NO_INTERSECT_REQ 0xFFFFFFFF -#define NO_UNION_REQ 0 - static struct country_code_to_enum_rd allCountries[] = { - {CTRY_DEBUG, NO_ENUMRD, "DB", "DEBUG", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_DEFAULT, DEF_REGDMN, "NA", "NO_COUNTRY_SET", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_ALBANIA, NULL1_WORLD, "AL", "ALBANIA", YES, NO, YES, YES, NO, - NO, NO, 7000}, - {CTRY_ALGERIA, NULL1_WORLD, "DZ", "ALGERIA", YES, NO, YES, YES, NO, - NO, NO, 7000}, - {CTRY_ARGENTINA, APL3_WORLD, "AR", "ARGENTINA", YES, NO, NO, YES, - NO, YES, NO, 7000}, - {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_AUSTRALIA, FCC2_WORLD, "AU", "AUSTRALIA", YES, YES, YES, YES, - YES, YES, YES, 7000}, - {CTRY_AUSTRALIA2, FCC6_WORLD, "AU", "AUSTRALIA2", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_BAHRAIN, APL6_WORLD, "BH", "BAHRAIN", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_BELGIUM2, ETSI4_WORLD, "BL", "BELGIUM", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_BELIZE, APL1_ETSIC, "BZ", "BELIZE", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_BOLIVIA, APL1_ETSIC, "BO", "BOLVIA", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA", "BOSNIA_HERZGOWINA", YES, NO, - YES, YES, YES, YES, NO, 7000}, - {CTRY_BRAZIL, FCC3_WORLD, "BR", "BRAZIL", YES, NO, NO, YES, NO, - YES, NO, 7000}, - {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN", "BRUNEI DARUSSALAM", - YES, YES, YES, YES, YES, YES, YES, 7000}, - {CTRY_BULGARIA, ETSI6_WORLD, "BG", "BULGARIA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_CANADA, FCC2_FCCA, "CA", "CANADA", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_CANADA2, FCC6_FCCA, "CA", "CANADA2", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_CHILE, APL6_WORLD, "CL", "CHILE", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_CHINA, APL1_WORLD, "CN", "CHINA", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_COLOMBIA, FCC1_FCCA, "CO", "COLOMBIA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_COSTA_RICA, FCC1_WORLD, "CR", "COSTA RICA", YES, NO, YES, - YES, YES, YES, NO, 7000}, - {CTRY_CROATIA, ETSI3_WORLD, "HR", "CROATIA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_CZECH, ETSI3_WORLD, "CZ", "CZECH REPUBLIC", YES, NO, YES, - YES, YES, YES, YES, 7000}, - {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO", "DOMINICAN REPUBLIC", - YES, YES, YES, YES, YES, YES, YES, 7000}, - {CTRY_ECUADOR, FCC1_WORLD, "EC", "ECUADOR", YES, NO, NO, YES, YES, - YES, NO, 7000}, - {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_EL_SALVADOR, FCC1_WORLD, "SV", "EL SALVADOR", YES, NO, YES, - YES, YES, YES, NO, 7000}, - {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA", YES, YES, YES, YES, - YES, YES, YES, 7000}, - {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_GUATEMALA, FCC1_FCCA, "GT", "GUATEMALA", YES, YES, YES, YES, - YES, YES, YES, 7000}, - {CTRY_HONDURAS, NULL1_WORLD, "HN", "HONDURAS", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_HONG_KONG, FCC2_WORLD, "HK", "HONG KONG", YES, YES, YES, YES, - YES, YES, YES, 7000}, - {CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_INDIA, APL6_WORLD, "IN", "INDIA", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_INDONESIA, APL1_WORLD, "ID", "INDONESIA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_IRAN, APL1_WORLD, "IR", "IRAN", YES, YES, YES, YES, YES, YES, - YES, 7000}, - {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_ISRAEL, NULL1_WORLD, "IL", "ISRAEL", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_JAMAICA, ETSI1_WORLD, "JM", "JAMAICA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - - {CTRY_JAPAN, MKK1_MKKA, "JP", "JAPAN", YES, NO, NO, YES, YES, YES, - YES, 7000}, - {CTRY_JAPAN1, MKK1_MKKB, "JP", "JAPAN1", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN2, MKK1_FCCA, "JP", "JAPAN2", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN3, MKK2_MKKA, "JP", "JAPAN3", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN4, MKK1_MKKA1, "JP", "JAPAN4", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN5, MKK1_MKKA2, "JP", "JAPAN5", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN6, MKK1_MKKC, "JP", "JAPAN6", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN7, MKK3_MKKB, "JP", "JAPAN7", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN8, MKK3_MKKA2, "JP", "JAPAN8", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN9, MKK3_MKKC, "JP", "JAPAN9", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN10, MKK4_MKKB, "JP", "JAPAN10", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN11, MKK4_MKKA2, "JP", "JAPAN11", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN12, MKK4_MKKC, "JP", "JAPAN12", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN13, MKK5_MKKB, "JP", "JAPAN13", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN14, MKK5_MKKA2, "JP", "JAPAN14", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN15, MKK5_MKKC, "JP", "JAPAN15", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN16, MKK6_MKKB, "JP", "JAPAN16", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN17, MKK6_MKKA2, "JP", "JAPAN17", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN18, MKK6_MKKC, "JP", "JAPAN18", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN19, MKK7_MKKB, "JP", "JAPAN19", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN20, MKK7_MKKA2, "JP", "JAPAN20", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN21, MKK7_MKKC, "JP", "JAPAN21", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN22, MKK8_MKKB, "JP", "JAPAN22", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN23, MKK8_MKKA2, "JP", "JAPAN23", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN24, MKK8_MKKC, "JP", "JAPAN24", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN25, MKK3_MKKA, "JP", "JAPAN25", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN26, MKK3_MKKA1, "JP", "JAPAN26", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN27, MKK3_FCCA, "JP", "JAPAN27", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN28, MKK4_MKKA1, "JP", "JAPAN28", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN29, MKK4_FCCA, "JP", "JAPAN29", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN30, MKK6_MKKA1, "JP", "JAPAN30", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN31, MKK6_FCCA, "JP", "JAPAN31", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN32, MKK7_MKKA1, "JP", "JAPAN32", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN33, MKK7_FCCA, "JP", "JAPAN33", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN34, MKK9_MKKA, "JP", "JAPAN34", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN35, MKK10_MKKA, "JP", "JAPAN35", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN36, MKK4_MKKA, "JP", "JAPAN36", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN37, MKK9_FCCA, "JP", "JAPAN37", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN38, MKK9_MKKA1, "JP", "JAPAN38", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN39, MKK9_MKKC, "JP", "JAPAN39", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN40, MKK9_MKKA2, "JP", "JAPAN40", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN41, MKK10_FCCA, "JP", "JAPAN41", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN42, MKK10_MKKA1, "JP", "JAPAN42", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN43, MKK10_MKKC, "JP", "JAPAN43", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN44, MKK10_MKKA2, "JP", "JAPAN44", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN45, MKK11_MKKA, "JP", "JAPAN45", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN46, MKK11_FCCA, "JP", "JAPAN46", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN47, MKK11_MKKA1, "JP", "JAPAN47", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN48, MKK11_MKKC, "JP", "JAPAN48", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN49, MKK11_MKKA2, "JP", "JAPAN49", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN50, MKK12_MKKA, "JP", "JAPAN50", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN51, MKK12_FCCA, "JP", "JAPAN51", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN52, MKK12_MKKA1, "JP", "JAPAN52", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN53, MKK12_MKKC, "JP", "JAPAN53", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN54, MKK12_MKKA2, "JP", "JAPAN54", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JAPAN57, MKK13_MKKB, "JP", "JAPAN57", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN58, MKK14_MKKA1, "JP", "JAPAN58", YES, NO, NO, YES, YES, - YES, YES, 7000}, - {CTRY_JAPAN59, MKK15_MKKA1, "JP", "JAPAN59", YES, NO, NO, YES, YES, - YES, YES, 7000}, - - {CTRY_JORDAN, ETSI2_WORLD, "JO", "JORDAN", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN", YES, NO, YES, - YES, YES, NO, NO, 7000}, - {CTRY_KOREA_NORTH, APL9_WORLD, "KP", "NORTH KOREA", YES, NO, NO, - YES, YES, YES, YES, 7000}, - {CTRY_KOREA_ROC, APL9_WORLD, "KR", "KOREA REPUBLIC", YES, NO, NO, - YES, NO, YES, NO, 7000}, - {CTRY_KOREA_ROC2, APL2_WORLD, "K2", "KOREA REPUBLIC2", YES, NO, NO, - YES, NO, YES, NO, 7000}, - {CTRY_KOREA_ROC3, APL9_WORLD, "K3", "KOREA REPUBLIC3", YES, NO, NO, - YES, NO, YES, NO, 7000}, - {CTRY_KUWAIT, NULL1_WORLD, "KW", "KUWAIT", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_LEBANON, NULL1_WORLD, "LB", "LEBANON", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI", "LIECHTENSTEIN", YES, NO, - YES, YES, YES, YES, YES, 7000}, - {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG", YES, NO, YES, - YES, YES, YES, YES, 7000}, - {CTRY_MACAU, FCC2_WORLD, "MO", "MACAU", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_MACEDONIA, NULL1_WORLD, "MK", "MACEDONIA", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_MALAYSIA, APL8_WORLD, "MY", "MALAYSIA", YES, NO, NO, YES, NO, - YES, NO, 7000}, - {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_MEXICO, FCC1_FCCA, "MX", "MEXICO", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_MONACO, ETSI4_WORLD, "MC", "MONACO", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_MOROCCO, NULL1_WORLD, "MA", "MOROCCO", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_NEPAL, APL1_WORLD, "NP", "NEPAL", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS", YES, NO, YES, - YES, YES, YES, YES, 7000}, - {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN", - "NETHERLANDS-ANTILLES", YES, NO, YES, YES, YES, YES, YES, 7000}, - {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ", "NEW ZEALAND", YES, NO, YES, - YES, YES, YES, NO, 7000}, - {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_OMAN, APL6_WORLD, "OM", "OMAN", YES, NO, YES, YES, YES, YES, - NO, 7000}, - {CTRY_PAKISTAN, NULL1_WORLD, "PK", "PAKISTAN", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG", "PAPUA NEW GUINEA", YES, - YES, YES, YES, YES, YES, YES, 7000}, - {CTRY_PERU, APL1_WORLD, "PE", "PERU", YES, NO, YES, YES, YES, YES, - NO, 7000}, - {CTRY_PHILIPPINES, APL1_WORLD, "PH", "PHILIPPINES", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_PUERTO_RICO, FCC1_FCCA, "PR", "PUERTO RICO", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_QATAR, NULL1_WORLD, "QA", "QATAR", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_ROMANIA, NULL1_WORLD, "RO", "ROMANIA", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_RUSSIA, NULL1_WORLD, "RU", "RUSSIA", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA", "SAUDI ARABIA", YES, NO, - YES, YES, YES, NO, NO, 7000}, - {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS", "SERBIA & MONTENEGRO", - YES, NO, YES, YES, YES, YES, YES, 7000}, - {CTRY_SINGAPORE, APL6_WORLD, "SG", "SINGAPORE", YES, YES, YES, YES, - YES, YES, YES, 7000}, - {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAK REPUBLIC", YES, NO, YES, - YES, YES, YES, YES, 7000}, - {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA", YES, NO, YES, YES, - YES, YES, YES, 7000}, - {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA", "SOUTH AFRICA", YES, NO, YES, - YES, YES, YES, NO, 7000}, - {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_SRI_LANKA, FCC3_WORLD, "LK", "SRI LANKA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN", YES, NO, YES, YES, YES, - YES, YES, 7000}, - {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND", YES, NO, YES, - YES, YES, YES, YES, 7000}, - {CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIA", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_TAIWAN, APL3_FCCA, "TW", "TAIWAN", YES, YES, YES, YES, YES, - YES, YES, 7000}, - {CTRY_THAILAND, NULL1_WORLD, "TH", "THAILAND", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT", "TRINIDAD & TOBAGO", - YES, NO, YES, YES, YES, YES, NO, 7000}, - {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_TURKEY, ETSI3_WORLD, "TR", "TURKEY", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_UKRAINE, NULL1_WORLD, "UA", "UKRAINE", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_UAE, NULL1_WORLD, "AE", "UNITED ARAB EMIRATES", YES, NO, YES, - YES, YES, NO, NO, 7000}, - {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB", "UNITED KINGDOM", YES, NO, - YES, YES, YES, YES, YES, 7000}, - {CTRY_UNITED_STATES, FCC3_FCCA, "US", "UNITED STATES", YES, YES, - YES, YES, YES, YES, YES, 5825}, - {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS", - "UNITED STATES (PUBLIC SAFETY)", YES, YES, YES, YES, YES, YES, - YES, 7000}, - {CTRY_URUGUAY, APL2_WORLD, "UY", "URUGUAY", YES, NO, YES, YES, YES, - YES, NO, 7000}, - {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ", "UZBEKISTAN", YES, YES, YES, - YES, YES, YES, YES, 7000}, - {CTRY_VENEZUELA, APL2_ETSIC, "VE", "VENEZUELA", YES, NO, YES, YES, - YES, YES, NO, 7000}, - {CTRY_VIET_NAM, NULL1_WORLD, "VN", "VIET NAM", YES, NO, YES, YES, - YES, NO, NO, 7000}, - {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN", YES, NO, YES, YES, YES, - NO, NO, 7000}, - {CTRY_ZIMBABWE, NULL1_WORLD, "ZW", "ZIMBABWE", YES, NO, YES, YES, - YES, NO, NO, 7000} -}; - -enum { - NO_DFS = 0x0000000000000000ULL, - DFS_FCC3 = 0x0000000000000001ULL, - DFS_ETSI = 0x0000000000000002ULL, - DFS_MKK4 = 0x0000000000000004ULL, -}; - -enum { - F1_4915_4925, - F1_4935_4945, - F1_4920_4980, - F1_4942_4987, - F1_4945_4985, - F1_4950_4980, - F1_5035_5040, - F1_5040_5080, - F1_5055_5055, - - F1_5120_5240, - - F1_5170_5230, - F2_5170_5230, - - F1_5180_5240, - F2_5180_5240, - F3_5180_5240, - F4_5180_5240, - F5_5180_5240, - F6_5180_5240, - F7_5180_5240, - F8_5180_5240, - - F1_5180_5320, - - F1_5240_5280, - - F1_5260_5280, - - F1_5260_5320, - F2_5260_5320, - F3_5260_5320, - F4_5260_5320, - F5_5260_5320, - F6_5260_5320, - - F1_5260_5700, - - F1_5280_5320, - - F1_5500_5580, - - F1_5500_5620, - - F1_5500_5700, - F2_5500_5700, - F3_5500_5700, - F4_5500_5700, - F5_5500_5700, - - F1_5660_5700, - - F1_5745_5805, - F2_5745_5805, - F3_5745_5805, - - F1_5745_5825, - F2_5745_5825, - F3_5745_5825, - F4_5745_5825, - F5_5745_5825, - F6_5745_5825, - - W1_4920_4980, - W1_5040_5080, - W1_5170_5230, - W1_5180_5240, - W1_5260_5320, - W1_5745_5825, - W1_5500_5700, - A_DEMO_ALL_CHANNELS -}; - -static struct RegDmnFreqBand regDmn5GhzFreq[] = { - {4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, - {4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, - {4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7}, - {4942, 4987, 27, 6, 5, 5, NO_DFS, PSCAN_FCC, 0}, - {4945, 4985, 30, 6, 10, 5, NO_DFS, PSCAN_FCC, 0}, - {4950, 4980, 33, 6, 20, 5, NO_DFS, PSCAN_FCC, 0}, - {5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, - {5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2}, - {5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, - - {5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, - - {5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1}, - {5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1}, - - {5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0}, - {5180, 5240, 17, 6, 20, 20, NO_DFS, NO_PSCAN, 1}, - {5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0}, - {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0}, - {5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0}, - {5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 0}, - {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK3, 0}, - {5180, 5240, 23, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, - - {5180, 5320, 20, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, - - {5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0}, - - {5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI, - PSCAN_FCC | PSCAN_ETSI, 0}, - - {5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI, - PSCAN_FCC | PSCAN_ETSI, 0}, - - {5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, - PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3, 0}, - - - {5260, 5320, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, - PSCAN_FCC | PSCAN_ETSI, 2}, - {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2}, - {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0}, - {5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, - - {5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0}, - - {5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0}, - - {5500, 5580, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0}, - - {5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0}, - - {5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4}, - {5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI, - PSCAN_FCC | PSCAN_ETSI, 0}, - {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, - PSCAN_FCC | PSCAN_ETSI, 0}, - {5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, - PSCAN_MKK3 | PSCAN_FCC, 0}, - {5500, 5700, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0}, - - {5660, 5700, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0}, - - {5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5805, 30, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, - {5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5825, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, - {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3}, - {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, - - - {4920, 4980, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, - {5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, - {5170, 5230, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, - {5180, 5240, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, - {5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, - {5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, - {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, - {4920, 6100, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, -}; - -enum { - T1_5130_5650, - T1_5150_5670, - - T1_5200_5200, - T2_5200_5200, - T3_5200_5200, - T4_5200_5200, - T5_5200_5200, - T6_5200_5200, - T7_5200_5200, - T8_5200_5200, - - T1_5200_5280, - T2_5200_5280, - T3_5200_5280, - T4_5200_5280, - T5_5200_5280, - T6_5200_5280, - - T1_5200_5240, - T1_5210_5210, - T2_5210_5210, - T3_5210_5210, - T4_5210_5210, - T5_5210_5210, - T6_5210_5210, - T7_5210_5210, - T8_5210_5210, - T9_5210_5210, - T10_5210_5210, - T1_5240_5240, - - T1_5210_5250, - T1_5210_5290, - T2_5210_5290, - T3_5210_5290, - - T1_5280_5280, - T2_5280_5280, - T1_5290_5290, - T2_5290_5290, - T3_5290_5290, - T1_5250_5290, - T2_5250_5290, - T3_5250_5290, - T4_5250_5290, - - T1_5540_5660, - T2_5540_5660, - T3_5540_5660, - T1_5760_5800, - T2_5760_5800, - T3_5760_5800, - T4_5760_5800, - T5_5760_5800, - T6_5760_5800, - T7_5760_5800, - - T1_5765_5805, - T2_5765_5805, - T3_5765_5805, - T4_5765_5805, - T5_5765_5805, - T6_5765_5805, - T7_5765_5805, - T8_5765_5805, - T9_5765_5805, - - WT1_5210_5250, - WT1_5290_5290, - WT1_5540_5660, - WT1_5760_5800, -}; - -enum { - F1_2312_2372, - F2_2312_2372, - - F1_2412_2472, - F2_2412_2472, - F3_2412_2472, - - F1_2412_2462, - F2_2412_2462, - - F1_2432_2442, - - F1_2457_2472, - - F1_2467_2472, - - F1_2484_2484, - F2_2484_2484, - - F1_2512_2732, - - W1_2312_2372, - W1_2412_2412, - W1_2417_2432, - W1_2437_2442, - W1_2447_2457, - W1_2462_2462, - W1_2467_2467, - W2_2467_2467, - W1_2472_2472, - W2_2472_2472, - W1_2484_2484, - W2_2484_2484, -}; - -static struct RegDmnFreqBand regDmn2GhzFreq[] = { - {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, - {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, - - {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0}, - - {2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2484, 2484, 20, 0, 20, 5, NO_DFS, - PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0}, - - {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, - {2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, - {2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, - {2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, - {2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, - {2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, -}; - -enum { - G1_2312_2372, - G2_2312_2372, - - G1_2412_2472, - G2_2412_2472, - G3_2412_2472, - - G1_2412_2462, - G2_2412_2462, - - G1_2432_2442, - - G1_2457_2472, - - G1_2512_2732, - - G1_2467_2472, - - WG1_2312_2372, - WG1_2412_2462, - WG1_2467_2472, - WG2_2467_2472, - G_DEMO_ALL_CHANNELS -}; - -static struct RegDmnFreqBand regDmn2Ghz11gFreq[] = { - {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, - {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0}, - - {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, - - {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0}, - - {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2412, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, - {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, - {2467, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, - {2312, 2732, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, -}; - -enum { - T1_2312_2372, - T1_2437_2437, - T2_2437_2437, - T3_2437_2437, - T1_2512_2732 + {CTRY_DEBUG, NO_ENUMRD, "DB"}, + {CTRY_DEFAULT, FCC1_FCCA, "CO"}, + {CTRY_ALBANIA, NULL1_WORLD, "AL"}, + {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, + {CTRY_ARGENTINA, APL3_WORLD, "AR"}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, + {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, + {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHRAIN, APL6_WORLD, "BH"}, + {CTRY_BELARUS, ETSI1_WORLD, "BY"}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, + {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, + {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, + {CTRY_BRAZIL, FCC3_WORLD, "BR"}, + {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, + {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, + {CTRY_CANADA, FCC2_FCCA, "CA"}, + {CTRY_CANADA2, FCC6_FCCA, "CA"}, + {CTRY_CHILE, APL6_WORLD, "CL"}, + {CTRY_CHINA, APL1_WORLD, "CN"}, + {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, + {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, + {CTRY_CROATIA, ETSI3_WORLD, "HR"}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, + {CTRY_CZECH, ETSI3_WORLD, "CZ"}, + {CTRY_DENMARK, ETSI1_WORLD, "DK"}, + {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"}, + {CTRY_ECUADOR, FCC1_WORLD, "EC"}, + {CTRY_EGYPT, ETSI3_WORLD, "EG"}, + {CTRY_EL_SALVADOR, FCC1_WORLD, "SV"}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE"}, + {CTRY_FINLAND, ETSI1_WORLD, "FI"}, + {CTRY_FRANCE, ETSI1_WORLD, "FR"}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE"}, + {CTRY_GERMANY, ETSI1_WORLD, "DE"}, + {CTRY_GREECE, ETSI1_WORLD, "GR"}, + {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, + {CTRY_HONDURAS, NULL1_WORLD, "HN"}, + {CTRY_HONG_KONG, FCC2_WORLD, "HK"}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, + {CTRY_ICELAND, ETSI1_WORLD, "IS"}, + {CTRY_INDIA, APL6_WORLD, "IN"}, + {CTRY_INDONESIA, APL1_WORLD, "ID"}, + {CTRY_IRAN, APL1_WORLD, "IR"}, + {CTRY_IRELAND, ETSI1_WORLD, "IE"}, + {CTRY_ISRAEL, NULL1_WORLD, "IL"}, + {CTRY_ITALY, ETSI1_WORLD, "IT"}, + {CTRY_JAMAICA, ETSI1_WORLD, "JM"}, + + {CTRY_JAPAN, MKK1_MKKA, "JP"}, + {CTRY_JAPAN1, MKK1_MKKB, "JP"}, + {CTRY_JAPAN2, MKK1_FCCA, "JP"}, + {CTRY_JAPAN3, MKK2_MKKA, "JP"}, + {CTRY_JAPAN4, MKK1_MKKA1, "JP"}, + {CTRY_JAPAN5, MKK1_MKKA2, "JP"}, + {CTRY_JAPAN6, MKK1_MKKC, "JP"}, + {CTRY_JAPAN7, MKK3_MKKB, "JP"}, + {CTRY_JAPAN8, MKK3_MKKA2, "JP"}, + {CTRY_JAPAN9, MKK3_MKKC, "JP"}, + {CTRY_JAPAN10, MKK4_MKKB, "JP"}, + {CTRY_JAPAN11, MKK4_MKKA2, "JP"}, + {CTRY_JAPAN12, MKK4_MKKC, "JP"}, + {CTRY_JAPAN13, MKK5_MKKB, "JP"}, + {CTRY_JAPAN14, MKK5_MKKA2, "JP"}, + {CTRY_JAPAN15, MKK5_MKKC, "JP"}, + {CTRY_JAPAN16, MKK6_MKKB, "JP"}, + {CTRY_JAPAN17, MKK6_MKKA2, "JP"}, + {CTRY_JAPAN18, MKK6_MKKC, "JP"}, + {CTRY_JAPAN19, MKK7_MKKB, "JP"}, + {CTRY_JAPAN20, MKK7_MKKA2, "JP"}, + {CTRY_JAPAN21, MKK7_MKKC, "JP"}, + {CTRY_JAPAN22, MKK8_MKKB, "JP"}, + {CTRY_JAPAN23, MKK8_MKKA2, "JP"}, + {CTRY_JAPAN24, MKK8_MKKC, "JP"}, + {CTRY_JAPAN25, MKK3_MKKA, "JP"}, + {CTRY_JAPAN26, MKK3_MKKA1, "JP"}, + {CTRY_JAPAN27, MKK3_FCCA, "JP"}, + {CTRY_JAPAN28, MKK4_MKKA1, "JP"}, + {CTRY_JAPAN29, MKK4_FCCA, "JP"}, + {CTRY_JAPAN30, MKK6_MKKA1, "JP"}, + {CTRY_JAPAN31, MKK6_FCCA, "JP"}, + {CTRY_JAPAN32, MKK7_MKKA1, "JP"}, + {CTRY_JAPAN33, MKK7_FCCA, "JP"}, + {CTRY_JAPAN34, MKK9_MKKA, "JP"}, + {CTRY_JAPAN35, MKK10_MKKA, "JP"}, + {CTRY_JAPAN36, MKK4_MKKA, "JP"}, + {CTRY_JAPAN37, MKK9_FCCA, "JP"}, + {CTRY_JAPAN38, MKK9_MKKA1, "JP"}, + {CTRY_JAPAN39, MKK9_MKKC, "JP"}, + {CTRY_JAPAN40, MKK9_MKKA2, "JP"}, + {CTRY_JAPAN41, MKK10_FCCA, "JP"}, + {CTRY_JAPAN42, MKK10_MKKA1, "JP"}, + {CTRY_JAPAN43, MKK10_MKKC, "JP"}, + {CTRY_JAPAN44, MKK10_MKKA2, "JP"}, + {CTRY_JAPAN45, MKK11_MKKA, "JP"}, + {CTRY_JAPAN46, MKK11_FCCA, "JP"}, + {CTRY_JAPAN47, MKK11_MKKA1, "JP"}, + {CTRY_JAPAN48, MKK11_MKKC, "JP"}, + {CTRY_JAPAN49, MKK11_MKKA2, "JP"}, + {CTRY_JAPAN50, MKK12_MKKA, "JP"}, + {CTRY_JAPAN51, MKK12_FCCA, "JP"}, + {CTRY_JAPAN52, MKK12_MKKA1, "JP"}, + {CTRY_JAPAN53, MKK12_MKKC, "JP"}, + {CTRY_JAPAN54, MKK12_MKKA2, "JP"}, + {CTRY_JAPAN57, MKK13_MKKB, "JP"}, + {CTRY_JAPAN58, MKK14_MKKA1, "JP"}, + {CTRY_JAPAN59, MKK15_MKKA1, "JP"}, + + {CTRY_JORDAN, ETSI2_WORLD, "JO"}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"}, + {CTRY_KOREA_NORTH, APL9_WORLD, "KP"}, + {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, + {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, + {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, + {CTRY_KUWAIT, NULL1_WORLD, "KW"}, + {CTRY_LATVIA, ETSI1_WORLD, "LV"}, + {CTRY_LEBANON, NULL1_WORLD, "LB"}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT"}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, + {CTRY_MACAU, FCC2_WORLD, "MO"}, + {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, + {CTRY_MALAYSIA, APL8_WORLD, "MY"}, + {CTRY_MALTA, ETSI1_WORLD, "MT"}, + {CTRY_MEXICO, FCC1_FCCA, "MX"}, + {CTRY_MONACO, ETSI4_WORLD, "MC"}, + {CTRY_MOROCCO, NULL1_WORLD, "MA"}, + {CTRY_NEPAL, APL1_WORLD, "NP"}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, + {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, + {CTRY_NORWAY, ETSI1_WORLD, "NO"}, + {CTRY_OMAN, APL6_WORLD, "OM"}, + {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, + {CTRY_PANAMA, FCC1_FCCA, "PA"}, + {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, + {CTRY_PERU, APL1_WORLD, "PE"}, + {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, + {CTRY_POLAND, ETSI1_WORLD, "PL"}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, + {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, + {CTRY_QATAR, NULL1_WORLD, "QA"}, + {CTRY_ROMANIA, NULL1_WORLD, "RO"}, + {CTRY_RUSSIA, NULL1_WORLD, "RU"}, + {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, + {CTRY_SINGAPORE, APL6_WORLD, "SG"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI"}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"}, + {CTRY_SPAIN, ETSI1_WORLD, "ES"}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK"}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE"}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, + {CTRY_SYRIA, NULL1_WORLD, "SY"}, + {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_THAILAND, NULL1_WORLD, "TH"}, + {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, + {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UKRAINE, NULL1_WORLD, "UA"}, + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, + /* This "PS" is for US public safety actually... to support this we + * would need to assign new special alpha2 to CRDA db as with the world + * regdomain and use another alpha2 */ + {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, + {CTRY_URUGUAY, APL2_WORLD, "UY"}, + {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, + {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, + {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, + {CTRY_YEMEN, NULL1_WORLD, "YE"}, + {CTRY_ZIMBABWE, NULL1_WORLD, "ZW"}, }; -static struct regDomain regDomains[] = { - - {DEBUG_REG_DMN, FCC, DFS_FCC3, NO_PSCAN, NO_REQ, - BM(A_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5130_5650, T1_5150_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5200_5240, T1_5280_5280, T1_5540_5660, T1_5765_5805, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(F1_2312_2372, F1_2412_2472, F1_2484_2484, F1_2512_2732, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(G_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_2312_2372, T1_2437_2437, T1_2512_2732, -1, -1, -1, -1, -1, - -1, -1, -1, -1)}, - - {APL1, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL2, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F1_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL3, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F1_5280_5320, F2_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5290_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL4, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F4_5180_5240, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5210_5210, T3_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5200_5200, T3_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL5, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F2_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T4_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T4_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL6, ETSI, DFS_ETSI, PSCAN_FCC_T | PSCAN_FCC, NO_REQ, - BM(F4_5180_5240, F2_5260_5320, F3_5745_5825, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T2_5210_5210, T1_5250_5290, T1_5760_5800, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T1_5200_5280, T5_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL7, ETSI, DFS_ETSI, PSCAN_ETSI, NO_REQ, - BM(F1_5280_5320, F5_5500_5700, F3_5745_5805, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL8, ETSI, NO_DFS, NO_PSCAN, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F6_5260_5320, F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T2_5290_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL9, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F1_5180_5320, F1_5500_5620, F3_5745_5805, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {APL10, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F1_5180_5320, F5_5500_5700, F3_5745_5805, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI1, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F4_5180_5240, F2_5260_5320, F2_5500_5700, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_5200_5280, T2_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI2, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F3_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI3, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI4, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F3_5180_5240, F1_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T2_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI5, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F1_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T4_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {ETSI6, ETSI, DFS_ETSI, PSCAN_ETSI, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F5_5180_5240, F1_5260_5280, F3_5500_5700, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T1_5210_5250, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T4_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC1, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F2_5180_5240, F4_5260_5320, F5_5745_5825, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T6_5210_5210, T2_5250_5290, T6_5760_5800, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T1_5200_5240, T2_5280_5280, T7_5765_5805, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC2, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F6_5180_5240, F5_5260_5320, F6_5745_5825, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1, - -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC3, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, - BM(F2_5180_5240, F3_5260_5320, F1_5500_5700, F5_5745_5825, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T4_5200_5200, T8_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC4, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, - BM(F1_4942_4987, F1_4945_4985, F1_4950_4980, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T8_5210_5210, T4_5250_5290, T7_5760_5800, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T1_5200_5240, T1_5280_5280, T9_5765_5805, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC5, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BM(F2_5180_5240, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T8_5200_5200, T7_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - {FCC6, FCC, DFS_FCC3, PSCAN_FCC, NO_REQ, - BM(F8_5180_5240, F5_5260_5320, F1_5500_5580, F1_5660_5700, - F6_5745_5825, -1, -1, -1, -1, -1, -1, -1), - BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1, - -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {MKK1, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, - BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - {MKK2, MKK, NO_DFS, PSCAN_MKK2, DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5055_5055, F1_5040_5080, F1_5170_5230, F4_5180_5240, - F2_5260_5320, F4_5500_5700, -1, -1), - BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK3, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, - BM(F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK4, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, - BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T10_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK5, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, - BM(F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK6, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, - BM(F2_5170_5230, F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK7, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, - DISALLOW_ADHOC_11A_TURB, - BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T5_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK8, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, - DISALLOW_ADHOC_11A_TURB, - BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK9, MKK, NO_DFS, PSCAN_MKK2 | PSCAN_MKK3, - DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5055_5055, F1_5040_5080, F4_5180_5240, -1, -1, -1, -1, -1), - BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK10, MKK, DFS_MKK4, PSCAN_MKK2 | PSCAN_MKK3, - DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, -1, -1, - -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK11, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, - F4_5500_5700, -1, -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK12, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, - DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5055_5055, F1_5040_5080, F1_5170_5230, F4_5180_5240, - F2_5260_5320, F4_5500_5700, -1, -1), - BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO}, - - - {MKK13, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BM(F1_5170_5230, F7_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, - -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO, - BMZERO, - BMZERO}, - - - {MKK14, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5040_5080, F1_5055_5055, F1_5170_5230, F4_5180_5240, -1, -1, - -1, -1), - BMZERO, - BMZERO, - BMZERO, - BMZERO, - BMZERO}, - - - {MKK15, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, - BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, - F1_5040_5080, F1_5055_5055, F1_5170_5230, F4_5180_5240, - F2_5260_5320, -1, -1, -1), - BMZERO, - BMZERO, - BMZERO, - BMZERO, - BMZERO}, - - - {APLD, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, - BMZERO, - BMZERO, - BMZERO, - BM(F2_2312_2372, F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(G2_2312_2372, G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BMZERO}, - - {ETSIA, NO_CTL, NO_DFS, PSCAN_ETSIA, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BMZERO, - BMZERO, - BMZERO, - BM(F1_2457_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G1_2457_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {ETSIB, ETSI, NO_DFS, PSCAN_ETSIB, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BMZERO, - BMZERO, - BMZERO, - BM(F1_2432_2442, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G1_2432_2442, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {ETSIC, ETSI, NO_DFS, PSCAN_ETSIC, - DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, - BMZERO, - BMZERO, - BMZERO, - BM(F3_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G3_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {FCCA, FCC, NO_DFS, NO_PSCAN, NO_REQ, - BMZERO, - BMZERO, - BMZERO, - BM(F1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {MKKA, MKK, NO_DFS, - PSCAN_MKKA | PSCAN_MKKA_G | PSCAN_MKKA1 | PSCAN_MKKA1_G | - PSCAN_MKKA2 | PSCAN_MKKA2_G, DISALLOW_ADHOC_11A_TURB, - BMZERO, - BMZERO, - BMZERO, - BM(F2_2412_2462, F1_2467_2472, F2_2484_2484, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(G2_2412_2462, G1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {MKKC, MKK, NO_DFS, NO_PSCAN, NO_REQ, - BMZERO, - BMZERO, - BMZERO, - BM(F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WORLD, ETSI, NO_DFS, NO_PSCAN, NO_REQ, - BMZERO, - BMZERO, - BMZERO, - BM(F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR0_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, - -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR01_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, - ADHOC_PER_11D, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, - W1_2447_2457, -1, -1, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR02_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, - ADHOC_PER_11D, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {EU1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W2_2472_2472, - W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG2_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, - -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR2_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, - W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, - -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR3_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, - BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG2_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR4_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, - W1_2447_2457, -1, -1, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR5_ETSIC, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BMZERO, - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WOR9_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, - -1, -1, -1, -1, -1, -1), - BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, - -1, -1, -1, -1, -1), - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, - W1_2447_2457, -1, -1, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WORA_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, - -1, -1, -1, -1, -1, -1), - BMZERO, - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {WORB_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, - BM(W1_5260_5320, W1_5180_5240, W1_5500_5700, -1, -1, -1, -1, -1, - -1, -1, -1, -1), - BMZERO, - BMZERO, - BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, - W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), - BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1), - BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, - - {NULL1, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, - BMZERO, - BMZERO, - BMZERO, - BMZERO, - BMZERO, - BMZERO} -}; - -static const struct cmode modes[] = { - {ATH9K_MODE_11A, CHANNEL_A}, - {ATH9K_MODE_11B, CHANNEL_B}, - {ATH9K_MODE_11G, CHANNEL_G}, - {ATH9K_MODE_11NG_HT20, CHANNEL_G_HT20}, - {ATH9K_MODE_11NG_HT40PLUS, CHANNEL_G_HT40PLUS}, - {ATH9K_MODE_11NG_HT40MINUS, CHANNEL_G_HT40MINUS}, - {ATH9K_MODE_11NA_HT20, CHANNEL_A_HT20}, - {ATH9K_MODE_11NA_HT40PLUS, CHANNEL_A_HT40PLUS}, - {ATH9K_MODE_11NA_HT40MINUS, CHANNEL_A_HT40MINUS}, -}; - -static struct japan_bandcheck j_bandcheck[] = { - {F1_5170_5230, AR_EEPROM_EEREGCAP_EN_KK_U1_ODD}, - {F4_5180_5240, AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN}, - {F2_5260_5320, AR_EEPROM_EEREGCAP_EN_KK_U2}, - {F4_5500_5700, AR_EEPROM_EEREGCAP_EN_KK_MIDBAND} -}; - - #endif diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c new file mode 100644 index 000000000000..1ff429b027d7 --- /dev/null +++ b/drivers/net/wireless/ath9k/virtual.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +struct ath9k_vif_iter_data { + int count; + u8 *addr; +}; + +static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath9k_vif_iter_data *iter_data = data; + u8 *nbuf; + + nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN, + GFP_ATOMIC); + if (nbuf == NULL) + return; + + memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN); + iter_data->addr = nbuf; + iter_data->count++; +} + +void ath9k_set_bssid_mask(struct ieee80211_hw *hw) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath9k_vif_iter_data iter_data; + int i, j; + u8 mask[ETH_ALEN]; + + /* + * Add primary MAC address even if it is not in active use since it + * will be configured to the hardware as the starting point and the + * BSSID mask will need to be changed if another address is active. + */ + iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); + if (iter_data.addr) { + memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); + iter_data.count = 1; + } else + iter_data.count = 0; + + /* Get list of all active MAC addresses */ + spin_lock_bh(&sc->wiphy_lock); + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, + &iter_data); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] == NULL) + continue; + ieee80211_iterate_active_interfaces_atomic( + sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); + } + spin_unlock_bh(&sc->wiphy_lock); + + /* Generate an address mask to cover all active addresses */ + memset(mask, 0, ETH_ALEN); + for (i = 0; i < iter_data.count; i++) { + u8 *a1 = iter_data.addr + i * ETH_ALEN; + for (j = i + 1; j < iter_data.count; j++) { + u8 *a2 = iter_data.addr + j * ETH_ALEN; + mask[0] |= a1[0] ^ a2[0]; + mask[1] |= a1[1] ^ a2[1]; + mask[2] |= a1[2] ^ a2[2]; + mask[3] |= a1[3] ^ a2[3]; + mask[4] |= a1[4] ^ a2[4]; + mask[5] |= a1[5] ^ a2[5]; + } + } + + kfree(iter_data.addr); + + /* Invert the mask and configure hardware */ + sc->bssidmask[0] = ~mask[0]; + sc->bssidmask[1] = ~mask[1]; + sc->bssidmask[2] = ~mask[2]; + sc->bssidmask[3] = ~mask[3]; + sc->bssidmask[4] = ~mask[4]; + sc->bssidmask[5] = ~mask[5]; + + ath9k_hw_setbssidmask(sc); +} + +int ath9k_wiphy_add(struct ath_softc *sc) +{ + int i, error; + struct ath_wiphy *aphy; + struct ieee80211_hw *hw; + u8 addr[ETH_ALEN]; + + hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); + if (hw == NULL) + return -ENOMEM; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] == NULL) + break; + } + + if (i == sc->num_sec_wiphy) { + /* No empty slot available; increase array length */ + struct ath_wiphy **n; + n = krealloc(sc->sec_wiphy, + (sc->num_sec_wiphy + 1) * + sizeof(struct ath_wiphy *), + GFP_ATOMIC); + if (n == NULL) { + spin_unlock_bh(&sc->wiphy_lock); + ieee80211_free_hw(hw); + return -ENOMEM; + } + n[i] = NULL; + sc->sec_wiphy = n; + sc->num_sec_wiphy++; + } + + SET_IEEE80211_DEV(hw, sc->dev); + + aphy = hw->priv; + aphy->sc = sc; + aphy->hw = hw; + sc->sec_wiphy[i] = aphy; + spin_unlock_bh(&sc->wiphy_lock); + + memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); + addr[0] |= 0x02; /* Locally managed address */ + /* + * XOR virtual wiphy index into the least significant bits to generate + * a different MAC address for each virtual wiphy. + */ + addr[5] ^= i & 0xff; + addr[4] ^= (i & 0xff00) >> 8; + addr[3] ^= (i & 0xff0000) >> 16; + + SET_IEEE80211_PERM_ADDR(hw, addr); + + ath_set_hw_capab(sc, hw); + + error = ieee80211_register_hw(hw); + + if (error == 0) { + /* Make sure wiphy scheduler is started (if enabled) */ + ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); + } + + return error; +} + +int ath9k_wiphy_del(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + int i; + + spin_lock_bh(&sc->wiphy_lock); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (aphy == sc->sec_wiphy[i]) { + sc->sec_wiphy[i] = NULL; + spin_unlock_bh(&sc->wiphy_lock); + ieee80211_unregister_hw(aphy->hw); + ieee80211_free_hw(aphy->hw); + return 0; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return -ENOENT; +} + +static int ath9k_send_nullfunc(struct ath_wiphy *aphy, + struct ieee80211_vif *vif, const u8 *bssid, + int ps) +{ + struct ath_softc *sc = aphy->sc; + struct ath_tx_control txctl; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + __le16 fc; + struct ieee80211_tx_info *info; + + skb = dev_alloc_skb(24); + if (skb == NULL) + return -ENOMEM; + hdr = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(hdr, 0, 24); + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + if (ps) + fc |= cpu_to_le16(IEEE80211_FCTL_PM); + hdr->frame_control = fc; + memcpy(hdr->addr1, bssid, ETH_ALEN); + memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr3, bssid, ETH_ALEN); + + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; + info->control.vif = vif; + info->control.rates[0].idx = 0; + info->control.rates[0].count = 4; + info->control.rates[1].idx = -1; + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; + txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; + + if (ath_tx_start(aphy->hw, skb, &txctl) != 0) + goto exit; + + return 0; +exit: + dev_kfree_skb_any(skb); + return -1; +} + +static bool __ath9k_wiphy_pausing(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) + return true; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) + return true; + } + return false; +} + +static bool ath9k_wiphy_pausing(struct ath_softc *sc) +{ + bool ret; + spin_lock_bh(&sc->wiphy_lock); + ret = __ath9k_wiphy_pausing(sc); + spin_unlock_bh(&sc->wiphy_lock); + return ret; +} + +static bool __ath9k_wiphy_scanning(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) + return true; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) + return true; + } + return false; +} + +bool ath9k_wiphy_scanning(struct ath_softc *sc) +{ + bool ret; + spin_lock_bh(&sc->wiphy_lock); + ret = __ath9k_wiphy_scanning(sc); + spin_unlock_bh(&sc->wiphy_lock); + return ret; +} + +static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); + +/* caller must hold wiphy_lock */ +static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) +{ + if (aphy == NULL) + return; + if (aphy->chan_idx != aphy->sc->chan_idx) + return; /* wiphy not on the selected channel */ + __ath9k_wiphy_unpause(aphy); +} + +static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + __ath9k_wiphy_unpause_ch(sc->pri_wiphy); + for (i = 0; i < sc->num_sec_wiphy; i++) + __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); + spin_unlock_bh(&sc->wiphy_lock); +} + +void ath9k_wiphy_chan_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); + struct ath_wiphy *aphy = sc->next_wiphy; + + if (aphy == NULL) + return; + + /* + * All pending interfaces paused; ready to change + * channels. + */ + + /* Change channels */ + mutex_lock(&sc->mutex); + /* XXX: remove me eventually */ + ath9k_update_ichannel(sc, aphy->hw, + &sc->sc_ah->channels[sc->chan_idx]); + ath_update_chainmask(sc, sc->chan_is_ht); + if (ath_set_channel(sc, aphy->hw, + &sc->sc_ah->channels[sc->chan_idx]) < 0) { + printk(KERN_DEBUG "ath9k: Failed to set channel for new " + "virtual wiphy\n"); + mutex_unlock(&sc->mutex); + return; + } + mutex_unlock(&sc->mutex); + + ath9k_wiphy_unpause_channel(sc); +} + +/* + * ath9k version of ieee80211_tx_status() for TX frames that are generated + * internally in the driver. + */ +void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath_wiphy *aphy = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && + aphy->state == ATH_WIPHY_PAUSING) { + if (!(info->flags & IEEE80211_TX_STAT_ACK)) { + printk(KERN_DEBUG "ath9k: %s: no ACK for pause " + "frame\n", wiphy_name(hw->wiphy)); + /* + * The AP did not reply; ignore this to allow us to + * continue. + */ + } + aphy->state = ATH_WIPHY_PAUSED; + if (!ath9k_wiphy_pausing(aphy->sc)) { + /* + * Drop from tasklet to work to allow mutex for channel + * change. + */ + queue_work(aphy->sc->hw->workqueue, + &aphy->sc->chan_work); + } + } + + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + + dev_kfree_skb(skb); +} + +static void ath9k_mark_paused(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + aphy->state = ATH_WIPHY_PAUSED; + if (!__ath9k_wiphy_pausing(sc)) + queue_work(sc->hw->workqueue, &sc->chan_work); +} + +static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_wiphy *aphy = data; + struct ath_vif *avp = (void *) vif->drv_priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) { + ath9k_mark_paused(aphy); + break; + } + /* TODO: could avoid this if already in PS mode */ + if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { + printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", + __func__); + ath9k_mark_paused(aphy); + } + break; + case NL80211_IFTYPE_AP: + /* Beacon transmission is paused by aphy->state change */ + ath9k_mark_paused(aphy); + break; + default: + break; + } +} + +/* caller must hold wiphy_lock */ +static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) +{ + ieee80211_stop_queues(aphy->hw); + aphy->state = ATH_WIPHY_PAUSING; + /* + * TODO: handle PAUSING->PAUSED for the case where there are multiple + * active vifs (now we do it on the first vif getting ready; should be + * on the last) + */ + ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, + aphy); + return 0; +} + +int ath9k_wiphy_pause(struct ath_wiphy *aphy) +{ + int ret; + spin_lock_bh(&aphy->sc->wiphy_lock); + ret = __ath9k_wiphy_pause(aphy); + spin_unlock_bh(&aphy->sc->wiphy_lock); + return ret; +} + +static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_wiphy *aphy = data; + struct ath_vif *avp = (void *) vif->drv_priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) + break; + ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); + break; + case NL80211_IFTYPE_AP: + /* Beacon transmission is re-enabled by aphy->state change */ + break; + default: + break; + } +} + +/* caller must hold wiphy_lock */ +static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) +{ + ieee80211_iterate_active_interfaces_atomic(aphy->hw, + ath9k_unpause_iter, aphy); + aphy->state = ATH_WIPHY_ACTIVE; + ieee80211_wake_queues(aphy->hw); + return 0; +} + +int ath9k_wiphy_unpause(struct ath_wiphy *aphy) +{ + int ret; + spin_lock_bh(&aphy->sc->wiphy_lock); + ret = __ath9k_wiphy_unpause(aphy); + spin_unlock_bh(&aphy->sc->wiphy_lock); + return ret; +} + +static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) + sc->pri_wiphy->state = ATH_WIPHY_PAUSED; + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) + sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; + } +} + +/* caller must hold wiphy_lock */ +static void __ath9k_wiphy_pause_all(struct ath_softc *sc) +{ + int i; + if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) + __ath9k_wiphy_pause(sc->pri_wiphy); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) + __ath9k_wiphy_pause(sc->sec_wiphy[i]); + } +} + +int ath9k_wiphy_select(struct ath_wiphy *aphy) +{ + struct ath_softc *sc = aphy->sc; + bool now; + + spin_lock_bh(&sc->wiphy_lock); + if (__ath9k_wiphy_scanning(sc)) { + /* + * For now, we are using mac80211 sw scan and it expects to + * have full control over channel changes, so avoid wiphy + * scheduling during a scan. This could be optimized if the + * scanning control were moved into the driver. + */ + spin_unlock_bh(&sc->wiphy_lock); + return -EBUSY; + } + if (__ath9k_wiphy_pausing(sc)) { + if (sc->wiphy_select_failures == 0) + sc->wiphy_select_first_fail = jiffies; + sc->wiphy_select_failures++; + if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) + { + printk(KERN_DEBUG "ath9k: Previous wiphy select timed " + "out; disable/enable hw to recover\n"); + __ath9k_wiphy_mark_all_paused(sc); + /* + * TODO: this workaround to fix hardware is unlikely to + * be specific to virtual wiphy changes. It can happen + * on normal channel change, too, and as such, this + * should really be made more generic. For example, + * tricker radio disable/enable on GTT interrupt burst + * (say, 10 GTT interrupts received without any TX + * frame being completed) + */ + spin_unlock_bh(&sc->wiphy_lock); + ath_radio_disable(sc); + ath_radio_enable(sc); + queue_work(aphy->sc->hw->workqueue, + &aphy->sc->chan_work); + return -EBUSY; /* previous select still in progress */ + } + spin_unlock_bh(&sc->wiphy_lock); + return -EBUSY; /* previous select still in progress */ + } + sc->wiphy_select_failures = 0; + + /* Store the new channel */ + sc->chan_idx = aphy->chan_idx; + sc->chan_is_ht = aphy->chan_is_ht; + sc->next_wiphy = aphy; + + __ath9k_wiphy_pause_all(sc); + now = !__ath9k_wiphy_pausing(aphy->sc); + spin_unlock_bh(&sc->wiphy_lock); + + if (now) { + /* Ready to request channel change immediately */ + queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); + } + + /* + * wiphys will be unpaused in ath9k_tx_status() once channel has been + * changed if any wiphy needs time to become paused. + */ + + return 0; +} + +bool ath9k_wiphy_started(struct ath_softc *sc) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { + spin_unlock_bh(&sc->wiphy_lock); + return true; + } + } + spin_unlock_bh(&sc->wiphy_lock); + return false; +} + +static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, + struct ath_wiphy *selected) +{ + if (selected->state == ATH_WIPHY_SCAN) { + if (aphy == selected) + return; + /* + * Pause all other wiphys for the duration of the scan even if + * they are on the current channel now. + */ + } else if (aphy->chan_idx == selected->chan_idx) + return; + aphy->state = ATH_WIPHY_PAUSED; + ieee80211_stop_queues(aphy->hw); +} + +void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, + struct ath_wiphy *selected) +{ + int i; + spin_lock_bh(&sc->wiphy_lock); + if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); + for (i = 0; i < sc->num_sec_wiphy; i++) { + if (sc->sec_wiphy[i] && + sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) + ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); + } + spin_unlock_bh(&sc->wiphy_lock); +} + +void ath9k_wiphy_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + wiphy_work.work); + struct ath_wiphy *aphy = NULL; + bool first = true; + + spin_lock_bh(&sc->wiphy_lock); + + if (sc->wiphy_scheduler_int == 0) { + /* wiphy scheduler is disabled */ + spin_unlock_bh(&sc->wiphy_lock); + return; + } + +try_again: + sc->wiphy_scheduler_index++; + while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { + aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; + if (aphy && aphy->state != ATH_WIPHY_INACTIVE) + break; + + sc->wiphy_scheduler_index++; + aphy = NULL; + } + if (aphy == NULL) { + sc->wiphy_scheduler_index = 0; + if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { + if (first) { + first = false; + goto try_again; + } + /* No wiphy is ready to be scheduled */ + } else + aphy = sc->pri_wiphy; + } + + spin_unlock_bh(&sc->wiphy_lock); + + if (aphy && + aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && + ath9k_wiphy_select(aphy)) { + printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " + "change\n"); + } + + queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, + sc->wiphy_scheduler_int); +} + +void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) +{ + cancel_delayed_work_sync(&sc->wiphy_work); + sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); + if (sc->wiphy_scheduler_int) + queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, + sc->wiphy_scheduler_int); +} diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index c92f0c6e4adc..689bdbf78808 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "core.h" +#include "ath9k.h" #define BITS_PER_BYTE 8 #define OFDM_PLCP_BITS 22 @@ -55,94 +55,23 @@ static u32 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) -/* - * Insert a chain of ath_buf (descriptors) on a txq and - * assume the descriptors are already chained together by caller. - * NB: must be called with txq lock held - */ - +static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head); +static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct list_head *bf_q, + int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, - struct list_head *head) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf; - - /* - * Insert the frame on the outbound list and - * pass it on to the hardware. - */ - - if (list_empty(head)) - return; - - bf = list_first_entry(head, struct ath_buf, list); - - list_splice_tail_init(head, &txq->axq_q); - txq->axq_depth++; - txq->axq_totalqueued++; - txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - - DPRINTF(sc, ATH_DBG_QUEUE, - "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); - - if (txq->axq_link == NULL) { - ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - DPRINTF(sc, ATH_DBG_XMIT, - "TXDP[%u] = %llx (%p)\n", - txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); - } else { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); - } - txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); - ath9k_hw_txstart(ah, txq->axq_qnum); -} - -static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - int hdrlen, padsize; - - DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - } - - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; - } - - if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } - - tx_info->status.rates[0].count = tx_status->retries + 1; - - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - /* - * Remove MAC header padding before giving the frame back to - * mac80211. - */ - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - ieee80211_tx_status(hw, skb); -} + struct list_head *head); +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok); +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + int nbad, int txok, bool update_rc); -/* Check if it's okay to send out aggregates */ +/*********************/ +/* Aggregation logic */ +/*********************/ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) { @@ -156,232 +85,19 @@ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) return 0; } -static void ath_get_beaconconfig(struct ath_softc *sc, int if_id, - struct ath_beacon_config *conf) -{ - struct ieee80211_hw *hw = sc->hw; - - /* fill in beacon config data */ - - conf->beacon_interval = hw->conf.beacon_int; - conf->listen_interval = 100; - conf->dtim_count = 1; - conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; -} - -/* Calculate Atheros packet type from IEEE80211 packet header */ - -static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - enum ath9k_pkt_type htype; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_beacon(fc)) - htype = ATH9K_PKT_TYPE_BEACON; - else if (ieee80211_is_probe_resp(fc)) - htype = ATH9K_PKT_TYPE_PROBE_RESP; - else if (ieee80211_is_atim(fc)) - htype = ATH9K_PKT_TYPE_ATIM; - else if (ieee80211_is_pspoll(fc)) - htype = ATH9K_PKT_TYPE_PSPOLL; - else - htype = ATH9K_PKT_TYPE_NORMAL; - - return htype; -} - -static bool is_pae(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_data(fc)) { - if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - return true; - } - } - - return false; -} - -static int get_hw_crypto_keytype(struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (tx_info->control.hw_key) { - if (tx_info->control.hw_key->alg == ALG_WEP) - return ATH9K_KEY_TYPE_WEP; - else if (tx_info->control.hw_key->alg == ALG_TKIP) - return ATH9K_KEY_TYPE_TKIP; - else if (tx_info->control.hw_key->alg == ALG_CCMP) - return ATH9K_KEY_TYPE_AES; - } - - return ATH9K_KEY_TYPE_CLEAR; -} - -/* Called only when tx aggregation is enabled and HT is supported */ - -static void assign_aggr_tid_seqno(struct sk_buff *skb, - struct ath_buf *bf) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr; - struct ath_node *an; - struct ath_atx_tid *tid; - __le16 fc; - u8 *qc; - - if (!tx_info->control.sta) - return; - - an = (struct ath_node *)tx_info->control.sta->drv_priv; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - /* Get tidno */ - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - bf->bf_tidno = qc[0] & 0xf; - } - - /* Get seqno */ - /* For HT capable stations, we save tidno for later use. - * We also override seqno set by upper layer with the one - * in tx aggregation state. - * - * If fragmentation is on, the sequence number is - * not overridden, since it has been - * incremented by the fragmentation routine. - * - * FIXME: check if the fragmentation threshold exceeds - * IEEE80211 max. - */ - tid = ATH_AN_2_TID(an, bf->bf_tidno); - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); - bf->bf_seqno = tid->seq_next; - INCR(tid->seq_next, IEEE80211_SEQ_MAX); -} - -static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, - struct ath_txq *txq) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int flags = 0; - - flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ - flags |= ATH9K_TXDESC_INTREQ; - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - flags |= ATH9K_TXDESC_NOACK; - if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - flags |= ATH9K_TXDESC_RTSENA; - - return flags; -} - -static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) -{ - struct ath_buf *bf = NULL; - - spin_lock_bh(&sc->tx.txbuflock); - - if (unlikely(list_empty(&sc->tx.txbuf))) { - spin_unlock_bh(&sc->tx.txbuflock); - return NULL; - } - - bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - list_del(&bf->list); - - spin_unlock_bh(&sc->tx.txbuflock); - - return bf; -} - -/* To complete a chain of buffers associated a frame */ - -static void ath_tx_complete_buf(struct ath_softc *sc, - struct ath_buf *bf, - struct list_head *bf_q, - int txok, int sendbar) -{ - struct sk_buff *skb = bf->bf_mpdu; - struct ath_xmit_status tx_status; - unsigned long flags; - - /* - * Set retry information. - * NB: Don't use the information in the descriptor, because the frame - * could be software retried. - */ - tx_status.retries = bf->bf_retries; - tx_status.flags = 0; - - if (sendbar) - tx_status.flags = ATH_TX_BAR; - - if (!txok) { - tx_status.flags |= ATH_TX_ERROR; - - if (bf_isxretried(bf)) - tx_status.flags |= ATH_TX_XRETRY; - } - - /* Unmap this frame */ - pci_unmap_single(sc->pdev, - bf->bf_dmacontext, - skb->len, - PCI_DMA_TODEVICE); - /* complete this frame */ - ath_tx_complete(sc, skb, &tx_status); - - /* - * Return the list of ath_buf of this mpdu to free queue - */ - spin_lock_irqsave(&sc->tx.txbuflock, flags); - list_splice_tail_init(bf_q, &sc->tx.txbuf); - spin_unlock_irqrestore(&sc->tx.txbuflock, flags); -} - -/* - * queue up a dest/ac pair for tx scheduling - * NB: must be called with txq lock held - */ - static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; - /* - * if tid is paused, hold off - */ if (tid->paused) return; - /* - * add tid to ac atmost once - */ if (tid->sched) return; tid->sched = true; list_add_tail(&tid->list, &ac->tid_q); - /* - * add node ac to txq atmost once - */ if (ac->sched) return; @@ -389,22 +105,16 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) list_add_tail(&ac->list, &txq->axq_acq); } -/* pause a tid */ - static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; spin_lock_bh(&txq->axq_lock); - tid->paused++; - spin_unlock_bh(&txq->axq_lock); } -/* resume a tid and schedule aggregate */ - -void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; @@ -419,63 +129,39 @@ void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) if (list_empty(&tid->buf_q)) goto unlock; - /* - * Add this TID to scheduler and try to send out aggregates - */ ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); unlock: spin_unlock_bh(&txq->axq_lock); } -/* Compute the number of bad frames */ - -static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok) +static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_buf *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; - u16 seq_st = 0; - u32 ba[WME_BA_BMP_SIZE >> 5]; - int ba_index; - int nbad = 0; - int isaggr = 0; - - if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) - return 0; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + struct ath_buf *bf; + struct list_head bf_head; + INIT_LIST_HEAD(&bf_head); - isaggr = bf_isaggr(bf); - if (isaggr) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); - } + ASSERT(tid->paused > 0); + spin_lock_bh(&txq->axq_lock); - while (bf) { - ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno); - if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) - nbad++; + tid->paused--; - bf = bf->bf_next; + if (tid->paused > 0) { + spin_unlock_bh(&txq->axq_lock); + return; } - return nbad; -} - -static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) -{ - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - - bf->bf_state.bf_type |= BUF_RETRY; - bf->bf_retries++; + while (!list_empty(&tid->buf_q)) { + bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + ASSERT(!bf_isretried(bf)); + list_move_tail(&bf->list, &bf_head); + ath_tx_send_ht_normal(sc, txq, tid, &bf_head); + } - skb = bf->bf_mpdu; - hdr = (struct ieee80211_hdr *)skb->data; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); + spin_unlock_bh(&txq->axq_lock); } -/* Update block ack window */ - static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno) { @@ -492,296 +178,150 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } } -/* - * ath_pkt_dur - compute packet duration (NB: not NAV) - * - * rix - rate index - * pktlen - total bytes (delims + data + fcs + pads + pad delims) - * width - 0 for 20 MHz, 1 for 40 MHz - * half_gi - to use 4us v/s 3.6 us for symbol time - */ -static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, - int width, int half_gi, bool shortPreamble) +static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + struct ath_buf *bf) { - struct ath_rate_table *rate_table = sc->cur_rate_table; - u32 nbits, nsymbits, duration, nsymbols; - u8 rc; - int streams, pktlen; - - pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rate_table->info[rix].ratecode; - - /* for legacy rates, use old function to compute packet duration */ - if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, - rix, shortPreamble); + int index, cindex; - /* find number of symbols: PLCP + data */ - nbits = (pktlen << 3) + OFDM_PLCP_BITS; - nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; - nsymbols = (nbits + nsymbits - 1) / nsymbits; + if (bf_isretried(bf)) + return; - if (!half_gi) - duration = SYMBOL_TIME(nsymbols); - else - duration = SYMBOL_TIME_HALFGI(nsymbols); + index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - /* addup duration for legacy/ht training and signal fields */ - streams = HT_RC_2_STREAMS(rc); - duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + ASSERT(tid->tx_buf[cindex] == NULL); + tid->tx_buf[cindex] = bf; - return duration; + if (index >= ((tid->baw_tail - tid->baw_head) & + (ATH_TID_MAX_BUFS - 1))) { + tid->baw_tail = cindex; + INCR(tid->baw_tail, ATH_TID_MAX_BUFS); + } } -/* Rate module function to set rate related fields in tx descriptor */ +/* + * TODO: For frame(s) that are in the retry state, we will reuse the + * sequence number(s) without setting the retry bit. The + * alternative is to give up on these and BAR the receiver's window + * forward. + */ +static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_hal *ah = sc->sc_ah; - struct ath_rate_table *rt; - struct ath_desc *ds = bf->bf_desc; - struct ath_desc *lastds = bf->bf_lastbf->bf_desc; - struct ath9k_11n_rate_series series[4]; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ieee80211_tx_rate *rates; - struct ieee80211_hdr *hdr; - int i, flags, rtsctsena = 0; - u32 ctsduration = 0; - u8 rix = 0, cix, ctsrate = 0; - __le16 fc; - - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - - skb = (struct sk_buff *)bf->bf_mpdu; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->control.rates; - - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - rates[0].count = ATH_TXMAXTRY; - } + struct ath_buf *bf; + struct list_head bf_head; + INIT_LIST_HEAD(&bf_head); - /* get the cix for the lowest valid rix */ - rt = sc->cur_rate_table; - for (i = 3; i >= 0; i--) { - if (rates[i].count && (rates[i].idx >= 0)) { - rix = rates[i].idx; + for (;;) { + if (list_empty(&tid->buf_q)) break; - } - } - - flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)); - cix = rt->info[rix].ctrl_rate; - - /* - * If 802.11g protection is enabled, determine whether to use RTS/CTS or - * just CTS. Note that this is only done for OFDM/HT unicast frames. - */ - if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK) - && (rt->info[rix].phy == WLAN_RC_PHY_OFDM || - WLAN_RC_PHY_HT(rt->info[rix].phy))) { - if (sc->sc_protmode == PROT_M_RTSCTS) - flags = ATH9K_TXDESC_RTSENA; - else if (sc->sc_protmode == PROT_M_CTSONLY) - flags = ATH9K_TXDESC_CTSENA; - - cix = rt->info[sc->sc_protrix].ctrl_rate; - rtsctsena = 1; - } - - /* For 11n, the default behavior is to enable RTS for hw retried frames. - * We enable the global flag here and let rate series flags determine - * which rates will actually use RTS. - */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { - /* 802.11g protection not needed, use our default behavior */ - if (!rtsctsena) - flags = ATH9K_TXDESC_RTSENA; - } - - /* Set protection if aggregate protection on */ - if (sc->sc_config.ath_aggr_prot && - (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { - flags = ATH9K_TXDESC_RTSENA; - cix = rt->info[sc->sc_protrix].ctrl_rate; - rtsctsena = 1; - } - - /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) - flags &= ~(ATH9K_TXDESC_RTSENA); - /* - * CTS transmit rate is derived from the transmit rate by looking in the - * h/w rate table. We must also factor in whether or not a short - * preamble is to be used. NB: cix is set above where RTS/CTS is enabled - */ - ctsrate = rt->info[cix].ratecode | - (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0); - - for (i = 0; i < 4; i++) { - if (!rates[i].count || (rates[i].idx < 0)) - continue; - - rix = rates[i].idx; - - series[i].Rate = rt->info[rix].ratecode | - (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0); - - series[i].Tries = rates[i].count; - - series[i].RateFlags = ( - (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ? - ATH9K_RATESERIES_RTS_CTS : 0) | - ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? - ATH9K_RATESERIES_2040 : 0) | - ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ? - ATH9K_RATESERIES_HALFGI : 0); - - series[i].PktDuration = ath_pkt_duration(sc, rix, bf, - (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, - (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), - bf_isshpreamble(bf)); + bf = list_first_entry(&tid->buf_q, struct ath_buf, list); + list_move_tail(&bf->list, &bf_head); - series[i].ChSel = sc->sc_tx_chainmask; + if (bf_isretried(bf)) + ath_tx_update_baw(sc, tid, bf->bf_seqno); - if (rtsctsena) - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + spin_unlock(&txq->axq_lock); + ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + spin_lock(&txq->axq_lock); } - /* set dur_update_en for l-sig computation except for PS-Poll frames */ - ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf), - ctsrate, ctsduration, - series, 4, flags); - - if (sc->sc_config.ath_aggr_prot && flags) - ath9k_hw_set11n_burstduration(ah, ds, 8192); + tid->seq_next = tid->seq_start; + tid->baw_tail = tid->baw_head; } -/* - * Function to send a normal HT (non-AMPDU) frame - * NB: must be called with txq lock held - */ -static int ath_tx_send_normal(struct ath_softc *sc, - struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head) +static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_buf *bf; - - BUG_ON(list_empty(bf_head)); - - bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ - - /* update starting sequence number for subsequent ADDBA request */ - INCR(tid->seq_start, IEEE80211_SEQ_MAX); + struct sk_buff *skb; + struct ieee80211_hdr *hdr; - /* Queue to h/w without aggregation */ - bf->bf_nframes = 1; - bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); + bf->bf_state.bf_type |= BUF_RETRY; + bf->bf_retries++; - return 0; + skb = bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); } -/* flush tid's software queue and send frames as non-ampdu's */ - -static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) +static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - struct ath_buf *bf; - struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); + struct ath_buf *tbf; - ASSERT(tid->paused > 0); - spin_lock_bh(&txq->axq_lock); + spin_lock_bh(&sc->tx.txbuflock); + ASSERT(!list_empty((&sc->tx.txbuf))); + tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&tbf->list); + spin_unlock_bh(&sc->tx.txbuflock); - tid->paused--; + ATH_TXBUF_RESET(tbf); - if (tid->paused > 0) { - spin_unlock_bh(&txq->axq_lock); - return; - } + tbf->bf_mpdu = bf->bf_mpdu; + tbf->bf_buf_addr = bf->bf_buf_addr; + *(tbf->bf_desc) = *(bf->bf_desc); + tbf->bf_state = bf->bf_state; + tbf->bf_dmacontext = bf->bf_dmacontext; - while (!list_empty(&tid->buf_q)) { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf_isretried(bf)); - list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); - ath_tx_send_normal(sc, txq, tid, &bf_head); - } - - spin_unlock_bh(&txq->axq_lock); + return tbf; } -/* Completion routine of an aggregate */ - -static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, - struct ath_txq *txq, - struct ath_buf *bf, - struct list_head *bf_q, - int txok) +static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf, struct list_head *bf_q, + int txok) { struct ath_node *an = NULL; struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; struct ath_atx_tid *tid = NULL; - struct ath_buf *bf_last = bf->bf_lastbf; + struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; - struct ath_buf *bf_next, *bf_lastq = NULL; struct list_head bf_head, bf_pending; - u16 seq_st = 0; + u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; - int isaggr, txfail, txpending, sendbar = 0, needreset = 0; + int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; + bool rc_update = true; skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); + hdr = (struct ieee80211_hdr *)skb->data; - if (tx_info->control.sta) { - an = (struct ath_node *)tx_info->control.sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); + rcu_read_lock(); + + sta = ieee80211_find_sta(sc->hw, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + return; } + an = (struct ath_node *)sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + isaggr = bf_isaggr(bf); - if (isaggr) { - if (txok) { - if (ATH_DS_TX_BA(ds)) { - /* - * extract starting sequence and - * block-ack bitmap - */ - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, - ATH_DS_BA_BITMAP(ds), - WME_BA_BMP_SIZE >> 3); - } else { - memset(ba, 0, WME_BA_BMP_SIZE >> 3); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); - /* - * AR5416 can become deaf/mute when BA - * issue happens. Chip needs to be reset. - * But AP code may have sychronization issues - * when perform internal reset in this routine. - * Only enable reset in STA mode for now. - */ - if (sc->sc_ah->ah_opmode == - NL80211_IFTYPE_STATION) - needreset = 1; - } + if (isaggr && txok) { + if (ATH_DS_TX_BA(ds)) { + seq_st = ATH_DS_BA_SEQ(ds); + memcpy(ba, ATH_DS_BA_BITMAP(ds), + WME_BA_BMP_SIZE >> 3); } else { - memset(ba, 0, WME_BA_BMP_SIZE >> 3); + /* + * AR5416 can become deaf/mute when BA + * issue happens. Chip needs to be reset. + * But AP code may have sychronization issues + * when perform internal reset in this routine. + * Only enable reset in STA mode for now. + */ + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) + needreset = 1; } } INIT_LIST_HEAD(&bf_pending); INIT_LIST_HEAD(&bf_head); + nbad = ath_tx_num_badfrms(sc, bf, txok); while (bf) { txfail = txpending = 0; bf_next = bf->bf_next; @@ -789,10 +329,11 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { /* transmit completion, subframe is * acked by block ack */ + acked_cnt++; } else if (!isaggr && txok) { /* transmit completion */ + acked_cnt++; } else { - if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { @@ -802,6 +343,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, bf->bf_state.bf_type |= BUF_XRETRY; txfail = 1; sendbar = 1; + txfail_cnt++; } } else { /* @@ -811,37 +353,12 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, txfail = 1; } } - /* - * Remove ath_buf's of this sub-frame from aggregate queue. - */ - if (bf_next == NULL) { /* last subframe in the aggregate */ - ASSERT(bf->bf_lastfrm == bf_last); - - /* - * The last descriptor of the last sub frame could be - * a holding descriptor for h/w. If that's the case, - * bf->bf_lastfrm won't be in the bf_q. - * Make sure we handle bf_q properly here. - */ - if (!list_empty(bf_q)) { - bf_lastq = list_entry(bf_q->prev, - struct ath_buf, list); - list_cut_position(&bf_head, - bf_q, &bf_lastq->list); - } else { - /* - * XXX: if the last subframe only has one - * descriptor which is also being used as - * a holding descriptor. Then the ath_buf - * is not in the bf_q at all. - */ - INIT_LIST_HEAD(&bf_head); - } + if (bf_next == NULL) { + INIT_LIST_HEAD(&bf_head); } else { ASSERT(!list_empty(bf_q)); - list_cut_position(&bf_head, - bf_q, &bf->bf_lastfrm->list); + list_move_tail(&bf->list, &bf_head); } if (!txpending) { @@ -853,62 +370,29 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ath_tx_update_baw(sc, tid, bf->bf_seqno); spin_unlock_bh(&txq->axq_lock); - /* complete this sub-frame */ + if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { + ath_tx_rc_status(bf, ds, nbad, txok, true); + rc_update = false; + } else { + ath_tx_rc_status(bf, ds, nbad, txok, false); + } + ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); } else { - /* - * retry the un-acked ones - */ - /* - * XXX: if the last descriptor is holding descriptor, - * in order to requeue the frame to software queue, we - * need to allocate a new descriptor and - * copy the content of holding descriptor to it. - */ + /* retry the un-acked ones */ if (bf->bf_next == NULL && bf_last->bf_status & ATH_BUFSTATUS_STALE) { struct ath_buf *tbf; - /* allocate new descriptor */ - spin_lock_bh(&sc->tx.txbuflock); - ASSERT(!list_empty((&sc->tx.txbuf))); - tbf = list_first_entry(&sc->tx.txbuf, - struct ath_buf, list); - list_del(&tbf->list); - spin_unlock_bh(&sc->tx.txbuflock); - - ATH_TXBUF_RESET(tbf); - - /* copy descriptor content */ - tbf->bf_mpdu = bf_last->bf_mpdu; - tbf->bf_buf_addr = bf_last->bf_buf_addr; - *(tbf->bf_desc) = *(bf_last->bf_desc); - - /* link it to the frame */ - if (bf_lastq) { - bf_lastq->bf_desc->ds_link = - tbf->bf_daddr; - bf->bf_lastfrm = tbf; - ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_lastfrm->bf_desc); - } else { - tbf->bf_state = bf_last->bf_state; - tbf->bf_lastfrm = tbf; - ath9k_hw_cleartxdesc(sc->sc_ah, - tbf->bf_lastfrm->bf_desc); - - /* copy the DMA context */ - tbf->bf_dmacontext = - bf_last->bf_dmacontext; - } + tbf = ath_clone_txbuf(sc, bf_last); + ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); list_add_tail(&tbf->list, &bf_head); } else { /* * Clear descriptor status words for * software retry */ - ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_lastfrm->bf_desc); + ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc); } /* @@ -922,332 +406,33 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, } if (tid->state & AGGR_CLEANUP) { - /* check to see if we're done with cleaning the h/w queue */ - spin_lock_bh(&txq->axq_lock); - if (tid->baw_head == tid->baw_tail) { tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; - spin_unlock_bh(&txq->axq_lock); - tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ ath_tx_flush_tid(sc, tid); - } else - spin_unlock_bh(&txq->axq_lock); - + } + rcu_read_unlock(); return; } - /* - * prepend un-acked frames to the beginning of the pending frame queue - */ + /* prepend un-acked frames to the beginning of the pending frame queue */ if (!list_empty(&bf_pending)) { spin_lock_bh(&txq->axq_lock); - /* Note: we _prepend_, we _do_not_ at to - * the end of the queue ! */ list_splice(&bf_pending, &tid->buf_q); ath_tx_queue_tid(txq, tid); spin_unlock_bh(&txq->axq_lock); } + rcu_read_unlock(); + if (needreset) ath_reset(sc, false); - - return; -} - -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) -{ - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - - tx_info_priv->update_rc = false; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { - if (bf_isdata(bf)) { - memcpy(&tx_info_priv->tx, &ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; - tx_info_priv->update_rc = true; - } - } -} - -/* Process completed xmit descriptors from the specified queue */ - -static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf, *lastbf, *bf_held = NULL; - struct list_head bf_head; - struct ath_desc *ds; - int txok, nbad = 0; - int status; - - DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", - txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), - txq->axq_link); - - for (;;) { - spin_lock_bh(&txq->axq_lock); - if (list_empty(&txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; - spin_unlock_bh(&txq->axq_lock); - break; - } - bf = list_first_entry(&txq->axq_q, struct ath_buf, list); - - /* - * There is a race condition that a BH gets scheduled - * after sw writes TxE and before hw re-load the last - * descriptor to get the newly chained one. - * Software must keep the last DONE descriptor as a - * holding descriptor - software does so by marking - * it with the STALE flag. - */ - bf_held = NULL; - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - bf_held = bf; - if (list_is_last(&bf_held->list, &txq->axq_q)) { - /* FIXME: - * The holding descriptor is the last - * descriptor in queue. It's safe to remove - * the last holding descriptor in BH context. - */ - spin_unlock_bh(&txq->axq_lock); - break; - } else { - /* Lets work with the next buffer now */ - bf = list_entry(bf_held->list.next, - struct ath_buf, list); - } - } - - lastbf = bf->bf_lastbf; - ds = lastbf->bf_desc; /* NB: last decriptor */ - - status = ath9k_hw_txprocdesc(ah, ds); - if (status == -EINPROGRESS) { - spin_unlock_bh(&txq->axq_lock); - break; - } - if (bf->bf_desc == txq->axq_lastdsWithCTS) - txq->axq_lastdsWithCTS = NULL; - if (ds == txq->axq_gatingds) - txq->axq_gatingds = NULL; - - /* - * Remove ath_buf's of the same transmit unit from txq, - * however leave the last descriptor back as the holding - * descriptor for hw. - */ - lastbf->bf_status |= ATH_BUFSTATUS_STALE; - INIT_LIST_HEAD(&bf_head); - - if (!list_is_singular(&lastbf->list)) - list_cut_position(&bf_head, - &txq->axq_q, lastbf->list.prev); - - txq->axq_depth--; - - if (bf_isaggr(bf)) - txq->axq_aggr_depth--; - - txok = (ds->ds_txstat.ts_status == 0); - - spin_unlock_bh(&txq->axq_lock); - - if (bf_held) { - list_del(&bf_held->list); - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - } - - if (!bf_isampdu(bf)) { - /* - * This frame is sent out as a single frame. - * Use hardware retry status for this frame. - */ - bf->bf_retries = ds->ds_txstat.ts_longretry; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_state.bf_type |= BUF_XRETRY; - nbad = 0; - } else { - nbad = ath_tx_num_badfrms(sc, bf, txok); - } - - ath_tx_rc_status(bf, ds, nbad); - - /* - * Complete this transmit unit - */ - if (bf_isampdu(bf)) - ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok); - else - ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); - - /* Wake up mac80211 queue */ - - spin_lock_bh(&txq->axq_lock); - if (txq->stopped && ath_txq_depth(sc, txq->axq_qnum) <= - (ATH_TXBUF - 20)) { - int qnum; - qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); - if (qnum != -1) { - ieee80211_wake_queue(sc->hw, qnum); - txq->stopped = 0; - } - - } - - /* - * schedule any pending packets if aggregation is enabled - */ - if (sc->sc_flags & SC_OP_TXAGGR) - ath_txq_schedule(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } -} - -static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) -{ - struct ath_hal *ah = sc->sc_ah; - - (void) ath9k_hw_stoptxdma(ah, txq->axq_qnum); - DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n", - txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum), - txq->axq_link); -} - -/* Drain only the data queues */ - -static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hal *ah = sc->sc_ah; - int i, status, npend = 0; - - if (!(sc->sc_flags & SC_OP_INVALID)) { - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - ath_tx_stopdma(sc, &sc->tx.txq[i]); - /* The TxDMA may not really be stopped. - * Double check the hal tx pending count */ - npend += ath9k_hw_numtxpending(ah, - sc->tx.txq[i].axq_qnum); - } - } - } - - if (npend) { - /* TxDMA not stopped, reset the hal */ - DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, - sc->sc_ah->ah_curchan, - sc->tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, true, &status)) { - - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; hal status %u\n", - status); - } - spin_unlock_bh(&sc->sc_resetlock); - } - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx); - } } -/* Add a sub-frame to block ack window */ - -static void ath_tx_addto_baw(struct ath_softc *sc, - struct ath_atx_tid *tid, - struct ath_buf *bf) -{ - int index, cindex; - - if (bf_isretried(bf)) - return; - - index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); - cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - - ASSERT(tid->tx_buf[cindex] == NULL); - tid->tx_buf[cindex] = bf; - - if (index >= ((tid->baw_tail - tid->baw_head) & - (ATH_TID_MAX_BUFS - 1))) { - tid->baw_tail = cindex; - INCR(tid->baw_tail, ATH_TID_MAX_BUFS); - } -} - -/* - * Function to send an A-MPDU - * NB: must be called with txq lock held - */ -static int ath_tx_send_ampdu(struct ath_softc *sc, - struct ath_atx_tid *tid, - struct list_head *bf_head, - struct ath_tx_control *txctl) -{ - struct ath_buf *bf; - - BUG_ON(list_empty(bf_head)); - - bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_state.bf_type |= BUF_AMPDU; - - /* - * Do not queue to h/w when any of the following conditions is true: - * - there are pending frames in software queue - * - the TID is currently paused for ADDBA/BAR request - * - seqno is not within block-ack window - * - h/w queue depth exceeds low water mark - */ - if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || - txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { - /* - * Add this frame to software queue for scheduling later - * for aggregation. - */ - list_splice_tail_init(bf_head, &tid->buf_q); - ath_tx_queue_tid(txctl->txq, tid); - return 0; - } - - /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf); - - /* Queue to h/w without aggregation */ - bf->bf_nframes = 1; - bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txctl->txq, bf_head); - - return 0; -} - -/* - * looks up the rate - * returns aggr limit based on lowest of the rates - */ -static u32 ath_lookup_rate(struct ath_softc *sc, - struct ath_buf *bf, +static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { struct ath_rate_table *rate_table = sc->cur_rate_table; @@ -1255,15 +440,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; - u32 max_4ms_framelen, frame_length; + u32 max_4ms_framelen, frmlen; u16 aggr_limit, legacy = 0, maxampdu; int i; skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; - tx_info_priv = - (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; + tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; /* * Find the lowest frame length among the rate series that will have a @@ -1279,9 +463,8 @@ static u32 ath_lookup_rate(struct ath_softc *sc, break; } - frame_length = - rate_table->info[rates[i].idx].max_4ms_framelen; - max_4ms_framelen = min(max_4ms_framelen, frame_length); + frmlen = rate_table->info[rates[i].idx].max_4ms_framelen; + max_4ms_framelen = min(max_4ms_framelen, frmlen); } } @@ -1293,8 +476,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, - (u32)ATH_AMPDU_LIMIT_DEFAULT); + aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); /* * h/w can accept aggregates upto 16 bit lengths (65535). @@ -1309,14 +491,12 @@ static u32 ath_lookup_rate(struct ath_softc *sc, } /* - * returns the number of delimiters to be added to + * Returns the number of delimiters to be added to * meet the minimum required mpdudensity. - * caller should make sure that the rate is HT rate . + * caller should make sure that the rate is HT rate . */ -static int ath_compute_num_delims(struct ath_softc *sc, - struct ath_atx_tid *tid, - struct ath_buf *bf, - u16 frmlen) +static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, + struct ath_buf *bf, u16 frmlen) { struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; @@ -1370,9 +550,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; - /* Is frame shorter than required minimum length? */ if (frmlen < minlen) { - /* Get the minimum number of delimiters required. */ mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ; ndelim = max(mindelim, ndelim); } @@ -1380,37 +558,23 @@ static int ath_compute_num_delims(struct ath_softc *sc, return ndelim; } -/* - * For aggregation from software buffer queue. - * NB: must be called with txq lock held - */ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, - struct ath_atx_tid *tid, - struct list_head *bf_q, - struct ath_buf **bf_last, - struct aggr_rifs_param *param, - int *prev_frames) + struct ath_atx_tid *tid, + struct list_head *bf_q) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *tbf, *bf_first, *bf_prev = NULL; - struct list_head bf_head; - int rl = 0, nframes = 0, ndelim; + struct ath_buf *bf, *bf_first, *bf_prev = NULL; + int rl = 0, nframes = 0, ndelim, prev_al = 0; u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; - int prev_al = 0; - INIT_LIST_HEAD(&bf_head); - - BUG_ON(list_empty(&tid->buf_q)); bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); do { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - /* - * do not step over block-ack window - */ + /* do not step over block-ack window */ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) { status = ATH_AGGR_BAW_CLOSED; break; @@ -1421,29 +585,23 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, rl = 1; } - /* - * do not exceed aggregation limit - */ + /* do not exceed aggregation limit */ al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen; - if (nframes && (aggr_limit < - (al + bpad + al_delta + prev_al))) { + if (nframes && + (aggr_limit < (al + bpad + al_delta + prev_al))) { status = ATH_AGGR_LIMITED; break; } - /* - * do not exceed subframe limit - */ - if ((nframes + *prev_frames) >= - min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { + /* do not exceed subframe limit */ + if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { status = ATH_AGGR_LIMITED; break; } + nframes++; - /* - * add padding for previous frame to aggregation length - */ + /* add padding for previous frame to aggregation length */ al += bpad + al_delta; /* @@ -1451,69 +609,35 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * density for this node. */ ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); - bpad = PADBYTES(al_delta) + (ndelim << 2); bf->bf_next = NULL; - bf->bf_lastfrm->bf_desc->ds_link = 0; + bf->bf_desc->ds_link = 0; - /* - * this packet is part of an aggregate - * - remove all descriptors belonging to this frame from - * software queue - * - add it to block ack window - * - set up descriptors for aggregation - */ - list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); + /* link buffers of this frame to the aggregate */ ath_tx_addto_baw(sc, tid, bf); - - list_for_each_entry(tbf, &bf_head, list) { - ath9k_hw_set11n_aggr_middle(sc->sc_ah, - tbf->bf_desc, ndelim); - } - - /* - * link buffers of this frame to the aggregate - */ - list_splice_tail_init(&bf_head, bf_q); - nframes++; - + ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); + list_move_tail(&bf->list, bf_q); if (bf_prev) { bf_prev->bf_next = bf; - bf_prev->bf_lastfrm->bf_desc->ds_link = bf->bf_daddr; + bf_prev->bf_desc->ds_link = bf->bf_daddr; } bf_prev = bf; - -#ifdef AGGR_NOSHORT - /* - * terminate aggregation on a small packet boundary - */ - if (bf->bf_frmlen < ATH_AGGR_MINPLEN) { - status = ATH_AGGR_SHORTPKT; - break; - } -#endif } while (!list_empty(&tid->buf_q)); bf_first->bf_al = al; bf_first->bf_nframes = nframes; - *bf_last = bf_prev; + return status; #undef PADBYTES } -/* - * process pending frames possibly doing a-mpdu aggregation - * NB: must be called with txq lock held - */ -static void ath_tx_sched_aggr(struct ath_softc *sc, - struct ath_txq *txq, struct ath_atx_tid *tid) +static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) { - struct ath_buf *bf, *tbf, *bf_last, *bf_lastaggr = NULL; + struct ath_buf *bf; enum ATH_AGGR_STATUS status; struct list_head bf_q; - struct aggr_rifs_param param = {0, 0, 0, 0, NULL}; - int prev_frames = 0; do { if (list_empty(&tid->buf_q)) @@ -1521,382 +645,169 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, INIT_LIST_HEAD(&bf_q); - status = ath_tx_form_aggr(sc, tid, &bf_q, &bf_lastaggr, ¶m, - &prev_frames); + status = ath_tx_form_aggr(sc, tid, &bf_q); /* - * no frames picked up to be aggregated; block-ack - * window is not open + * no frames picked up to be aggregated; + * block-ack window is not open. */ if (list_empty(&bf_q)) break; bf = list_first_entry(&bf_q, struct ath_buf, list); - bf_last = list_entry(bf_q.prev, struct ath_buf, list); - bf->bf_lastbf = bf_last; + bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); - /* - * if only one frame, send as non-aggregate - */ + /* if only one frame, send as non-aggregate */ if (bf->bf_nframes == 1) { - ASSERT(bf->bf_lastfrm == bf_last); - bf->bf_state.bf_type &= ~BUF_AGGR; - /* - * clear aggr bits for every descriptor - * XXX TODO: is there a way to optimize it? - */ - list_for_each_entry(tbf, &bf_q, list) { - ath9k_hw_clr11n_aggr(sc->sc_ah, tbf->bf_desc); - } - + ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txq, &bf_q); continue; } - /* - * setup first desc with rate and aggr info - */ + /* setup first desc of aggregate */ bf->bf_state.bf_type |= BUF_AGGR; ath_buf_set_rate(sc, bf); ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al); - /* - * anchor last frame of aggregate correctly - */ - ASSERT(bf_lastaggr); - ASSERT(bf_lastaggr->bf_lastfrm == bf_last); - tbf = bf_lastaggr; - ath9k_hw_set11n_aggr_last(sc->sc_ah, tbf->bf_desc); - - /* XXX: We don't enter into this loop, consider removing this */ - while (!list_empty(&bf_q) && !list_is_last(&tbf->list, &bf_q)) { - tbf = list_entry(tbf->list.next, struct ath_buf, list); - ath9k_hw_set11n_aggr_last(sc->sc_ah, tbf->bf_desc); - } + /* anchor last desc of aggregate */ + ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); txq->axq_aggr_depth++; - - /* - * Normal aggregate, queue to hardware - */ ath_tx_txqaddbuf(sc, txq, &bf_q); } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && status != ATH_AGGR_BAW_CLOSED); } -/* Called with txq lock held */ - -static void ath_tid_drain(struct ath_softc *sc, - struct ath_txq *txq, - struct ath_atx_tid *tid) - -{ - struct ath_buf *bf; - struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); - - for (;;) { - if (list_empty(&tid->buf_q)) - break; - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - - list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); - - /* update baw for software retried frame */ - if (bf_isretried(bf)) - ath_tx_update_baw(sc, tid, bf->bf_seqno); - - /* - * do not indicate packets while holding txq spinlock. - * unlock is intentional here - */ - spin_unlock(&txq->axq_lock); - - /* complete this sub-frame */ - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - - spin_lock(&txq->axq_lock); - } - - /* - * TODO: For frame(s) that are in the retry state, we will reuse the - * sequence number(s) without setting the retry bit. The - * alternative is to give up on these and BAR the receiver's window - * forward. - */ - tid->seq_next = tid->seq_start; - tid->baw_tail = tid->baw_head; -} - -/* - * Drain all pending buffers - * NB: must be called with txq lock held - */ -static void ath_txq_drain_pending_buffers(struct ath_softc *sc, - struct ath_txq *txq) -{ - struct ath_atx_ac *ac, *ac_tmp; - struct ath_atx_tid *tid, *tid_tmp; - - list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { - list_del(&ac->list); - ac->sched = false; - list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { - list_del(&tid->list); - tid->sched = false; - ath_tid_drain(sc, txq, tid); - } - } -} - -static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, - struct sk_buff *skb, - struct ath_tx_control *txctl) +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_tx_info_priv *tx_info_priv; - int hdrlen; - __le16 fc; - - tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - if (unlikely(!tx_info_priv)) - return -ENOMEM; - tx_info->rate_driver_data[0] = tx_info_priv; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - ATH_TXBUF_RESET(bf); - - /* Frame type */ - - bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); - - ieee80211_is_data(fc) ? - (bf->bf_state.bf_type |= BUF_DATA) : - (bf->bf_state.bf_type &= ~BUF_DATA); - ieee80211_is_back_req(fc) ? - (bf->bf_state.bf_type |= BUF_BAR) : - (bf->bf_state.bf_type &= ~BUF_BAR); - ieee80211_is_pspoll(fc) ? - (bf->bf_state.bf_type |= BUF_PSPOLL) : - (bf->bf_state.bf_type &= ~BUF_PSPOLL); - (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? - (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : - (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); - (sc->hw->conf.ht.enabled && !is_pae(skb) && - (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ? - (bf->bf_state.bf_type |= BUF_HT) : - (bf->bf_state.bf_type &= ~BUF_HT); - - bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); - - /* Crypto */ - - bf->bf_keytype = get_hw_crypto_keytype(skb); - - if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { - bf->bf_frmlen += tx_info->control.hw_key->icv_len; - bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; - } else { - bf->bf_keyix = ATH9K_TXKEYIX_INVALID; - } - - /* Assign seqno, tidno */ - - if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR)) - assign_aggr_tid_seqno(skb, bf); + struct ath_atx_tid *txtid; + struct ath_node *an; - /* DMA setup */ - bf->bf_mpdu = skb; + an = (struct ath_node *)sta->drv_priv; - bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) { - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "pci_dma_mapping_error() on TX\n"); - return -ENOMEM; + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->state |= AGGR_ADDBA_PROGRESS; + ath_tx_pause_tid(sc, txtid); + *ssn = txtid->seq_start; } - bf->bf_buf_addr = bf->bf_dmacontext; return 0; } -/* FIXME: tx power */ -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_control *txctl) +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_node *an = NULL; + struct ath_node *an = (struct ath_node *)sta->drv_priv; + struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; + struct ath_buf *bf; struct list_head bf_head; - struct ath_desc *ds; - struct ath_atx_tid *tid; - struct ath_hal *ah = sc->sc_ah; - int frm_type; - - frm_type = get_hw_packet_type(skb); - INIT_LIST_HEAD(&bf_head); - list_add_tail(&bf->list, &bf_head); - - /* setup descriptor */ - - ds = bf->bf_desc; - ds->ds_link = 0; - ds->ds_data = bf->bf_buf_addr; - /* Formulate first tx descriptor with tx controls */ - - ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, - bf->bf_keyix, bf->bf_keytype, bf->bf_flags); - - ath9k_hw_filltxdesc(ah, ds, - skb->len, /* segment length */ - true, /* first segment */ - true, /* last segment */ - ds); /* first descriptor */ - - bf->bf_lastfrm = bf; + if (txtid->state & AGGR_CLEANUP) + return 0; - spin_lock_bh(&txctl->txq->axq_lock); + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->addba_exchangeattempts = 0; + return 0; + } - if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && - tx_info->control.sta) { - an = (struct ath_node *)tx_info->control.sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); + ath_tx_pause_tid(sc, txtid); - if (ath_aggr_query(sc, an, bf->bf_tidno)) { - /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. - */ - ath_tx_send_ampdu(sc, tid, &bf_head, txctl); - } else { + /* drop all software retried frames and mark this TID */ + spin_lock_bh(&txq->axq_lock); + while (!list_empty(&txtid->buf_q)) { + bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); + if (!bf_isretried(bf)) { /* - * Send this frame as regular when ADDBA - * exchange is neither complete nor pending. + * NB: it's based on the assumption that + * software retried frame will always stay + * at the head of software queue. */ - ath_tx_send_normal(sc, txctl->txq, - tid, &bf_head); + break; } - } else { - bf->bf_lastbf = bf; - bf->bf_nframes = 1; + list_move_tail(&bf->list, &bf_head); + ath_tx_update_baw(sc, txtid, bf->bf_seqno); + ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + } + spin_unlock_bh(&txq->axq_lock); - ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); + if (txtid->baw_head != txtid->baw_tail) { + txtid->state |= AGGR_CLEANUP; + } else { + txtid->state &= ~AGGR_ADDBA_COMPLETE; + txtid->addba_exchangeattempts = 0; + ath_tx_flush_tid(sc, txtid); } - spin_unlock_bh(&txctl->txq->axq_lock); + return 0; } -/* Upon failure caller should free skb */ -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, - struct ath_tx_control *txctl) +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { - struct ath_buf *bf; - int r; - - /* Check if a tx buffer is available */ - - bf = ath_tx_get_buffer(sc); - if (!bf) { - DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); - return -1; - } - - r = ath_tx_setup_buffer(sc, bf, skb, txctl); - if (unlikely(r)) { - struct ath_txq *txq = txctl->txq; - - DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); - - /* upon ath_tx_processq() this TX queue will be resumed, we - * guarantee this will happen by knowing beforehand that - * we will at least have to run TX completionon one buffer - * on the queue */ - spin_lock_bh(&txq->axq_lock); - if (ath_txq_depth(sc, txq->axq_qnum) > 1) { - ieee80211_stop_queue(sc->hw, - skb_get_queue_mapping(skb)); - txq->stopped = 1; - } - spin_unlock_bh(&txq->axq_lock); + struct ath_atx_tid *txtid; + struct ath_node *an; - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); + an = (struct ath_node *)sta->drv_priv; - return r; + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); } - - ath_tx_start_dma(sc, bf, txctl); - - return 0; } -/* Initialize TX queue and h/w */ - -int ath_tx_init(struct ath_softc *sc, int nbufs) +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) { - int error = 0; + struct ath_atx_tid *txtid; - do { - spin_lock_init(&sc->tx.txbuflock); + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return false; - /* Setup tx descriptors */ - error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, - "tx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate tx descriptors: %d\n", - error); - break; - } + txtid = ATH_AN_2_TID(an, tidno); - /* XXX allocate beacon state together with vap */ - error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, - "beacon", ATH_BCBUF, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate beacon descriptors: %d\n", - error); - break; + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + if (!(txtid->state & AGGR_ADDBA_PROGRESS) && + (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { + txtid->addba_exchangeattempts++; + return true; } + } - } while (0); - - if (error != 0) - ath_tx_cleanup(sc); - - return error; + return false; } -/* Reclaim all tx queue resources */ +/********************/ +/* Queue Management */ +/********************/ -int ath_tx_cleanup(struct ath_softc *sc) +static void ath_txq_drain_pending_buffers(struct ath_softc *sc, + struct ath_txq *txq) { - /* cleanup beacon descriptors */ - if (sc->beacon.bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); - - /* cleanup tx descriptors */ - if (sc->tx.txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); + struct ath_atx_ac *ac, *ac_tmp; + struct ath_atx_tid *tid, *tid_tmp; - return 0; + list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { + list_del(&ac->list); + ac->sched = false; + list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { + list_del(&tid->list); + tid->sched = false; + ath_tid_drain(sc, txq, tid); + } + } } -/* Setup a h/w transmit queue */ - struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; int qnum; @@ -1959,43 +870,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) return &sc->tx.txq[qnum]; } -/* Reclaim resources for a setup queue */ - -void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) -{ - ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); - sc->tx.txqsetup &= ~(1<<txq->axq_qnum); -} - -/* - * Setup a hardware data transmit queue for the specified - * access control. The hal may not support all requested - * queues in which case it will return a reference to a - * previously setup queue. We record the mapping from ac's - * to h/w queues for use by ath_tx_start and also track - * the set of h/w queues being used to optimize work in the - * transmit interrupt handler and related routines. - */ - -int ath_tx_setup(struct ath_softc *sc, int haltype) -{ - struct ath_txq *txq; - - if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc, ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->tx.hwq_map)); - return 0; - } - txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); - if (txq != NULL) { - sc->tx.hwq_map[haltype] = txq->axq_qnum; - return 1; - } else - return 0; -} - -int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) +static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) { int qnum; @@ -2021,8 +896,6 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) return qnum; } -/* Get a transmit queue, if available */ - struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) { struct ath_txq *txq = NULL; @@ -2033,9 +906,8 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) spin_lock_bh(&txq->axq_lock); - /* Try to avoid running out of descriptors */ if (txq->axq_depth >= (ATH_TXBUF - 20)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc, ATH_DBG_XMIT, "TX queue: %d is full, depth: %d\n", qnum, txq->axq_depth); ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); @@ -2049,12 +921,10 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) return txq; } -/* Update parameters for a transmit queue */ - int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *qinfo) { - struct ath_hal *ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; int error = 0; struct ath9k_tx_queue_info qi; @@ -2082,7 +952,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { - ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */ + ath9k_hw_resettxqueue(ah, qnum); } return error; @@ -2092,55 +962,36 @@ int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; int qnum = sc->beacon.cabq->axq_qnum; - struct ath_beacon_config conf; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); /* * Ensure the readytime % is within the bounds. */ - if (sc->sc_config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) - sc->sc_config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; - else if (sc->sc_config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) - sc->sc_config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; - - ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf); - qi.tqi_readyTime = - (conf.beacon_interval * sc->sc_config.cabqReadytime) / 100; + if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) + sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; + else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) + sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; + + qi.tqi_readyTime = (sc->hw->conf.beacon_int * + sc->config.cabqReadytime) / 100; ath_txq_update(sc, qnum, &qi); return 0; } -/* Deferred processing of transmit interrupt */ - -void ath_tx_tasklet(struct ath_softc *sc) -{ - int i; - u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); - - ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); - - /* - * Process each active queue. - */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - ath_tx_processq(sc, &sc->tx.txq[i]); - } -} - -void ath_tx_draintxq(struct ath_softc *sc, - struct ath_txq *txq, bool retry_tx) +/* + * Drain a given TX queue (could be Beacon or Data) + * + * This assumes output has been stopped and + * we do not need to block ath_tx_tasklet. + */ +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) { struct ath_buf *bf, *lastbf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - /* - * NB: this assumes output has been stopped and - * we do not need to block ath_tx_tasklet - */ for (;;) { spin_lock_bh(&txq->axq_lock); @@ -2175,7 +1026,7 @@ void ath_tx_draintxq(struct ath_softc *sc, spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) - ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0); else ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); } @@ -2190,44 +1041,285 @@ void ath_tx_draintxq(struct ath_softc *sc, } } -/* Drain the transmit queues and reclaim resources */ +void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_txq *txq; + int i, npend = 0; + + if (sc->sc_flags & SC_OP_INVALID) + return; + + /* Stop beacon queue */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); -void ath_draintxq(struct ath_softc *sc, bool retry_tx) + /* Stop data queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + txq = &sc->tx.txq[i]; + ath9k_hw_stoptxdma(ah, txq->axq_qnum); + npend += ath9k_hw_numtxpending(ah, txq->axq_qnum); + } + } + + if (npend) { + int r; + + DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); + + spin_lock_bh(&sc->sc_resetlock); + r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); + if (r) + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %u\n", + r); + spin_unlock_bh(&sc->sc_resetlock); + } + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) + ath_draintxq(sc, &sc->tx.txq[i], retry_tx); + } +} + +void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) +{ + ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); + sc->tx.txqsetup &= ~(1<<txq->axq_qnum); +} + +void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { - /* stop beacon queue. The beacon will be freed when - * we go to INIT state */ - if (!(sc->sc_flags & SC_OP_INVALID)) { - (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n", - ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq)); + struct ath_atx_ac *ac; + struct ath_atx_tid *tid; + + if (list_empty(&txq->axq_acq)) + return; + + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); + list_del(&ac->list); + ac->sched = false; + + do { + if (list_empty(&ac->tid_q)) + return; + + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); + list_del(&tid->list); + tid->sched = false; + + if (tid->paused) + continue; + + if ((txq->axq_depth % 2) == 0) + ath_tx_sched_aggr(sc, txq, tid); + + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (!list_empty(&tid->buf_q)) + ath_tx_queue_tid(txq, tid); + + break; + } while (!list_empty(&ac->tid_q)); + + if (!list_empty(&ac->tid_q)) { + if (!ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); + } } +} + +int ath_tx_setup(struct ath_softc *sc, int haltype) +{ + struct ath_txq *txq; - ath_drain_txdataq(sc, retry_tx); + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { + DPRINTF(sc, ATH_DBG_FATAL, + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); + return 0; + } + txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); + if (txq != NULL) { + sc->tx.hwq_map[haltype] = txq->axq_qnum; + return 1; + } else + return 0; } -u32 ath_txq_depth(struct ath_softc *sc, int qnum) +/***********/ +/* TX, DMA */ +/***********/ + +/* + * Insert a chain of ath_buf (descriptors) on a txq and + * assume the descriptors are already chained together by caller. + */ +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head) { - return sc->tx.txq[qnum].axq_depth; + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf; + + /* + * Insert the frame on the outbound list and + * pass it on to the hardware. + */ + + if (list_empty(head)) + return; + + bf = list_first_entry(head, struct ath_buf, list); + + list_splice_tail_init(head, &txq->axq_q); + txq->axq_depth++; + txq->axq_totalqueued++; + txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); + + DPRINTF(sc, ATH_DBG_QUEUE, + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); + + if (txq->axq_link == NULL) { + ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); + DPRINTF(sc, ATH_DBG_XMIT, + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); + } else { + *txq->axq_link = bf->bf_daddr; + DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", + txq->axq_qnum, txq->axq_link, + ito64(bf->bf_daddr), bf->bf_desc); + } + txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); + ath9k_hw_txstart(ah, txq->axq_qnum); } -u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum) +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) { - return sc->tx.txq[qnum].axq_aggr_depth; + struct ath_buf *bf = NULL; + + spin_lock_bh(&sc->tx.txbuflock); + + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; + } + + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->tx.txbuflock); + + return bf; } -bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) +static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, + struct list_head *bf_head, + struct ath_tx_control *txctl) { - struct ath_atx_tid *txtid; + struct ath_buf *bf; - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return false; + bf = list_first_entry(bf_head, struct ath_buf, list); + bf->bf_state.bf_type |= BUF_AMPDU; - txtid = ATH_AN_2_TID(an, tidno); + /* + * Do not queue to h/w when any of the following conditions is true: + * - there are pending frames in software queue + * - the TID is currently paused for ADDBA/BAR request + * - seqno is not within block-ack window + * - h/w queue depth exceeds low water mark + */ + if (!list_empty(&tid->buf_q) || tid->paused || + !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || + txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { + /* + * Add this frame to software queue for scheduling later + * for aggregation. + */ + list_move_tail(&bf->list, &tid->buf_q); + ath_tx_queue_tid(txctl->txq, tid); + return; + } - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - if (!(txtid->state & AGGR_ADDBA_PROGRESS) && - (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { - txtid->addba_exchangeattempts++; + /* Add sub-frame to BAW */ + ath_tx_addto_baw(sc, tid, bf); + + /* Queue to h/w without aggregation */ + bf->bf_nframes = 1; + bf->bf_lastbf = bf; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txctl->txq, bf_head); +} + +static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, + struct list_head *bf_head) +{ + struct ath_buf *bf; + + bf = list_first_entry(bf_head, struct ath_buf, list); + bf->bf_state.bf_type &= ~BUF_AMPDU; + + /* update starting sequence number for subsequent ADDBA request */ + INCR(tid->seq_start, IEEE80211_SEQ_MAX); + + bf->bf_nframes = 1; + bf->bf_lastbf = bf; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txq, bf_head); +} + +static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *bf_head) +{ + struct ath_buf *bf; + + bf = list_first_entry(bf_head, struct ath_buf, list); + + bf->bf_lastbf = bf; + bf->bf_nframes = 1; + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txq, bf_head); +} + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + enum ath9k_pkt_type htype; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_beacon(fc)) + htype = ATH9K_PKT_TYPE_BEACON; + else if (ieee80211_is_probe_resp(fc)) + htype = ATH9K_PKT_TYPE_PROBE_RESP; + else if (ieee80211_is_atim(fc)) + htype = ATH9K_PKT_TYPE_ATIM; + else if (ieee80211_is_pspoll(fc)) + htype = ATH9K_PKT_TYPE_PSPOLL; + else + htype = ATH9K_PKT_TYPE_NORMAL; + + return htype; +} + +static bool is_pae(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_data(fc)) { + if (ieee80211_is_nullfunc(fc) || + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { return true; } } @@ -2235,175 +1327,766 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) return false; } -/* Start TX aggregation */ +static int get_hw_crypto_keytype(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + if (tx_info->control.hw_key) { + if (tx_info->control.hw_key->alg == ALG_WEP) + return ATH9K_KEY_TYPE_WEP; + else if (tx_info->control.hw_key->alg == ALG_TKIP) + return ATH9K_KEY_TYPE_TKIP; + else if (tx_info->control.hw_key->alg == ALG_CCMP) + return ATH9K_KEY_TYPE_AES; + } + + return ATH9K_KEY_TYPE_CLEAR; +} + +static void assign_aggr_tid_seqno(struct sk_buff *skb, + struct ath_buf *bf) { - struct ath_atx_tid *txtid; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; struct ath_node *an; + struct ath_atx_tid *tid; + __le16 fc; + u8 *qc; - an = (struct ath_node *)sta->drv_priv; + if (!tx_info->control.sta) + return; - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->state |= AGGR_ADDBA_PROGRESS; - ath_tx_pause_tid(sc, txtid); + an = (struct ath_node *)tx_info->control.sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + bf->bf_tidno = qc[0] & 0xf; } - return 0; + /* + * For HT capable stations, we save tidno for later use. + * We also override seqno set by upper layer with the one + * in tx aggregation state. + * + * If fragmentation is on, the sequence number is + * not overridden, since it has been + * incremented by the fragmentation routine. + * + * FIXME: check if the fragmentation threshold exceeds + * IEEE80211 max. + */ + tid = ATH_AN_2_TID(an, bf->bf_tidno); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << + IEEE80211_SEQ_SEQ_SHIFT); + bf->bf_seqno = tid->seq_next; + INCR(tid->seq_next, IEEE80211_SEQ_MAX); } -/* Stop tx aggregation */ - -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, + struct ath_txq *txq) { - struct ath_node *an = (struct ath_node *)sta->drv_priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; - ath_tx_aggr_teardown(sc, an, tid); - return 0; + flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= ATH9K_TXDESC_NOACK; + + return flags; } -/* Resume tx aggregation */ +/* + * rix - rate index + * pktlen - total bytes (delims + data + fcs + pads + pad delims) + * width - 0 for 20 MHz, 1 for 40 MHz + * half_gi - to use 4us v/s 3.6 us for symbol time + */ +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, + int width, int half_gi, bool shortPreamble) +{ + struct ath_rate_table *rate_table = sc->cur_rate_table; + u32 nbits, nsymbits, duration, nsymbols; + u8 rc; + int streams, pktlen; -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) + pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; + rc = rate_table->info[rix].ratecode; + + /* for legacy rates, use old function to compute packet duration */ + if (!IS_HT_RATE(rc)) + return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, + rix, shortPreamble); + + /* find number of symbols: PLCP + data */ + nbits = (pktlen << 3) + OFDM_PLCP_BITS; + nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + nsymbols = (nbits + nsymbits - 1) / nsymbits; + + if (!half_gi) + duration = SYMBOL_TIME(nsymbols); + else + duration = SYMBOL_TIME_HALFGI(nsymbols); + + /* addup duration for legacy/ht training and signal fields */ + streams = HT_RC_2_STREAMS(rc); + duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + + return duration; +} + +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_atx_tid *txtid; - struct ath_node *an; + struct ath_rate_table *rt = sc->cur_rate_table; + struct ath9k_11n_rate_series series[4]; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + struct ieee80211_hdr *hdr; + int i, flags = 0; + u8 rix = 0, ctsrate = 0; + bool is_pspoll; - an = (struct ath_node *)sta->drv_priv; + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->baw_size = - IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - ath_tx_resume_tid(sc, txtid); + skb = (struct sk_buff *)bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + hdr = (struct ieee80211_hdr *)skb->data; + is_pspoll = ieee80211_is_pspoll(hdr->frame_control); + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode | + rt->info[tx_info->control.rts_cts_rate_idx].short_preamble; + else + ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode; + + /* + * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. + * Check the first rate in the series to decide whether RTS/CTS + * or CTS-to-self has to be used. + */ + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + flags = ATH9K_TXDESC_CTSENA; + else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags = ATH9K_TXDESC_RTSENA; + + /* FIXME: Handle aggregation protection */ + if (sc->config.ath_aggr_prot && + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { + flags = ATH9K_TXDESC_RTSENA; + } + + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit)) + flags &= ~(ATH9K_TXDESC_RTSENA); + + for (i = 0; i < 4; i++) { + if (!rates[i].count || (rates[i].idx < 0)) + continue; + + rix = rates[i].idx; + series[i].Tries = rates[i].count; + series[i].ChSel = sc->tx_chainmask; + + if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + series[i].Rate = rt->info[rix].ratecode | + rt->info[rix].short_preamble; + else + series[i].Rate = rt->info[rix].ratecode; + + if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) + series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + series[i].RateFlags |= ATH9K_RATESERIES_2040; + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; + + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), + (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)); } + + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, + bf->bf_lastbf->bf_desc, + !is_pspoll, ctsrate, + 0, series, 4, flags); + + if (sc->config.ath_aggr_prot && flags) + ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); } -/* - * Performs transmit side cleanup when TID changes from aggregated to - * unaggregated. - * - Pause the TID and mark cleanup in progress - * - Discard all retry frames from the s/w queue. - */ +static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, + struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_tx_info_priv *tx_info_priv; + int hdrlen; + __le16 fc; + + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + if (unlikely(!tx_info_priv)) + return -ENOMEM; + tx_info->rate_driver_data[0] = tx_info_priv; + tx_info_priv->aphy = aphy; + tx_info_priv->frame_type = txctl->frame_type; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + + ATH_TXBUF_RESET(bf); + + bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); + + if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) + bf->bf_state.bf_type |= BUF_HT; + + bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + + bf->bf_keytype = get_hw_crypto_keytype(skb); + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + bf->bf_frmlen += tx_info->control.hw_key->icv_len; + bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; + } else { + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + } + + if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + bf->bf_mpdu = skb; + + bf->bf_dmacontext = dma_map_single(sc->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "dma_mapping_error() on TX\n"); + return -ENOMEM; + } + + bf->bf_buf_addr = bf->bf_dmacontext; + return 0; +} -void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_control *txctl) { - struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; - struct ath_buf *bf; + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath_node *an = NULL; struct list_head bf_head; + struct ath_desc *ds; + struct ath_atx_tid *tid; + struct ath_hw *ah = sc->sc_ah; + int frm_type; + __le16 fc; + + frm_type = get_hw_packet_type(skb); + fc = hdr->frame_control; + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); - if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */ - return; + ds = bf->bf_desc; + ds->ds_link = 0; + ds->ds_data = bf->bf_buf_addr; - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - txtid->addba_exchangeattempts = 0; - return; - } + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + bf->bf_keyix, bf->bf_keytype, bf->bf_flags); - /* TID must be paused first */ - ath_tx_pause_tid(sc, txtid); + ath9k_hw_filltxdesc(ah, ds, + skb->len, /* segment length */ + true, /* first segment */ + true, /* last segment */ + ds); /* first descriptor */ - /* drop all software retried frames and mark this TID */ - spin_lock_bh(&txq->axq_lock); - while (!list_empty(&txtid->buf_q)) { - bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); - if (!bf_isretried(bf)) { + spin_lock_bh(&txctl->txq->axq_lock); + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && + tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + + if (!ieee80211_is_data_qos(fc)) { + ath_tx_send_normal(sc, txctl->txq, &bf_head); + goto tx_done; + } + + if (ath_aggr_query(sc, an, bf->bf_tidno)) { /* - * NB: it's based on the assumption that - * software retried frame will always stay - * at the head of software queue. + * Try aggregation if it's a unicast data frame + * and the destination is HT capable. */ - break; + ath_tx_send_ampdu(sc, tid, &bf_head, txctl); + } else { + /* + * Send this frame as regular when ADDBA + * exchange is neither complete nor pending. + */ + ath_tx_send_ht_normal(sc, txctl->txq, + tid, &bf_head); } - list_cut_position(&bf_head, - &txtid->buf_q, &bf->bf_lastfrm->list); - ath_tx_update_baw(sc, txtid, bf->bf_seqno); + } else { + ath_tx_send_normal(sc, txctl->txq, &bf_head); + } - /* complete this sub-frame */ - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); +tx_done: + spin_unlock_bh(&txctl->txq->axq_lock); +} + +/* Upon failure caller should free skb */ +int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_buf *bf; + int r; + + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + return -1; } - if (txtid->baw_head != txtid->baw_tail) { - spin_unlock_bh(&txq->axq_lock); - txtid->state |= AGGR_CLEANUP; - } else { - txtid->state &= ~AGGR_ADDBA_COMPLETE; - txtid->addba_exchangeattempts = 0; + r = ath_tx_setup_buffer(hw, bf, skb, txctl); + if (unlikely(r)) { + struct ath_txq *txq = txctl->txq; + + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); + + /* upon ath_tx_processq() this TX queue will be resumed, we + * guarantee this will happen by knowing beforehand that + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); + if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { + ieee80211_stop_queue(sc->hw, + skb_get_queue_mapping(skb)); + txq->stopped = 1; + } spin_unlock_bh(&txq->axq_lock); - ath_tx_flush_tid(sc, txtid); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + return r; } -} -/* - * Tx scheduling logic - * NB: must be called with txq lock held - */ + ath_tx_start_dma(sc, bf, txctl); -void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) + return 0; +} + +void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_tx_control txctl; - /* nothing to schedule */ - if (list_empty(&txq->axq_acq)) - return; - /* - * get the first node/ac pair on the queue - */ - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); - list_del(&ac->list); - ac->sched = false; + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* - * process a single tid per destination + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. */ - do { - /* nothing to schedule */ - if (list_empty(&ac->tid_q)) + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->tx.seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + } + + /* Add the padding after the header if this is not already done */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + padsize = hdrlen % 4; + if (skb_headroom(skb) < padsize) { + DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); + dev_kfree_skb_any(skb); return; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; + txctl.txq = sc->beacon.cabq; - if (tid->paused) /* check next tid to keep h/w busy */ - continue; + DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); - if ((txq->axq_depth % 2) == 0) - ath_tx_sched_aggr(sc, txq, tid); + if (ath_tx_start(hw, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); + goto exit; + } + return; +exit: + dev_kfree_skb_any(skb); +} + +/*****************/ +/* TX Completion */ +/*****************/ + +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + int tx_flags) +{ + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + int hdrlen, padsize; + int frame_type = ATH9K_NOT_INTERNAL; + + DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + + if (tx_info_priv) { + hw = tx_info_priv->aphy->hw; + frame_type = tx_info_priv->frame_type; + } + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + } + + if (tx_flags & ATH_TX_BAR) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + + if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { /* - * add tid to round-robin queue if more frames - * are pending for the tid + * Remove MAC header padding before giving the frame back to + * mac80211. */ - if (!list_empty(&tid->buf_q)) - ath_tx_queue_tid(txq, tid); + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } - /* only schedule one TID at a time */ - break; - } while (!list_empty(&ac->tid_q)); + if (frame_type == ATH9K_NOT_INTERNAL) + ieee80211_tx_status(hw, skb); + else + ath9k_tx_status(hw, skb); +} + +static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct list_head *bf_q, + int txok, int sendbar) +{ + struct sk_buff *skb = bf->bf_mpdu; + unsigned long flags; + int tx_flags = 0; + + + if (sendbar) + tx_flags = ATH_TX_BAR; + + if (!txok) { + tx_flags |= ATH_TX_ERROR; + + if (bf_isxretried(bf)) + tx_flags |= ATH_TX_XRETRY; + } + + dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); + ath_tx_complete(sc, skb, tx_flags); /* - * schedule AC if more TIDs need processing + * Return the list of ath_buf of this mpdu to free queue */ - if (!list_empty(&ac->tid_q)) { + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); +} + +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok) +{ + struct ath_buf *bf_last = bf->bf_lastbf; + struct ath_desc *ds = bf_last->bf_desc; + u16 seq_st = 0; + u32 ba[WME_BA_BMP_SIZE >> 5]; + int ba_index; + int nbad = 0; + int isaggr = 0; + + if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + return 0; + + isaggr = bf_isaggr(bf); + if (isaggr) { + seq_st = ATH_DS_BA_SEQ(ds); + memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); + } + + while (bf) { + ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno); + if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) + nbad++; + + bf = bf->bf_next; + } + + return nbad; +} + +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + int nbad, int txok, bool update_rc) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + struct ieee80211_hw *hw = tx_info_priv->aphy->hw; + u8 i, tx_rateindex; + + if (txok) + tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; + + tx_rateindex = ds->ds_txstat.ts_rateindex; + WARN_ON(tx_rateindex >= hw->max_rates); + + tx_info_priv->update_rc = update_rc; + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { + if (ieee80211_is_data(hdr->frame_control)) { + memcpy(&tx_info_priv->tx, &ds->ds_txstat, + sizeof(tx_info_priv->tx)); + tx_info_priv->n_frames = bf->bf_nframes; + tx_info_priv->n_bad_frames = nbad; + } + } + + for (i = tx_rateindex + 1; i < hw->max_rates; i++) + tx_info->status.rates[i].count = 0; + + tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; +} + +static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) +{ + int qnum; + + spin_lock_bh(&txq->axq_lock); + if (txq->stopped && + sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { + qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); + if (qnum != -1) { + ieee80211_wake_queue(sc->hw, qnum); + txq->stopped = 0; + } + } + spin_unlock_bh(&txq->axq_lock); +} + +static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_buf *bf, *lastbf, *bf_held = NULL; + struct list_head bf_head; + struct ath_desc *ds; + int txok; + int status; + + DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), + txq->axq_link); + + for (;;) { + spin_lock_bh(&txq->axq_lock); + if (list_empty(&txq->axq_q)) { + txq->axq_link = NULL; + txq->axq_linkbuf = NULL; + spin_unlock_bh(&txq->axq_lock); + break; + } + bf = list_first_entry(&txq->axq_q, struct ath_buf, list); + /* - * add dest ac to txq if not already added + * There is a race condition that a BH gets scheduled + * after sw writes TxE and before hw re-load the last + * descriptor to get the newly chained one. + * Software must keep the last DONE descriptor as a + * holding descriptor - software does so by marking + * it with the STALE flag. */ - if (!ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + bf_held = NULL; + if (bf->bf_status & ATH_BUFSTATUS_STALE) { + bf_held = bf; + if (list_is_last(&bf_held->list, &txq->axq_q)) { + txq->axq_link = NULL; + txq->axq_linkbuf = NULL; + spin_unlock_bh(&txq->axq_lock); + + /* + * The holding descriptor is the last + * descriptor in queue. It's safe to remove + * the last holding descriptor in BH context. + */ + spin_lock_bh(&sc->tx.txbuflock); + list_move_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + break; + } else { + bf = list_entry(bf_held->list.next, + struct ath_buf, list); + } + } + + lastbf = bf->bf_lastbf; + ds = lastbf->bf_desc; + + status = ath9k_hw_txprocdesc(ah, ds); + if (status == -EINPROGRESS) { + spin_unlock_bh(&txq->axq_lock); + break; + } + if (bf->bf_desc == txq->axq_lastdsWithCTS) + txq->axq_lastdsWithCTS = NULL; + if (ds == txq->axq_gatingds) + txq->axq_gatingds = NULL; + + /* + * Remove ath_buf's of the same transmit unit from txq, + * however leave the last descriptor back as the holding + * descriptor for hw. + */ + lastbf->bf_status |= ATH_BUFSTATUS_STALE; + INIT_LIST_HEAD(&bf_head); + if (!list_is_singular(&lastbf->list)) + list_cut_position(&bf_head, + &txq->axq_q, lastbf->list.prev); + + txq->axq_depth--; + if (bf_isaggr(bf)) + txq->axq_aggr_depth--; + + txok = (ds->ds_txstat.ts_status == 0); + spin_unlock_bh(&txq->axq_lock); + + if (bf_held) { + spin_lock_bh(&sc->tx.txbuflock); + list_move_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + } + + if (!bf_isampdu(bf)) { + /* + * This frame is sent out as a single frame. + * Use hardware retry status for this frame. + */ + bf->bf_retries = ds->ds_txstat.ts_longretry; + if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) + bf->bf_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(bf, ds, 0, txok, true); } + + if (bf_isampdu(bf)) + ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); + else + ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); + + ath_wake_mac80211_queue(sc, txq); + + spin_lock_bh(&txq->axq_lock); + if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } +} + + +void ath_tx_tasklet(struct ath_softc *sc) +{ + int i; + u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); + + ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) + ath_tx_processq(sc, &sc->tx.txq[i]); } } -/* Initialize per-node transmit state */ +/*****************/ +/* Init, Cleanup */ +/*****************/ + +int ath_tx_init(struct ath_softc *sc, int nbufs) +{ + int error = 0; + + do { + spin_lock_init(&sc->tx.txbuflock); + + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, + "tx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate tx descriptors: %d\n", + error); + break; + } + + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, + "beacon", ATH_BCBUF, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate beacon descriptors: %d\n", + error); + break; + } + + } while (0); + + if (error != 0) + ath_tx_cleanup(sc); + + return error; +} + +int ath_tx_cleanup(struct ath_softc *sc) +{ + if (sc->beacon.bdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); + + if (sc->tx.txdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); + + return 0; +} void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { @@ -2411,9 +2094,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) struct ath_atx_ac *ac; int tidno, acno; - /* - * Init per tid tx state - */ for (tidno = 0, tid = &an->tid[tidno]; tidno < WME_NUM_TID; tidno++, tid++) { @@ -2423,22 +2103,16 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_size = WME_MAX_BA; tid->baw_head = tid->baw_tail = 0; tid->sched = false; - tid->paused = false; + tid->paused = false; tid->state &= ~AGGR_CLEANUP; INIT_LIST_HEAD(&tid->buf_q); - acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; - - /* ADDBA state */ tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_ADDBA_PROGRESS; tid->addba_exchangeattempts = 0; } - /* - * Init per ac tx state - */ for (acno = 0, ac = &an->ac[acno]; acno < WME_NUM_AC; acno++, ac++) { ac->sched = false; @@ -2465,14 +2139,13 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) } } -/* Cleanupthe pending buffers for the node. */ - void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { int i; struct ath_atx_ac *ac, *ac_tmp; struct ath_atx_tid *tid, *tid_tmp; struct ath_txq *txq; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->tx.txq[i]; @@ -2503,51 +2176,3 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } } - -void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) -{ - int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_tx_control txctl; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } - - /* Add the padding after the header if this is not already done */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - padsize = hdrlen % 4; - if (skb_headroom(skb) < padsize) { - DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); - dev_kfree_skb_any(skb); - return; - } - skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); - } - - txctl.txq = sc->beacon.cabq; - - DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); - - if (ath_tx_start(sc, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); - goto exit; - } - - return; -exit: - dev_kfree_skb_any(skb); -} |