aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r--drivers/net/wireless/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath9k/ahb.c192
-rw-r--r--drivers/net/wireless/ath9k/ani.c290
-rw-r--r--drivers/net/wireless/ath9k/ani.h138
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h1700
-rw-r--r--drivers/net/wireless/ath9k/beacon.c814
-rw-r--r--drivers/net/wireless/ath9k/calib.c555
-rw-r--r--drivers/net/wireless/ath9k/calib.h124
-rw-r--r--drivers/net/wireless/ath9k/core.h787
-rw-r--r--drivers/net/wireless/ath9k/debug.c417
-rw-r--r--drivers/net/wireless/ath9k/debug.h165
-rw-r--r--drivers/net/wireless/ath9k/eeprom.c3325
-rw-r--r--drivers/net/wireless/ath9k/eeprom.h507
-rw-r--r--drivers/net/wireless/ath9k/hw.c1717
-rw-r--r--drivers/net/wireless/ath9k/hw.h1559
-rw-r--r--drivers/net/wireless/ath9k/initvals.h718
-rw-r--r--drivers/net/wireless/ath9k/mac.c235
-rw-r--r--drivers/net/wireless/ath9k/mac.h680
-rw-r--r--drivers/net/wireless/ath9k/main.c1944
-rw-r--r--drivers/net/wireless/ath9k/pci.c295
-rw-r--r--drivers/net/wireless/ath9k/phy.c242
-rw-r--r--drivers/net/wireless/ath9k/phy.h51
-rw-r--r--drivers/net/wireless/ath9k/rc.c350
-rw-r--r--drivers/net/wireless/ath9k/rc.h30
-rw-r--r--drivers/net/wireless/ath9k/recv.c179
-rw-r--r--drivers/net/wireless/ath9k/reg.h125
-rw-r--r--drivers/net/wireless/ath9k/regd.c1248
-rw-r--r--drivers/net/wireless/ath9k/regd.h209
-rw-r--r--drivers/net/wireless/ath9k/regd_common.h2060
-rw-r--r--drivers/net/wireless/ath9k/virtual.c662
-rw-r--r--drivers/net/wireless/ath9k/xmit.c2891
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, &centers);
+ 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, &centers);
- 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, &centers);
+ 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, &centers);
-
- 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, &centers);
- 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, &centers);
- 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, &centers);
-
- 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, &centers);
@@ -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, &centers);
+ 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, &centers);
- 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, &centers);
- } 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, &centers);
+
+ 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, &centers);
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, &reg_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, &reg_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, &reg_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, &regDomains[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 = &regDomainPairs[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 &regDomainPairs[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 = &regDmn5GhzFreq[0];
- ctl = rd->conformanceTestLimit;
- break;
- case ATH9K_MODE_11B:
- rd = &rd2GHz;
- channelBM = rd->chan11b;
- freqs = &regDmn2GhzFreq[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 = &regDmn2Ghz11gFreq[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, &param,
- &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);
-}