aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-11-26 15:28:40 -0800
committerDavid S. Miller <davem@davemloft.net>2008-11-26 15:28:40 -0800
commitb5ddedc9cc01b1d86015af08c5f1694191804530 (patch)
treedb08f24da9ef4dcec0976ee4de4d77e5e596057e
parentpkt_sched: gen_estimator: Optimize gen_estimator_active() (diff)
parentmac80211_hwsim: fix-up some print_mac merge damage (diff)
downloadlinux-dev-b5ddedc9cc01b1d86015af08c5f1694191804530.tar.xz
linux-dev-b5ddedc9cc01b1d86015af08c5f1694191804530.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
-rw-r--r--drivers/net/wireless/Kconfig17
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h7
-rw-r--r--drivers/net/wireless/ath5k/attach.c12
-rw-r--r--drivers/net/wireless/ath5k/base.c15
-rw-r--r--drivers/net/wireless/ath5k/eeprom.c1194
-rw-r--r--drivers/net/wireless/ath5k/eeprom.h253
-rw-r--r--drivers/net/wireless/ath5k/reset.c2
-rw-r--r--drivers/net/wireless/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h49
-rw-r--r--drivers/net/wireless/ath9k/beacon.c88
-rw-r--r--drivers/net/wireless/ath9k/calib.c4
-rw-r--r--drivers/net/wireless/ath9k/core.c1652
-rw-r--r--drivers/net/wireless/ath9k/core.h280
-rw-r--r--drivers/net/wireless/ath9k/eeprom.c11
-rw-r--r--drivers/net/wireless/ath9k/hw.c276
-rw-r--r--drivers/net/wireless/ath9k/hw.h23
-rw-r--r--drivers/net/wireless/ath9k/initvals.h701
-rw-r--r--drivers/net/wireless/ath9k/mac.c4
-rw-r--r--drivers/net/wireless/ath9k/main.c1503
-rw-r--r--drivers/net/wireless/ath9k/rc.c1696
-rw-r--r--drivers/net/wireless/ath9k/rc.h219
-rw-r--r--drivers/net/wireless/ath9k/recv.c600
-rw-r--r--drivers/net/wireless/ath9k/xmit.c465
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-io.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c121
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h55
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c75
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c157
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c272
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c14
-rw-r--r--drivers/net/wireless/orinoco/orinoco.c160
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h6
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c21
-rw-r--r--drivers/net/wireless/p54/p54.h3
-rw-r--r--drivers/net/wireless/p54/p54common.c69
-rw-r--r--drivers/net/wireless/p54/p54common.h2
-rw-r--r--drivers/net/wireless/p54/p54pci.c42
-rw-r--r--drivers/net/wireless/p54/p54pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c125
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c125
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c151
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00leds.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c25
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h18
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h22
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c113
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h136
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c161
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c433
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h7
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c214
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rtl8225.c6
-rw-r--r--include/linux/ieee80211.h62
-rw-r--r--include/linux/nl80211.h5
-rw-r--r--include/linux/rfkill.h1
-rw-r--r--include/net/wireless.h22
-rw-r--r--net/mac80211/Kconfig8
-rw-r--r--net/mac80211/ht.c2
-rw-r--r--net/mac80211/main.c5
-rw-r--r--net/mac80211/mlme.c15
-rw-r--r--net/mac80211/rc80211_pid_algo.c2
-rw-r--r--net/mac80211/wep.c7
-rw-r--r--net/rfkill/rfkill.c17
-rw-r--r--net/wireless/Kconfig11
-rw-r--r--net/wireless/core.c5
-rw-r--r--net/wireless/core.h13
-rw-r--r--net/wireless/nl80211.c5
-rw-r--r--net/wireless/reg.c586
-rw-r--r--net/wireless/reg.h21
83 files changed, 6608 insertions, 5991 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 84b49c83ae67..ea543fcf2687 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -214,6 +214,21 @@ config HERMES
configure your card and that /etc/pcmcia/wireless.opts works :
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
+config HERMES_CACHE_FW_ON_INIT
+ bool "Cache Hermes firmware on driver initialisation"
+ depends on HERMES
+ default y
+ ---help---
+ Say Y to cache any firmware required by the Hermes drivers
+ on startup. The firmware will remain cached until the
+ driver is unloaded. The cache uses 64K of RAM.
+
+ Otherwise load the firmware from userspace as required. In
+ this case the driver should be unloaded and restarted
+ whenever the firmware is changed.
+
+ If you are not sure, say Y.
+
config APPLE_AIRPORT
tristate "Apple Airport support (built-in)"
depends on PPC_PMAC && HERMES
@@ -508,7 +523,7 @@ config RTL8180
config RTL8187
tristate "Realtek 8187 and 8187B USB support"
- depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+ depends on MAC80211 && USB && WLAN_80211
select EEPROM_93CX6
---help---
This is a driver for RTL8187 and RTL8187B based cards.
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index a725bb94a52d..5ee2dd1814c2 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -821,13 +821,6 @@ struct ath5k_athchan_2ghz {
return (false); \
} while (0)
-enum ath5k_ant_setting {
- AR5K_ANT_VARIABLE = 0, /* variable by programming */
- AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
- AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
- AR5K_ANT_MAX = 3,
-};
-
/*
* Hardware interrupt abstraction
*/
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index 51d569883cdd..49d82d79d3fc 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
{
struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev;
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] = {};
int ret;
u32 srev;
@@ -317,15 +317,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
- /* Set MAC address */
- ret = ath5k_eeprom_read_mac(ah, mac);
- if (ret) {
- ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
- sc->pdev->device);
- goto err_free;
- }
-
+ /* MAC address is cleared until add_interface */
ath5k_hw_set_lladdr(ah, mac);
+
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
memset(ah->ah_bssid, 0xff, ETH_ALEN);
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 34cd1a4a297f..4bcea5a9d70b 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -200,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev);
#endif /* CONFIG_PM */
static struct pci_driver ath5k_pci_driver = {
- .name = "ath5k_pci",
+ .name = KBUILD_MODNAME,
.id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe,
.remove = __devexit_p(ath5k_pci_remove),
@@ -707,7 +707,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] = {};
int ret;
ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
@@ -777,7 +777,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
- ath5k_hw_get_lladdr(ah, mac);
+ ret = ath5k_eeprom_read_mac(ah, mac);
+ if (ret) {
+ ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+ sc->pdev->device);
+ goto err_queues;
+ }
+
SET_IEEE80211_PERM_ADDR(hw, mac);
/* All MAC address bits matter for ACKs */
memset(sc->bssidmask, 0xff, ETH_ALEN);
@@ -2765,6 +2771,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
/* Set to a reasonable value. Note that this will
* be set to mac80211's value at ath5k_config(). */
sc->bintval = 1000;
+ ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
ret = 0;
end:
@@ -2777,11 +2784,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ath5k_softc *sc = hw->priv;
+ u8 mac[ETH_ALEN] = {};
mutex_lock(&sc->lock);
if (sc->vif != conf->vif)
goto end;
+ ath5k_hw_set_lladdr(sc->ah, mac);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
index a883839b6a9f..1cb7edfae625 100644
--- a/drivers/net/wireless/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
/*
* Translate binary channel representation in EEPROM to frequency
*/
-static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
- unsigned int mode)
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+ unsigned int mode)
{
u16 val;
@@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
return bin;
if (mode == AR5K_EEPROM_MODE_11A) {
- if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
val = (5 * bin) + 4800;
else
val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
(bin * 10) + 5100;
} else {
- if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
val = bin + 2300;
else
val = bin + 2400;
@@ -88,6 +89,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
}
/*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ int ret;
+ u16 val;
+
+ /* Initial TX thermal adjustment values */
+ ee->ee_tx_clip = 4;
+ ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+ ee->ee_gain_select = 1;
+
+ /*
+ * Read values from EEPROM and store them in the capability structure
+ */
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+ /* Return if we have an old EEPROM */
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+ return 0;
+
+#ifdef notyet
+ /*
+ * Validate the checksum of the EEPROM date. There are some
+ * devices with invalid EEPROMs.
+ */
+ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+ cksum ^= val;
+ }
+ if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+ return -EIO;
+ }
+#endif
+
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+ ee_ant_gain);
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+ }
+
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+ ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+ ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+ }
+
+ return 0;
+}
+
+
+/*
* Read antenna infos from eeprom
*/
static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
@@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
AR5K_EEPROM_READ(o++, val);
ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
- ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
+ ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f;
ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
AR5K_EEPROM_READ(o++, val);
@@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
u16 val;
int ret;
+ ee->ee_n_piers[mode] = 0;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ ee->ee_ob[mode][3] = (val >> 5) & 0x7;
+ ee->ee_db[mode][3] = (val >> 2) & 0x7;
+ ee->ee_ob[mode][2] = (val << 1) & 0x7;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
+ ee->ee_db[mode][2] = (val >> 12) & 0x7;
+ ee->ee_ob[mode][1] = (val >> 9) & 0x7;
+ ee->ee_db[mode][1] = (val >> 6) & 0x7;
+ ee->ee_ob[mode][0] = (val >> 3) & 0x7;
+ ee->ee_db[mode][0] = val & 0x7;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ case AR5K_EEPROM_MODE_11B:
+ ee->ee_ob[mode][1] = (val >> 4) & 0x7;
+ ee->ee_db[mode][1] = val & 0x7;
+ break;
+ }
+
AR5K_EEPROM_READ(o++, val);
ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
ee->ee_thr_62[mode] = val & 0xff;
@@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
AR5K_EEPROM_READ(o++, val);
ee->ee_i_gain[mode] |= (val << 3) & 0x38;
- if (mode == AR5K_EEPROM_MODE_11G)
+ if (mode == AR5K_EEPROM_MODE_11G) {
ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+ ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+ }
}
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
@@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
- mode == AR5K_EEPROM_MODE_11G)
- ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+ goto done;
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+ break;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_margin_tx_rx[mode] = val & 0x3f;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ AR5K_EEPROM_READ(o++, val);
+
+ ee->ee_pwr_cal_b[0].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ ee->ee_pwr_cal_b[1].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+ if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_pwr_cal_b[2].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ AR5K_EEPROM_READ(o++, val);
+
+ ee->ee_pwr_cal_g[0].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ ee->ee_pwr_cal_g[1].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+ if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_turbo_max_power[mode] = val & 0x7f;
+ ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_pwr_cal_g[2].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+ ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ }
+ break;
+ }
+
+done:
/* return new offset */
*offset = o;
@@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
}
/*
- * Initialize eeprom & capabilities structs
+ * Read turbo mode information on newer EEPROM versions
*/
-int ath5k_eeprom_init(struct ath5k_hw *ah)
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+ u32 *offset, unsigned int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- unsigned int mode, i;
- int ret;
- u32 offset;
+ u32 o = *offset;
u16 val;
+ int ret;
- /* Initial TX thermal adjustment values */
- ee->ee_tx_clip = 4;
- ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
- ee->ee_gain_select = 1;
+ if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+ return 0;
- /*
- * Read values from EEPROM and store them in the capability structure
- */
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+ switch (mode){
+ case AR5K_EEPROM_MODE_11A:
+ ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
- /* Return if we have an old EEPROM */
- if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
- return 0;
+ ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+ ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+ ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+ ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+ if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+ ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+ ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+ ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+ ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+ ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+ break;
+ }
+
+ /* return new offset */
+ *offset = o;
+
+ return 0;
+}
+
+
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ u32 mode_offset[3];
+ unsigned int mode;
+ u32 offset;
+ int ret;
-#ifdef notyet
/*
- * Validate the checksum of the EEPROM date. There are some
- * devices with invalid EEPROMs.
+ * Get values for all modes
*/
- for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
- AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
- cksum ^= val;
+ mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+ mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+ mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+ ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+ AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+ for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+ offset = mode_offset[mode];
+
+ ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+ if (ret)
+ return ret;
+
+ ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+ if (ret)
+ return ret;
+
+ ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+ if (ret)
+ return ret;
}
- if (cksum != AR5K_EEPROM_INFO_CKSUM) {
- ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
- return -EIO;
+
+ /* override for older eeprom versions for better performance */
+ if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
}
-#endif
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
- ee_ant_gain);
+ return 0;
+}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
- }
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+ const static u16 intercepts3[] =
+ { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+ const static u16 intercepts3_2[] =
+ { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+ const u16 *ip;
+ int i;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+ ip = intercepts3_2;
+ else
+ ip = intercepts3;
- if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
- AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
- ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
- ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+ for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+ *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
- AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
- ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
- ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+ struct ath5k_chan_pcal_info *pc, u8 *count)
+{
+ int o = *offset;
+ int i = 0;
+ u8 f1, f2;
+ int ret;
+ u16 val;
+
+ while(i < max) {
+ AR5K_EEPROM_READ(o++, val);
+
+ f1 = (val >> 8) & 0xff;
+ f2 = val & 0xff;
+
+ if (f1)
+ pc[i++].freq = f1;
+
+ if (f2)
+ pc[i++].freq = f2;
+
+ if (!f1 || !f2)
+ break;
}
+ *offset = o;
+ *count = i;
- /*
- * Get conformance test limit values
- */
- offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
- ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+ return 0;
+}
+
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+ int i, ret;
+ u16 val;
+ u8 mask;
+
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+ ath5k_eeprom_read_freq_list(ah, &offset,
+ AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+ &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]);
+ } else {
+ mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
- for (i = 0; i < ee->ee_ctls; i++) {
AR5K_EEPROM_READ(offset++, val);
- ee->ee_ctl[i] = (val >> 8) & 0xff;
- ee->ee_ctl[i + 1] = val & 0xff;
+ pcal[0].freq = (val >> 9) & mask;
+ pcal[1].freq = (val >> 2) & mask;
+ pcal[2].freq = (val << 5) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[2].freq |= (val >> 11) & 0x1f;
+ pcal[3].freq = (val >> 4) & mask;
+ pcal[4].freq = (val << 3) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[4].freq |= (val >> 13) & 0x7;
+ pcal[5].freq = (val >> 6) & mask;
+ pcal[6].freq = (val << 1) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[6].freq |= (val >> 15) & 0x1;
+ pcal[7].freq = (val >> 8) & mask;
+ pcal[8].freq = (val >> 1) & mask;
+ pcal[9].freq = (val << 6) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[9].freq |= (val >> 10) & 0x3f;
+ ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
}
- /*
- * Get values for 802.11a (5GHz)
- */
- mode = AR5K_EEPROM_MODE_11A;
+ for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) {
+ pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+ pcal[i].freq, AR5K_EEPROM_MODE_11A);
+ }
- ee->ee_turbo_max_power[mode] =
- AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+ return 0;
+}
- offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal;
+ int i;
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11B:
+ pcal = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ pcal = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ ath5k_eeprom_read_freq_list(ah, &offset,
+ AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+ &ee->ee_n_piers[mode]);
+ for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) {
+ pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+ pcal[i].freq, mode);
+ }
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][3] = (val >> 5) & 0x7;
- ee->ee_db[mode][3] = (val >> 2) & 0x7;
- ee->ee_ob[mode][2] = (val << 1) & 0x7;
-
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
- ee->ee_db[mode][2] = (val >> 12) & 0x7;
- ee->ee_ob[mode][1] = (val >> 9) & 0x7;
- ee->ee_db[mode][1] = (val >> 6) & 0x7;
- ee->ee_ob[mode][0] = (val >> 3) & 0x7;
- ee->ee_db[mode][0] = val & 0x7;
-
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ return 0;
+}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_margin_tx_rx[mode] = val & 0x3f;
+
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal;
+ int offset, ret;
+ int i, j;
+ u16 val;
+
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+
+ ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+ offset + AR5K_EEPROM_GROUP1_OFFSET);
+ if (ret < 0)
+ return ret;
+
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+ pcal = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+ !AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ pcal = ee->ee_pwr_cal_b;
+ offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+ /* fixed piers */
+ pcal[0].freq = 2412;
+ pcal[1].freq = 2447;
+ pcal[2].freq = 2484;
+ ee->ee_n_piers[mode] = 3;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ pcal = ee->ee_pwr_cal_g;
+ offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+ /* fixed piers */
+ pcal[0].freq = 2312;
+ pcal[1].freq = 2412;
+ pcal[2].freq = 2484;
+ ee->ee_n_piers[mode] = 3;
+ break;
+ default:
+ return -EINVAL;
}
- /*
- * Get values for 802.11b (2.4GHz)
- */
- mode = AR5K_EEPROM_MODE_11B;
- offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ struct ath5k_chan_pcal_info_rf5111 *cdata =
+ &pcal[i].rf5111_info;
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+ cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+ cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][1] = (val >> 4) & 0x7;
- ee->ee_db[mode][1] = val & 0x7;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pwr[0] |= ((val >> 14) & 0x3);
+ cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pwr[3] |= ((val >> 12) & 0xf);
+ cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M);
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][0] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
- ee->ee_cal_pier[mode][1] =
- ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+ cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][2] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+ cdata->pwr[8] |= ((val >> 14) & 0x3);
+ cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+ ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+ cdata->pcdac_max, cdata->pcdac);
+
+ for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) {
+ cdata->pwr[j] = (u16)
+ (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]);
+ }
}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
- ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ return 0;
+}
- /*
- * Get values for 802.11g (2.4GHz)
- */
- mode = AR5K_EEPROM_MODE_11G;
- offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+ struct ath5k_chan_pcal_info *gen_chan_info;
+ u32 offset;
+ unsigned int i, c;
+ u16 val;
+ int ret;
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ /*
+ * Read 5GHz EEPROM channels
+ */
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+ gen_chan_info = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+ /* NB: frequency piers parsed during mode init */
+ gen_chan_info = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP4_OFFSET;
+ else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+ /* NB: frequency piers parsed during mode init */
+ gen_chan_info = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][1] = (val >> 4) & 0x7;
- ee->ee_db[mode][1] = val & 0x7;
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ chan_pcal_info = &gen_chan_info[i].rf5112_info;
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ /* Power values in dBm * 4
+ * for the lower xpd gain curve
+ * (0 dBm -> higher output power) */
+ for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr_x0[c] = (val & 0xff);
+ chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff);
+ }
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ /* PCDAC steps
+ * corresponding to the above power
+ * measurements */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][0] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
- ee->ee_cal_pier[mode][1] =
- ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+ chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+ chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+ chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
+ /* Power values in dBm * 4
+ * for the higher xpd gain curve
+ * (18 dBm -> lower output power) */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_turbo_max_power[mode] = val & 0x7f;
- ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+ chan_pcal_info->pwr_x3[0] = (val & 0xff);
+ chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff);
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][2] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+ chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+ /* PCDAC steps
+ * corresponding to the above power
+ * measurements (static) */
+ chan_pcal_info->pcdac_x3[0] = 20;
+ chan_pcal_info->pcdac_x3[1] = 35;
+ chan_pcal_info->pcdac_x3[2] = 63;
+
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+ chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff);
+
+ /* Last xpd0 power level is also channel maximum */
+ gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+ } else {
+ chan_pcal_info->pcdac_x0[0] = 1;
+ gen_chan_info[i].max_pwr = ((val >> 8) & 0xff);
+ }
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
- ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ /* Recreate pcdac_x0 table for this channel using pcdac steps */
+ chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0];
+ chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1];
+ chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2];
+ }
+
+ return 0;
+}
+
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+ static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+ unsigned int sz;
+
+ sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+ sz *= ee->ee_n_piers[mode];
+
+ return sz;
+}
+
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+ u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11G:
+ if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2;
+ /* fall through */
+ case AR5K_EEPROM_MODE_11B:
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5;
+ /* fall through */
+ case AR5K_EEPROM_MODE_11A:
+ break;
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info;
+ struct ath5k_chan_pcal_info *gen_chan_info;
+ unsigned int i, c;
+ u32 offset;
+ int ret;
+ u16 val;
+ u8 pd_gains = 0;
+
+ if (ee->ee_x_gain[mode] & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++;
+ ee->ee_pd_gains[mode] = pd_gains;
+
+ offset = ath5k_cal_data_offset_2413(ee, mode);
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+
+ ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+ offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+ gen_chan_info = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+ return 0;
+ ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+ gen_chan_info = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+ gen_chan_info = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (pd_gains == 0)
+ return 0;
+
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ chan_pcal_info = &gen_chan_info[i].rf2413_info;
+
+ /*
+ * Read pwr_i, pddac_i and the first
+ * 2 pd points (pwr, pddac)
+ */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
- ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+ chan_pcal_info->pwr_i[0] = val & 0x1f;
+ chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f;
+ chan_pcal_info->pwr[0][0] =
+ (val >> 12) & 0xf;
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[0][0] = val & 0x3f;
+ chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf;
+ chan_pcal_info->pddac[0][1] =
+ (val >> 10) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[0][2] = val & 0xf;
+ chan_pcal_info->pddac[0][2] =
+ (val >> 4) & 0x3f;
+
+ chan_pcal_info->pwr[0][3] = 0;
+ chan_pcal_info->pddac[0][3] = 0;
+
+ if (pd_gains > 1) {
+ /*
+ * Pd gain 0 is not the last pd gain
+ * so it only has 2 pd points.
+ * Continue wih pd gain 1.
+ */
+ chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f;
+
+ chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1;
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1;
+
+ chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf;
+ chan_pcal_info->pddac[1][0] =
+ (val >> 10) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[1][1] = val & 0xf;
+ chan_pcal_info->pddac[1][1] =
+ (val >> 4) & 0x3f;
+ chan_pcal_info->pwr[1][2] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[1][2] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[1][2] |=
+ (val & 0xF) << 2;
+
+ chan_pcal_info->pwr[1][3] = 0;
+ chan_pcal_info->pddac[1][3] = 0;
+ } else if (pd_gains == 1) {
+ /*
+ * Pd gain 0 is the last one so
+ * read the extra point.
+ */
+ chan_pcal_info->pwr[0][3] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[0][3] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[0][3] |=
+ (val & 0xF) << 2;
+ }
+
+ /*
+ * Proceed with the other pd_gains
+ * as above.
+ */
+ if (pd_gains > 2) {
+ chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f;
+ chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[2][0] =
+ (val >> 0) & 0xf;
+ chan_pcal_info->pddac[2][0] =
+ (val >> 4) & 0x3f;
+ chan_pcal_info->pwr[2][1] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[2][1] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[2][1] |=
+ (val & 0xF) << 2;
+
+ chan_pcal_info->pwr[2][2] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[2][2] =
+ (val >> 8) & 0x3f;
+
+ chan_pcal_info->pwr[2][3] = 0;
+ chan_pcal_info->pddac[2][3] = 0;
+ } else if (pd_gains == 2) {
+ chan_pcal_info->pwr[1][3] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[1][3] =
+ (val >> 8) & 0x3f;
+ }
+
+ if (pd_gains > 3) {
+ chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+ chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f;
+ chan_pcal_info->pwr[3][0] =
+ (val >> 10) & 0xf;
+ chan_pcal_info->pddac[3][0] =
+ (val >> 14) & 0x3;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[3][0] |=
+ (val & 0xF) << 2;
+ chan_pcal_info->pwr[3][1] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[3][1] =
+ (val >> 8) & 0x3f;
+
+ chan_pcal_info->pwr[3][2] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[3][2] |=
+ ((val >> 0) & 0x3) << 2;
+
+ chan_pcal_info->pddac[3][2] =
+ (val >> 2) & 0x3f;
+ chan_pcal_info->pwr[3][3] =
+ (val >> 8) & 0xf;
+
+ chan_pcal_info->pddac[3][3] =
+ (val >> 12) & 0xF;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[3][3] |=
+ ((val >> 0) & 0x3) << 4;
+ } else if (pd_gains == 3) {
+ chan_pcal_info->pwr[2][3] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[2][3] |=
+ ((val >> 0) & 0x3) << 2;
+
+ chan_pcal_info->pddac[2][3] =
+ (val >> 2) & 0x3f;
+ }
+
+ for (c = 0; c < pd_gains; c++) {
+ /* Recreate pwr table for this channel using pwr steps */
+ chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2;
+ chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0];
+ chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1];
+ chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2];
+ if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2])
+ chan_pcal_info->pwr[c][3] = 0;
+
+ /* Recreate pddac table for this channel using pddac steps */
+ chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c];
+ chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0];
+ chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1];
+ chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2];
+ if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2])
+ chan_pcal_info->pddac[c][3] = 0;
}
}
- /*
- * Read 5GHz EEPROM channels
- */
+ return 0;
+}
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_rate_pcal_info *rate_pcal_info;
+ u16 *rate_target_pwr_num;
+ u32 offset;
+ u16 val;
+ int ret, i;
+
+ offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+ rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_a;
+ ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_b;
+ ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_g;
+ ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Different freq mask for older eeproms (<= v3.2) */
+ if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+ for (i = 0; i < (*rate_target_pwr_num); i++) {
+ AR5K_EEPROM_READ(offset++, val);
+ rate_pcal_info[i].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+ rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+ rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+
+ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+ val == 0) {
+ (*rate_target_pwr_num) = i;
+ break;
+ }
+
+ rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+ rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+ rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+ }
+ } else {
+ for (i = 0; i < (*rate_target_pwr_num); i++) {
+ AR5K_EEPROM_READ(offset++, val);
+ rate_pcal_info[i].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+ rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+ rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+
+ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+ val == 0) {
+ (*rate_target_pwr_num) = i;
+ break;
+ }
+
+ rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+ rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+ rate_pcal_info[i].target_power_54 = (val & 0x3f);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ int (*read_pcal)(struct ath5k_hw *hw, int mode);
+ int mode;
+ int err;
+
+ if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+ (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+ read_pcal = ath5k_eeprom_read_pcal_info_5112;
+ else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+ (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+ read_pcal = ath5k_eeprom_read_pcal_info_2413;
+ else
+ read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+ for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+ err = read_pcal(ah, mode);
+ if (err)
+ return err;
+
+ err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Read conformance test limits */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_edge_power *rep;
+ unsigned int fmask, pmask;
+ unsigned int ctl_mode;
+ int ret, i, j;
+ u32 offset;
+ u16 val;
+
+ pmask = AR5K_EEPROM_POWER_M;
+ fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+ offset = AR5K_EEPROM_CTL(ee->ee_version);
+ ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+ for (i = 0; i < ee->ee_ctls; i += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ ee->ee_ctl[i] = (val >> 8) & 0xff;
+ ee->ee_ctl[i + 1] = val & 0xff;
+ }
+
+ offset = AR5K_EEPROM_GROUP8_OFFSET;
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+ offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+ AR5K_EEPROM_GROUP5_OFFSET;
+ else
+ offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
+
+ rep = ee->ee_ctl_pwr;
+ for(i = 0; i < ee->ee_ctls; i++) {
+ switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+ case AR5K_CTL_11A:
+ case AR5K_CTL_TURBO:
+ ctl_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ default:
+ ctl_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ }
+ if (ee->ee_ctl[i] == 0) {
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+ offset += 8;
+ else
+ offset += 7;
+ rep += AR5K_EEPROM_N_EDGES;
+ continue;
+ }
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[j].freq = (val >> 8) & fmask;
+ rep[j + 1].freq = val & fmask;
+ }
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[j].edge = (val >> 8) & pmask;
+ rep[j].flag = (val >> 14) & 1;
+ rep[j + 1].edge = val & pmask;
+ rep[j + 1].flag = (val >> 6) & 1;
+ }
+ } else {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[0].freq = (val >> 9) & fmask;
+ rep[1].freq = (val >> 2) & fmask;
+ rep[2].freq = (val << 5) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[2].freq |= (val >> 11) & 0x1f;
+ rep[3].freq = (val >> 4) & fmask;
+ rep[4].freq = (val << 3) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[4].freq |= (val >> 13) & 0x7;
+ rep[5].freq = (val >> 6) & fmask;
+ rep[6].freq = (val << 1) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[6].freq |= (val >> 15) & 0x1;
+ rep[7].freq = (val >> 8) & fmask;
+
+ rep[0].edge = (val >> 2) & pmask;
+ rep[1].edge = (val << 4) & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[1].edge |= (val >> 12) & 0xf;
+ rep[2].edge = (val >> 6) & pmask;
+ rep[3].edge = val & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[4].edge = (val >> 10) & pmask;
+ rep[5].edge = (val >> 4) & pmask;
+ rep[6].edge = (val << 2) & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[6].edge |= (val >> 14) & 0x3;
+ rep[7].edge = (val >> 8) & pmask;
+ }
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+ rep[j].freq = ath5k_eeprom_bin2freq(ee,
+ rep[j].freq, ctl_mode);
+ }
+ rep += AR5K_EEPROM_N_EDGES;
+ }
return 0;
}
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+ int err;
+
+ err = ath5k_eeprom_init_header(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_init_modes(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_read_pcal_info(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_read_ctl_info(ah);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
/*
* Read the MAC address from eeprom
*/
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h
index a468ecfbb18a..09eb7d0176a4 100644
--- a/drivers/net/wireless/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath5k/eeprom.h
@@ -25,24 +25,8 @@
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
-#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
-#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
-#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
-#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
-#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
-#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
-#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
-#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
-#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
-#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
-#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
-#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
-#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
-#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
-#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
#define AR5K_EEPROM_INFO_CKSUM 0xffff
@@ -53,15 +37,19 @@
#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */
#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */
#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */
#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3 0x4003
+#define AR5K_EEPROM_VERSION_4_3 0x4003 /* power calibration changes */
#define AR5K_EEPROM_VERSION_4_4 0x4004
#define AR5K_EEPROM_VERSION_4_5 0x4005
#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7 0x4007
+#define AR5K_EEPROM_VERSION_4_7 0x3007 /* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */
#define AR5K_EEPROM_MODE_11A 0
#define AR5K_EEPROM_MODE_11B 1
@@ -74,8 +62,8 @@
#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */
#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */
#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */
#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c
#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
@@ -87,27 +75,95 @@
(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1)
/* calibration settings */
#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET 0x0
+#define AR5K_EEPROM_GROUP2_OFFSET 0x5
+#define AR5K_EEPROM_GROUP3_OFFSET 0x37
+#define AR5K_EEPROM_GROUP4_OFFSET 0x46
+#define AR5K_EEPROM_GROUP5_OFFSET 0x55
+#define AR5K_EEPROM_GROUP6_OFFSET 0x65
+#define AR5K_EEPROM_GROUP7_OFFSET 0x69
+#define AR5K_EEPROM_GROUP8_OFFSET 0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
/* [3.1 - 3.3] */
#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec
#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0 0x00c4
-#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
-#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
-#define AR5K_EEPROM_MISC1 0x00c5
-#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
-
+#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
/* Some EEPROM defines */
#define AR5K_EEPROM_EEP_SCALE 100
@@ -115,8 +171,11 @@
#define AR5K_EEPROM_N_MODES 3
#define AR5K_EEPROM_N_5GHZ_CHAN 10
#define AR5K_EEPROM_N_2GHZ_CHAN 3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
#define AR5K_EEPROM_MAX_CHAN 10
+#define AR5K_EEPROM_N_PWR_POINTS_5111 11
#define AR5K_EEPROM_N_PCDAC 11
+#define AR5K_EEPROM_N_PHASE_CAL 5
#define AR5K_EEPROM_N_TEST_FREQ 8
#define AR5K_EEPROM_N_EDGES 8
#define AR5K_EEPROM_N_INTERCEPTS 11
@@ -136,6 +195,8 @@
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
#define AR5K_EEPROM_N_XPD0_POINTS 4
#define AR5K_EEPROM_N_XPD3_POINTS 3
+#define AR5K_EEPROM_N_PD_GAINS 4
+#define AR5K_EEPROM_N_PD_POINTS 5
#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35
#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
#define AR5K_EEPROM_POWER_M 0x3f
@@ -158,8 +219,99 @@
#define AR5K_EEPROM_READ_HDR(_o, _v) \
AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \
-/* Struct to hold EEPROM calibration data */
+enum ath5k_ant_setting {
+ AR5K_ANT_VARIABLE = 0, /* variable by programming */
+ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
+ AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
+ AR5K_ANT_MAX = 3,
+};
+
+enum ath5k_ctl_mode {
+ AR5K_CTL_11A = 0,
+ AR5K_CTL_11B = 1,
+ AR5K_CTL_11G = 2,
+ AR5K_CTL_TURBO = 3,
+ AR5K_CTL_108G = 4,
+ AR5K_CTL_2GHT20 = 5,
+ AR5K_CTL_5GHT20 = 6,
+ AR5K_CTL_2GHT40 = 7,
+ AR5K_CTL_5GHT40 = 8,
+ AR5K_CTL_MODE_M = 15,
+};
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+ /* Power levels in half dbm units
+ * for one power curve. */
+ u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+ /* PCDAC table steps
+ * for the above values */
+ u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+ /* Starting PCDAC step */
+ u8 pcdac_min;
+ /* Final PCDAC step */
+ u8 pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+ /* Power levels in quarter dBm units
+ * for lower (0) and higher (3)
+ * level curves */
+ s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+ s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+ /* PCDAC table steps
+ * for the above values */
+ u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+ u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+ /* Starting pwr/pddac values */
+ s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
+ u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
+ /* (pwr,pddac) points */
+ s8 pwr[AR5K_EEPROM_N_PD_GAINS]
+ [AR5K_EEPROM_N_PD_POINTS];
+ u8 pddac[AR5K_EEPROM_N_PD_GAINS]
+ [AR5K_EEPROM_N_PD_POINTS];
+};
+
+struct ath5k_chan_pcal_info {
+ /* Frequency */
+ u16 freq;
+ /* Max available power */
+ s8 max_pwr;
+ union {
+ struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+ struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+ struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+ };
+};
+
+/* Per rate calibration data for each mode, used for power table setup */
+struct ath5k_rate_pcal_info {
+ u16 freq; /* Frequency */
+ /* Power level for 6-24Mbit/s rates */
+ u16 target_power_6to24;
+ /* Power level for 36Mbit rate */
+ u16 target_power_36;
+ /* Power level for 48Mbit rate */
+ u16 target_power_48;
+ /* Power level for 54Mbit rate */
+ u16 target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+ u16 freq;
+ u16 edge; /* in half dBm */
+ bool flag;
+};
+
+/* EEPROM calibration data */
struct ath5k_eeprom_info {
+
+ /* Header information */
u16 ee_magic;
u16 ee_protect;
u16 ee_regdomain;
@@ -168,6 +320,11 @@ struct ath5k_eeprom_info {
u16 ee_ant_gain;
u16 ee_misc0;
u16 ee_misc1;
+ u16 ee_misc2;
+ u16 ee_misc3;
+ u16 ee_misc4;
+ u16 ee_misc5;
+ u16 ee_misc6;
u16 ee_cck_ofdm_gain_delta;
u16 ee_cck_ofdm_power_delta;
u16 ee_scaled_cck_delta;
@@ -185,7 +342,7 @@ struct ath5k_eeprom_info {
u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES];
u16 ee_xr_power[AR5K_EEPROM_N_MODES];
u16 ee_switch_settling[AR5K_EEPROM_N_MODES];
- u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+ u16 ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
@@ -198,18 +355,40 @@ struct ath5k_eeprom_info {
u16 ee_x_gain[AR5K_EEPROM_N_MODES];
u16 ee_i_gain[AR5K_EEPROM_N_MODES];
u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+ u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+ u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+ u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
- /* Unused */
+ /* Power calibration data */
u16 ee_false_detect[AR5K_EEPROM_N_MODES];
- u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
- u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+ /* Number of pd gain curves per mode (RF2413) */
+ u8 ee_pd_gains[AR5K_EEPROM_N_MODES];
+
+ u8 ee_n_piers[AR5K_EEPROM_N_MODES];
+ struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+ struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
+ struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
+
+ /* Per rate target power levels */
+ u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
/* Conformance test limits (Unused) */
u16 ee_ctls;
u16 ee_ctl[AR5K_EEPROM_MAX_CTLS];
+ struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
/* Noise Floor Calibration settings */
s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES];
s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+ s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+ s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+ s8 ee_pd_gain_overlap;
+
+ u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
+
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index 5003263c9ea4..dc2d7d8bdb7a 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
0xffffc07f);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
- (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+ (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
0xfffc0fff);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index c58cfdeb49c9..c741e8d34748 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -9,7 +9,6 @@ ath9k-y += hw.o \
main.o \
recv.o \
xmit.o \
- rc.o \
- core.o
+ rc.o
obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 3a180ce1770b..5b9bc545e964 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -401,22 +401,6 @@ enum ath9k_int {
ATH9K_INT_NOCARD = 0xffffffff
};
-struct ath9k_rate_table {
- int rateCount;
- u8 rateCodeToIndex[256];
- struct {
- u8 valid;
- u8 phy;
- u32 rateKbps;
- u8 rateCode;
- u8 shortPreamble;
- u8 dot11Rate;
- u8 controlRate;
- u16 lpAckDuration;
- u16 spAckDuration;
- } info[32];
-};
-
#define ATH9K_RATESERIES_RTS_CTS 0x0001
#define ATH9K_RATESERIES_2040 0x0002
#define ATH9K_RATESERIES_HALFGI 0x0004
@@ -492,12 +476,10 @@ struct ath9k_channel {
(((_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_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B)
#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_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0)
#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)
@@ -506,6 +488,7 @@ struct ath9k_channel {
#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) || \
@@ -702,13 +685,19 @@ enum ath9k_ani_cmd {
ATH9K_ANI_ALL = 0xff
};
-enum phytype {
- PHY_DS,
- PHY_FH,
- PHY_OFDM,
- PHY_HT,
+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 PHY_CCK PHY_DS
enum ath9k_tp_scale {
ATH9K_TP_SCALE_MAX = 0,
@@ -828,6 +817,8 @@ struct chan_centers {
u16 ext_center;
};
+struct ath_rate_table;
+
/* Helpers */
enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
@@ -838,7 +829,7 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
u16 flags, u16 *low,
u16 *high);
u16 ath9k_hw_computetxtime(struct ath_hal *ah,
- const struct ath9k_rate_table *rates,
+ struct ath_rate_table *rates,
u32 frameLen, u16 rateix,
bool shortPreamble);
u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
@@ -883,12 +874,6 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
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);
-
-/* Rate table */
-
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
- u32 mode);
-
/* HW Capabilities */
bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
@@ -904,7 +889,7 @@ 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);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
void ath9k_enable_rfkill(struct ath_hal *ah);
#endif
int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index d186cd41c235..377d2df05316 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -14,13 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
- /* Implementation of beacon processing. */
-
#include "core.h"
/*
- * Configure parameters for the beacon queue
- *
* This function will modify certain transmit queue properties depending on
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
* settings and channel width min/max
@@ -54,9 +50,15 @@ static int ath_beaconq_config(struct ath_softc *sc)
}
}
+static void ath_bstuck_process(struct ath_softc *sc)
+{
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: stuck beacon; resetting (bmiss count %u)\n",
+ __func__, sc->sc_bmisscount);
+ ath_reset(sc, false);
+}
+
/*
- * Setup the beacon frame for transmit.
- *
* 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.
@@ -68,7 +70,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
- const struct ath9k_rate_table *rt;
+ struct ath_rate_table *rt;
int flags, antenna;
u8 rix, rate;
int ctsrate = 0;
@@ -106,10 +108,10 @@ static void ath_beacon_setup(struct ath_softc *sc,
* XXX everything at min xmit rate
*/
rix = 0;
- rt = sc->sc_currates;
- rate = rt->info[rix].rateCode;
+ rt = sc->hw_rate_table[sc->sc_curmode];
+ rate = rt->info[rix].ratecode;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- rate |= rt->info[rix].shortPreamble;
+ rate |= rt->info[rix].short_preamble;
ath9k_hw_set11n_txdesc(ah, ds,
skb->len + FCS_LEN, /* frame length */
@@ -138,14 +140,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
ctsrate, ctsduration, series, 4, 0);
}
-/*
- * Generate beacon frame and queue cab data for a vap.
- *
- * Updates the contents of the beacon frame. It is assumed that the buffer for
- * the beacon frame has been allocated in the ATH object, and simply needs to
- * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will
- * be added to the beacon frame at this point.
-*/
+/* Generate beacon frame and queue cab data for a vap */
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
{
struct ath_buf *bf;
@@ -275,14 +270,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc);
}
-/*
- * Setup a h/w transmit queue for beacons.
- *
- * This function allocates an information structure (struct ath9k_txq_info)
- * on the stack, sets some specific parameters (zero out channel width
- * min/max, and enable aifs). The info structure does not need to be
- * persistant.
-*/
int ath_beaconq_setup(struct ath_hal *ah)
{
struct ath9k_tx_queue_info qi;
@@ -295,14 +282,6 @@ int ath_beaconq_setup(struct ath_hal *ah)
return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
}
-
-/*
- * Allocate and setup an initial beacon frame.
- *
- * Allocate a beacon state variable for a specific VAP instance created on
- * the ATH interface. This routine also calculates the beacon "slot" for
- * staggared beacons in the mBSSID case.
-*/
int ath_beacon_alloc(struct ath_softc *sc, int if_id)
{
struct ieee80211_vif *vif;
@@ -321,7 +300,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
if (!avp->av_bcbuf) {
/* Allocate beacon state for hostap/ibss. We know
* a buffer is available. */
-
avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
struct ath_buf, list);
list_del(&avp->av_bcbuf->list);
@@ -427,12 +405,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
return 0;
}
-/*
- * Reclaim beacon resources and return buffer to the pool.
- *
- * Checks the VAP to put the beacon frame buffer back to the ATH object
- * queue, and de-allocates any skbs that were sent as CAB traffic.
-*/
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
{
if (avp->av_bcbuf != NULL) {
@@ -458,13 +430,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
}
}
-/*
- * Tasklet for Sending Beacons
- *
- * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame
- * contents are done as needed and the slot time is also adjusted based on
- * current state.
-*/
void ath9k_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -481,9 +446,7 @@ void ath9k_beacon_tasklet(unsigned long data)
if (sc->sc_flags & SC_OP_NO_RESET) {
show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
- &rx_clear,
- &rx_frame,
- &tx_frame);
+ &rx_clear, &rx_frame, &tx_frame);
}
/*
@@ -605,9 +568,10 @@ void ath9k_beacon_tasklet(unsigned long data)
if (sc->sc_updateslot == UPDATE) {
sc->sc_updateslot = COMMIT; /* commit next beacon */
sc->sc_slotupdate = slot;
- } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
- ath_setslottime(sc); /* commit change to hardware */
-
+ } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) {
+ ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
+ sc->sc_updateslot = OK;
+ }
if (bfaddr != 0) {
/*
* Stop any current dma and put the new frame(s) on the queue.
@@ -630,20 +594,6 @@ void ath9k_beacon_tasklet(unsigned long data)
}
/*
- * Tasklet for Beacon Stuck processing
- *
- * Processing for Beacon Stuck.
- * Basically resets the chip.
-*/
-void ath_bstuck_process(struct ath_softc *sc)
-{
- DPRINTF(sc, ATH_DBG_BEACON,
- "%s: stuck beacon; resetting (bmiss count %u)\n",
- __func__, sc->sc_bmisscount);
- ath_reset(sc, false);
-}
-
-/*
* Configure the beacon and sleep timers.
*
* When operating as an AP this resets the TSF and sets
@@ -886,8 +836,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
}
}
-/* Function to collect beacon rssi data and resync beacon if necessary */
-
void ath_beacon_sync(struct ath_softc *sc, int if_id)
{
/*
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c
index 1690759fe7b8..0e214f746a96 100644
--- a/drivers/net/wireless/ath9k/calib.c
+++ b/drivers/net/wireless/ath9k/calib.c
@@ -176,14 +176,14 @@ static bool getNoiseFloorThresh(struct ath_hal *ah,
case CHANNEL_A_HT20:
case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS:
- *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+ *nft = (int8_t)ath9k_hw_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 = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+ *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
break;
default:
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
deleted file mode 100644
index 5f5184acb274..000000000000
--- a/drivers/net/wireless/ath9k/core.c
+++ /dev/null
@@ -1,1652 +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.
- */
-
-#include "core.h"
-#include "regd.h"
-
-static u32 ath_chainmask_sel_up_rssi_thres =
- ATH_CHAINMASK_SEL_UP_RSSI_THRES;
-static u32 ath_chainmask_sel_down_rssi_thres =
- ATH_CHAINMASK_SEL_DOWN_RSSI_THRES;
-static u32 ath_chainmask_sel_period =
- ATH_CHAINMASK_SEL_TIMEOUT;
-
-/* 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 u8 parse_mpdudensity(u8 mpdudensity)
-{
- /*
- * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
- * 0 for no restriction
- * 1 for 1/4 us
- * 2 for 1/2 us
- * 3 for 1 us
- * 4 for 2 us
- * 5 for 4 us
- * 6 for 8 us
- * 7 for 16 us
- */
- switch (mpdudensity) {
- case 0:
- return 0;
- case 1:
- case 2:
- case 3:
- /* Our lower layer calculations limit our precision to
- 1 microsecond */
- return 1;
- case 4:
- return 2;
- case 5:
- return 4;
- case 6:
- return 8;
- case 7:
- return 16;
- default:
- return 0;
- }
-}
-
-/*
- * Set current operating mode
- *
- * This function initializes and fills the rate table in the ATH object based
- * on the operating mode.
-*/
-static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
-{
- const struct ath9k_rate_table *rt;
- int i;
-
- memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
- rt = ath9k_hw_getratetable(sc->sc_ah, mode);
- BUG_ON(!rt);
-
- for (i = 0; i < rt->rateCount; i++)
- sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
-
- memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
- for (i = 0; i < 256; i++) {
- u8 ix = rt->rateCodeToIndex[i];
-
- if (ix == 0xff)
- continue;
-
- sc->sc_hwmap[i].ieeerate =
- rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
- sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps;
-
- if (rt->info[ix].shortPreamble ||
- rt->info[ix].phy == PHY_OFDM) {
- /* XXX: Handle this */
- }
-
- /* NB: this uses the last entry if the rate isn't found */
- /* XXX beware of overlow */
- }
- sc->sc_currates = rt;
- sc->sc_curmode = 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);
-}
-
-/*
- * Set up rate table (legacy rates)
- */
-static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
-{
- struct ath_hal *ah = sc->sc_ah;
- const struct ath9k_rate_table *rt = NULL;
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate;
- int i, maxrates;
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G);
- break;
- case IEEE80211_BAND_5GHZ:
- rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A);
- break;
- default:
- break;
- }
-
- if (rt == NULL)
- return;
-
- sband = &sc->sbands[band];
- rate = sc->rates[band];
-
- if (rt->rateCount > ATH_RATE_MAX)
- maxrates = ATH_RATE_MAX;
- else
- maxrates = rt->rateCount;
-
- for (i = 0; i < maxrates; i++) {
- rate[i].bitrate = rt->info[i].rateKbps / 100;
- rate[i].hw_value = rt->info[i].rateCode;
- sband->n_bitrates++;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Rate: %2dMbps, ratecode: %2d\n",
- __func__,
- rate[i].bitrate / 10,
- rate[i].hw_value);
- }
-}
-
-/*
- * Set up channel list
- */
-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,
- "%s: unable to collect channel list; "
- "regdomain likely %u country code %u\n",
- __func__, 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,
- "%s: 2MHz channel: %d, "
- "channelFlags: 0x%x\n",
- __func__, 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,
- "%s: 5MHz channel: %d, "
- "channelFlags: 0x%x\n",
- __func__, c->channel, c->channelFlags);
- }
- }
-
- return 0;
-}
-
-/*
- * Determine mode from channel flags
- *
- * This routine will provide the enumerated WIRELESSS_MODE value based
- * on the settings of the channel flags. If no valid set of flags
- * exist, the lowest mode (11b) is selected.
-*/
-
-static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
-{
- 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;
-}
-
-/*
- * Set the current channel
- *
- * 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 after a la ath_init.
-*/
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
-{
- struct ath_hal *ah = sc->sc_ah;
- bool fastcc = true, stopped;
-
- if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
- return -EIO;
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
- __func__,
- ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
- sc->sc_ah->ah_curchan->channelFlags),
- sc->sc_ah->ah_curchan->channel,
- ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
- hchan->channel, hchan->channelFlags);
-
- 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); /* disable interrupts */
- ath_draintxq(sc, false); /* clear pending tx frames */
- stopped = ath_stoprecv(sc); /* turn off frame recv */
-
- /* 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;
-
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, hchan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask,
- sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing,
- fastcc, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset channel %u (%uMhz) "
- "flags 0x%x hal status %u\n", __func__,
- 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);
-
- sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
- sc->sc_flags &= ~SC_OP_FULL_RESET;
-
- /* Re-enable rx framework */
- if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to restart recv logic\n", __func__);
- return -EIO;
- }
- /*
- * Change channels and update the h/w rate map
- * if we're switching; e.g. 11a to 11b/g.
- */
- ath_setcurmode(sc, ath_chan2mode(hchan));
-
- ath_update_txpow(sc); /* update tx power state */
- /*
- * Re-enable interrupts.
- */
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
- }
- return 0;
-}
-
-/**********************/
-/* Chainmask Handling */
-/**********************/
-
-static void ath_chainmask_sel_timertimeout(unsigned long data)
-{
- struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data;
- cm->switch_allowed = 1;
-}
-
-/* Start chainmask select timer */
-static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm)
-{
- cm->switch_allowed = 0;
- mod_timer(&cm->timer, ath_chainmask_sel_period);
-}
-
-/* Stop chainmask select timer */
-static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm)
-{
- cm->switch_allowed = 0;
- del_timer_sync(&cm->timer);
-}
-
-static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an)
-{
- struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
- memset(cm, 0, sizeof(struct ath_chainmask_sel));
-
- cm->cur_tx_mask = sc->sc_tx_chainmask;
- cm->cur_rx_mask = sc->sc_rx_chainmask;
- cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER;
- setup_timer(&cm->timer,
- ath_chainmask_sel_timertimeout, (unsigned long) cm);
-}
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
-{
- struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
- /*
- * Disable auto-swtiching in one of the following if conditions.
- * sc_chainmask_auto_sel is used for internal global auto-switching
- * enabled/disabled setting
- */
- if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) {
- cm->cur_tx_mask = sc->sc_tx_chainmask;
- return cm->cur_tx_mask;
- }
-
- if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER)
- return cm->cur_tx_mask;
-
- if (cm->switch_allowed) {
- /* Switch down from tx 3 to tx 2. */
- if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 &&
- ATH_RSSI_OUT(cm->tx_avgrssi) >=
- ath_chainmask_sel_down_rssi_thres) {
- cm->cur_tx_mask = sc->sc_tx_chainmask;
-
- /* Don't let another switch happen until
- * this timer expires */
- ath_chainmask_sel_timerstart(cm);
- }
- /* Switch up from tx 2 to 3. */
- else if (cm->cur_tx_mask == sc->sc_tx_chainmask &&
- ATH_RSSI_OUT(cm->tx_avgrssi) <=
- ath_chainmask_sel_up_rssi_thres) {
- cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3;
-
- /* Don't let another switch happen
- * until this timer expires */
- ath_chainmask_sel_timerstart(cm);
- }
- }
-
- return cm->cur_tx_mask;
-}
-
-/*
- * Update tx/rx chainmask. For legacy association,
- * hard code chainmask to 1x1, for 11n association, use
- * the chainmask configuration.
- */
-
-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;
- } else {
- sc->sc_tx_chainmask = 1;
- sc->sc_rx_chainmask = 1;
- }
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
- __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
-}
-
-/*******/
-/* ANI */
-/*******/
-
-/*
- * This routine performs the periodic noise floor calibration function
- * that is used to adjust and optimize the chip performance. This
- * takes environmental changes (location, temperature) into account.
- * When the task is complete, it reschedules itself depending on the
- * appropriate interval that was calculated.
- */
-
-static void ath_ani_calibrate(unsigned long data)
-{
- struct ath_softc *sc;
- struct ath_hal *ah;
- bool longcal = false;
- bool shortcal = false;
- bool aniflag = false;
- unsigned int timestamp = jiffies_to_msecs(jiffies);
- u32 cal_interval;
-
- sc = (struct ath_softc *)data;
- ah = sc->sc_ah;
-
- /*
- * don't calibrate when we're scanning.
- * we are most likely not on our home channel.
- */
- if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
- return;
-
- /* Long calibration runs independently of short calibration. */
- if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
- longcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
- __func__, jiffies);
- sc->sc_ani.sc_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) {
- shortcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
- __func__, jiffies);
- sc->sc_ani.sc_shortcal_timer = timestamp;
- sc->sc_ani.sc_resetcal_timer = timestamp;
- }
- } else {
- if ((timestamp - sc->sc_ani.sc_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;
- }
- }
-
- /* Verify whether we must check ANI */
- if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
- ATH_ANI_POLLINTERVAL) {
- aniflag = true;
- sc->sc_ani.sc_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);
-
- /* Perform calibration if necessary */
- if (longcal || shortcal) {
- bool iscaldone = false;
-
- if (ath9k_hw_calibrate(ah, ah->ah_curchan,
- sc->sc_rx_chainmask, longcal,
- &iscaldone)) {
- if (longcal)
- sc->sc_ani.sc_noise_floor =
- ath9k_hw_getchan_noise(ah,
- ah->ah_curchan);
-
- DPRINTF(sc, ATH_DBG_ANI,
- "%s: calibrate chan %u/%x nf: %d\n",
- __func__,
- ah->ah_curchan->channel,
- ah->ah_curchan->channelFlags,
- sc->sc_ani.sc_noise_floor);
- } else {
- DPRINTF(sc, ATH_DBG_ANY,
- "%s: calibrate chan %u/%x failed\n",
- __func__,
- ah->ah_curchan->channel,
- ah->ah_curchan->channelFlags);
- }
- sc->sc_ani.sc_caldone = iscaldone;
- }
- }
-
- /*
- * 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_ANI_POLLINTERVAL;
- if (!sc->sc_ani.sc_caldone)
- cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
-
- mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-}
-
-/********/
-/* Core */
-/********/
-
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
-{
- struct ath_hal *ah = sc->sc_ah;
- int status;
- int error = 0;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
- __func__, sc->sc_ah->ah_opmode);
-
- /* Reset SERDES registers */
- ath9k_hw_configpcipowersave(ah, 0);
-
- /*
- * The basic interface to setting the hardware in a good
- * state is ``reset''. On return the hardware is known to
- * be powered up and with interrupts disabled. This must
- * be followed by initialization of the appropriate bits
- * and then setup of the interrupt mask.
- */
-
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, initial_chan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask, sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing, false, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset hardware; hal status %u "
- "(freq %u flags 0x%x)\n", __func__, status,
- initial_chan->channel, initial_chan->channelFlags);
- error = -EIO;
- spin_unlock_bh(&sc->sc_resetlock);
- goto done;
- }
- spin_unlock_bh(&sc->sc_resetlock);
-
- /*
- * This is needed only to setup initial state
- * but it's best done after a reset.
- */
- ath_update_txpow(sc);
-
- /*
- * Setup the hardware after reset:
- * The receive engine is set going.
- * Frame transmit is handled entirely
- * in the frame output path; there's nothing to do
- * here except setup the interrupt mask.
- */
- if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to start recv logic\n", __func__);
- error = -EIO;
- goto done;
- }
-
- /* Setup our intr mask. */
- sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
- | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
- | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
-
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
- sc->sc_imask |= ATH9K_INT_GTT;
-
- if (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(ah) &&
- ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
- (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
- 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 ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
- (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
- !sc->sc_config.swBeaconProcess)
- sc->sc_imask |= ATH9K_INT_TIM;
-
- ath_setcurmode(sc, ath_chan2mode(initial_chan));
-
- 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);
-
- ieee80211_wake_queues(sc->hw);
-done:
- return error;
-}
-
-void ath_stop(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__);
-
- ieee80211_stop_queues(sc->hw);
-
- /* make sure h/w will not generate any interrupt
- * before setting the invalid flag. */
- ath9k_hw_set_interrupts(ah, 0);
-
- if (!(sc->sc_flags & SC_OP_INVALID)) {
- ath_draintxq(sc, false);
- ath_stoprecv(sc);
- ath9k_hw_phy_disable(ah);
- } else
- sc->sc_rxlink = NULL;
-
-#ifdef CONFIG_RFKILL
- if (sc->sc_ah->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 */
- ath9k_hw_disable(sc->sc_ah);
- ath9k_hw_configpcipowersave(sc->sc_ah, 1);
-
- sc->sc_flags |= SC_OP_INVALID;
-}
-
-int ath_reset(struct ath_softc *sc, bool retry_tx)
-{
- struct ath_hal *ah = sc->sc_ah;
- int status;
- int error = 0;
-
- ath9k_hw_set_interrupts(ah, 0);
- ath_draintxq(sc, retry_tx);
- ath_stoprecv(sc);
- ath_flushrecv(sc);
-
- /* Reset chip */
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask, sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing, false, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset hardware; hal status %u\n",
- __func__, status);
- error = -EIO;
- }
- spin_unlock_bh(&sc->sc_resetlock);
-
- if (ath_startrecv(sc) != 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to start recv logic\n", __func__);
-
- /*
- * We may be doing a reset in response to a request
- * 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_update_txpow(sc);
-
- if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
-
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
-
- /* Restart the txq */
- if (retry_tx) {
- int i;
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (ATH_TXQ_SETUP(sc, i)) {
- spin_lock_bh(&sc->sc_txq[i].axq_lock);
- ath_txq_schedule(sc, &sc->sc_txq[i]);
- spin_unlock_bh(&sc->sc_txq[i].axq_lock);
- }
- }
- }
-
- return error;
-}
-
-/* Interrupt handler. Most of the actual processing is deferred.
- * It's the caller's responsibility to ensure the chip is awake. */
-
-irqreturn_t ath_isr(int irq, void *dev)
-{
- struct ath_softc *sc = dev;
- struct ath_hal *ah = sc->sc_ah;
- enum ath9k_int status;
- bool sched = false;
-
- do {
- if (sc->sc_flags & SC_OP_INVALID) {
- /*
- * The hardware is not ready/present, don't
- * touch anything. Note this can happen early
- * on if the IRQ is shared.
- */
- return IRQ_NONE;
- }
- if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
- return IRQ_NONE;
- }
-
- /*
- * Figure out the reason(s) for the interrupt. Note
- * that the hal returns a pseudo-ISR that may include
- * bits we haven't explicitly enabled so we mask the
- * value to insure we only process bits we requested.
- */
- ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
-
- status &= sc->sc_imask; /* discard unasked-for bits */
-
- /*
- * If there are no status bits set, then this interrupt was not
- * for me (should have been caught above).
- */
-
- if (!status)
- return IRQ_NONE;
-
- sc->sc_intrstatus = status;
-
- if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
- sched = true;
- } else if (status & ATH9K_INT_RXORN) {
- /* need a chip reset */
- sched = true;
- } else {
- if (status & ATH9K_INT_SWBA) {
- /* schedule a tasklet for beacon handling */
- tasklet_schedule(&sc->bcon_tasklet);
- }
- if (status & ATH9K_INT_RXEOL) {
- /*
- * NB: the hardware should re-read the link when
- * RXE bit is written, but it doesn't work
- * at least on older hardware revs.
- */
- sched = true;
- }
-
- if (status & ATH9K_INT_TXURN)
- /* bump tx trigger level */
- ath9k_hw_updatetxtriglevel(ah, true);
- /* XXX: optimize this */
- if (status & ATH9K_INT_RX)
- sched = true;
- if (status & ATH9K_INT_TX)
- sched = true;
- if (status & ATH9K_INT_BMISS)
- sched = true;
- /* carrier sense timeout */
- if (status & ATH9K_INT_CST)
- sched = true;
- if (status & ATH9K_INT_MIB) {
- /*
- * Disable interrupts until we service the MIB
- * interrupt; otherwise it will continue to
- * fire.
- */
- ath9k_hw_set_interrupts(ah, 0);
- /*
- * Let the hal handle the event. We assume
- * it will clear whatever condition caused
- * the interrupt.
- */
- ath9k_hw_procmibevent(ah, &sc->sc_halstats);
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
- }
- if (status & ATH9K_INT_TIM_TIMER) {
- if (!(ah->ah_caps.hw_caps &
- ATH9K_HW_CAP_AUTOSLEEP)) {
- /* Clear RxAbort bit so that we can
- * receive frames */
- ath9k_hw_setrxabort(ah, 0);
- sched = true;
- }
- }
- }
- } while (0);
-
- if (sched) {
- /* turn off every interrupt except SWBA */
- ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
- tasklet_schedule(&sc->intr_tq);
- }
-
- return IRQ_HANDLED;
-}
-
-/* Deferred interrupt processing */
-
-static void ath9k_tasklet(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
- u32 status = sc->sc_intrstatus;
-
- if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
- ath_reset(sc, false);
- return;
- } else {
-
- if (status &
- (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
- /* XXX: fill me in */
- /*
- if (status & ATH9K_INT_RXORN) {
- }
- if (status & ATH9K_INT_RXEOL) {
- }
- */
- spin_lock_bh(&sc->sc_rxflushlock);
- ath_rx_tasklet(sc, 0);
- spin_unlock_bh(&sc->sc_rxflushlock);
- }
- /* XXX: optimize this */
- if (status & ATH9K_INT_TX)
- ath_tx_tasklet(sc);
- /* XXX: fill me in */
- /*
- if (status & ATH9K_INT_BMISS) {
- }
- if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) {
- if (status & ATH9K_INT_TIM) {
- }
- if (status & ATH9K_INT_DTIMSYNC) {
- }
- }
- */
- }
-
- /* re-enable hardware interrupt */
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
-}
-
-int ath_init(u16 devid, struct ath_softc *sc)
-{
- struct ath_hal *ah = NULL;
- int status;
- int error = 0, i;
- int csz = 0;
-
- /* XXX: hardware will not be ready until ath_open() being called */
- sc->sc_flags |= SC_OP_INVALID;
- sc->sc_debug = DBG_DEFAULT;
-
- spin_lock_init(&sc->sc_resetlock);
- tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
- tasklet_init(&sc->bcon_tasklet, ath9k_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);
- /* XXX assert csz is non-zero */
- sc->sc_cachelsz = csz << 2; /* convert to bytes */
-
- ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
- if (ah == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to attach hardware; HAL status %u\n",
- __func__, 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) {
- DPRINTF(sc, ATH_DBG_KEYCACHE,
- "%s: Warning, using only %u entries in %u key cache\n",
- __func__, ATH_KEYMAX, sc->sc_keymax);
- sc->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++)
- ath9k_hw_keyreset(ah, (u16) i);
- /*
- * Mark key cache slots associated with global keys
- * as in use. If we knew TKIP was not to be used we
- * could leave the +32, +64, and +32+64 slots free.
- * XXX only for splitmic.
- */
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- set_bit(i, sc->sc_keymap);
- set_bit(i + 32, sc->sc_keymap);
- set_bit(i + 64, sc->sc_keymap);
- set_bit(i + 32 + 64, sc->sc_keymap);
- }
-
- /* Collect the channel list using the default country code */
-
- error = ath_setup_channels(sc);
- if (error)
- goto bad;
-
- /* default to MONITOR mode */
- sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
-
- /* Setup rate tables */
-
- ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
- ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
-
- /* NB: setup here so ath_rate_update is happy */
- ath_setcurmode(sc, ATH9K_MODE_11A);
-
- /*
- * Allocate hardware transmit queues: one queue for
- * beacon frames and one data queue for each QoS
- * priority. Note that the hal handles reseting
- * these queues at the needed time.
- */
- sc->sc_bhalq = ath_beaconq_setup(ah);
- if (sc->sc_bhalq == -1) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup a beacon xmit queue\n", __func__);
- error = -EIO;
- goto bad2;
- }
- sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
- if (sc->sc_cabq == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup CAB xmit queue\n", __func__);
- error = -EIO;
- goto bad2;
- }
-
- sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
- ath_cabq_update(sc);
-
- for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
- sc->sc_haltype2q[i] = -1;
-
- /* Setup data queues */
- /* NB: ensure BK queue is the lowest priority h/w queue */
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for BK traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
-
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for BE traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for VI traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for VO traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
-
- /* 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->sc_rc = ath_rate_attach(ah);
- if (sc->sc_rc == NULL) {
- error = -EIO;
- goto bad2;
- }
-
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)) {
- /*
- * Whether we should enable h/w TKIP MIC.
- * XXX: if we don't support WME TKIP MIC, then we wouldn't
- * report WMM capable, so it's always safe to turn on
- * TKIP MIC in this case.
- */
- ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
- 0, 1, NULL);
- }
-
- /*
- * Check whether the separate key cache entries
- * are required to handle both tx+rx MIC keys.
- * With split mic keys the number of stations is limited
- * to 27 otherwise 59.
- */
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_MIC, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
- 0, NULL))
- sc->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;
-
- /* 11n Capabilities */
- if (ah->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;
-
- ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
- sc->sc_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);
- }
-
- sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
-
- /* initialize beacon slots */
- for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
- sc->sc_bslot[i] = ATH_IF_ID_ANY;
-
- /* save MISC configurations */
- sc->sc_config.swBeaconProcess = 1;
-
-#ifdef CONFIG_SLOW_ANT_DIV
- /* range is 40 - 255, we use something in the middle */
- ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
-#endif
-
- /* setup channels and rates */
-
- sc->sbands[IEEE80211_BAND_2GHZ].channels =
- sc->channels[IEEE80211_BAND_2GHZ];
- sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
- sc->rates[IEEE80211_BAND_2GHZ];
- sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
- sc->sbands[IEEE80211_BAND_5GHZ].channels =
- sc->channels[IEEE80211_BAND_5GHZ];
- sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
- sc->rates[IEEE80211_BAND_5GHZ];
- sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
- }
-
- return 0;
-bad2:
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-bad:
- if (ah)
- ath9k_hw_detach(ah);
-
- return error;
-}
-
-/*******************/
-/* Node Management */
-/*******************/
-
-void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
-{
- struct ath_node *an;
-
- an = (struct ath_node *)sta->drv_priv;
-
- if (sc->sc_flags & SC_OP_TXAGGR)
- ath_tx_node_init(sc, an);
-
- an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
- sta->ht_cap.ampdu_factor);
- an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
-
- ath_chainmask_sel_init(sc, an);
- ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
-}
-
-void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
-{
- struct ath_node *an = (struct ath_node *)sta->drv_priv;
-
- ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
-
- if (sc->sc_flags & SC_OP_TXAGGR)
- ath_tx_node_cleanup(sc, an);
-}
-
-/*
- * Set up New Node
- *
- * Setup driver-specific state for a newly associated node. This routine
- * really only applies if compression or XR are enabled, there is no code
- * covering any other cases.
-*/
-
-void ath_newassoc(struct ath_softc *sc,
- struct ath_node *an, int isnew, int isuapsd)
-{
- int tidno;
-
- /* if station reassociates, tear down the aggregation state. */
- if (!isnew) {
- for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
- if (sc->sc_flags & SC_OP_TXAGGR)
- ath_tx_aggr_teardown(sc, an, tidno);
- }
- }
-}
-
-/**************/
-/* Encryption */
-/**************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
-{
- ath9k_hw_keyreset(sc->sc_ah, keyix);
- if (freeslot)
- clear_bit(keyix, sc->sc_keymap);
-}
-
-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;
-}
-
-/***********************/
-/* TX Power/Regulatory */
-/***********************/
-
-/*
- * Set Transmit power in HAL
- *
- * This routine makes the actual HAL calls to set the new transmit power
- * limit.
-*/
-
-void ath_update_txpow(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
- u32 txpow;
-
- if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
- ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
- /* read back in case value is clamped */
- ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
- sc->sc_curtxpow = txpow;
- }
-}
-
-/**************************/
-/* Slow Antenna Diversity */
-/**************************/
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
- struct ath_softc *sc,
- int32_t rssitrig)
-{
- int trig;
-
- /* antdivf_rssitrig can range from 40 - 0xff */
- trig = (rssitrig > 0xff) ? 0xff : rssitrig;
- trig = (rssitrig < 40) ? 40 : rssitrig;
-
- antdiv->antdiv_sc = sc;
- antdiv->antdivf_rssitrig = trig;
-}
-
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
- u8 num_antcfg,
- const u8 *bssid)
-{
- antdiv->antdiv_num_antcfg =
- num_antcfg < ATH_ANT_DIV_MAX_CFG ?
- num_antcfg : ATH_ANT_DIV_MAX_CFG;
- antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
- antdiv->antdiv_curcfg = 0;
- antdiv->antdiv_bestcfg = 0;
- antdiv->antdiv_laststatetsf = 0;
-
- memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid));
-
- antdiv->antdiv_start = 1;
-}
-
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv)
-{
- antdiv->antdiv_start = 0;
-}
-
-static int32_t ath_find_max_val(int32_t *val,
- u8 num_val, u8 *max_index)
-{
- u32 MaxVal = *val++;
- u32 cur_index = 0;
-
- *max_index = 0;
- while (++cur_index < num_val) {
- if (*val > MaxVal) {
- MaxVal = *val;
- *max_index = cur_index;
- }
-
- val++;
- }
-
- return MaxVal;
-}
-
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
- struct ieee80211_hdr *hdr,
- struct ath_rx_status *rx_stats)
-{
- struct ath_softc *sc = antdiv->antdiv_sc;
- struct ath_hal *ah = sc->sc_ah;
- u64 curtsf = 0;
- u8 bestcfg, curcfg = antdiv->antdiv_curcfg;
- __le16 fc = hdr->frame_control;
-
- if (antdiv->antdiv_start && ieee80211_is_beacon(fc)
- && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) {
- antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi;
- antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah);
- curtsf = antdiv->antdiv_lastbtsf[curcfg];
- } else {
- return;
- }
-
- switch (antdiv->antdiv_state) {
- case ATH_ANT_DIV_IDLE:
- if ((antdiv->antdiv_lastbrssi[curcfg] <
- antdiv->antdivf_rssitrig)
- && ((curtsf - antdiv->antdiv_laststatetsf) >
- ATH_ANT_DIV_MIN_IDLE_US)) {
-
- curcfg++;
- if (curcfg == antdiv->antdiv_num_antcfg)
- curcfg = 0;
-
- if (!ath9k_hw_select_antconfig(ah, curcfg)) {
- antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg;
- antdiv->antdiv_curcfg = curcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
- }
- }
- break;
-
- case ATH_ANT_DIV_SCAN:
- if ((curtsf - antdiv->antdiv_laststatetsf) <
- ATH_ANT_DIV_MIN_SCAN_US)
- break;
-
- curcfg++;
- if (curcfg == antdiv->antdiv_num_antcfg)
- curcfg = 0;
-
- if (curcfg == antdiv->antdiv_bestcfg) {
- ath_find_max_val(antdiv->antdiv_lastbrssi,
- antdiv->antdiv_num_antcfg, &bestcfg);
- if (!ath9k_hw_select_antconfig(ah, bestcfg)) {
- antdiv->antdiv_bestcfg = bestcfg;
- antdiv->antdiv_curcfg = bestcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
- }
- } else {
- if (!ath9k_hw_select_antconfig(ah, curcfg)) {
- antdiv->antdiv_curcfg = curcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
- }
- }
-
- break;
- }
-}
-
-/***********************/
-/* Descriptor Handling */
-/***********************/
-
-/*
- * Set up DMA descriptors
- *
- * This function will allocate both the DMA descriptor structure, and the
- * buffers it contains. These are used to contain the descriptors used
- * by the system.
-*/
-
-int ath_descdma_setup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head,
- const char *name,
- int nbuf,
- int ndesc)
-{
-#define DS2PHYS(_dd, _ds) \
- ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
- struct ath_desc *ds;
- struct ath_buf *bf;
- int i, bsize, error;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
- __func__, name, nbuf, ndesc);
-
- /* ath_desc must be a multiple of DWORDs */
- if ((sizeof(struct ath_desc) % 4) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
- __func__);
- ASSERT((sizeof(struct ath_desc) % 4) == 0);
- error = -ENOMEM;
- goto fail;
- }
-
- dd->dd_name = name;
- dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
- /*
- * Need additional DMA memory because we can't use
- * 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)) {
- u32 ndesc_skipped =
- ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
- u32 dma_len;
-
- while (ndesc_skipped) {
- dma_len = ndesc_skipped * sizeof(struct ath_desc);
- dd->dd_desc_len += dma_len;
-
- ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
- };
- }
-
- /* allocate descriptors */
- dd->dd_desc = pci_alloc_consistent(sc->pdev,
- dd->dd_desc_len,
- &dd->dd_desc_paddr);
- if (dd->dd_desc == NULL) {
- error = -ENOMEM;
- goto fail;
- }
- ds = dd->dd_desc;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
- __func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
- /* allocate buffers */
- bsize = sizeof(struct ath_buf) * nbuf;
- bf = kmalloc(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 &
- ATH9K_HW_CAP_4KB_SPLITTRANS)) {
- /*
- * Skip descriptor addresses which can cause 4KB
- * boundary crossing (addr + length) with a 32 dword
- * descriptor fetch.
- */
- while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
- ASSERT((caddr_t) bf->bf_desc <
- ((caddr_t) dd->dd_desc +
- dd->dd_desc_len));
-
- ds += ndesc;
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(dd, ds);
- }
- }
- list_add_tail(&bf->list, head);
- }
- return 0;
-fail2:
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-fail:
- memset(dd, 0, sizeof(*dd));
- return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-/*
- * Cleanup DMA descriptors
- *
- * This function will free the DMA block that was allocated for the descriptor
- * pool. Since this was allocated as one "chunk", it is freed in the same
- * manner.
-*/
-
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head)
-{
- /* Free memory associated with descriptors */
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-
- INIT_LIST_HEAD(head);
- kfree(dd->dd_bufptr);
- memset(dd, 0, sizeof(*dd));
-}
-
-/*************/
-/* Utilities */
-/*************/
-
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case 0:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
- break;
- case 1:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
- break;
- case 2:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
- break;
- case 3:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
- break;
- default:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
- break;
- }
-
- return qnum;
-}
-
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case ATH9K_WME_AC_VO:
- qnum = 0;
- break;
- case ATH9K_WME_AC_VI:
- qnum = 1;
- break;
- case ATH9K_WME_AC_BE:
- qnum = 2;
- break;
- case ATH9K_WME_AC_BK:
- qnum = 3;
- break;
- default:
- qnum = -1;
- break;
- }
-
- return qnum;
-}
-
-
-/*
- * Expand time stamp to TSF
- *
- * Extend 15-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the current h/w TSF.
-*/
-
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
-{
- u64 tsf;
-
- tsf = ath9k_hw_gettsf64(sc->sc_ah);
- if ((tsf & 0x7fff) < rstamp)
- tsf -= 0x8000;
- return (tsf & ~0x7fff) | rstamp;
-}
-
-/*
- * Set Default Antenna
- *
- * Call into the HAL to set the default antenna to use. Not really valid for
- * MIMO technology.
-*/
-
-void ath_setdefantenna(void *context, u32 antenna)
-{
- struct ath_softc *sc = (struct ath_softc *)context;
- struct ath_hal *ah = sc->sc_ah;
-
- /* XXX block beacon interrupts */
- ath9k_hw_setantenna(ah, antenna);
- sc->sc_defant = antenna;
- sc->sc_rxotherant = 0;
-}
-
-/*
- * Set Slot Time
- *
- * This will wake up the chip if required, and set the slot time for the
- * frame (maximum transmit time). Slot time is assumed to be already set
- * in the ATH object member sc_slottime
-*/
-
-void ath_setslottime(struct ath_softc *sc)
-{
- ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
- sc->sc_updateslot = OK;
-}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 69e8d3e41131..f0c54377dfe6 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -47,10 +47,6 @@
struct ath_node;
-/******************/
-/* Utility macros */
-/******************/
-
/* Macro to expand scalars to 64-bit objects */
#define ito64(x) (sizeof(x) == 8) ? \
@@ -86,11 +82,6 @@ struct ath_node;
#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
-static inline unsigned long get_timestamp(void)
-{
- return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
-}
-
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/*************/
@@ -141,34 +132,6 @@ struct ath_config {
u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */
};
-/***********************/
-/* Chainmask Selection */
-/***********************/
-
-#define ATH_CHAINMASK_SEL_TIMEOUT 6000
-/* Default - Number of last RSSI values that is used for
- * chainmask selection */
-#define ATH_CHAINMASK_SEL_RSSI_CNT 10
-/* Means use 3x3 chainmask instead of configured chainmask */
-#define ATH_CHAINMASK_SEL_3X3 7
-/* Default - Rssi threshold below which we have to switch to 3x3 */
-#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20
-/* Default - Rssi threshold above which we have to switch to
- * user configured values */
-#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35
-/* Struct to store the chainmask select related info */
-struct ath_chainmask_sel {
- struct timer_list timer;
- int cur_tx_mask; /* user configured or 3x3 */
- int cur_rx_mask; /* user configured or 3x3 */
- int tx_avgrssi;
- u8 switch_allowed:1, /* timer will set this */
- cm_sel_enabled : 1;
-};
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an);
-void ath_update_chainmask(struct ath_softc *sc, int is_ht);
-
/*************************/
/* Descriptor Management */
/*************************/
@@ -203,7 +166,6 @@ struct ath_buf_state {
int bfs_seqno; /* sequence number */
int bfs_tidno; /* tid of this frame */
int bfs_retries; /* current retries */
- struct ath_rc_series bfs_rcs[4]; /* rate series */
u32 bf_type; /* BUF_* (enum buffer_type) */
/* key type use to encrypt this frame */
u32 bfs_keyix;
@@ -241,7 +203,6 @@ struct ath_buf {
an aggregate) */
struct ath_buf *bf_lastfrm; /* last buf of this frame */
struct ath_buf *bf_next; /* next subframe in the aggregate */
- struct ath_buf *bf_rifslast; /* last buf for RIFS burst */
void *bf_mpdu; /* enclosing frame structure */
struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
@@ -279,80 +240,27 @@ struct ath_descdma {
dma_addr_t dd_dmacontext;
};
-/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */
-
-struct ath_rx_context {
- struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */
-};
-#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb)
-
-int ath_descdma_setup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head,
- const char *name,
- int nbuf,
- int ndesc);
-int ath_desc_alloc(struct ath_softc *sc);
-void ath_desc_free(struct ath_softc *sc);
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
+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 */
-/******/
+/***********/
+/* RX / TX */
+/***********/
#define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512
#define WME_NUM_TID 16
-/* per frame rx status block */
-struct ath_recv_status {
- u64 tsf; /* mac tsf */
- int8_t rssi; /* RSSI (noise floor ajusted) */
- int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int8_t abs_rssi; /* absolute RSSI */
- u8 rateieee; /* data rate received (IEEE rate code) */
- u8 ratecode; /* phy rate code */
- int rateKbps; /* data rate received (Kbps) */
- int antenna; /* rx antenna */
- int flags; /* status of associated skb */
-#define ATH_RX_FCS_ERROR 0x01
-#define ATH_RX_MIC_ERROR 0x02
-#define ATH_RX_DECRYPT_ERROR 0x04
-#define ATH_RX_RSSI_VALID 0x08
-/* if any of ctl,extn chainrssis are valid */
-#define ATH_RX_CHAIN_RSSI_VALID 0x10
-/* if extn chain rssis are valid */
-#define ATH_RX_RSSI_EXTN_VALID 0x20
-/* set if 40Mhz, clear if 20Mhz */
-#define ATH_RX_40MHZ 0x40
-/* set if short GI, clear if full GI */
-#define ATH_RX_SHORT_GI 0x80
-};
-
-struct ath_rxbuf {
- struct sk_buff *rx_wbuf;
- unsigned long rx_time; /* system time when received */
- struct ath_recv_status rx_status; /* cached rx status */
-};
-
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);
-void ath_handle_rx_intr(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);
-int _ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix);
-/******/
-/* TX */
-/******/
#define ATH_TXBUF 512
/* max number of transmit attempts (tries) */
@@ -500,9 +408,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
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_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- struct ath_xmit_status *tx_status);
void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
/**********************/
@@ -567,25 +472,41 @@ struct ath_node_aggr {
/* driver-specific node state */
struct ath_node {
struct ath_softc *an_sc;
- struct ath_chainmask_sel an_chainmask_sel;
struct ath_node_aggr an_aggr;
u16 maxampdu;
u8 mpdudensity;
};
-void ath_tx_resume_tid(struct ath_softc *sc,
- struct ath_atx_tid *tid);
+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);
+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);
-void ath_newassoc(struct ath_softc *sc,
- struct ath_node *node, int isnew, int isuapsd);
-void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta);
-void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta);
+
+/********/
+/* 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))
+
+/* driver-specific vap state */
+struct ath_vap {
+ int av_bslot; /* beacon slot index */
+ enum ath9k_opmode av_opmode; /* VAP operational mode */
+ struct ath_buf *av_bcbuf; /* beacon buffer */
+ struct ath_tx_control av_btxctl; /* txctl information for beacon */
+};
/*******************/
/* Beacon Handling */
@@ -620,80 +541,8 @@ 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_bstuck_process(struct ath_softc *sc);
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
void ath_beacon_sync(struct ath_softc *sc, int if_id);
-void ath_get_beaconconfig(struct ath_softc *sc,
- int if_id,
- struct ath_beacon_config *conf);
-/********/
-/* 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))
-
-/* VAP configuration (from protocol layer) */
-struct ath_vap_config {
- u32 av_fixed_rateset;
- u32 av_fixed_retryset;
-};
-
-/* driver-specific vap state */
-struct ath_vap {
- int av_bslot; /* beacon slot index */
- enum ath9k_opmode av_opmode; /* VAP operational mode */
- struct ath_buf *av_bcbuf; /* beacon buffer */
- struct ath_tx_control av_btxctl; /* txctl information for beacon */
- struct ath_vap_config av_config;/* vap configuration parameters*/
- struct ath_rate_node *rc_node;
-};
-
-/*********************/
-/* Antenna diversity */
-/*********************/
-
-#define ATH_ANT_DIV_MAX_CFG 2
-#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */
-#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */
-
-enum ATH_ANT_DIV_STATE{
- ATH_ANT_DIV_IDLE,
- ATH_ANT_DIV_SCAN, /* evaluating antenna */
-};
-
-struct ath_antdiv {
- struct ath_softc *antdiv_sc;
- u8 antdiv_start;
- enum ATH_ANT_DIV_STATE antdiv_state;
- u8 antdiv_num_antcfg;
- u8 antdiv_curcfg;
- u8 antdiv_bestcfg;
- int32_t antdivf_rssitrig;
- int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG];
- u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG];
- u64 antdiv_laststatetsf;
- u8 antdiv_bssid[ETH_ALEN];
-};
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
- struct ath_softc *sc, int32_t rssitrig);
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
- u8 num_antcfg,
- const u8 *bssid);
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv);
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
- struct ieee80211_hdr *wh,
- struct ath_rx_status *rx_stats);
-void ath_setdefantenna(void *sc, u32 antenna);
/*******/
/* ANI */
@@ -775,30 +624,8 @@ struct ath_rfkill {
#define ATH_IF_ID_ANY 0xff
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
-
-#define RSSI_LPF_THRESHOLD -20
-#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
-#define ATH_RATE_DUMMY_MARKER 0
-#define ATH_RSSI_LPF_LEN 10
-#define ATH_RSSI_DUMMY_MARKER 0x127
-
-#define ATH_EP_MUL(x, mul) ((x) * (mul))
-#define ATH_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define ATH_RSSI_OUT(x) \
- (((x) != ATH_RSSI_DUMMY_MARKER) ? \
- (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER)
-#define ATH_RSSI_IN(x) \
- (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
-#define ATH_LPF_RSSI(x, y, len) \
- ((x != ATH_RSSI_DUMMY_MARKER) ? \
- (((x) * ((len) - 1) + (y)) / (len)) : (y))
-#define ATH_RSSI_LPF(x, y) do { \
- if ((y) >= RSSI_LPF_THRESHOLD) \
- x = ATH_LPF_RSSI((x), \
- ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
- } while (0)
-
+#define ATH_RSSI_DUMMY_MARKER 0x127
+#define ATH_RATE_DUMMY_MARKER 0
enum PROT_MODE {
PROT_M_NONE = 0,
@@ -806,17 +633,6 @@ enum PROT_MODE {
PROT_M_CTSONLY
};
-enum RATE_TYPE {
- NORMAL_RATE = 0,
- HALF_RATE,
- QUARTER_RATE
-};
-
-struct ath_ht_info {
- enum ath9k_ht_macmode tx_chan_width;
- u8 ext_chan_offset;
-};
-
#define SC_OP_INVALID BIT(0)
#define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2)
@@ -839,7 +655,6 @@ struct ath_softc {
struct tasklet_struct bcon_tasklet;
struct ath_config sc_config;
struct ath_hal *sc_ah;
- struct ath_rate_softc *sc_rc;
void __iomem *mem;
u8 sc_curbssid[ETH_ALEN];
@@ -871,8 +686,8 @@ struct ath_softc {
u8 sc_rxotherant; /* rx's on non-default antenna */
struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
- struct ath_ht_info sc_ht_info;
enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
+ enum ath9k_ht_macmode tx_chan_width;
#ifdef CONFIG_SLOW_ANT_DIV
struct ath_antdiv sc_antdiv;
@@ -914,13 +729,8 @@ struct ath_softc {
/* Rate */
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
- const struct ath9k_rate_table *sc_currates;
- u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */
+ struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
u8 sc_protrix; /* protection rate index */
- struct {
- u32 rateKbps; /* transfer rate in kbs */
- u8 ieeerate; /* IEEE rate */
- } sc_hwmap[256]; /* h/w rate ix mappings */
/* Channel, Band */
struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
@@ -945,27 +755,9 @@ struct ath_softc {
struct ath_ani sc_ani;
};
-int ath_init(u16 devid, struct ath_softc *sc);
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-void ath_stop(struct ath_softc *sc);
-irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
-
-/*********************/
-/* Utility Functions */
-/*********************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot);
-int ath_keyset(struct ath_softc *sc,
- u16 keyix,
- struct ath9k_keyval *hk,
- const u8 mac[ETH_ALEN]);
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
-void ath_setslottime(struct ath_softc *sc);
-void ath_update_txpow(struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
index f5fd03c0edd7..466dbce2c5f7 100644
--- a/drivers/net/wireless/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath9k/eeprom.c
@@ -1244,7 +1244,7 @@ bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
- ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config);
+ ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
@@ -1551,9 +1551,9 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
switch (param) {
case EEP_NFTHRESH_5:
- return -pModal[0].noiseFloorThreshCh[0];
+ return pModal[0].noiseFloorThreshCh[0];
case EEP_NFTHRESH_2:
- return -pModal[1].noiseFloorThreshCh[0];
+ return pModal[1].noiseFloorThreshCh[0];
case AR_EEPROM_MAC(0):
return pBase->macAddr[0] << 8 | pBase->macAddr[1];
case AR_EEPROM_MAC(1):
@@ -1584,6 +1584,11 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
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;
}
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index ff6457e0cb00..6eef10477896 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -86,10 +86,11 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
const struct ath9k_channel *chan)
{
- if (IS_CHAN_CCK(chan))
- return ATH9K_MODE_11A;
+ if (IS_CHAN_B(chan))
+ return ATH9K_MODE_11B;
if (IS_CHAN_G(chan))
return ATH9K_MODE_11G;
+
return ATH9K_MODE_11A;
}
@@ -142,27 +143,27 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
}
u16 ath9k_hw_computetxtime(struct ath_hal *ah,
- const struct ath9k_rate_table *rates,
+ struct ath_rate_table *rates,
u32 frameLen, u16 rateix,
bool shortPreamble)
{
u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
u32 kbps;
- kbps = rates->info[rateix].rateKbps;
+ kbps = rates->info[rateix].ratekbps;
if (kbps == 0)
return 0;
switch (rates->info[rateix].phy) {
- case PHY_CCK:
+ case WLAN_RC_PHY_CCK:
phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
- if (shortPreamble && rates->info[rateix].shortPreamble)
+ if (shortPreamble && rates->info[rateix].short_preamble)
phyTime >>= 1;
numBits = frameLen << 3;
txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
break;
- case PHY_OFDM:
+ case WLAN_RC_PHY_OFDM:
if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3);
@@ -557,6 +558,54 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah)
return 0;
}
+static void ath9k_hw_init_rxgain_ini(struct ath_hal *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 (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+ INIT_INI_ARRAY(&ahp->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,
+ ar9280Modes_backoff_23db_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
+ else
+ INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+ ar9280Modes_original_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+ } else
+ INIT_INI_ARRAY(&ahp->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)
+{
+ 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 (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+ INIT_INI_ARRAY(&ahp->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,
+ ar9280Modes_original_tx_gain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+ } else
+ INIT_INI_ARRAY(&ahp->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)
{
int ecode;
@@ -800,6 +849,14 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (ecode != 0)
goto bad;
+ /* rxgain table */
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ ath9k_hw_init_rxgain_ini(ah);
+
+ /* txgain table */
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ ath9k_hw_init_txgain_ini(ah);
+
#ifndef CONFIG_SLOW_ANT_DIV
if (ah->ah_devid == AR9280_DEVID_PCI) {
for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
@@ -853,7 +910,7 @@ static void ath9k_hw_init_bb(struct ath_hal *ah,
u32 synthDelay;
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_CCK(chan))
+ if (IS_CHAN_B(chan))
synthDelay = (4 * synthDelay) / 22;
else
synthDelay /= 10;
@@ -1258,6 +1315,12 @@ static int ath9k_hw_process_ini(struct ath_hal *ah,
DO_DELAY(regWrites);
}
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
+
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ REG_WRITE_ARRAY(&ahp->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);
@@ -1585,7 +1648,7 @@ static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
}
if (!IS_CHAN_OFDM(chan) &&
- !IS_CHAN_CCK(chan) &&
+ !IS_CHAN_B(chan) &&
!IS_CHAN_HT20(chan) &&
!IS_CHAN_HT40(chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
@@ -1649,7 +1712,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah,
}
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_CCK(chan))
+ if (IS_CHAN_B(chan))
synthDelay = (4 * synthDelay) / 22;
else
synthDelay /= 10;
@@ -2169,8 +2232,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
((chan->channelFlags & CHANNEL_ALL) ==
(ah->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->ah_curchan)))) {
if (ath9k_hw_channel_change(ah, chan, macmode)) {
ath9k_hw_loadnf(ah, ah->ah_curchan);
@@ -2278,7 +2340,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
ath9k_hw_init_qos(ah);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
ath9k_enable_rfkill(ah);
#endif
@@ -3128,190 +3190,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
}
-/***************/
-/* Rate tables */
-/***************/
-
-static struct ath9k_rate_table ar5416_11a_table = {
- 8,
- {0},
- {
- {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
- {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
- {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
- },
-};
-
-static struct ath9k_rate_table ar5416_11b_table = {
- 4,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
- },
-};
-
-static struct ath9k_rate_table ar5416_11g_table = {
- 12,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
- {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
- {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
- {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
- },
-};
-
-static struct ath9k_rate_table ar5416_11ng_table = {
- 28,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
- {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
- {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
- {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
- {true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
- {true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
- {true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
- {true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
- {true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
- {true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
- {true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
- {true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
- {true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
- {true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
- {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
- {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
- {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
- {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
- {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
- {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
- },
-};
-
-static struct ath9k_rate_table ar5416_11na_table = {
- 24,
- {0},
- {
- {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
- {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
- {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
- {true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
- {true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
- {true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
- {true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
- {true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
- {true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
- {true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
- {true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
- {true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
- {true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
- {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
- {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
- {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
- {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
- {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
- {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
- },
-};
-
-static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
- struct ath9k_rate_table *rt)
-{
- int i;
-
- if (rt->rateCodeToIndex[0] != 0)
- return;
-
- for (i = 0; i < 256; i++)
- rt->rateCodeToIndex[i] = (u8) -1;
-
- for (i = 0; i < rt->rateCount; i++) {
- u8 code = rt->info[i].rateCode;
- u8 cix = rt->info[i].controlRate;
-
- rt->rateCodeToIndex[code] = i;
- rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
-
- rt->info[i].lpAckDuration =
- ath9k_hw_computetxtime(ah, rt,
- WLAN_CTRL_FRAME_SIZE,
- cix,
- false);
- rt->info[i].spAckDuration =
- ath9k_hw_computetxtime(ah, rt,
- WLAN_CTRL_FRAME_SIZE,
- cix,
- true);
- }
-}
-
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
- u32 mode)
-{
- struct ath9k_rate_table *rt;
-
- switch (mode) {
- case ATH9K_MODE_11A:
- rt = &ar5416_11a_table;
- break;
- case ATH9K_MODE_11B:
- rt = &ar5416_11b_table;
- break;
- case ATH9K_MODE_11G:
- rt = &ar5416_11g_table;
- break;
- case ATH9K_MODE_11NG_HT20:
- case ATH9K_MODE_11NG_HT40PLUS:
- case ATH9K_MODE_11NG_HT40MINUS:
- rt = &ar5416_11ng_table;
- break;
- case ATH9K_MODE_11NA_HT20:
- case ATH9K_MODE_11NA_HT40PLUS:
- case ATH9K_MODE_11NA_HT40MINUS:
- rt = &ar5416_11na_table;
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
- __func__, mode);
- return NULL;
- }
-
- ath9k_hw_setup_rate_table(ah, rt);
-
- return rt;
-}
-
/*******************/
/* HW Capabilities */
/*******************/
@@ -3453,7 +3331,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-#ifdef CONFIG_RFKILL
+#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 =
@@ -3710,7 +3588,7 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
AR_GPIO_BIT(gpio));
}
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
void ath9k_enable_rfkill(struct ath_hal *ah)
{
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 6a29f2d43c21..02256c3ec076 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -415,6 +415,9 @@ struct ar5416Stats {
#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
@@ -436,6 +439,16 @@ struct ar5416Stats {
#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
+
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
@@ -454,6 +467,8 @@ enum eeprom_param {
EEP_MINOR_REV,
EEP_TX_MASK,
EEP_RX_MASK,
+ EEP_RXGAIN_TYPE,
+ EEP_TXGAIN_TYPE,
};
enum ar5416_rates {
@@ -485,7 +500,11 @@ struct base_eep_header {
u32 binBuildNumber;
u8 deviceType;
u8 pwdclkind;
- u8 futureBase[32];
+ u8 futureBase_1[2];
+ u8 rxGainType;
+ u8 futureBase_2[3];
+ u8 txGainType;
+ u8 futureBase_3[25];
} __packed;
struct spur_chan {
@@ -792,6 +811,8 @@ struct ath_hal_5416 {
struct ar5416IniArray ah_iniAddac;
struct ar5416IniArray ah_iniPcieSerdes;
struct ar5416IniArray ah_iniModesAdditional;
+ struct ar5416IniArray ah_iniModesRxGain;
+ struct ar5416IniArray ah_iniModesTxGain;
};
#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h
index 3dd3815940a4..1b08b54b31d7 100644
--- a/drivers/net/wireless/ath9k/initvals.h
+++ b/drivers/net/wireless/ath9k/initvals.h
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* AR5416 to Fowl ar5146.ini */
static const u32 ar5416Modes_9100[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de },
+ { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
{ 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
- { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
@@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
+ { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 },
@@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
+ { 0x00008338, 0x00070000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 },
@@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = {
{0x000098c4, 0x00000000 },
};
+/* ar5416 - howl ar5416_howl.ini */
static const u32 ar5416Modes[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = {
{ 0x0000994c, 0x00020028 },
{ 0x0000c95c, 0x004b6a8e },
{ 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb514 },
+ { 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@@ -1311,7 +1313,7 @@ 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 },
@@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+ { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+ { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
{ 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
{ 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
@@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
+ { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 },
@@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
+ { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 },
@@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00009958, 0x2108ecff },
{ 0x00009940, 0x00750604 },
{ 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
@@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a244, 0x00007bb6 },
{ 0x0000a248, 0x0fff3ffc },
{ 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x0000a000 },
+ { 0x0000a250, 0x0000e000 },
{ 0x0000a254, 0x00000000 },
{ 0x0000a258, 0x0cc75380 },
{ 0x0000a25c, 0x0f0f0f01 },
@@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a34c, 0x3fffffff },
{ 0x0000a350, 0x3fffffff },
{ 0x0000a354, 0x0003ffff },
- { 0x0000a358, 0x79a8aa33 },
+ { 0x0000a358, 0x79bfaa03 },
{ 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 },
@@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = {
};
static const u32 ar5416Bank6_9160[][3] = {
-
{ 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 },
@@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = {
{ 0x000098cc, 0x0000000e },
};
-
static u32 ar5416Addac_9160[][2] = {
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
@@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = {
{0x000098cc, 0x00000000 },
};
-
static u32 ar5416Addac_91601_1[][2] = {
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
@@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = {
{0x000098cc, 0x00000000 },
};
-
-
+/* XXX 9280 1 */
static const u32 ar9280Modes_9280[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = {
{ 0x00007898, 0x2a850160 },
};
-
-
-
+/* XXX 9280 2 */
static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e },
+ { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
- { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
{ 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+ { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
{ 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c },
- { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
{ 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
@@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
- { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
- { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
- { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
- { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
- { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
- { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
- { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
- { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
- { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
- { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
- { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
- { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
- { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
- { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
- { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
- { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
- { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
- { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
- { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
- { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
- { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
- { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
- { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
- { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
- { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
- { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
- { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
- { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
- { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
- { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
- { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
- { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
- { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
- { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
- { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
- { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
- { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
- { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
- { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
- { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
- { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
- { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
- { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
- { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
- { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
- { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
- { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
- { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
- { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
- { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
- { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
- { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
- { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
- { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
- { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
- { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
- { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
- { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
- { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
- { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
- { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
- { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
- { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
- { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
- { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
- { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
- { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
- { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
- { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
- { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
- { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
- { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
- { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
- { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
- { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
- { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
- { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
- { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
- { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
- { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
- { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
- { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
- { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
- { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
- { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
- { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
- { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
- { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
- { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
- { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
- { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
- { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
- { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
- { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
- { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
- { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
- { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
- { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
- { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
{ 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
{ 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
- { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 },
+ { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
{ 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
- { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
- { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
- { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
- { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
- { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
- { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
- { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
- { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
- { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
- { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
- { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
- { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
- { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
- { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
- { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
- { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
- { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
- { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
- { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
- { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
{ 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
{ 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
@@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
+ { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 },
@@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
+ { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
{ 0x00008344, 0x00581043 },
@@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009958, 0x2108ecff },
{ 0x00009940, 0x14750604 },
{ 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
+ { 0x00009968, 0x000003ce },
{ 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
@@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x000099ec, 0x0cc80caa },
{ 0x000099f0, 0x00000000 },
{ 0x000099fc, 0x00001042 },
+ { 0x0000a208, 0x803e4788 },
{ 0x0000a210, 0x4080a333 },
{ 0x0000a214, 0x40206c10 },
{ 0x0000a218, 0x009c4060 },
{ 0x0000a220, 0x01834061 },
{ 0x0000a224, 0x00000400 },
{ 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x233f71c0 },
+ { 0x0000a22c, 0x233f7180 },
{ 0x0000a234, 0x20202020 },
{ 0x0000a238, 0x20202020 },
{ 0x0000a23c, 0x13c88000 },
@@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000b26c, 0x0ebae9c6 },
{ 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
{ 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 },
@@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00007808, 0x04924914 },
{ 0x0000780c, 0x21084210 },
{ 0x00007810, 0x6d801300 },
- { 0x00007814, 0x0019beff },
{ 0x00007818, 0x07e41000 },
{ 0x0000781c, 0x00392000 },
{ 0x00007820, 0x92592480 },
@@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000782c, 0x04924914 },
{ 0x00007830, 0x21084210 },
{ 0x00007834, 0x6d801300 },
- { 0x00007838, 0x0019beff },
{ 0x0000783c, 0x07e40000 },
{ 0x00007840, 0x00392000 },
{ 0x00007844, 0x92592480 },
@@ -3110,12 +2952,465 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
{ 0x00009828, 0x0b020001, 0x0b020001 },
{ 0x00009834, 0x00000f0f, 0x00000f0f },
{ 0x00009844, 0x03721821, 0x03721821 },
- { 0x00009914, 0x00000898, 0x00000898 },
+ { 0x00009914, 0x00000898, 0x00001130 },
{ 0x00009918, 0x0000000b, 0x00000016 },
{ 0x00009944, 0xdfbc1210, 0xdfbc1210 },
};
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
+ { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+};
+
+static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
+ { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+};
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
+ { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+};
+
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
+ { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 },
+ { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 },
+ { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 },
+ { 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 },
+ { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+ { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+ { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
+};
+
+static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
+ { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
+ { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
+ { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
+ { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
+ { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
+ { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
+ { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+ { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
+ { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
+ { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
+ { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
+ { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
+ { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
+ { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
+ { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
+ { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
+ { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
+ { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
+ { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
+ { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+ { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+ { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+ { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
+};
static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
{0x00004040, 0x9248fd00 },
@@ -3123,23 +3418,21 @@ static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
{0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 },
- {0x00004040, 0x401dcffc },
- {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
};
-
-
static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004040, 0x9248fd00 },
{0x00004040, 0x24924924 },
{0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 },
- {0x00004040, 0x401dcffd },
- {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c
index c344a81e738a..36955e0b1849 100644
--- a/drivers/net/wireless/ath9k/mac.c
+++ b/drivers/net/wireless/ath9k/mac.c
@@ -293,8 +293,10 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
if (ads->ds_txstatus1 & AR_Filtered)
ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
- if (ads->ds_txstatus1 & AR_FIFOUnderrun)
+ if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
if (ads->ds_txstatus9 & AR_TxOpExceeded)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
if (ads->ds_txstatus1 & AR_TxTimerExpired)
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index fbb2dd2373c8..437e38a3c6d7 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -14,8 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* mac80211 and PCI callbacks */
-
#include <linux/nl80211.h>
#include "core.h"
#include "reg.h"
@@ -40,6 +38,577 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
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->sc_curmode = 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);
+}
+
+static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
+{
+ 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;
+}
+
+static void ath_update_txpow(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 txpow;
+
+ if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
+ ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
+ /* read back in case value is clamped */
+ ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
+ sc->sc_curtxpow = txpow;
+ }
+}
+
+static u8 parse_mpdudensity(u8 mpdudensity)
+{
+ /*
+ * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+ * 0 for no restriction
+ * 1 for 1/4 us
+ * 2 for 1/2 us
+ * 3 for 1 us
+ * 4 for 2 us
+ * 5 for 4 us
+ * 6 for 8 us
+ * 7 for 16 us
+ */
+ switch (mpdudensity) {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ /* Our lower layer calculations limit our precision to
+ 1 microsecond */
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ return 4;
+ case 6:
+ return 8;
+ case 7:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
+{
+ struct ath_rate_table *rate_table = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *rate;
+ int i, maxrates;
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11G];
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11A];
+ break;
+ default:
+ break;
+ }
+
+ if (rate_table == NULL)
+ return;
+
+ sband = &sc->sbands[band];
+ rate = sc->rates[band];
+
+ if (rate_table->rate_cnt > ATH_RATE_MAX)
+ maxrates = ATH_RATE_MAX;
+ else
+ maxrates = rate_table->rate_cnt;
+
+ for (i = 0; i < maxrates; i++) {
+ rate[i].bitrate = rate_table->info[i].ratekbps / 100;
+ rate[i].hw_value = rate_table->info[i].ratecode;
+ sband->n_bitrates++;
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Rate: %2dMbps, ratecode: %2d\n",
+ __func__, 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,
+ "%s: unable to collect channel list; "
+ "regdomain likely %u country code %u\n",
+ __func__, 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, "%s: 2MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ __func__, 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, "%s: 5MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ __func__, 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)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ bool fastcc = true, stopped;
+
+ 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); /* disable interrupts */
+ ath_draintxq(sc, false); /* clear pending tx frames */
+ stopped = ath_stoprecv(sc); /* turn off frame recv */
+
+ /* 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,
+ "%s: (%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n",
+ __func__,
+ 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,
+ "%s: unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n", __func__,
+ 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);
+
+ sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
+ sc->sc_flags &= ~SC_OP_FULL_RESET;
+
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to restart recv logic\n", __func__);
+ return -EIO;
+ }
+
+ ath_setcurmode(sc, ath_chan2mode(hchan));
+ ath_update_txpow(sc);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ return 0;
+}
+
+/*
+ * This routine performs the periodic noise floor calibration function
+ * that is used to adjust and optimize the chip performance. This
+ * takes environmental changes (location, temperature) into account.
+ * When the task is complete, it reschedules itself depending on the
+ * appropriate interval that was calculated.
+ */
+static void ath_ani_calibrate(unsigned long data)
+{
+ struct ath_softc *sc;
+ struct ath_hal *ah;
+ bool longcal = false;
+ bool shortcal = false;
+ bool aniflag = false;
+ unsigned int timestamp = jiffies_to_msecs(jiffies);
+ u32 cal_interval;
+
+ sc = (struct ath_softc *)data;
+ ah = sc->sc_ah;
+
+ /*
+ * don't calibrate when we're scanning.
+ * we are most likely not on our home channel.
+ */
+ if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
+ return;
+
+ /* Long calibration runs independently of short calibration. */
+ if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
+ longcal = true;
+ DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
+ __func__, jiffies);
+ sc->sc_ani.sc_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) {
+ shortcal = true;
+ DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
+ __func__, jiffies);
+ sc->sc_ani.sc_shortcal_timer = timestamp;
+ sc->sc_ani.sc_resetcal_timer = timestamp;
+ }
+ } else {
+ if ((timestamp - sc->sc_ani.sc_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;
+ }
+ }
+
+ /* Verify whether we must check ANI */
+ if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
+ ATH_ANI_POLLINTERVAL) {
+ aniflag = true;
+ sc->sc_ani.sc_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);
+
+ /* Perform calibration if necessary */
+ if (longcal || shortcal) {
+ bool iscaldone = false;
+
+ if (ath9k_hw_calibrate(ah, ah->ah_curchan,
+ sc->sc_rx_chainmask, longcal,
+ &iscaldone)) {
+ if (longcal)
+ sc->sc_ani.sc_noise_floor =
+ ath9k_hw_getchan_noise(ah,
+ ah->ah_curchan);
+
+ DPRINTF(sc, ATH_DBG_ANI,
+ "%s: calibrate chan %u/%x nf: %d\n",
+ __func__,
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags,
+ sc->sc_ani.sc_noise_floor);
+ } else {
+ DPRINTF(sc, ATH_DBG_ANY,
+ "%s: calibrate chan %u/%x failed\n",
+ __func__,
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags);
+ }
+ sc->sc_ani.sc_caldone = iscaldone;
+ }
+ }
+
+ /*
+ * 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_ANI_POLLINTERVAL;
+ if (!sc->sc_ani.sc_caldone)
+ cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
+
+ mod_timer(&sc->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.
+ */
+static 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;
+ } else {
+ sc->sc_tx_chainmask = 1;
+ sc->sc_rx_chainmask = 1;
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
+ __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
+}
+
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+ struct ath_node *an;
+
+ an = (struct ath_node *)sta->drv_priv;
+
+ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_tx_node_init(sc, an);
+
+ an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ sta->ht_cap.ampdu_factor);
+ an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+}
+
+static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
+
+ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_tx_node_cleanup(sc, an);
+}
+
+static void ath9k_tasklet(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ u32 status = sc->sc_intrstatus;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ ath_reset(sc, false);
+ return;
+ } else {
+
+ if (status &
+ (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+ spin_lock_bh(&sc->sc_rxflushlock);
+ ath_rx_tasklet(sc, 0);
+ spin_unlock_bh(&sc->sc_rxflushlock);
+ }
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_TX)
+ ath_tx_tasklet(sc);
+ }
+
+ /* re-enable hardware interrupt */
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+}
+
+static irqreturn_t ath_isr(int irq, void *dev)
+{
+ struct ath_softc *sc = dev;
+ struct ath_hal *ah = sc->sc_ah;
+ enum ath9k_int status;
+ bool sched = false;
+
+ do {
+ if (sc->sc_flags & SC_OP_INVALID) {
+ /*
+ * The hardware is not ready/present, don't
+ * touch anything. Note this can happen early
+ * on if the IRQ is shared.
+ */
+ return IRQ_NONE;
+ }
+ if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
+ return IRQ_NONE;
+ }
+
+ /*
+ * Figure out the reason(s) for the interrupt. Note
+ * that the hal returns a pseudo-ISR that may include
+ * bits we haven't explicitly enabled so we mask the
+ * value to insure we only process bits we requested.
+ */
+ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
+
+ status &= sc->sc_imask; /* discard unasked-for bits */
+
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
+ */
+ if (!status)
+ return IRQ_NONE;
+
+ sc->sc_intrstatus = status;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ sched = true;
+ } else if (status & ATH9K_INT_RXORN) {
+ /* need a chip reset */
+ sched = true;
+ } else {
+ if (status & ATH9K_INT_SWBA) {
+ /* schedule a tasklet for beacon handling */
+ tasklet_schedule(&sc->bcon_tasklet);
+ }
+ if (status & ATH9K_INT_RXEOL) {
+ /*
+ * NB: the hardware should re-read the link when
+ * RXE bit is written, but it doesn't work
+ * at least on older hardware revs.
+ */
+ sched = true;
+ }
+
+ if (status & ATH9K_INT_TXURN)
+ /* bump tx trigger level */
+ ath9k_hw_updatetxtriglevel(ah, true);
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_RX)
+ sched = true;
+ if (status & ATH9K_INT_TX)
+ sched = true;
+ if (status & ATH9K_INT_BMISS)
+ sched = true;
+ /* carrier sense timeout */
+ if (status & ATH9K_INT_CST)
+ sched = true;
+ if (status & ATH9K_INT_MIB) {
+ /*
+ * Disable interrupts until we service the MIB
+ * interrupt; otherwise it will continue to
+ * fire.
+ */
+ ath9k_hw_set_interrupts(ah, 0);
+ /*
+ * Let the hal handle the event. We assume
+ * it will clear whatever condition caused
+ * the interrupt.
+ */
+ ath9k_hw_procmibevent(ah, &sc->sc_halstats);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ if (status & ATH9K_INT_TIM_TIMER) {
+ if (!(ah->ah_caps.hw_caps &
+ ATH9K_HW_CAP_AUTOSLEEP)) {
+ /* Clear RxAbort bit so that we can
+ * receive frames */
+ ath9k_hw_setrxabort(ah, 0);
+ sched = true;
+ }
+ }
+ }
+ } while (0);
+
+ if (sched) {
+ /* turn off every interrupt except SWBA */
+ ath9k_hw_set_interrupts(ah, (sc->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)
{
@@ -54,11 +623,13 @@ static int ath_get_channel(struct ath_softc *sc,
}
static u32 ath_get_extchanmode(struct ath_softc *sc,
- struct ieee80211_channel *chan)
+ struct ieee80211_channel *chan,
+ struct ieee80211_bss_conf *bss_conf)
{
u32 chanmode = 0;
- u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset;
- enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width;
+ u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset;
+ enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ?
+ ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
switch (chan->band) {
case IEEE80211_BAND_2GHZ:
@@ -90,6 +661,23 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
+static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
+{
+ ath9k_hw_keyreset(sc->sc_ah, keyix);
+ if (freeslot)
+ clear_bit(keyix, sc->sc_keymap);
+}
+
+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,
struct ieee80211_key_conf *key,
@@ -236,82 +824,20 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
-static int ath_rate2idx(struct ath_softc *sc, int rate)
-{
- 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;
-
- for (i = 0; i < n_rates; i++) {
- if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
- break;
- }
-
- /*
- * NB:mac80211 validates rx rate index against the supported legacy rate
- * index only (should be done against ht rates also), return the highest
- * legacy rate index for rx rate which does not match any one of the
- * supported basic and extended rates to make mac80211 happy.
- * The following hack will be cleaned up once the issue with
- * the rx rate index validation in mac80211 is fixed.
- */
- if (i == n_rates)
- return n_rates - 1;
- return i;
-}
-
-static void ath9k_rx_prepare(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_channel *curchan = hw->conf.channel;
-
- memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-
- rx_status->mactime = status->tsf;
- rx_status->band = curchan->band;
- rx_status->freq = curchan->center_freq;
- rx_status->noise = sc->sc_ani.sc_noise_floor;
- rx_status->signal = rx_status->noise + status->rssi;
- rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
- rx_status->antenna = status->antenna;
-
- /* at 45 you will be able to use MCS 15 reliably. A more elaborate
- * scheme can be used here but it requires tables of SNR/throughput for
- * each possible mode used. */
- rx_status->qual = status->rssi * 100 / 45;
-
- /* rssi can be more than 45 though, anything above that
- * should be considered at 100% */
- if (rx_status->qual > 100)
- rx_status->qual = 100;
-
- if (status->flags & ATH_RX_MIC_ERROR)
- rx_status->flag |= RX_FLAG_MMIC_ERROR;
- if (status->flags & ATH_RX_FCS_ERROR)
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-
- rx_status->flag |= RX_FLAG_TSFT;
-}
-
static void ath9k_ht_conf(struct ath_softc *sc,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_ht_info *ht_info = &sc->sc_ht_info;
-
if (sc->hw->conf.ht.enabled) {
- ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset;
-
if (bss_conf->ht.width_40_ok)
- ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
+ sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
else
- ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
+ sc->tx_chan_width = ATH9K_HT_MACMODE_20;
- ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
+ ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: BSS Changed HT, chanwidth: %d\n",
+ __func__, sc->tx_chan_width);
}
}
@@ -365,120 +891,34 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
return;
}
- if (hw->conf.ht.enabled)
+ if (hw->conf.ht.enabled) {
sc->sc_ah->ah_channels[pos].chanmode =
- ath_get_extchanmode(sc, curchan);
- else
+ ath_get_extchanmode(sc, curchan, bss_conf);
+
+ if (bss_conf->ht.width_40_ok)
+ sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
+ else
+ sc->tx_chan_width = ATH9K_HT_MACMODE_20;
+ } else {
sc->sc_ah->ah_channels[pos].chanmode =
(curchan->band == IEEE80211_BAND_2GHZ) ?
CHANNEL_G : CHANNEL_A;
+ }
/* set h/w channel */
if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to set channel\n",
- __func__);
-
- ath_rate_newstate(sc, avp);
- /* Update ratectrl about the new state */
- ath_rc_node_update(hw, avp->rc_node);
-
+ "%s: Unable to set channel\n", __func__);
/* Start ANI */
mod_timer(&sc->sc_ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
} else {
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Bss Info DISSOC\n", __func__);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info DISSOC\n", __func__);
sc->sc_curaid = 0;
}
}
-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;
-}
-
-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);
-
- DPRINTF(sc, ATH_DBG_XMIT,
- "%s: TX complete: skb: %p\n", __func__, skb);
-
- ieee80211_tx_info_clear_status(tx_info);
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
- tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
- /* free driver's private data area of tx_info, XXX: HACK! */
- if (tx_info->control.vif != NULL)
- kfree(tx_info->control.vif);
- tx_info->control.vif = 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;
-
- ieee80211_tx_status(hw, skb);
-}
-
-int _ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_rx_status rx_status;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- int padsize;
-
- /* see if any padding is done by the hw and remove it */
- if (hdrlen & 3) {
- padsize = hdrlen % 4;
- memmove(skb->data + padsize, skb->data, hdrlen);
- skb_pull(skb, padsize);
- }
-
- /* Prepare rx status */
- ath9k_rx_prepare(sc, skb, status, &rx_status);
-
- if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
- !(status->flags & ATH_RX_DECRYPT_ERROR)) {
- rx_status.flag |= RX_FLAG_DECRYPTED;
- } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
- && !(status->flags & ATH_RX_DECRYPT_ERROR)
- && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, sc->sc_keymap))
- rx_status.flag |= RX_FLAG_DECRYPTED;
- }
-
- __ieee80211_rx(hw, skb, &rx_status);
-
- return 0;
-}
-
/********************************/
/* LED functions */
/********************************/
@@ -594,7 +1034,7 @@ fail:
ath_deinit_leds(sc);
}
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/*******************/
/* Rfkill */
@@ -607,7 +1047,7 @@ static void ath_radio_enable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
@@ -665,7 +1105,7 @@ static void ath_radio_disable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
@@ -810,9 +1250,9 @@ 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);
- ath_detach(sc);
pci_iounmap(sc->pdev, sc->mem);
pci_release_region(sc->pdev, 0);
pci_disable_device(sc->pdev);
@@ -834,15 +1274,14 @@ static void ath_detach(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
- ieee80211_unregister_hw(hw);
-
- ath_deinit_leds(sc);
-
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
ath_deinit_rfkill(sc);
#endif
+ ath_deinit_leds(sc);
+
+ ieee80211_unregister_hw(hw);
+
ath_rate_control_unregister();
- ath_rate_detach(sc->sc_rc);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
@@ -861,6 +1300,244 @@ static void ath_detach(struct ath_softc *sc)
ath9k_hw_detach(sc->sc_ah);
}
+static int ath_init(u16 devid, struct ath_softc *sc)
+{
+ struct ath_hal *ah = NULL;
+ int status;
+ int error = 0, i;
+ int csz = 0;
+
+ /* XXX: hardware will not be ready until ath_open() being called */
+ sc->sc_flags |= SC_OP_INVALID;
+ sc->sc_debug = DBG_DEFAULT;
+
+ spin_lock_init(&sc->sc_resetlock);
+ tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+ tasklet_init(&sc->bcon_tasklet, ath9k_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);
+ /* XXX assert csz is non-zero */
+ sc->sc_cachelsz = csz << 2; /* convert to bytes */
+
+ ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
+ if (ah == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to attach hardware; HAL status %u\n",
+ __func__, 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) {
+ DPRINTF(sc, ATH_DBG_KEYCACHE,
+ "%s: Warning, using only %u entries in %u key cache\n",
+ __func__, ATH_KEYMAX, sc->sc_keymax);
+ sc->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++)
+ ath9k_hw_keyreset(ah, (u16) i);
+ /*
+ * Mark key cache slots associated with global keys
+ * as in use. If we knew TKIP was not to be used we
+ * could leave the +32, +64, and +32+64 slots free.
+ * XXX only for splitmic.
+ */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ set_bit(i, sc->sc_keymap);
+ set_bit(i + 32, sc->sc_keymap);
+ set_bit(i + 64, sc->sc_keymap);
+ set_bit(i + 32 + 64, sc->sc_keymap);
+ }
+
+ /* Collect the channel list using the default country code */
+
+ error = ath_setup_channels(sc);
+ if (error)
+ goto bad;
+
+ /* default to MONITOR mode */
+ sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
+
+ /* Setup rate tables */
+
+ ath_rate_attach(sc);
+ ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
+ ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
+
+ /*
+ * Allocate hardware transmit queues: one queue for
+ * beacon frames and one data queue for each QoS
+ * priority. Note that the hal handles reseting
+ * these queues at the needed time.
+ */
+ sc->sc_bhalq = ath_beaconq_setup(ah);
+ if (sc->sc_bhalq == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup a beacon xmit queue\n", __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+ if (sc->sc_cabq == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup CAB xmit queue\n", __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
+ ath_cabq_update(sc);
+
+ for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
+ sc->sc_haltype2q[i] = -1;
+
+ /* Setup data queues */
+ /* NB: ensure BK queue is the lowest priority h/w queue */
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for BK traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for BE traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for VI traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for VO traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ /* 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);
+
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)) {
+ /*
+ * Whether we should enable h/w TKIP MIC.
+ * XXX: if we don't support WME TKIP MIC, then we wouldn't
+ * report WMM capable, so it's always safe to turn on
+ * TKIP MIC in this case.
+ */
+ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
+ 0, 1, NULL);
+ }
+
+ /*
+ * Check whether the separate key cache entries
+ * are required to handle both tx+rx MIC keys.
+ * With split mic keys the number of stations is limited
+ * to 27 otherwise 59.
+ */
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_MIC, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
+ 0, NULL))
+ sc->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;
+
+ /* 11n Capabilities */
+ if (ah->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;
+
+ ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+ sc->sc_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);
+ }
+
+ sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
+
+ /* initialize beacon slots */
+ for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
+ sc->sc_bslot[i] = ATH_IF_ID_ANY;
+
+ /* save MISC configurations */
+ sc->sc_config.swBeaconProcess = 1;
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ /* range is 40 - 255, we use something in the middle */
+ ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
+#endif
+
+ /* setup channels and rates */
+
+ sc->sbands[IEEE80211_BAND_2GHZ].channels =
+ sc->channels[IEEE80211_BAND_2GHZ];
+ sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
+ sc->rates[IEEE80211_BAND_2GHZ];
+ sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+ sc->sbands[IEEE80211_BAND_5GHZ].channels =
+ sc->channels[IEEE80211_BAND_5GHZ];
+ sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ sc->rates[IEEE80211_BAND_5GHZ];
+ sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ }
+
+ return 0;
+bad2:
+ /* cleanup tx queues */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+bad:
+ if (ah)
+ ath9k_hw_detach(ah);
+
+ return error;
+}
+
static int ath_attach(u16 devid, struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
@@ -887,6 +1564,8 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 4;
+ hw->max_rates = 4;
+ hw->max_rate_tries = ATH_11N_TXMAXTRY;
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vap);
@@ -912,16 +1591,16 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
- error = ieee80211_register_hw(hw);
- if (error != 0) {
- ath_rate_control_unregister();
- goto bad;
- }
+ /* initialize tx/rx engine */
+ error = ath_tx_init(sc, ATH_TXBUF);
+ if (error != 0)
+ goto detach;
- /* Initialize LED control */
- ath_init_leds(sc);
+ error = ath_rx_init(sc, ATH_RXBUF);
+ if (error != 0)
+ goto detach;
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/* Initialze h/w Rfkill */
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
@@ -931,15 +1610,14 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
goto detach;
#endif
- /* initialize tx/rx engine */
-
- error = ath_tx_init(sc, ATH_TXBUF);
- if (error != 0)
- goto detach;
+ error = ieee80211_register_hw(hw);
+ if (error != 0) {
+ ath_rate_control_unregister();
+ goto bad;
+ }
- error = ath_rx_init(sc, ATH_RXBUF);
- if (error != 0)
- goto detach;
+ /* Initialize LED control */
+ ath_init_leds(sc);
return 0;
detach:
@@ -948,41 +1626,351 @@ bad:
return error;
}
+int ath_reset(struct ath_softc *sc, bool retry_tx)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+ int error = 0;
+
+ ath9k_hw_set_interrupts(ah, 0);
+ ath_draintxq(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)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset hardware; hal status %u\n",
+ __func__, status);
+ error = -EIO;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ if (ath_startrecv(sc) != 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to start recv logic\n", __func__);
+
+ /*
+ * We may be doing a reset in response to a request
+ * 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_update_txpow(sc);
+
+ if (sc->sc_flags & SC_OP_BEACONS)
+ ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
+
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+ if (retry_tx) {
+ int i;
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ spin_lock_bh(&sc->sc_txq[i].axq_lock);
+ ath_txq_schedule(sc, &sc->sc_txq[i]);
+ spin_unlock_bh(&sc->sc_txq[i].axq_lock);
+ }
+ }
+ }
+
+ return error;
+}
+
+/*
+ * This function will allocate both the DMA descriptor structure, and the
+ * buffers it contains. These are used to contain the descriptors used
+ * by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+ struct list_head *head, const char *name,
+ int nbuf, int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
+ __func__, name, nbuf, ndesc);
+
+ /* ath_desc must be a multiple of DWORDs */
+ if ((sizeof(struct ath_desc) % 4) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
+ __func__);
+ ASSERT((sizeof(struct ath_desc) % 4) == 0);
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dd->dd_name = name;
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+ /*
+ * Need additional DMA memory because we can't use
+ * 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)) {
+ u32 ndesc_skipped =
+ ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+ u32 dma_len;
+
+ while (ndesc_skipped) {
+ dma_len = ndesc_skipped * sizeof(struct ath_desc);
+ dd->dd_desc_len += dma_len;
+
+ ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+ };
+ }
+
+ /* allocate descriptors */
+ dd->dd_desc = pci_alloc_consistent(sc->pdev,
+ dd->dd_desc_len,
+ &dd->dd_desc_paddr);
+ if (dd->dd_desc == NULL) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ ds = dd->dd_desc;
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
+ __func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+ /* allocate buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = kmalloc(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 &
+ ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ /*
+ * Skip descriptor addresses which can cause 4KB
+ * boundary crossing (addr + length) with a 32 dword
+ * descriptor fetch.
+ */
+ while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+ ASSERT((caddr_t) bf->bf_desc <
+ ((caddr_t) dd->dd_desc +
+ dd->dd_desc_len));
+
+ ds += ndesc;
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+ }
+ }
+ list_add_tail(&bf->list, head);
+ }
+ return 0;
+fail2:
+ pci_free_consistent(sc->pdev,
+ dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+fail:
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+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);
+
+ INIT_LIST_HEAD(head);
+ kfree(dd->dd_bufptr);
+ memset(dd, 0, sizeof(*dd));
+}
+
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case 0:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
+ break;
+ case 1:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
+ break;
+ case 2:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
+ break;
+ case 3:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
+ break;
+ default:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
+ break;
+ }
+
+ return qnum;
+}
+
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case ATH9K_WME_AC_VO:
+ qnum = 0;
+ break;
+ case ATH9K_WME_AC_VI:
+ qnum = 1;
+ break;
+ case ATH9K_WME_AC_BE:
+ qnum = 2;
+ break;
+ case ATH9K_WME_AC_BK:
+ qnum = 3;
+ break;
+ default:
+ qnum = -1;
+ break;
+ }
+
+ return qnum;
+}
+
+/**********************/
+/* mac80211 callbacks */
+/**********************/
+
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ieee80211_channel *curchan = hw->conf.channel;
- int error = 0, pos;
+ struct ath9k_channel *init_channel;
+ int error = 0, pos, status;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
"initial channel: %d MHz\n", __func__, curchan->center_freq);
- memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info));
-
/* setup initial channel */
pos = ath_get_channel(sc, curchan);
if (pos == -1) {
DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
error = -EINVAL;
- goto exit;
+ goto error;
}
+ 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];
+
+ /* Reset SERDES registers */
+ ath9k_hw_configpcipowersave(sc->sc_ah, 0);
- error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
- if (error) {
+ /*
+ * The basic interface to setting the hardware in a good
+ * state is ``reset''. On return the hardware is known to
+ * be powered up and with interrupts disabled. This must
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+ 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)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to complete ath_open\n", __func__);
- goto exit;
+ "%s: unable to reset hardware; hal status %u "
+ "(freq %u flags 0x%x)\n", __func__, status,
+ init_channel->channel, init_channel->channelFlags);
+ error = -EIO;
+ spin_unlock_bh(&sc->sc_resetlock);
+ goto error;
}
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ /*
+ * This is needed only to setup initial state
+ * but it's best done after a reset.
+ */
+ ath_update_txpow(sc);
+
+ /*
+ * Setup the hardware after reset:
+ * The receive engine is set going.
+ * Frame transmit is handled entirely
+ * in the frame output path; there's nothing to do
+ * here except setup the interrupt mask.
+ */
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to start recv logic\n", __func__);
+ error = -EIO;
+ goto error;
+ }
+
+ /* Setup our intr mask. */
+ sc->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->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 == ATH9K_M_STA) ||
+ (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
+ 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 == ATH9K_M_STA) &&
+ !sc->sc_config.swBeaconProcess)
+ sc->sc_imask |= ATH9K_INT_TIM;
+
+ ath_setcurmode(sc, ath_chan2mode(init_channel));
+
+ 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);
-#ifdef CONFIG_RFKILL
+ ieee80211_wake_queues(sc->hw);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
error = ath_start_rfkill_poll(sc);
#endif
-exit:
+error:
return error;
}
@@ -1049,7 +2037,30 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return;
}
- ath_stop(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__);
+
+ ieee80211_stop_queues(sc->hw);
+
+ /* 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_stoprecv(sc);
+ ath9k_hw_phy_disable(sc->sc_ah);
+ } else
+ sc->sc_rxlink = NULL;
+
+#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
+ /* disable HAL and put h/w to sleep */
+ ath9k_hw_disable(sc->sc_ah);
+ ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+ sc->sc_flags |= SC_OP_INVALID;
DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
}
@@ -1100,10 +2111,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
/* Set the device opmode */
sc->sc_ah->ah_opmode = ic_opmode;
- /* default VAP configuration */
- avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
- avp->av_config.av_fixed_retryset = 0x03030303;
-
if (conf->type == NL80211_IFTYPE_AP) {
/* TODO: is this a suitable place to start ANI for AP mode? */
/* Start ANI */
@@ -1144,39 +2151,37 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_softc *sc = hw->priv;
- struct ieee80211_channel *curchan = hw->conf.channel;
struct ieee80211_conf *conf = &hw->conf;
- int pos;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
- __func__,
- curchan->center_freq);
- /* Update chainmask */
- ath_update_chainmask(sc, conf->ht.enabled);
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int pos;
- pos = ath_get_channel(sc, curchan);
- if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
- return -EINVAL;
- }
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+ __func__, curchan->center_freq);
- sc->sc_ah->ah_channels[pos].chanmode =
- (curchan->band == IEEE80211_BAND_2GHZ) ?
- CHANNEL_G : CHANNEL_A;
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+ return -EINVAL;
+ }
- if (sc->sc_curaid && hw->conf.ht.enabled)
+ sc->tx_chan_width = ATH9K_HT_MACMODE_20;
sc->sc_ah->ah_channels[pos].chanmode =
- ath_get_extchanmode(sc, curchan);
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
+
+ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to set channel\n", __func__);
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_HT)
+ ath_update_chainmask(sc, conf->ht.enabled);
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->sc_config.txpowlimit = 2 * conf->power_level;
- /* set h/w channel */
- if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
- __func__);
-
return 0;
}
@@ -1206,9 +2211,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- /* Update ratectrl about the new state */
- ath_rate_newstate(sc, avp);
-
/* Set BSSID */
memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
sc->sc_curaid = 0;
@@ -1419,11 +2421,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
- if (changed & BSS_CHANGED_HT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n",
- __func__);
+ if (changed & BSS_CHANGED_HT)
ath9k_ht_conf(sc, bss_conf);
- }
if (changed & BSS_CHANGED_ASSOC) {
DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
@@ -1592,10 +2591,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (pci_enable_device(pdev))
return -EIO;
- /* XXX 32-bit addressing only */
- if (pci_set_dma_mask(pdev, 0xffffffff)) {
- printk(KERN_ERR "ath_pci: 32-bit DMA not available\n");
- ret = -ENODEV;
+ 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 faled\n");
goto bad;
}
@@ -1722,7 +2729,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-#ifdef CONFIG_RFKILL
+#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
@@ -1759,7 +2766,7 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/*
* check the h/w rfkill state on resume
* and start the rfkill poll timer
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index 517992d14808..93dfea897ff2 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -15,143 +15,136 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Atheros rate control algorithm
- */
-
#include "core.h"
-/* FIXME: remove this include! */
-#include "../net/mac80211/rate.h"
-
-static u32 tx_triglevel_max;
static struct ath_rate_table ar5416_11na_ratetable = {
42,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
0, 2, 1, 0, 0, 0, 0, 0 },
- { TRUE, TRUE, WLAN_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 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
2, 4, 2, 2, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 6, 2, 3, 3, 3, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
4, 10, 3, 4, 4, 4, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 14, 3, 5, 5, 5, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 20, 3, 6, 6, 6, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 23, 3, 7, 7, 7, 7, 0 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
0, 2, 3, 8, 24, 8, 24, 3216 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
2, 4, 3, 9, 25, 9, 25, 6434 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
2, 6, 3, 10, 26, 10, 26, 9650 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
4, 10, 3, 11, 27, 11, 27, 12868 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
4, 14, 3, 12, 28, 12, 28, 19304 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
4, 20, 3, 13, 29, 13, 29, 25740 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
4, 23, 3, 14, 30, 14, 30, 28956 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 15, 32, 32180 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
8, 0, 2, 3, 16, 33, 16, 33, 6430 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
2, 4, 3, 17, 34, 17, 34, 12860 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
2, 6, 3, 18, 35, 18, 35, 19300 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
4, 10, 3, 19, 36, 19, 36, 25736 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
4, 14, 3, 20, 37, 20, 37, 38600 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
4, 20, 3, 21, 38, 21, 38, 51472 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
4, 23, 3, 22, 39, 22, 39, 57890 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 23, 41, 64320 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
0, 2, 3, 8, 24, 24, 24, 6684 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
2, 4, 3, 9, 25, 25, 25, 13368 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
2, 6, 3, 10, 26, 26, 26, 20052 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
4, 10, 3, 11, 27, 27, 27, 26738 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
4, 14, 3, 12, 28, 28, 28, 40104 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
4, 20, 3, 13, 29, 29, 29, 53476 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
4, 23, 3, 14, 30, 30, 30, 60156 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 32, 32, 66840 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 32, 32, 74200 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
0, 2, 3, 16, 33, 33, 33, 13360 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
2, 4, 3, 17, 34, 34, 34, 26720 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
2, 6, 3, 18, 35, 35, 35, 40080 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
4, 10, 3, 19, 36, 36, 36, 53440 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
4, 14, 3, 20, 37, 37, 37, 80160 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
4, 20, 3, 21, 38, 38, 38, 106880 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
4, 23, 3, 22, 39, 39, 39, 120240 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 41, 41, 133600 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 41, 41, 148400 },
},
@@ -160,153 +153,149 @@ static struct ath_rate_table ar5416_11na_ratetable = {
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
-/* TRUE_ALL - valid for 20/40/Legacy,
- * TRUE - Legacy only,
- * TRUE_20 - HT 20 only,
- * TRUE_40 - HT 40 only */
-
/* 4ms frame limit not used for NG mode. The values filled
* for HT are the 64K max aggregate limit */
static struct ath_rate_table ar5416_11ng_ratetable = {
46,
+ {0},
{
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 1, 0, 0, 0, 0, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 1, 1, 1, 1, 1, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 2, 2, 2, 2, 2, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 2, 3, 3, 3, 3, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 2, 1, 4, 4, 4, 4, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 3, 1, 5, 5, 5, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
6, 4, 1, 6, 6, 6, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
6, 6, 2, 7, 7, 7, 7, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
8, 10, 3, 8, 8, 8, 8, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
8, 14, 3, 9, 9, 9, 9, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 20, 3, 10, 10, 10, 10, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
8, 23, 3, 11, 11, 11, 11, 0 },
- { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
4, 2, 3, 12, 28, 12, 28, 3216 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
6, 4, 3, 13, 29, 13, 29, 6434 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
6, 6, 3, 14, 30, 14, 30, 9650 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
8, 10, 3, 15, 31, 15, 31, 12868 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
8, 14, 3, 16, 32, 16, 32, 19304 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
8, 20, 3, 17, 33, 17, 33, 25740 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
8, 23, 3, 18, 34, 18, 34, 28956 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
8, 25, 3, 19, 35, 19, 36, 32180 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
4, 2, 3, 20, 37, 20, 37, 6430 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
6, 4, 3, 21, 38, 21, 38, 12860 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
6, 6, 3, 22, 39, 22, 39, 19300 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
8, 10, 3, 23, 40, 23, 40, 25736 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
8, 14, 3, 24, 41, 24, 41, 38600 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
8, 20, 3, 25, 42, 25, 42, 51472 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
8, 23, 3, 26, 43, 26, 44, 57890 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
8, 25, 3, 27, 44, 27, 45, 64320 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
8, 2, 3, 12, 28, 28, 28, 6684 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
8, 4, 3, 13, 29, 29, 29, 13368 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
8, 6, 3, 14, 30, 30, 30, 20052 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
8, 10, 3, 15, 31, 31, 31, 26738 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
8, 14, 3, 16, 32, 32, 32, 40104 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
8, 20, 3, 17, 33, 33, 33, 53476 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
8, 23, 3, 18, 34, 34, 34, 60156 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
8, 23, 3, 19, 35, 36, 36, 66840 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
8, 25, 3, 19, 35, 36, 36, 74200 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
8, 2, 3, 20, 37, 37, 37, 13360 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
8, 4, 3, 21, 38, 38, 38, 26720 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
8, 6, 3, 22, 39, 39, 39, 40080 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
8, 10, 3, 23, 40, 40, 40, 53440 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
8, 14, 3, 24, 41, 41, 41, 80160 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
8, 20, 3, 25, 42, 42, 42, 106880 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
8, 23, 3, 26, 43, 43, 43, 120240 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
8, 23, 3, 27, 44, 45, 45, 133600 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
8, 25, 3, 27, 44, 45, 45, 148400 },
},
@@ -317,29 +306,30 @@ static struct ath_rate_table ar5416_11ng_ratetable = {
static struct ath_rate_table ar5416_11a_ratetable = {
8,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
0, 2, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 23, 3, 7, 0 },
},
@@ -348,109 +338,44 @@ static struct ath_rate_table ar5416_11a_ratetable = {
0, /* Phy rates allowed initially */
};
-static struct ath_rate_table ar5416_11a_ratetable_Half = {
- 8,
- {
- { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */
- 2700, 0x0b, 0x00, (0x80|6),
- 0, 2, 1, 0, 0},
- { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */
- 3900, 0x0f, 0x00, 9,
- 0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */
- 5000, 0x0a, 0x00, (0x80|12),
- 2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */
- 6950, 0x0e, 0x00, 18,
- 2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */
- 8650, 0x09, 0x00, (0x80|24),
- 4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */
- 11500, 0x0d, 0x00, 36,
- 4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */
- 13700, 0x08, 0x00, 48,
- 4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */
- 14650, 0x0c, 0x00, 54,
- 4, 23, 3, 7, 0 },
- },
- 50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static struct ath_rate_table ar5416_11a_ratetable_Quarter = {
- 8,
- {
- { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */
- 1350, 0x0b, 0x00, (0x80|3),
- 0, 2, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */
- 1950, 0x0f, 0x00, 4,
- 0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */
- 2500, 0x0a, 0x00, (0x80|6),
- 2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */
- 3475, 0x0e, 0x00, 9,
- 2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */
- 4325, 0x09, 0x00, (0x80|12),
- 4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */
- 5750, 0x0d, 0x00, 18,
- 4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */
- 6850, 0x08, 0x00, 24,
- 4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */
- 7325, 0x0c, 0x00, 27,
- 4, 23, 3, 7, 0 },
- },
- 50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
static struct ath_rate_table ar5416_11g_ratetable = {
12,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 2, 3, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 2, 1, 4, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 3, 1, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
6, 4, 1, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
6, 6, 2, 7, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
8, 10, 3, 8, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
8, 14, 3, 9, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 19, 3, 10, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
8, 23, 3, 11, 0 },
},
@@ -461,17 +386,18 @@ static struct ath_rate_table ar5416_11g_ratetable = {
static struct ath_rate_table ar5416_11b_ratetable = {
4,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, (0x80|2),
0, 0, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1800, 0x1a, 0x04, (0x80|4),
1, 1, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4300, 0x19, 0x04, (0x80|11),
1, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
7100, 0x18, 0x04, (0x80|22),
1, 4, 100, 3, 0 },
},
@@ -480,48 +406,6 @@ static struct ath_rate_table ar5416_11b_ratetable = {
0, /* Phy rates allowed initially */
};
-static void ar5416_attach_ratetables(struct ath_rate_softc *sc)
-{
- /*
- * Attach rate tables.
- */
- sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable;
-
- sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
- &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
- &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
- &ar5416_11ng_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
- &ar5416_11ng_ratetable;
-}
-
-static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter;
- return;
-}
-
-static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half;
- return;
-}
-
-static void ar5416_setfull_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
- return;
-}
-
-/*
- * Return the median of three numbers
- */
static inline int8_t median(int8_t a, int8_t b, int8_t c)
{
if (a >= b) {
@@ -541,68 +425,65 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c)
}
}
-static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_sort_validrates(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv)
{
u8 i, j, idx, idx_next;
- for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) {
+ for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
for (j = 0; j <= i-1; j++) {
- idx = rate_ctrl->valid_rate_index[j];
- idx_next = rate_ctrl->valid_rate_index[j+1];
+ idx = ath_rc_priv->valid_rate_index[j];
+ idx_next = ath_rc_priv->valid_rate_index[j+1];
if (rate_table->info[idx].ratekbps >
rate_table->info[idx_next].ratekbps) {
- rate_ctrl->valid_rate_index[j] = idx_next;
- rate_ctrl->valid_rate_index[j+1] = idx;
+ ath_rc_priv->valid_rate_index[j] = idx_next;
+ ath_rc_priv->valid_rate_index[j+1] = idx;
}
}
}
}
-/* Access functions for valid_txrate_mask */
-
-static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
{
u8 i;
- for (i = 0; i < rate_ctrl->rate_table_size; i++)
- rate_ctrl->valid_rate_index[i] = FALSE;
+ for (i = 0; i < ath_rc_priv->rate_table_size; i++)
+ ath_rc_priv->valid_rate_index[i] = 0;
}
-static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
- ASSERT(index <= rate_ctrl->rate_table_size);
- rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE;
+ ASSERT(index <= ath_rc_priv->rate_table_size);
+ ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index)
{
- ASSERT(index <= rate_ctrl->rate_table_size);
- return rate_ctrl->valid_rate_index[index];
+ ASSERT(index <= ath_rc_priv->rate_table_size);
+ return ath_rc_priv->valid_rate_index[index];
}
-/* Iterators for valid_txrate_mask */
-static inline int
-ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl,
- u8 cur_valid_txrate,
- u8 *next_idx)
+static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate,
+ u8 *next_idx)
{
u8 i;
- for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) {
- if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = rate_ctrl->valid_rate_index[i+1];
- return TRUE;
+ for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) {
+ if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = ath_rc_priv->valid_rate_index[i+1];
+ return 1;
}
}
/* No more valid rates */
*next_idx = 0;
- return FALSE;
+
+ return 0;
}
/* Return true only for single stream */
@@ -610,83 +491,72 @@ ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
{
if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG))
- return FALSE;
+ return 0;
if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
- return FALSE;
+ return 0;
if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
- return FALSE;
+ return 0;
if (!ignore_cw && WLAN_RC_PHY_HT(phy))
if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
- return FALSE;
+ return 0;
if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
- return FALSE;
- return TRUE;
+ return 0;
+ return 1;
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl,
+ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
- for (i = 1; i < rate_ctrl->max_valid_rate ; i++) {
- if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = rate_ctrl->valid_rate_index[i-1];
- return TRUE;
+ for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) {
+ if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = ath_rc_priv->valid_rate_index[i-1];
+ return 1;
}
}
- return FALSE;
+
+ return 0;
}
-/*
- * Initialize the Valid Rate Index from valid entries in Rate Table
- */
-static u8
-ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u32 capflag)
+static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ u32 capflag)
{
- struct ath_tx_ratectrl *rate_ctrl;
u8 i, hi = 0;
u32 valid;
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
for (i = 0; i < rate_table->rate_cnt; i++) {
valid = (ath_rc_priv->single_stream ?
rate_table->info[i].valid_single_stream :
rate_table->info[i].valid);
- if (valid == TRUE) {
+ if (valid == 1) {
u32 phy = rate_table->info[i].phy;
u8 valid_rate_count = 0;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
- valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy];
+ valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
- rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, i, TRUE);
+ ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
hi = A_MAX(hi, i);
}
}
+
return hi;
}
-/*
- * Initialize the Valid Rate Index from Rate Set
- */
-static u8
-ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- struct ath_rateset *rateset,
- u32 capflag)
+static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ struct ath_rateset *rateset,
+ u32 capflag)
{
- /* XXX: Clean me up and make identation friendly */
u8 i, j, hi = 0;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
/* Use intersection of working rates and valid rates */
for (i = 0; i < rateset->rs_nrates; i++) {
@@ -695,196 +565,89 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
u32 valid = (ath_rc_priv->single_stream ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
+ u8 rate = rateset->rs_rates[i];
+ u8 dot11rate = rate_table->info[j].dot11rate;
/* We allow a rate only if its valid and the
* capflag matches one of the validity
- * (TRUE/TRUE_20/TRUE_40) flags */
-
- /* XXX: catch the negative of this branch
- * first and then continue */
- if (((rateset->rs_rates[i] & 0x7F) ==
- (rate_table->info[j].dot11rate & 0x7F)) &&
- ((valid & WLAN_RC_CAP_MODE(capflag)) ==
- WLAN_RC_CAP_MODE(capflag)) &&
- !WLAN_RC_PHY_HT(phy)) {
+ * (VALID/VALID_20/VALID_40) flags */
+ if (((rate & 0x7F) == (dot11rate & 0x7F)) &&
+ ((valid & WLAN_RC_CAP_MODE(capflag)) ==
+ WLAN_RC_CAP_MODE(capflag)) &&
+ !WLAN_RC_PHY_HT(phy)) {
u8 valid_rate_count = 0;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
valid_rate_count =
- rate_ctrl->valid_phy_ratecnt[phy];
+ ath_rc_priv->valid_phy_ratecnt[phy];
- rate_ctrl->valid_phy_rateidx[phy]
+ ath_rc_priv->valid_phy_rateidx[phy]
[valid_rate_count] = j;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
}
+
return hi;
}
-static u8
-ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 *mcs_set, u32 capflag)
+static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ u8 *mcs_set, u32 capflag)
{
+ struct ath_rateset *rateset = (struct ath_rateset *)mcs_set;
+
u8 i, j, hi = 0;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
/* Use intersection of working rates and valid rates */
- for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) {
+ for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
u32 valid = (ath_rc_priv->single_stream ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
+ u8 rate = rateset->rs_rates[i];
+ u8 dot11rate = rate_table->info[j].dot11rate;
- if (((((struct ath_rateset *)
- mcs_set)->rs_rates[i] & 0x7F) !=
- (rate_table->info[j].dot11rate & 0x7F)) ||
+ if (((rate & 0x7F) != (dot11rate & 0x7F)) ||
!WLAN_RC_PHY_HT(phy) ||
!WLAN_RC_PHY_HT_VALID(valid, capflag))
continue;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
- rate_ctrl->valid_phy_rateidx[phy]
- [rate_ctrl->valid_phy_ratecnt[phy]] = j;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ ath_rc_priv->valid_phy_rateidx[phy]
+ [ath_rc_priv->valid_phy_ratecnt[phy]] = j;
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
- return hi;
-}
-
-/*
- * Attach to a device instance. Setup the public definition
- * of how much per-node space we need and setup the private
- * phy tables that have rate control parameters.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah)
-{
- struct ath_rate_softc *asc;
-
- /* we are only in user context so we can sleep for memory */
- asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL);
- if (asc == NULL)
- return NULL;
-
- ar5416_attach_ratetables(asc);
-
- /* Save Maximum TX Trigger Level (used for 11n) */
- tx_triglevel_max = ah->ah_caps.tx_triglevel_max;
- /* return alias for ath_rate_softc * */
- return asc;
-}
-
-static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp,
- struct ath_rate_softc *rsc,
- gfp_t gfp)
-{
- struct ath_rate_node *anode;
-
- anode = kzalloc(sizeof(struct ath_rate_node), gfp);
- if (anode == NULL)
- return NULL;
-
- anode->avp = avp;
- anode->asc = rsc;
- avp->rc_node = anode;
-
- return anode;
-}
-
-static void ath_rate_node_free(struct ath_rate_node *anode)
-{
- if (anode != NULL)
- kfree(anode);
-}
-
-void ath_rate_detach(struct ath_rate_softc *asc)
-{
- if (asc != NULL)
- kfree(asc);
-}
-
-u8 ath_rate_findrateix(struct ath_softc *sc,
- u8 dot11rate)
-{
- const struct ath_rate_table *ratetable;
- struct ath_rate_softc *rsc = sc->sc_rc;
- int i;
-
- ratetable = rsc->hw_rate_table[sc->sc_curmode];
-
- if (WARN_ON(!ratetable))
- return 0;
-
- for (i = 0; i < ratetable->rate_cnt; i++) {
- if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f))
- return i;
- }
- return 0;
-}
-
-/*
- * Update rate-control state on a device state change. When
- * operating as a station this includes associate/reassociate
- * with an AP. Otherwise this gets called, for example, when
- * the we transition to run state when operating as an AP.
- */
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
-{
- struct ath_rate_softc *asc = sc->sc_rc;
-
- /* For half and quarter rate channles use different
- * rate tables
- */
- if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF)
- ar5416_sethalf_ratetable(asc);
- else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER)
- ar5416_setquarter_ratetable(asc);
- else /* full rate */
- ar5416_setfull_ratetable(asc);
-
- if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) {
- asc->fixedrix =
- sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff];
- /* NB: check the fixed rate exists */
- if (asc->fixedrix == 0xff)
- asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
- } else {
- asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
- }
+ return hi;
}
static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
int probe_allowed, int *is_probing,
int is_retry)
{
u32 dt, best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
int8_t rssi_last, rssi_reduce = 0, index = 0;
- struct ath_tx_ratectrl *rate_ctrl = NULL;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ?
- (ath_rc_priv) : NULL);
- *is_probing = FALSE;
+ *is_probing = 0;
- rssi_last = median(rate_ctrl->rssi_last,
- rate_ctrl->rssi_last_prev,
- rate_ctrl->rssi_last_prev2);
+ rssi_last = median(ath_rc_priv->rssi_last,
+ ath_rc_priv->rssi_last_prev,
+ ath_rc_priv->rssi_last_prev2);
/*
* Age (reduce) last ack rssi based on how old it is.
@@ -896,7 +659,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
*/
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - rate_ctrl->rssi_time;
+ dt = now_msec - ath_rc_priv->rssi_time;
if (dt >= 185)
rssi_reduce = 10;
@@ -915,7 +678,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
*/
best_thruput = 0;
- maxindex = rate_ctrl->max_valid_rate-1;
+ maxindex = ath_rc_priv->max_valid_rate-1;
minindex = 0;
best_rate = minindex;
@@ -927,8 +690,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
for (index = maxindex; index >= minindex ; index--) {
u8 per_thres;
- rate = rate_ctrl->valid_rate_index[index];
- if (rate > rate_ctrl->rate_max_phy)
+ rate = ath_rc_priv->valid_rate_index[index];
+ if (rate > ath_rc_priv->rate_max_phy)
continue;
/*
@@ -942,7 +705,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = rate_ctrl->state[rate].per;
+ per_thres = ath_rc_priv->state[rate].per;
if (per_thres < 12)
per_thres = 12;
@@ -961,41 +724,35 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* of max retries, use the min rate for the next retry
*/
if (is_retry)
- rate = rate_ctrl->valid_rate_index[minindex];
+ rate = ath_rc_priv->valid_rate_index[minindex];
- rate_ctrl->rssi_last_lookup = rssi_last;
+ ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
* non-monoticity of 11g's rate table
*/
- if (rate >= rate_ctrl->rate_max_phy && probe_allowed) {
- rate = rate_ctrl->rate_max_phy;
+ if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) {
+ 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,
- rate_ctrl, rate, &next_rate) &&
- (now_msec - rate_ctrl->probe_time >
+ ath_rc_priv, rate, &next_rate) &&
+ (now_msec - ath_rc_priv->probe_time >
rate_table->probe_interval) &&
- (rate_ctrl->hw_maxretry_pktcnt >= 1)) {
+ (ath_rc_priv->hw_maxretry_pktcnt >= 1)) {
rate = next_rate;
- rate_ctrl->probe_rate = rate;
- rate_ctrl->probe_time = now_msec;
- rate_ctrl->hw_maxretry_pktcnt = 0;
- *is_probing = TRUE;
+ ath_rc_priv->probe_rate = rate;
+ ath_rc_priv->probe_time = now_msec;
+ ath_rc_priv->hw_maxretry_pktcnt = 0;
+ *is_probing = 1;
}
}
- /*
- * Make sure rate is not higher than the allowed maximum.
- * We should also enforce the min, but I suspect the min is
- * normally 1 rather than 0 because of the rate 9 vs 6 issue
- * in the old code.
- */
- if (rate > (rate_ctrl->rate_table_size - 1))
- rate = rate_ctrl->rate_table_size - 1;
+ if (rate > (ath_rc_priv->rate_table_size - 1))
+ rate = ath_rc_priv->rate_table_size - 1;
ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
(rate_table->info[rate].valid_single_stream &&
@@ -1004,40 +761,36 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
return rate;
}
-static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table ,
- struct ath_rc_series *series,
- u8 tries,
- u8 rix,
- int rtsctsenable)
+static void ath_rc_rate_set_series(struct ath_rate_table *rate_table ,
+ struct ieee80211_tx_rate *rate,
+ u8 tries, u8 rix, int rtsctsenable)
{
- series->tries = tries;
- series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) |
- (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ?
- ATH_RC_DS_FLAG : 0) |
- (WLAN_RC_PHY_40(rate_table->info[rix].phy) ?
- ATH_RC_CW40_FLAG : 0) |
- (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ?
- ATH_RC_SGI_FLAG : 0);
-
- series->rix = rate_table->info[rix].base_index;
- series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen;
+ rate->count = tries;
+ rate->idx = rix;
+
+ if (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;
+ if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (WLAN_RC_PHY_HT(rate_table->info[rix].phy))
+ rate->flags |= IEEE80211_TX_RC_MCS;
}
static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
u8 rix, u16 stepdown,
u16 min_rate)
{
u32 j;
u8 nextindex;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
if (min_rate) {
for (j = RATE_TABLE_SIZE; j > 0; j--) {
if (ath_rc_get_nextlowervalid_txrate(rate_table,
- rate_ctrl, rix, &nextindex))
+ ath_rc_priv, rix, &nextindex))
rix = nextindex;
else
break;
@@ -1045,7 +798,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
} else {
for (j = stepdown; j > 0; j--) {
if (ath_rc_get_nextlowervalid_txrate(rate_table,
- rate_ctrl, rix, &nextindex))
+ ath_rc_priv, rix, &nextindex))
rix = nextindex;
else
break;
@@ -1055,41 +808,39 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
}
static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- int num_tries, int num_rates, unsigned int rcflag,
- struct ath_rc_series series[], int *is_probe,
+ 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)
{
u8 try_per_rate = 0, i = 0, rix, nrix;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_table *rate_table;
+ struct ieee80211_tx_rate *rates = tx_info->control.rates;
- rate_table =
- (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
- (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
+ rate_table = sc->hw_rate_table[sc->sc_curmode];
+ rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1,
is_probe, is_retry);
nrix = rix;
- if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*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,
- &series[i++], 1, nrix, FALSE);
+ &rates[i++], 1, nrix, 0);
try_per_rate = (num_tries/num_rates);
/* 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, FALSE);
+ ath_rc_priv, rate_table, nrix, 1, 0);
ath_rc_rate_set_series(rate_table,
- &series[i++], try_per_rate, nrix, 0);
+ &rates[i++], try_per_rate, nrix, 0);
} else {
try_per_rate = (num_tries/num_rates);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table,
- &series[i++], try_per_rate, nrix, FALSE);
+ &rates[i++], try_per_rate, nrix, 0);
}
/* Fill in the other rates for multirate retry */
@@ -1099,14 +850,13 @@ static void ath_rc_ratefind(struct ath_softc *sc,
try_num = ((i + 1) == num_rates) ?
num_tries - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == num_rates) &&
- (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
+ min_rate = (((i + 1) == num_rates) && 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,
- &series[i], try_num, nrix, TRUE);
+ &rates[i], try_num, nrix, 1);
}
/*
@@ -1132,107 +882,22 @@ static void ath_rc_ratefind(struct ath_softc *sc,
if (i == 4 &&
((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
(dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
- series[3].rix = series[2].rix;
- series[3].flags = series[2].flags;
- series[3].max_4ms_framelen = series[2].max_4ms_framelen;
- }
- }
-}
-
-/*
- * Return the Tx rate series.
- */
-static void ath_rate_findrate(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- int num_tries,
- int num_rates,
- unsigned int rcflag,
- struct ath_rc_series series[],
- int *is_probe,
- int is_retry)
-{
- struct ath_vap *avp = ath_rc_priv->avp;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- if (!num_rates || !num_tries)
- return;
-
- if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) {
- ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates,
- rcflag, series, is_probe, is_retry);
- } else {
- /* Fixed rate */
- int idx;
- u8 flags;
- u32 rix;
- struct ath_rate_softc *asc = ath_rc_priv->asc;
- struct ath_rate_table *rate_table;
-
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
-
- for (idx = 0; idx < 4; idx++) {
- unsigned int mcs;
- u8 series_rix = 0;
-
- series[idx].tries = IEEE80211_RATE_IDX_ENTRY(
- avp->av_config.av_fixed_retryset, idx);
-
- mcs = IEEE80211_RATE_IDX_ENTRY(
- avp->av_config.av_fixed_rateset, idx);
-
- if (idx == 3 && (mcs & 0xf0) == 0x70)
- mcs = (mcs & ~0xf0)|0x80;
-
- if (!(mcs & 0x80))
- flags = 0;
- else
- flags = ((ath_rc_priv->ht_cap &
- WLAN_RC_DS_FLAG) ?
- ATH_RC_DS_FLAG : 0) |
- ((ath_rc_priv->ht_cap &
- WLAN_RC_40_FLAG) ?
- ATH_RC_CW40_FLAG : 0) |
- ((ath_rc_priv->ht_cap &
- WLAN_RC_SGI_FLAG) ?
- ((ath_rc_priv->ht_cap &
- WLAN_RC_40_FLAG) ?
- ATH_RC_SGI_FLAG : 0) : 0);
-
- series[idx].rix = sc->sc_rixmap[mcs];
- series_rix = series[idx].rix;
-
- /* XXX: Give me some cleanup love */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[series_rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[series_rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[series_rix].cw40index;
- else
- rix = rate_table->info[series_rix].base_index;
- series[idx].max_4ms_framelen =
- rate_table->info[rix].max_4ms_framelen;
- series[idx].flags = flags;
+ rates[3].idx = rates[2].idx;
+ rates[3].flags = rates[2].flags;
}
}
}
-static void ath_rc_update_ht(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- struct ath_tx_info_priv *info_priv,
- int tx_rate, int xretries, int retries)
+static bool ath_rc_update_per(struct ath_softc *sc,
+ struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_tx_info_priv *tx_info_priv,
+ int tx_rate, int xretries, int retries,
+ u32 now_msec)
{
- struct ath_tx_ratectrl *rate_ctrl;
- u32 now_msec = jiffies_to_msecs(jiffies);
- int state_change = FALSE, rate, count;
+ bool state_change = false;
+ int count;
u8 last_per;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
- struct ath_rate_table *rate_table =
- (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
-
static u32 nretry_to_per_lookup[10] = {
100 * 0 / 1,
100 * 1 / 4,
@@ -1246,54 +911,35 @@ static void ath_rc_update_ht(struct ath_softc *sc,
100 * 9 / 10
};
- if (!ath_rc_priv)
- return;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
-
- ASSERT(tx_rate >= 0);
- if (tx_rate < 0)
- return;
-
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- info_priv->tx.ts_rssi =
- info_priv->tx.ts_rssi < 3 ? 0 :
- info_priv->tx.ts_rssi - 3;
-
- last_per = rate_ctrl->state[tx_rate].per;
+ last_per = ath_rc_priv->state[tx_rate].per;
if (xretries) {
- /* Update the PER. */
if (xretries == 1) {
- rate_ctrl->state[tx_rate].per += 30;
- if (rate_ctrl->state[tx_rate].per > 100)
- rate_ctrl->state[tx_rate].per = 100;
+ ath_rc_priv->state[tx_rate].per += 30;
+ if (ath_rc_priv->state[tx_rate].per > 100)
+ ath_rc_priv->state[tx_rate].per = 100;
} else {
/* xretries == 2 */
count = ARRAY_SIZE(nretry_to_per_lookup);
if (retries >= count)
retries = count - 1;
+
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- rate_ctrl->state[tx_rate].per =
- (u8)(rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- ((100) >> 3));
+ ath_rc_priv->state[tx_rate].per =
+ (u8)(last_per - (last_per >> 3) + (100 >> 3));
}
/* xretries == 1 or 2 */
- if (rate_ctrl->probe_rate == tx_rate)
- rate_ctrl->probe_rate = 0;
+ if (ath_rc_priv->probe_rate == tx_rate)
+ ath_rc_priv->probe_rate = 0;
- } else { /* xretries == 0 */
- /* Update the PER. */
- /* Make sure it doesn't index out of array's bounds. */
+ } else { /* xretries == 0 */
count = ARRAY_SIZE(nretry_to_per_lookup);
if (retries >= count)
retries = count - 1;
- if (info_priv->n_bad_frames) {
+
+ if (tx_info_priv->n_bad_frames) {
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
* Assuming that n_frames is not 0. The current PER
* from the retries is 100 * retries / (retries+1),
@@ -1306,37 +952,35 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* the above PER. The expression below is a
* simplified version of the sum of these two terms.
*/
- if (info_priv->n_frames > 0)
- rate_ctrl->state[tx_rate].per
- = (u8)
- (rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- ((100*(retries*info_priv->n_frames +
- info_priv->n_bad_frames) /
- (info_priv->n_frames *
- (retries+1))) >> 3));
+ if (tx_info_priv->n_frames > 0) {
+ int n_frames, n_bad_frames;
+ u8 cur_per, new_per;
+
+ n_bad_frames = retries * tx_info_priv->n_frames +
+ tx_info_priv->n_bad_frames;
+ n_frames = tx_info_priv->n_frames * (retries + 1);
+ cur_per = (100 * n_bad_frames / n_frames) >> 3;
+ new_per = (u8)(last_per - (last_per >> 3) + cur_per);
+ ath_rc_priv->state[tx_rate].per = new_per;
+ }
} else {
- /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
-
- rate_ctrl->state[tx_rate].per = (u8)
- (rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- (nretry_to_per_lookup[retries] >> 3));
+ ath_rc_priv->state[tx_rate].per =
+ (u8)(last_per - (last_per >> 3) +
+ (nretry_to_per_lookup[retries] >> 3));
}
- rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev;
- rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last;
- rate_ctrl->rssi_last = info_priv->tx.ts_rssi;
- rate_ctrl->rssi_time = now_msec;
+ ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
+ ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
+ ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
+ ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
* this was a probe. Otherwise, ignore the probe.
*/
-
- if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) {
- if (retries > 0 || 2 * info_priv->n_bad_frames >
- info_priv->n_frames) {
+ if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
+ if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
+ tx_info_priv->n_frames) {
/*
* Since we probed with just a single attempt,
* any retries means the probe failed. Also,
@@ -1344,17 +988,18 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* the subframes were bad then also consider
* the probe a failure.
*/
- rate_ctrl->probe_rate = 0;
+ ath_rc_priv->probe_rate = 0;
} else {
u8 probe_rate = 0;
- rate_ctrl->rate_max_phy = rate_ctrl->probe_rate;
- probe_rate = rate_ctrl->probe_rate;
+ ath_rc_priv->rate_max_phy =
+ ath_rc_priv->probe_rate;
+ probe_rate = ath_rc_priv->probe_rate;
- if (rate_ctrl->state[probe_rate].per > 30)
- rate_ctrl->state[probe_rate].per = 20;
+ if (ath_rc_priv->state[probe_rate].per > 30)
+ ath_rc_priv->state[probe_rate].per = 20;
- rate_ctrl->probe_rate = 0;
+ ath_rc_priv->probe_rate = 0;
/*
* Since this probe succeeded, we allow the next
@@ -1362,8 +1007,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* to move up faster if the probes are
* succesful.
*/
- rate_ctrl->probe_time = now_msec -
- rate_table->probe_interval / 2;
+ ath_rc_priv->probe_time =
+ now_msec - rate_table->probe_interval / 2;
}
}
@@ -1373,74 +1018,114 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* this was because of collisions or poor signal.
*
* Later: if rssi_ack is close to
- * rate_ctrl->state[txRate].rssi_thres and we see lots
+ * ath_rc_priv->state[txRate].rssi_thres and we see lots
* of retries, then we could increase
- * rate_ctrl->state[txRate].rssi_thres.
+ * ath_rc_priv->state[txRate].rssi_thres.
*/
- rate_ctrl->hw_maxretry_pktcnt = 0;
+ ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
+ int32_t rssi_ackAvg;
+ int8_t rssi_thres;
+ int8_t rssi_ack_vmin;
+
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
*/
- if (tx_rate == rate_ctrl->rate_max_phy &&
- rate_ctrl->hw_maxretry_pktcnt < 255) {
- rate_ctrl->hw_maxretry_pktcnt++;
+ if (tx_rate == ath_rc_priv->rate_max_phy &&
+ ath_rc_priv->hw_maxretry_pktcnt < 255) {
+ ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (info_priv->tx.ts_rssi >=
- rate_table->info[tx_rate].rssi_ack_validmin) {
- /* Average the rssi */
- if (tx_rate != rate_ctrl->rssi_sum_rate) {
- rate_ctrl->rssi_sum_rate = tx_rate;
- rate_ctrl->rssi_sum =
- rate_ctrl->rssi_sum_cnt = 0;
- }
+ if (tx_info_priv->tx.ts_rssi <
+ rate_table->info[tx_rate].rssi_ack_validmin)
+ goto exit;
- rate_ctrl->rssi_sum += info_priv->tx.ts_rssi;
- rate_ctrl->rssi_sum_cnt++;
-
- if (rate_ctrl->rssi_sum_cnt > 4) {
- int32_t rssi_ackAvg =
- (rate_ctrl->rssi_sum + 2) / 4;
- int8_t rssi_thres =
- rate_ctrl->state[tx_rate].
- rssi_thres;
- int8_t rssi_ack_vmin =
- rate_table->info[tx_rate].
- rssi_ack_validmin;
-
- rate_ctrl->rssi_sum =
- rate_ctrl->rssi_sum_cnt = 0;
-
- /* Now reduce the current
- * rssi threshold. */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- rate_ctrl->state[tx_rate].
- rssi_thres--;
- }
-
- state_change = TRUE;
- }
+ /* Average the rssi */
+ if (tx_rate != ath_rc_priv->rssi_sum_rate) {
+ ath_rc_priv->rssi_sum_rate = tx_rate;
+ ath_rc_priv->rssi_sum =
+ ath_rc_priv->rssi_sum_cnt = 0;
}
+
+ ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
+ ath_rc_priv->rssi_sum_cnt++;
+
+ if (ath_rc_priv->rssi_sum_cnt < 4)
+ goto exit;
+
+ rssi_ackAvg =
+ (ath_rc_priv->rssi_sum + 2) / 4;
+ rssi_thres =
+ ath_rc_priv->state[tx_rate].rssi_thres;
+ rssi_ack_vmin =
+ rate_table->info[tx_rate].rssi_ack_validmin;
+
+ ath_rc_priv->rssi_sum =
+ ath_rc_priv->rssi_sum_cnt = 0;
+
+ /* Now reduce the current rssi threshold */
+ if ((rssi_ackAvg < rssi_thres + 2) &&
+ (rssi_thres > rssi_ack_vmin)) {
+ ath_rc_priv->state[tx_rate].rssi_thres--;
+ }
+
+ state_change = true;
}
}
+exit:
+ return state_change;
+}
+
+/* Update PER, RSSI and whatever else that the code thinks it is doing.
+ If you can make sense of all this, you really need to go out more. */
+
+static void ath_rc_update_ht(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_tx_info_priv *tx_info_priv,
+ int tx_rate, int xretries, int retries)
+{
+#define CHK_RSSI(rate) \
+ ((ath_rc_priv->state[(rate)].rssi_thres + \
+ rate_table->info[(rate)].rssi_ack_deltamin) > \
+ ath_rc_priv->state[(rate)+1].rssi_thres)
+
+ u32 now_msec = jiffies_to_msecs(jiffies);
+ int rate;
+ u8 last_per;
+ bool state_change = false;
+ struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
+ int size = ath_rc_priv->rate_table_size;
+
+ if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
+ return;
+
+ /* To compensate for some imbalance between ctrl and ext. channel */
+
+ if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
+ tx_info_priv->tx.ts_rssi =
+ tx_info_priv->tx.ts_rssi < 3 ? 0 :
+ tx_info_priv->tx.ts_rssi - 3;
- /* For all cases */
+ last_per = ath_rc_priv->state[tx_rate].per;
+
+ /* Update PER first */
+ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
+ tx_info_priv, tx_rate, xretries,
+ retries, now_msec);
/*
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
- rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
- (u8) tx_rate, &rate_ctrl->rate_max_phy);
+ rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
+ ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
- rate_ctrl->probe_time = now_msec;
+ ath_rc_priv->probe_time = now_msec;
}
if (state_change) {
@@ -1451,20 +1136,15 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* made to keep the rssi thresholds monotonically
* increasing between the CCK and OFDM rates.)
*/
- for (rate = tx_rate; rate <
- rate_ctrl->rate_table_size - 1; rate++) {
+ for (rate = tx_rate; rate < size - 1; rate++) {
if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
+ rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin >
- rate_ctrl->state[rate+1].rssi_thres) {
- rate_ctrl->state[rate+1].rssi_thres =
- rate_ctrl->state[rate].
- rssi_thres +
- rate_table->info[rate].
- rssi_ack_deltamin;
+ if (CHK_RSSI(rate)) {
+ ath_rc_priv->state[rate+1].rssi_thres =
+ ath_rc_priv->state[rate].rssi_thres +
+ rate_table->info[rate].rssi_ack_deltamin;
}
}
@@ -1474,27 +1154,20 @@ static void ath_rc_update_ht(struct ath_softc *sc,
rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin >
- rate_ctrl->state[rate+1].rssi_thres) {
- if (rate_ctrl->state[rate+1].rssi_thres <
- rate_table->info[rate].
- rssi_ack_deltamin)
- rate_ctrl->state[rate].rssi_thres = 0;
+ if (CHK_RSSI(rate)) {
+ if (ath_rc_priv->state[rate+1].rssi_thres <
+ rate_table->info[rate].rssi_ack_deltamin)
+ ath_rc_priv->state[rate].rssi_thres = 0;
else {
- rate_ctrl->state[rate].rssi_thres =
- rate_ctrl->state[rate+1].
- rssi_thres -
- rate_table->info[rate].
- rssi_ack_deltamin;
+ ath_rc_priv->state[rate].rssi_thres =
+ ath_rc_priv->state[rate+1].rssi_thres -
+ rate_table->info[rate].rssi_ack_deltamin;
}
- if (rate_ctrl->state[rate].rssi_thres <
- rate_table->info[rate].
- rssi_ack_validmin) {
- rate_ctrl->state[rate].rssi_thres =
- rate_table->info[rate].
- rssi_ack_validmin;
+ if (ath_rc_priv->state[rate].rssi_thres <
+ rate_table->info[rate].rssi_ack_validmin) {
+ ath_rc_priv->state[rate].rssi_thres =
+ rate_table->info[rate].rssi_ack_validmin;
}
}
}
@@ -1502,74 +1175,86 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (rate_ctrl->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->state[tx_rate].per < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].per >
- rate_ctrl->state[rate+1].per) {
- rate_ctrl->state[rate].per =
- rate_ctrl->state[rate+1].per;
+ if (ath_rc_priv->state[rate].per >
+ ath_rc_priv->state[rate+1].per) {
+ ath_rc_priv->state[rate].per =
+ ath_rc_priv->state[rate+1].per;
}
}
}
/* Maintain monotonicity for rates above the current rate */
- for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) {
- if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per)
- rate_ctrl->state[rate+1].per =
- rate_ctrl->state[rate].per;
+ for (rate = tx_rate; rate < size - 1; rate++) {
+ if (ath_rc_priv->state[rate+1].per <
+ ath_rc_priv->state[rate].per)
+ ath_rc_priv->state[rate+1].per =
+ ath_rc_priv->state[rate].per;
}
/* Every so often, we reduce the thresholds and
* PER (different for CCK and OFDM). */
- if (now_msec - rate_ctrl->rssi_down_time >=
+ if (now_msec - ath_rc_priv->rssi_down_time >=
rate_table->rssi_reduce_interval) {
- for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
- if (rate_ctrl->state[rate].rssi_thres >
+ for (rate = 0; rate < size; rate++) {
+ if (ath_rc_priv->state[rate].rssi_thres >
rate_table->info[rate].rssi_ack_validmin)
- rate_ctrl->state[rate].rssi_thres -= 1;
+ ath_rc_priv->state[rate].rssi_thres -= 1;
}
- rate_ctrl->rssi_down_time = now_msec;
+ ath_rc_priv->rssi_down_time = now_msec;
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
- if (now_msec - rate_ctrl->per_down_time >=
+ if (now_msec - ath_rc_priv->per_down_time >=
rate_table->rssi_reduce_interval) {
- for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
- rate_ctrl->state[rate].per =
- 7 * rate_ctrl->state[rate].per / 8;
+ for (rate = 0; rate < size; rate++) {
+ ath_rc_priv->state[rate].per =
+ 7 * ath_rc_priv->state[rate].per / 8;
}
- rate_ctrl->per_down_time = now_msec;
+ ath_rc_priv->per_down_time = now_msec;
}
+
+#undef CHK_RSSI
}
-/*
- * This routine is called in rate control callback tx_status() to give
- * the status of previous frames.
- */
-static void ath_rc_update(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- struct ath_tx_info_priv *info_priv, int final_ts_idx,
- int xretries, int long_retry)
+static int ath_rc_get_rateindex(struct ath_rate_table *rate_table,
+ struct ieee80211_tx_rate *rate)
{
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ int rix;
+
+ if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (rate->flags & IEEE80211_TX_RC_SHORT_GI))
+ rix = rate_table->info[rate->idx].ht_index;
+ else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ rix = rate_table->info[rate->idx].sgi_index;
+ else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rix = rate_table->info[rate->idx].cw40index;
+ else
+ rix = rate_table->info[rate->idx].base_index;
+
+ return rix;
+}
+
+static void ath_rc_tx_status(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ieee80211_tx_info *tx_info,
+ int final_ts_idx, int xretries, int long_retry)
+{
+ struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
struct ath_rate_table *rate_table;
- struct ath_tx_ratectrl *rate_ctrl;
- struct ath_rc_series rcs[4];
+ struct ieee80211_tx_rate *rates = tx_info->status.rates;
u8 flags;
- u32 series = 0, rix;
+ u32 i = 0, rix;
- memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0]));
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
- ASSERT(rcs[0].tries != 0);
+ rate_table = sc->hw_rate_table[sc->sc_curmode];
/*
* If the first rate is not the final index, there
@@ -1577,32 +1262,22 @@ static void ath_rc_update(struct ath_softc *sc,
*/
if (final_ts_idx != 0) {
/* Process intermediate rates that failed.*/
- for (series = 0; series < final_ts_idx ; series++) {
- if (rcs[series].tries != 0) {
- flags = rcs[series].flags;
+ for (i = 0; i < final_ts_idx ; i++) {
+ if (rates[i].count != 0 && (rates[i].idx >= 0)) {
+ flags = rates[i].flags;
+
/* If HT40 and we have switched mode from
* 40 to 20 => don't update */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (rate_ctrl->rc_phy_mode !=
- (flags & ATH_RC_CW40_FLAG)))
+
+ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG))
return;
- if ((flags & ATH_RC_CW40_FLAG) &&
- (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[
- rcs[series].rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[
- rcs[series].rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[
- rcs[series].rix].cw40index;
- else
- rix = rate_table->info[
- rcs[series].rix].base_index;
+
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
ath_rc_update_ht(sc, ath_rc_priv,
- info_priv, rix,
+ tx_info_priv, rix,
xretries ? 1 : 2,
- rcs[series].tries);
+ rates[i].count);
}
}
} else {
@@ -1612,240 +1287,110 @@ static void ath_rc_update(struct ath_softc *sc,
* Treating it as an excessive retry penalizes the rate
* inordinately.
*/
- if (rcs[0].tries == 1 && xretries == 1)
+ if (rates[0].count == 1 && xretries == 1)
xretries = 2;
}
- flags = rcs[series].flags;
- /* If HT40 and we have switched mode from 40 to 20 => don't update */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG)))
- return;
-
- if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[rcs[series].rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[rcs[series].rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[rcs[series].rix].cw40index;
- else
- rix = rate_table->info[rcs[series].rix].base_index;
-
- ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix,
- xretries, long_retry);
-}
-
-/*
- * Process a tx descriptor for a completed transmit (success or failure).
- */
-static void ath_rate_tx_complete(struct ath_softc *sc,
- struct ath_node *an,
- struct ath_rate_node *rc_priv,
- struct ath_tx_info_priv *info_priv)
-{
- int final_ts_idx = info_priv->tx.ts_rateindex;
- int tx_status = 0, is_underrun = 0;
- struct ath_vap *avp;
+ flags = rates[i].flags;
- avp = rc_priv->avp;
- if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) ||
- (info_priv->tx.ts_status & ATH9K_TXERR_FILT))
+ /* If HT40 and we have switched mode from 40 to 20 => don't update */
+ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) {
return;
-
- if (info_priv->tx.ts_rssi > 0) {
- ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
- info_priv->tx.ts_rssi);
}
- /*
- * If underrun error is seen assume it as an excessive retry only
- * if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
- * times. This affects how ratectrl updates PER for the failed rate.
- */
- if (info_priv->tx.ts_flags &
- (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
- ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) {
- tx_status = 1;
- is_underrun = 1;
- }
-
- if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
- (info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
- tx_status = 1;
-
- ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
- info_priv->tx.ts_longretry);
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+ ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
+ xretries, long_retry);
}
-/*
- * Update the SIB's rate control information
- *
- * This should be called when the supported rates change
- * (e.g. SME operation, wireless mode change)
- *
- * It will determine which rates are valid for use.
- */
-static void ath_rc_sib_update(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- u32 capflag, int keep_state,
- struct ath_rateset *negotiated_rates,
- struct ath_rateset *negotiated_htrates)
+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 ath_rate_table *rate_table = NULL;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
- struct ath_rateset *rateset = negotiated_rates;
- u8 *ht_mcs = (u8 *)negotiated_htrates;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)ath_rc_priv;
+ 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;
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
+ rate_table = sc->hw_rate_table[sc->sc_curmode];
+
+ if (sta->ht_cap.ht_supported) {
+ if (sband->band == IEEE80211_BAND_2GHZ)
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
+ else
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
+
+ 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 */
- rate_ctrl->rate_table_size = MAX_TX_RATE_TBL;
+ ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
/* Initialize thresholds according to the global rate table */
- for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) {
- rate_ctrl->state[i].rssi_thres =
+ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
+ ath_rc_priv->state[i].rssi_thres =
rate_table->info[i].rssi_ack_validmin;
- rate_ctrl->state[i].per = 0;
+ ath_rc_priv->state[i].per = 0;
}
/* Determine the valid rates */
- ath_rc_init_valid_txmask(rate_ctrl);
+ ath_rc_init_valid_txmask(ath_rc_priv);
for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < MAX_TX_RATE_PHY; j++)
- rate_ctrl->valid_phy_rateidx[i][j] = 0;
- rate_ctrl->valid_phy_ratecnt[i] = 0;
+ ath_rc_priv->valid_phy_rateidx[i][j] = 0;
+ ath_rc_priv->valid_phy_ratecnt[i] = 0;
}
- rate_ctrl->rc_phy_mode = (capflag & 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 = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
+ ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
if (!rateset->rs_nrates) {
/* No working rate, just initialize valid rates */
- hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table,
- capflag);
+ hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
+ ath_rc_priv->ht_cap);
} else {
/* Use intersection of working rates and valid rates */
- hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table,
- rateset, capflag);
- if (capflag & WLAN_RC_HT_FLAG) {
- hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv,
+ hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
+ 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,
- capflag);
+ ath_rc_priv->ht_cap);
}
hi = A_MAX(hi, hthi);
}
- rate_ctrl->rate_table_size = hi + 1;
- rate_ctrl->rate_max_phy = 0;
- ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
+ ath_rc_priv->rate_table_size = hi + 1;
+ ath_rc_priv->rate_max_phy = 0;
+ ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
- for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) {
- rate_ctrl->valid_rate_index[k++] =
- rate_ctrl->valid_phy_rateidx[i][j];
+ for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
+ ath_rc_priv->valid_rate_index[k++] =
+ ath_rc_priv->valid_phy_rateidx[i][j];
}
- if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE)
- || !rate_ctrl->valid_phy_ratecnt[i])
+ if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1)
+ || !ath_rc_priv->valid_phy_ratecnt[i])
continue;
- rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1];
- }
- ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
- ASSERT(k <= MAX_TX_RATE_TBL);
-
- rate_ctrl->max_valid_rate = k;
- /*
- * Some third party vendors don't send the supported rate series in
- * order. So sorting to make sure its in order, otherwise our RateFind
- * Algo will select wrong rates
- */
- ath_rc_sort_validrates(rate_table, rate_ctrl);
- rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4];
-}
-
-/*
- * Update rate-control state on station associate/reassociate.
- */
-static int ath_rate_newassoc(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- unsigned int capflag,
- struct ath_rateset *negotiated_rates,
- struct ath_rateset *negotiated_htrates)
-{
-
-
- ath_rc_priv->ht_cap =
- ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
- ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) |
- ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) |
- ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0);
-
- ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0,
- negotiated_rates, negotiated_htrates);
-
- return 0;
-}
-
-/*
- * This routine is called to initialize the rate control parameters
- * in the SIB. It is called initially during system initialization
- * or when a station is associated with the AP.
- */
-static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
-{
- struct ath_tx_ratectrl *rate_ctrl;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
- rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies);
-}
-
-
-static void ath_setup_rates(struct ath_softc *sc,
- struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta,
- struct ath_rate_node *rc_priv)
-
-{
- int i, j = 0;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sta->supp_rates[sband->band] & BIT(i)) {
- rc_priv->neg_rates.rs_rates[j]
- = (sband->bitrates[i].bitrate * 2) / 10;
- j++;
- }
- }
- rc_priv->neg_rates.rs_nrates = j;
-}
-
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
-{
- struct ath_softc *sc = hw->priv;
- u32 capflag = 0;
-
- if (hw->conf.ht.enabled) {
- capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
- if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
- capflag |= ATH_RC_CW40_FLAG;
+ ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
}
+ ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
+ ASSERT(k <= RATE_TABLE_SIZE);
- ath_rate_newassoc(sc, rc_priv, capflag,
- &rc_priv->neg_rates,
- &rc_priv->neg_ht_rates);
-
+ ath_rc_priv->max_valid_rate = k;
+ ath_rc_sort_validrates(rate_table, ath_rc_priv);
+ ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
}
/* Rate Control callbacks */
@@ -1854,27 +1399,48 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct sk_buff *skb)
{
struct ath_softc *sc = priv;
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_node *an;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
+ struct ath_tx_info_priv *tx_info_priv = NULL;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
+ int final_ts_idx, tx_status = 0, is_underrun = 0;
__le16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
- /* XXX: UGLY HACK!! */
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+ tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ final_ts_idx = tx_info_priv->tx.ts_rateindex;
- an = (struct ath_node *)sta->drv_priv;
+ if (!priv_sta || !ieee80211_is_data(fc) ||
+ !tx_info_priv->update_rc)
+ goto exit;
- if (tx_info_priv == NULL)
- return;
+ if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+ goto exit;
- if (an && priv_sta && ieee80211_is_data(fc))
- ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
+ /*
+ * If underrun error is seen assume it as an excessive retry only
+ * if prefetch trigger level have reached the max (0x3f for 5416)
+ * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * times. This affects how ratectrl updates PER for the failed rate.
+ */
+ 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)) {
+ tx_status = 1;
+ is_underrun = 1;
+ }
+
+ if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
+ (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
+ tx_status = 1;
+ ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
+ (is_underrun) ? ATH_11N_TXMAXTRY :
+ tx_info_priv->tx.ts_longretry);
+
+exit:
kfree(tx_info_priv);
- tx_info->control.vif = NULL;
}
static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
@@ -1885,55 +1451,29 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_softc *sc = priv;
struct ieee80211_hw *hw = sc->hw;
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_rate_node *ath_rc_priv = priv_sta;
- struct ath_node *an;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- int is_probe = FALSE;
- s8 lowest_idx;
+ int is_probe = 0;
__le16 fc = hdr->frame_control;
- u8 *qc, tid;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
- /* allocate driver private area of tx_info, XXX: UGLY HACK! */
- tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
- ASSERT(tx_info_priv != NULL);
-
- lowest_idx = rate_lowest_index(sband, sta);
- tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
/* lowest rate for management and multicast/broadcast frames */
- if (!ieee80211_is_data(fc) ||
- is_multicast_ether_addr(hdr->addr1) || !sta) {
- tx_info->control.rates[0].idx = lowest_idx;
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+ tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
+ tx_info->control.rates[0].count =
+ is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;
return;
}
/* Find tx rate for unicast frames */
- ath_rate_findrate(sc, ath_rc_priv,
- ATH_11N_TXMAXTRY, 4,
- ATH_RC_PROBE_ALLOWED,
- tx_info_priv->rcs,
- &is_probe,
- false);
-#if 0
- if (is_probe)
- sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
-#endif
-
- /* Ratecontrol sometimes returns invalid rate index */
- if (tx_info_priv->rcs[0].rix != 0xff)
- ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix;
- else
- tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
-
- tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix;
+ 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;
@@ -1948,14 +1488,20 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct ath_softc *sc = priv;
- struct ath_rate_node *ath_rc_priv = priv_sta;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
int i, j = 0;
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sta->supp_rates[sband->band] & BIT(i)) {
+ ath_rc_priv->neg_rates.rs_rates[j]
+ = (sband->bitrates[i].bitrate * 2) / 10;
+ j++;
+ }
+ }
+ ath_rc_priv->neg_rates.rs_nrates = j;
- ath_setup_rates(sc, sband, sta, ath_rc_priv);
if (sta->ht_cap.ht_supported) {
- for (i = 0; i < 77; i++) {
+ for (i = 0, j = 0; i < 77; i++) {
if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
if (j == ATH_RATE_MAX)
@@ -1963,14 +1509,12 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
}
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
- ath_rc_node_update(sc->hw, priv_sta);
+
+ ath_rc_init(sc, priv_sta, sband, sta);
}
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
- struct ath_softc *sc = hw->priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
return hw->priv;
}
@@ -1981,26 +1525,19 @@ static void ath_rate_free(void *priv)
static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
- struct ieee80211_vif *vif;
struct ath_softc *sc = priv;
- struct ath_vap *avp;
- struct ath_rate_node *rate_priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- vif = sc->sc_vaps[0];
- ASSERT(vif);
-
- avp = (void *)vif->drv_priv;
+ struct ath_rate_priv *rate_priv;
- rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
+ rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
if (!rate_priv) {
DPRINTF(sc, ATH_DBG_FATAL,
"%s: Unable to allocate private rc structure\n",
__func__);
return NULL;
}
- ath_rc_sib_init(rate_priv);
+
+ rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
+ rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
return rate_priv;
}
@@ -2008,11 +1545,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{
- struct ath_rate_node *rate_priv = priv_sta;
- struct ath_softc *sc = priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
- ath_rate_node_free(rate_priv);
+ struct ath_rate_priv *rate_priv = priv_sta;
+ kfree(rate_priv);
}
static struct rate_control_ops ath_rate_ops = {
@@ -2027,6 +1561,63 @@ static struct rate_control_ops ath_rate_ops = {
.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] =
+ &ar5416_11b_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11A] =
+ &ar5416_11a_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11G] =
+ &ar5416_11g_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT20] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT20] =
+ &ar5416_11ng_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
+ &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)
{
return ieee80211_rate_control_register(&ath_rate_ops);
@@ -2036,4 +1627,3 @@ void ath_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&ath_rate_ops);
}
-
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index 6671097fad72..97c60d12e8aa 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -20,83 +20,24 @@
#define RC_H
#include "ath9k.h"
-/*
- * Interface definitions for transmit rate control modules for the
- * Atheros driver.
- *
- * A rate control module is responsible for choosing the transmit rate
- * for each data frame. Management+control frames are always sent at
- * a fixed rate.
- *
- * Only one module may be present at a time; the driver references
- * rate control interfaces by symbol name. If multiple modules are
- * to be supported we'll need to switch to a registration-based scheme
- * as is currently done, for example, for authentication modules.
- *
- * An instance of the rate control module is attached to each device
- * at attach time and detached when the device is destroyed. The module
- * may associate data with each device and each node (station). Both
- * sets of storage are opaque except for the size of the per-node storage
- * which must be provided when the module is attached.
- *
- * The rate control module is notified for each state transition and
- * station association/reassociation. Otherwise it is queried for a
- * rate for each outgoing frame and provided status from each transmitted
- * frame. Any ancillary processing is the responsibility of the module
- * (e.g. if periodic processing is required then the module should setup
- * it's own timer).
- *
- * In addition to the transmit rate for each frame the module must also
- * indicate the number of attempts to make at the specified rate. If this
- * number is != ATH_TXMAXTRY then an additional callback is made to setup
- * additional transmit state. The rate control code is assumed to write
- * this additional data directly to the transmit descriptor.
- */
struct ath_softc;
-#define TRUE 1
-#define FALSE 0
+#define ATH_RATE_MAX 30
+#define RATE_TABLE_SIZE 64
+#define MAX_TX_RATE_PHY 48
-#define ATH_RATE_MAX 30
+/* VALID_ALL - valid for 20/40/Legacy,
+ * VALID - Legacy only,
+ * VALID_20 - HT 20 only,
+ * VALID_40 - HT 40 only */
-enum ieee80211_fixed_rate_mode {
- IEEE80211_FIXED_RATE_NONE = 0,
- IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */
-};
-
-/*
- * Use the hal os glue code to get ms time
- */
-#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
-
-#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS
-#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS
-#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI
-#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS
-#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI
-#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS
-#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI
-
-#define WLAN_PHY_OFDM PHY_OFDM
-#define WLAN_PHY_CCK PHY_CCK
-
-#define TRUE_20 0x2
-#define TRUE_40 0x4
-#define TRUE_2040 (TRUE_20|TRUE_40)
-#define TRUE_ALL (TRUE_2040|TRUE)
-
-enum {
- WLAN_RC_PHY_HT_20_SS = 4,
- 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 INVALID 0x0
+#define VALID 0x1
+#define VALID_20 0x2
+#define VALID_40 0x4
+#define VALID_2040 (VALID_20|VALID_40)
+#define VALID_ALL (VALID_2040|VALID)
#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
@@ -113,26 +54,22 @@ enum {
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
-/* Returns the capflag mode */
#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
- (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
+ (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
/* Return TRUE if flag supports HT20 && client supports HT20 or
* return TRUE if flag supports HT40 && client supports HT40.
* This is used becos some rates overlap between HT20/HT40.
*/
-
-#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
- & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
- (capflag & WLAN_RC_40_FLAG)))
+#define WLAN_RC_PHY_HT_VALID(flag, capflag) \
+ (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+ ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
#define WLAN_RC_DS_FLAG (0x01)
#define WLAN_RC_40_FLAG (0x02)
#define WLAN_RC_SGI_FLAG (0x04)
#define WLAN_RC_HT_FLAG (0x08)
-#define RATE_TABLE_SIZE 64
-
/**
* struct ath_rate_table - Rate Control table
* @valid: valid for use in rate control
@@ -149,10 +86,11 @@ enum {
* @max_4ms_framelen: maximum frame length(bytes) for tx duration
* @probe_interval: interval for rate control to probe for other rates
* @rssi_reduce_interval: interval for rate control to reduce rssi
- * @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
+ * @initial_ratemax: initial ratemax value
*/
struct ath_rate_table {
int rate_cnt;
+ u8 rateCodeToIndex[256];
struct {
int valid;
int valid_single_stream;
@@ -170,42 +108,26 @@ 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;
u8 initial_ratemax;
};
-#define ATH_RC_PROBE_ALLOWED 0x00000001
-#define ATH_RC_MINRATE_LASTRATE 0x00000002
-
-struct ath_rc_series {
- u8 rix;
- u8 tries;
- u8 flags;
- u32 max_4ms_framelen;
-};
-
-/* rcs_flags definition */
-#define ATH_RC_DS_FLAG 0x01
-#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */
-#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */
-#define ATH_RC_HT_FLAG 0x08 /* HT */
-#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */
-
-/*
- * State structures for new rate adaptation code
- */
-#define MAX_TX_RATE_TBL 64
-#define MAX_TX_RATE_PHY 48
-
struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
};
+struct ath_rateset {
+ u8 rs_nrates;
+ u8 rs_rates[ATH_RATE_MAX];
+};
+
/**
- * struct ath_tx_ratectrl - TX Rate control Information
+ * struct ath_rate_priv - Rate Control priv data
* @state: RC state
* @rssi_last: last ACK rssi
* @rssi_last_lookup: last ACK rssi used for lookup
@@ -224,9 +146,13 @@ struct ath_tx_ratectrl_state {
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
* @probe_interval: interval for ratectrl to probe for other rates
+ * @prev_data_rix: rate idx of last data frame
+ * @ht_cap: HT capabilities
+ * @single_stream: When TRUE, only single TX stream possible
+ * @neg_rates: Negotatied rates
+ * @neg_ht_rates: Negotiated HT rates
*/
-struct ath_tx_ratectrl {
- struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
+struct ath_rate_priv {
int8_t rssi_last;
int8_t rssi_last_lookup;
int8_t rssi_last_prev;
@@ -236,89 +162,40 @@ struct ath_tx_ratectrl {
int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
- u32 rssi_time;
- u32 rssi_down_time;
- u32 probe_time;
u8 hw_maxretry_pktcnt;
u8 max_valid_rate;
- u8 valid_rate_index[MAX_TX_RATE_TBL];
- u32 per_down_time;
-
- /* 11n state */
+ u8 valid_rate_index[RATE_TABLE_SIZE];
+ u8 ht_cap;
+ u8 single_stream;
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
- u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
+ u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rc_phy_mode;
u8 rate_max_phy;
+ u32 rssi_time;
+ u32 rssi_down_time;
+ u32 probe_time;
+ u32 per_down_time;
u32 probe_interval;
-};
-
-struct ath_rateset {
- u8 rs_nrates;
- u8 rs_rates[ATH_RATE_MAX];
-};
-
-/* per-device state */
-struct ath_rate_softc {
- /* phy tables that contain rate control data */
- const void *hw_rate_table[ATH9K_MODE_MAX];
-
- /* -1 or index of fixed rate */
- int fixedrix;
-};
-
-/* per-node state */
-struct ath_rate_node {
- struct ath_tx_ratectrl tx_ratectrl;
-
- /* rate idx of last data frame */
u32 prev_data_rix;
-
- /* ht capabilities */
- u8 ht_cap;
-
- /* When TRUE, only single stream Tx possible */
- u8 single_stream;
-
- /* Negotiated rates */
+ u32 tx_triglevel_max;
+ struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
-
- /* Negotiated HT rates */
struct ath_rateset neg_ht_rates;
-
struct ath_rate_softc *asc;
- struct ath_vap *avp;
};
-/* Driver data of ieee80211_tx_info */
struct ath_tx_info_priv {
- struct ath_rc_series rcs[4];
struct ath_tx_status tx;
int n_frames;
int n_bad_frames;
- u8 min_rate;
+ bool update_rc;
};
-/*
- * Attach/detach a rate control module.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
-void ath_rate_detach(struct ath_rate_softc *asc);
-
-/*
- * Update/reset rate control state for 802.11 state transitions.
- * Important mostly as the analog to ath_rate_newassoc when operating
- * in station mode.
- */
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
-
-/*
- * Return rate index for given Dot11 Rate.
- */
-u8 ath_rate_findrateix(struct ath_softc *sc,
- u8 dot11_rate);
+#define ATH_TX_INFO_PRIV(tx_info) \
+ ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
-/* Routines to register/unregister rate control algorithm */
+void ath_rate_attach(struct ath_softc *sc);
+u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 2d72ac19fada..743ad228b833 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Implementation of receive path.
- */
-
#include "core.h"
/*
@@ -27,10 +23,7 @@
* MAC acknowledges BA status as long as it copies frames to host
* buffer (or rx fifo). This can incorrectly acknowledge packets
* to a sender if last desc is self-linked.
- *
- * NOTE: Caller should hold the rxbuf lock.
*/
-
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
@@ -40,19 +33,17 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
ATH_RXBUF_RESET(bf);
ds = bf->bf_desc;
- ds->ds_link = 0; /* link to null */
+ ds->ds_link = 0; /* link to null */
ds->ds_data = bf->bf_buf_addr;
- /* XXX For RADAR?
- * virtual addr of the beginning of the buffer. */
+ /* virtual addr of the beginning of the buffer. */
skb = bf->bf_mpdu;
ASSERT(skb != NULL);
ds->ds_vdata = skb->data;
/* setup rx descriptors */
- ath9k_hw_setuprxdesc(ah,
- ds,
- skb_tailroom(skb), /* buffer size */
+ ath9k_hw_setuprxdesc(ah, ds,
+ skb_tailroom(skb), /* buffer size */
0);
if (sc->sc_rxlink == NULL)
@@ -64,8 +55,29 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
ath9k_hw_rxena(ah);
}
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
- u32 len)
+static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
+{
+ /* XXX block beacon interrupts */
+ ath9k_hw_setantenna(sc->sc_ah, antenna);
+ sc->sc_defant = antenna;
+ sc->sc_rxotherant = 0;
+}
+
+/*
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the current h/w TSF.
+*/
+static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
+{
+ u64 tsf;
+
+ tsf = ath9k_hw_gettsf64(sc->sc_ah);
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+ return (tsf & ~0x7fff) | rstamp;
+}
+
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
{
struct sk_buff *skb;
u32 off;
@@ -91,59 +103,133 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
return skb;
}
-static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb)
+static int ath_rate2idx(struct ath_softc *sc, int rate)
{
- struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
+ int i = 0, cur_band, n_rates;
+ struct ieee80211_hw *hw = sc->hw;
- ASSERT(bf != NULL);
+ cur_band = hw->conf.channel->band;
+ n_rates = sc->sbands[cur_band].n_bitrates;
- spin_lock_bh(&sc->sc_rxbuflock);
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
- /*
- * This buffer is still held for hw acess.
- * Mark it as free to be re-queued it later.
- */
- bf->bf_status |= ATH_BUFSTATUS_FREE;
- } else {
- /* XXX: we probably never enter here, remove after
- * verification */
- list_add_tail(&bf->list, &sc->sc_rxbuf);
- ath_rx_buf_link(sc, bf);
+ for (i = 0; i < n_rates; i++) {
+ if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
+ break;
}
- spin_unlock_bh(&sc->sc_rxbuflock);
+
+ /*
+ * NB:mac80211 validates rx rate index against the supported legacy rate
+ * index only (should be done against ht rates also), return the highest
+ * legacy rate index for rx rate which does not match any one of the
+ * supported basic and extended rates to make mac80211 happy.
+ * The following hack will be cleaned up once the issue with
+ * the rx rate index validation in mac80211 is fixed.
+ */
+ if (i == n_rates)
+ return n_rates - 1;
+
+ return i;
}
/*
- * The skb indicated to upper stack won't be returned to us.
- * So we have to allocate a new one and queue it by ourselves.
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
*/
-static int ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix)
+static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
+ struct ieee80211_rx_status *rx_status, bool *decrypt_error,
+ struct ath_softc *sc)
{
- struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
- struct sk_buff *nskb;
- int type;
-
- /* indicate frame to the stack, which will free the old skb. */
- type = _ath_rx_indicate(sc, skb, status, keyix);
-
- /* allocate a new skb and queue it to for H/W processing */
- nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
- if (nskb != NULL) {
- bf->bf_mpdu = nskb;
- bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
- skb_end_pointer(nskb) - nskb->head,
- PCI_DMA_FROMDEVICE);
- bf->bf_dmacontext = bf->bf_buf_addr;
- ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
+ struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
+ struct ieee80211_hdr *hdr;
+ int ratekbps, rix;
+ u8 ratecode;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
- /* queue the new wbuf to H/W */
- ath_rx_requeue(sc, nskb);
+ if (ds->ds_rxstat.rs_more) {
+ /*
+ * Frame spans multiple descriptors; this cannot happen yet
+ * as we don't support jumbograms. If not in monitor mode,
+ * discard the frame. Enable this if you want to see
+ * error frames in Monitor mode.
+ */
+ if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
+ goto rx_next;
+ } else if (ds->ds_rxstat.rs_status != 0) {
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
+ goto rx_next;
+
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+ *decrypt_error = true;
+ } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
+ else
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ goto rx_next;
+ } else {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ goto rx_next;
+ }
+ }
}
- return type;
+ ratecode = ds->ds_rxstat.rs_rate;
+ rix = rate_table->rateCodeToIndex[ratecode];
+ ratekbps = rate_table->info[rix].ratekbps;
+
+ /* HT rate */
+ if (ratecode & 0x80) {
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
+ ratekbps = (ratekbps * 27) / 13;
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+ ratekbps = (ratekbps * 10) / 9;
+ }
+
+ 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->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100));
+ rx_status->antenna = ds->ds_rxstat.rs_antenna;
+
+ /* at 45 you will be able to use MCS 15 reliably. A more elaborate
+ * scheme can be used here but it requires tables of SNR/throughput for
+ * each possible mode used. */
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+
+ /* rssi can be more than 45 though, anything above that
+ * should be considered at 100% */
+ if (rx_status->qual > 100)
+ rx_status->qual = 100;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ return 1;
+rx_next:
+ return 0;
}
static void ath_opmode_init(struct ath_softc *sc)
@@ -185,12 +271,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->sc_rxbuflock);
- /*
- * Cisco's VPN software requires that drivers be able to
- * receive encapsulated frames that are larger than the MTU.
- * Since we can't be sure how large a frame we'll get, setup
- * to handle the larges on possible.
- */
sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(sc->sc_cachelsz,
(u16)64));
@@ -209,8 +289,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
break;
}
- /* Pre-allocate a wbuf for each rx buffer */
-
list_for_each_entry(bf, &sc->sc_rxbuf, list) {
skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
if (skb == NULL) {
@@ -223,7 +301,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
skb_end_pointer(skb) - skb->head,
PCI_DMA_FROMDEVICE);
bf->bf_dmacontext = bf->bf_buf_addr;
- ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
}
sc->sc_rxlink = NULL;
@@ -235,8 +312,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
return error;
}
-/* Reclaim all rx queue resources */
-
void ath_rx_cleanup(struct ath_softc *sc)
{
struct sk_buff *skb;
@@ -248,8 +323,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
dev_kfree_skb(skb);
}
- /* cleanup rx descriptors */
-
if (sc->sc_rxdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
}
@@ -297,20 +370,19 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
}
if (sc->sc_ah->ah_opmode == ATH9K_M_STA ||
- sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
+ sc->sc_ah->ah_opmode == ATH9K_M_IBSS)
rfilt |= ATH9K_RX_FILTER_BEACON;
/* If in HOSTAP mode, want to enable reception of PSPOLL frames
& beacon frames */
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+
return rfilt;
#undef RX_FILTER_PRESERVE
}
-/* Enable the receive h/w following a reset. */
-
int ath_startrecv(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
@@ -322,21 +394,6 @@ int ath_startrecv(struct ath_softc *sc)
sc->sc_rxlink = NULL;
list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) {
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
- /* restarting h/w, no need for holding descriptors */
- bf->bf_status &= ~ATH_BUFSTATUS_STALE;
- /*
- * Upper layer may not be done with the frame yet so
- * we can't just re-queue it to hardware. Remove it
- * from h/w queue. It'll be re-queued when upper layer
- * returns the frame and ath_rx_requeue_mpdu is called.
- */
- if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) {
- list_del(&bf->list);
- continue;
- }
- }
- /* chain descriptors */
ath_rx_buf_link(sc, bf);
}
@@ -346,120 +403,69 @@ int ath_startrecv(struct ath_softc *sc)
bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
ath9k_hw_putrxbuf(ah, bf->bf_daddr);
- ath9k_hw_rxena(ah); /* enable recv descriptors */
+ ath9k_hw_rxena(ah);
start_recv:
spin_unlock_bh(&sc->sc_rxbuflock);
- ath_opmode_init(sc); /* set filters, etc. */
- ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */
+ ath_opmode_init(sc);
+ ath9k_hw_startpcureceive(ah);
+
return 0;
}
-/* Disable the receive h/w in preparation for a reset. */
-
bool ath_stoprecv(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
- u64 tsf;
bool stopped;
- ath9k_hw_stoppcurecv(ah); /* disable PCU */
- ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */
- stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */
- mdelay(3); /* 3ms is long enough for 1 frame */
- tsf = ath9k_hw_gettsf64(ah);
- sc->sc_rxlink = NULL; /* just in case */
+ ath9k_hw_stoppcurecv(ah);
+ ath9k_hw_setrxfilter(ah, 0);
+ stopped = ath9k_hw_stopdmarecv(ah);
+ mdelay(3); /* 3ms is long enough for 1 frame */
+ sc->sc_rxlink = NULL;
+
return stopped;
}
-/* Flush receive queue */
-
void ath_flushrecv(struct ath_softc *sc)
{
- /*
- * ath_rx_tasklet may be used to handle rx interrupt and flush receive
- * queue at the same time. Use a lock to serialize the access of rx
- * queue.
- * ath_rx_tasklet cannot hold the spinlock while indicating packets.
- * Instead, do not claim the spinlock but check for a flush in
- * progress (see references to sc_rxflush)
- */
spin_lock_bh(&sc->sc_rxflushlock);
sc->sc_flags |= SC_OP_RXFLUSH;
-
ath_rx_tasklet(sc, 1);
-
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_unlock_bh(&sc->sc_rxflushlock);
}
-/* Process receive queue, as well as LED, etc. */
-
int ath_rx_tasklet(struct ath_softc *sc, int flush)
{
#define PA2DESC(_sc, _pa) \
((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
- struct ath_buf *bf, *bf_held = NULL;
+ struct ath_buf *bf;
struct ath_desc *ds;
- struct ieee80211_hdr *hdr;
- struct sk_buff *skb = NULL;
- struct ath_recv_status rx_status;
+ struct sk_buff *skb = NULL, *requeue_skb;
+ struct ieee80211_rx_status rx_status;
struct ath_hal *ah = sc->sc_ah;
- int type, rx_processed = 0;
- u32 phyerr;
- u8 chainreset = 0;
- int retval;
- __le16 fc;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padsize, retval;
+ bool decrypt_error = false;
+ u8 keyix;
+
+ spin_lock_bh(&sc->sc_rxbuflock);
do {
/* If handling rx interrupt and flush is in progress => exit */
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
break;
- spin_lock_bh(&sc->sc_rxbuflock);
if (list_empty(&sc->sc_rxbuf)) {
sc->sc_rxlink = NULL;
- spin_unlock_bh(&sc->sc_rxbuflock);
break;
}
bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
-
- /*
- * There is a race condition that BH gets scheduled after sw
- * writes RxE 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 (bf->bf_status & ATH_BUFSTATUS_STALE) {
- bf_held = bf;
- if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) {
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to
- * remove the last holding descriptor
- * in BH context.
- */
- list_del(&bf_held->list);
- bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
- sc->sc_rxlink = NULL;
-
- if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
- list_add_tail(&bf_held->list,
- &sc->sc_rxbuf);
- ath_rx_buf_link(sc, bf_held);
- }
- spin_unlock_bh(&sc->sc_rxbuflock);
- break;
- }
- bf = list_entry(bf->list.next, struct ath_buf, list);
- }
-
ds = bf->bf_desc;
- ++rx_processed;
/*
* Must provide the virtual address of the current
@@ -472,8 +478,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* on. All this is necessary because of our use of
* a self-linked list to avoid rx overruns.
*/
- retval = ath9k_hw_rxprocdesc(ah,
- ds,
+ retval = ath9k_hw_rxprocdesc(ah, ds,
bf->bf_daddr,
PA2DESC(sc, ds->ds_link),
0);
@@ -482,7 +487,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ath_desc *tds;
if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
- spin_unlock_bh(&sc->sc_rxbuflock);
+ sc->sc_rxlink = NULL;
break;
}
@@ -500,215 +505,87 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/
tds = tbf->bf_desc;
- retval = ath9k_hw_rxprocdesc(ah,
- tds, tbf->bf_daddr,
- PA2DESC(sc, tds->ds_link), 0);
+ retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
+ PA2DESC(sc, tds->ds_link), 0);
if (retval == -EINPROGRESS) {
- spin_unlock_bh(&sc->sc_rxbuflock);
break;
}
}
- /* XXX: we do not support frames spanning
- * multiple descriptors */
- bf->bf_status |= ATH_BUFSTATUS_DONE;
-
skb = bf->bf_mpdu;
- if (skb == NULL) { /* XXX ??? can this happen */
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (!skb)
continue;
- }
- /*
- * Now we know it's a completed frame, we can indicate the
- * frame. Remove the previous holding descriptor and leave
- * this one in the queue as the new holding descriptor.
- */
- if (bf_held) {
- list_del(&bf_held->list);
- bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
- if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
- list_add_tail(&bf_held->list, &sc->sc_rxbuf);
- /* try to requeue this descriptor */
- ath_rx_buf_link(sc, bf_held);
- }
- }
- bf->bf_status |= ATH_BUFSTATUS_STALE;
- bf_held = bf;
/*
- * Release the lock here in case ieee80211_input() return
- * the frame immediately by calling ath_rx_mpdu_requeue().
+ * If we're asked to flush receive queue, directly
+ * chain it back at the queue without processing it.
*/
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (flush)
+ goto requeue;
- if (flush) {
- /*
- * If we're asked to flush receive queue, directly
- * chain it back at the queue without processing it.
- */
- goto rx_next;
- }
+ if (!ds->ds_rxstat.rs_datalen)
+ goto requeue;
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- memset(&rx_status, 0, sizeof(struct ath_recv_status));
+ /* The status portion of the descriptor could get corrupted. */
+ if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
+ goto requeue;
- if (ds->ds_rxstat.rs_more) {
- /*
- * Frame spans multiple descriptors; this
- * cannot happen yet as we don't support
- * jumbograms. If not in monitor mode,
- * discard the frame.
- */
-#ifndef ERROR_FRAMES
- /*
- * Enable this if you want to see
- * error frames in Monitor mode.
- */
- if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
- goto rx_next;
-#endif
- /* fall thru for monitor mode handling... */
- } else if (ds->ds_rxstat.rs_status != 0) {
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
- rx_status.flags |= ATH_RX_FCS_ERROR;
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
- phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
- goto rx_next;
- }
+ if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+ goto requeue;
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
- /*
- * Decrypt error. We only mark packet status
- * here and always push up the frame up to let
- * mac80211 handle the actual error case, be
- * it no decryption key or real decryption
- * error. This let us keep statistics there.
- */
- rx_status.flags |= ATH_RX_DECRYPT_ERROR;
- } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
- /*
- * Demic error. We only mark frame status here
- * and always push up the frame up to let
- * mac80211 handle the actual error case. This
- * let us keep statistics there. Hardware may
- * post a false-positive MIC error.
- */
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- ds->ds_rxstat.rs_status &=
- ~ATH9K_RXERR_MIC;
- else
- rx_status.flags |= ATH_RX_MIC_ERROR;
- }
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- goto rx_next;
- } else {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- goto rx_next;
- }
- }
- }
- /*
- * The status portion of the descriptor could get corrupted.
- */
- if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
- goto rx_next;
- /*
- * Sync and unmap the frame. At this point we're
- * committed to passing the sk_buff somewhere so
- * clear buf_skb; this means a new sk_buff must be
- * allocated when the rx descriptor is setup again
- * to receive another frame.
- */
- skb_put(skb, ds->ds_rxstat.rs_datalen);
- skb->protocol = cpu_to_be16(ETH_P_CONTROL);
- rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
- rx_status.rateieee =
- sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate;
- rx_status.rateKbps =
- sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps;
- rx_status.ratecode = ds->ds_rxstat.rs_rate;
-
- /* HT rate */
- if (rx_status.ratecode & 0x80) {
- /* TODO - add table to avoid division */
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
- rx_status.flags |= ATH_RX_40MHZ;
- rx_status.rateKbps =
- (rx_status.rateKbps * 27) / 13;
- }
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
- rx_status.rateKbps =
- (rx_status.rateKbps * 10) / 9;
- else
- rx_status.flags |= ATH_RX_SHORT_GI;
- }
+ /* 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->sc_rxbufsize);
- /* sc_noise_floor is only available when the station
- attaches to an AP, so we use a default value
- if we are not yet attached. */
- rx_status.abs_rssi =
- ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
+ /* If there is no memory we ignore the current RX'd frame,
+ * tell hardware it can give us a new frame using the old
+ * skb and put it at the tail of the sc->sc_rxbuf list for
+ * processing. */
+ if (!requeue_skb)
+ goto requeue;
- pci_dma_sync_single_for_cpu(sc->pdev,
- bf->bf_buf_addr,
+ /* Sync and unmap the frame */
+ pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
skb_tailroom(skb),
PCI_DMA_FROMDEVICE);
- pci_unmap_single(sc->pdev,
- bf->bf_buf_addr,
+ pci_unmap_single(sc->pdev, bf->bf_buf_addr,
sc->sc_rxbufsize,
PCI_DMA_FROMDEVICE);
- /* XXX: Ah! make me more readable, use a helper */
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (ds->ds_rxstat.rs_moreaggr == 0) {
- rx_status.rssictl[0] =
- ds->ds_rxstat.rs_rssi_ctl0;
- rx_status.rssictl[1] =
- ds->ds_rxstat.rs_rssi_ctl1;
- rx_status.rssictl[2] =
- ds->ds_rxstat.rs_rssi_ctl2;
- rx_status.rssi = ds->ds_rxstat.rs_rssi;
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
- rx_status.rssiextn[0] =
- ds->ds_rxstat.rs_rssi_ext0;
- rx_status.rssiextn[1] =
- ds->ds_rxstat.rs_rssi_ext1;
- rx_status.rssiextn[2] =
- ds->ds_rxstat.rs_rssi_ext2;
- rx_status.flags |=
- ATH_RX_RSSI_EXTN_VALID;
- }
- rx_status.flags |= ATH_RX_RSSI_VALID |
- ATH_RX_CHAIN_RSSI_VALID;
- }
- } else {
- /*
- * Need to insert the "combined" rssi into the
- * status structure for upper layer processing
- */
- rx_status.rssi = ds->ds_rxstat.rs_rssi;
- rx_status.flags |= ATH_RX_RSSI_VALID;
+ skb_put(skb, ds->ds_rxstat.rs_datalen);
+ skb->protocol = cpu_to_be16(ETH_P_CONTROL);
+
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (hdrlen & 3) {
+ padsize = hdrlen % 4;
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
}
- /* Pass frames up to the stack. */
+ keyix = ds->ds_rxstat.rs_keyix;
- type = ath_rx_indicate(sc, skb,
- &rx_status, ds->ds_rxstat.rs_keyix);
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, sc->sc_keymap))
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ }
+
+ /* Send the frame to mac80211 */
+ __ieee80211_rx(sc->hw, 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,
+ sc->sc_rxbufsize,
+ PCI_DMA_FROMDEVICE);
+ bf->bf_dmacontext = bf->bf_buf_addr;
/*
* change the default rx antenna if rx diversity chooses the
@@ -716,37 +593,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/
if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
if (++sc->sc_rxotherant >= 3)
- ath_setdefantenna(sc,
- ds->ds_rxstat.rs_antenna);
+ ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
} else {
sc->sc_rxotherant = 0;
}
+requeue:
+ list_move_tail(&bf->list, &sc->sc_rxbuf);
+ ath_rx_buf_link(sc, bf);
+ } while (1);
-#ifdef CONFIG_SLOW_ANT_DIV
- if ((rx_status.flags & ATH_RX_RSSI_VALID) &&
- ieee80211_is_beacon(fc)) {
- ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat);
- }
-#endif
- /*
- * For frames successfully indicated, the buffer will be
- * returned to us by upper layers by calling
- * ath_rx_mpdu_requeue, either synchronusly or asynchronously.
- * So we don't want to do it here in this loop.
- */
- continue;
-
-rx_next:
- bf->bf_status |= ATH_BUFSTATUS_FREE;
- } while (TRUE);
-
- if (chainreset) {
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Reset rx chain mask. "
- "Do internal reset\n", __func__);
- ASSERT(flush == 0);
- ath_reset(sc, false);
- }
+ spin_unlock_bh(&sc->sc_rxbuflock);
return 0;
#undef PA2DESC
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 8937728b0301..413fbdd38ab6 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Implementation of transmit path.
- */
-
#include "core.h"
#define BITS_PER_BYTE 8
@@ -106,21 +102,35 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
ath9k_hw_txstart(ah, txq->axq_qnum);
}
-/* Get transmit rate index using rate in Kbps */
-
-static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
+static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_xmit_status *tx_status)
{
- int i;
- int ndx = 0;
+ 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);
- for (i = 0; i < rt->rateCount; i++) {
- if (rt->info[i].rateKbps == rate) {
- ndx = i;
- break;
- }
+ DPRINTF(sc, ATH_DBG_XMIT,
+ "%s: TX complete: skb: %p\n", __func__, 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;
}
- return ndx;
+ 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;
+
+ ieee80211_tx_status(hw, skb);
}
/* Check if it's okay to send out aggregates */
@@ -137,6 +147,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)
@@ -162,26 +185,23 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
return htype;
}
-static bool check_min_rate(struct sk_buff *skb)
+static bool is_pae(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
- bool use_minrate = false;
__le16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
- if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
- use_minrate = true;
- } else if (ieee80211_is_data(fc)) {
+ if (ieee80211_is_data(fc)) {
if (ieee80211_is_nullfunc(fc) ||
/* Port Access Entity (IEEE 802.1X) */
(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- use_minrate = true;
+ return true;
}
}
- return use_minrate;
+ return false;
}
static int get_hw_crypto_keytype(struct sk_buff *skb)
@@ -200,56 +220,6 @@ static int get_hw_crypto_keytype(struct sk_buff *skb)
return ATH9K_KEY_TYPE_CLEAR;
}
-static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_rc_series *rcs;
- struct ieee80211_hdr *hdr;
- const struct ath9k_rate_table *rt;
- bool use_minrate;
- __le16 fc;
- u8 rix;
-
- rt = sc->sc_currates;
- BUG_ON(!rt);
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; /* HACK */
- rcs = tx_info_priv->rcs;
-
- /* Check if min rates have to be used */
- use_minrate = check_min_rate(skb);
-
- if (ieee80211_is_data(fc) && !use_minrate) {
- if (is_multicast_ether_addr(hdr->addr1)) {
- rcs[0].rix =
- ath_tx_findindex(rt, tx_info_priv->min_rate);
- /* mcast packets are not re-tried */
- rcs[0].tries = 1;
- }
- } else {
- /* for management and control frames,
- or for NULL and EAPOL frames */
- if (use_minrate)
- rcs[0].rix = ath_rate_findrateix(sc, tx_info_priv->min_rate);
- else
- rcs[0].rix = 0;
- rcs[0].tries = ATH_MGT_TXMAXTRY;
- }
-
- rix = rcs[0].rix;
-
- if (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
- rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
- rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
- /* reset tries but keep rate index */
- rcs[0].tries = ATH_TXMAXTRY;
- }
-}
-
/* Called only when tx aggregation is enabled and HT is supported */
static void assign_aggr_tid_seqno(struct sk_buff *skb,
@@ -278,7 +248,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
/* Get seqno */
- if (ieee80211_is_data(fc) && !check_min_rate(skb)) {
+ if (ieee80211_is_data(fc) && !is_pae(skb)) {
/* 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.
@@ -523,27 +493,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
* 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)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
u32 nbits, nsymbits, duration, nsymbols;
u8 rc;
int streams, pktlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
- rc = rt->info[rix].rateCode;
+ rc = rate_table->info[rix].ratecode;
- /*
- * for legacy rates, use old function to compute packet duration
- */
+ /* for legacy rates, use old function to compute packet duration */
if (!IS_HT_RATE(rc))
- return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix,
- shortPreamble);
- /*
- * find number of symbols: PLCP + data
- */
+ 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;
@@ -553,9 +519,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
else
duration = SYMBOL_TIME_HALFGI(nsymbols);
- /*
- * addup duration for legacy/ht training and signal fields
- */
+ /* 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);
@@ -567,179 +531,125 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
- const struct ath9k_rate_table *rt;
+ 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;
- struct ath_node *an = NULL;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
+ __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 (tx_info->control.sta)
- an = (struct ath_node *)tx_info->control.sta->drv_priv;
+ 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;
+ }
- /*
- * get the cix for the lowest valid rix.
- */
- rt = sc->sc_currates;
- for (i = 4; i--;) {
- if (bf->bf_rcs[i].tries) {
- rix = bf->bf_rcs[i].rix;
+ /* get the cix for the lowest valid rix */
+ rt = sc->hw_rate_table[sc->sc_curmode];
+ for (i = 3; i >= 0; i--) {
+ if (rates[i].count && (rates[i].idx >= 0)) {
+ rix = rates[i].idx;
break;
}
}
+
flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
- cix = rt->info[rix].controlRate;
+ 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 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 &&
- (rt->info[rix].phy == PHY_OFDM ||
- rt->info[rix].phy == PHY_HT) &&
- (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+ 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].controlRate;
+ 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.
+ /* 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
- */
+ /* 802.11g protection not needed, use our default behavior */
if (!rtsctsena)
flags = ATH9K_TXDESC_RTSENA;
}
- /*
- * Set protection if aggregate protection on
- */
+ /* 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].controlRate;
+ 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)) {
- /*
- * Ensure that in the case of SM Dynamic power save
- * while we are bursting the second aggregate the
- * RTS is cleared.
- */
+ /* 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
- */
- BUG_ON(cix == 0xff);
- ctsrate = rt->info[cix].rateCode |
- (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
/*
- * Setup HAL rate series
+ * 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
*/
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+ ctsrate = rt->info[cix].ratecode |
+ (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
for (i = 0; i < 4; i++) {
- if (!bf->bf_rcs[i].tries)
+ if (!rates[i].count || (rates[i].idx < 0))
continue;
- rix = bf->bf_rcs[i].rix;
+ rix = rates[i].idx;
- series[i].Rate = rt->info[rix].rateCode |
- (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
+ series[i].Rate = rt->info[rix].ratecode |
+ (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
- series[i].Tries = bf->bf_rcs[i].tries;
+ series[i].Tries = rates[i].count;
series[i].RateFlags = (
- (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ?
+ (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
ATH9K_RATESERIES_RTS_CTS : 0) |
- ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ?
+ ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
ATH9K_RATESERIES_2040 : 0) |
- ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
+ ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
ATH9K_RATESERIES_HALFGI : 0);
series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
- (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
- (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
+ (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
+ (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
bf_isshpreamble(bf));
- if (bf_isht(bf) && an)
- series[i].ChSel = ath_chainmask_sel_logic(sc, an);
- else
- series[i].ChSel = sc->sc_tx_chainmask;
+ series[i].ChSel = sc->sc_tx_chainmask;
if (rtsctsena)
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
}
- /*
- * For non-HT devices, calculate RTS/CTS duration in software
- * and disable multi-rate retry.
- */
- if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) {
- /*
- * Compute the transmit duration based on the frame
- * size and the size of an ACK frame. We call into the
- * HAL to do the computation since it depends on the
- * characteristics of the actual PHY being used.
- *
- * NB: CTS is assumed the same size as an ACK so we can
- * use the precalculated ACK durations.
- */
- if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */
- ctsduration += bf_isshpreamble(bf) ?
- rt->info[cix].spAckDuration :
- rt->info[cix].lpAckDuration;
- }
-
- ctsduration += series[0].PktDuration;
-
- if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
- ctsduration += bf_isshpreamble(bf) ?
- rt->info[rix].spAckDuration :
- rt->info[rix].lpAckDuration;
- }
-
- /*
- * Disable multi-rate retry when using RTS/CTS by clearing
- * series 1, 2 and 3.
- */
- memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3);
- }
-
- /*
- * 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,
+ /* 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)
@@ -750,29 +660,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* 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)
{
struct ath_buf *bf;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
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 */
- skb = (struct sk_buff *)bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
-
- /* XXX: HACK! */
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
- memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
/* update starting sequence number for subsequent ADDBA request */
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
@@ -1051,18 +950,37 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
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 int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+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, *tmp_ds;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
- int nacked, txok, nbad = 0, isrifs = 0;
+ struct ath_desc *ds;
+ int txok, nbad = 0;
int status;
DPRINTF(sc, ATH_DBG_QUEUE,
@@ -1070,7 +988,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
txq->axq_link);
- nacked = 0;
for (;;) {
spin_lock_bh(&txq->axq_lock);
if (list_empty(&txq->axq_q)) {
@@ -1160,30 +1077,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
} else {
nbad = ath_tx_num_badfrms(sc, bf, txok);
}
- skb = bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
-
- /* XXX: HACK! */
- tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
- 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 (ds->ds_txstat.ts_status == 0)
- nacked++;
-
- if (bf_isdata(bf)) {
- if (isrifs)
- tmp_ds = bf->bf_rifslast->bf_desc;
- else
- tmp_ds = ds;
- memcpy(&tx_info_priv->tx,
- &tmp_ds->ds_txstat,
- sizeof(tx_info_priv->tx));
- tx_info_priv->n_frames = bf->bf_nframes;
- tx_info_priv->n_bad_frames = nbad;
- }
- }
+
+ ath_tx_rc_status(bf, ds, nbad);
/*
* Complete this transmit unit
@@ -1214,7 +1109,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_txq_schedule(sc, txq);
spin_unlock_bh(&txq->axq_lock);
}
- return nacked;
}
static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
@@ -1254,7 +1148,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah,
sc->sc_ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, true, &status)) {
@@ -1307,9 +1201,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
struct ath_tx_control *txctl)
{
struct ath_buf *bf;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
BUG_ON(list_empty(bf_head));
@@ -1335,12 +1226,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
return 0;
}
- skb = (struct sk_buff *)bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
- /* XXX: HACK! */
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
- memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
/* Add sub-frame to BAW */
ath_tx_addto_baw(sc, tid, bf);
@@ -1362,9 +1247,10 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
struct ath_buf *bf,
struct ath_atx_tid *tid)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
struct sk_buff *skb;
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;
u16 aggr_limit, legacy = 0, maxampdu;
@@ -1372,10 +1258,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
skb = (struct sk_buff *)bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
- tx_info_priv = (struct ath_tx_info_priv *)
- tx_info->control.vif; /* XXX: HACK! */
- memcpy(bf->bf_rcs,
- tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+ rates = tx_info->control.rates;
+ 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
@@ -1385,14 +1270,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
for (i = 0; i < 4; i++) {
- if (bf->bf_rcs[i].tries) {
- frame_length = bf->bf_rcs[i].max_4ms_framelen;
-
- if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
+ if (rates[i].count) {
+ if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
legacy = 1;
break;
}
+ frame_length =
+ rate_table->info[rates[i].idx].max_4ms_framelen;
max_4ms_framelen = min(max_4ms_framelen, frame_length);
}
}
@@ -1431,7 +1316,9 @@ static int ath_compute_num_delims(struct ath_softc *sc,
struct ath_buf *bf,
u16 frmlen)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rt = sc->hw_rate_table[sc->sc_curmode];
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols, mpdudensity;
u16 minlen;
u8 rc, flags, rix;
@@ -1464,11 +1351,11 @@ static int ath_compute_num_delims(struct ath_softc *sc,
if (mpdudensity == 0)
return ndelim;
- rix = bf->bf_rcs[0].rix;
- flags = bf->bf_rcs[0].flags;
- rc = rt->info[rix].rateCode;
- width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0;
- half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0;
+ rix = tx_info->control.rates[0].idx;
+ flags = tx_info->control.rates[0].flags;
+ rc = rt->info[rix].ratecode;
+ width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
+ half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi)
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
@@ -1510,7 +1397,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
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, is_ds_rate = 0;
+ int prev_al = 0;
INIT_LIST_HEAD(&bf_head);
BUG_ON(list_empty(&tid->buf_q));
@@ -1531,11 +1418,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
if (!rl) {
aggr_limit = ath_lookup_rate(sc, bf, tid);
rl = 1;
- /*
- * Is rate dual stream
- */
- is_ds_rate =
- (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0;
}
/*
@@ -1772,20 +1654,19 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
}
static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
- struct sk_buff *skb, struct scatterlist *sg,
+ struct sk_buff *skb,
struct ath_tx_control *txctl)
{
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;
- struct ath_rc_series *rcs;
int hdrlen;
__le16 fc;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+ tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_KERNEL);
+ tx_info->rate_driver_data[0] = tx_info_priv;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
- rcs = tx_info_priv->rcs;
ATH_TXBUF_RESET(bf);
@@ -1805,7 +1686,7 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
(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 &&
+ (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);
@@ -1823,15 +1704,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
}
- /* Rate series */
-
- setup_rate_retries(sc, skb);
-
- bf->bf_rcs[0] = rcs[0];
- bf->bf_rcs[1] = rcs[1];
- bf->bf_rcs[2] = rcs[2];
- bf->bf_rcs[3] = rcs[3];
-
/* Assign seqno, tidno */
if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
@@ -1847,7 +1719,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
/* FIXME: tx power */
static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
- struct scatterlist *sg, u32 n_sg,
struct ath_tx_control *txctl)
{
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
@@ -1876,10 +1747,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
ath9k_hw_filltxdesc(ah, ds,
- sg_dma_len(sg), /* segment length */
- true, /* first segment */
- (n_sg == 1) ? true : false, /* last segment */
- ds); /* first descriptor */
+ skb->len, /* segment length */
+ true, /* first segment */
+ true, /* last segment */
+ ds); /* first descriptor */
bf->bf_lastfrm = bf;
@@ -1919,7 +1790,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
struct ath_buf *bf;
- struct scatterlist sg;
/* Check if a tx buffer is available */
@@ -1930,15 +1800,8 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
return -1;
}
- ath_tx_setup_buffer(sc, bf, skb, &sg, txctl);
-
- /* Setup S/G */
-
- memset(&sg, 0, sizeof(struct scatterlist));
- sg_dma_address(&sg) = bf->bf_dmacontext;
- sg_dma_len(&sg) = skb->len;
-
- ath_tx_start_dma(sc, bf, &sg, 1, txctl);
+ ath_tx_setup_buffer(sc, bf, skb, txctl);
+ ath_tx_start_dma(sc, bf, txctl);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
index 1daa3f05a775..7dea1552a906 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l,
int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask,
- unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
+ unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret;
}
#define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 7187925bd0d5..2a924c10ff93 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -886,7 +886,6 @@ struct iwl3945_priv {
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
- struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index c43cf2f072cd..ab0b40531989 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -53,6 +53,7 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
* is not compatible with earlier drivers.
* This number will also appear in << 8 position of 1st dword of uCode file */
#define IWL4965_UCODE_API "-2"
+#define IWL4965_MODULE_FIRMWARE "iwlwifi-4965" IWL4965_UCODE_API ".ucode"
/* module parameters */
@@ -661,7 +662,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
int txq_id = txq->q.id;
/* Find out whether to activate Tx queue */
- int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
/* Set up and activate */
iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
@@ -691,9 +692,10 @@ static const u16 default_queue_to_tx_fifo[] = {
static int iwl4965_alive_notify(struct iwl_priv *priv)
{
u32 a;
- int i = 0;
unsigned long flags;
int ret;
+ int i, chan;
+ u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
@@ -717,6 +719,17 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
priv->scd_bc_tbls.dma >> 10);
+ /* Enable DMA channel */
+ for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++)
+ iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+ /* Update FH chicken bits */
+ reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+ iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+ reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
/* Disable chain mode for all queues */
iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
@@ -747,7 +760,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
(1 << priv->hw_params.max_txq_num) - 1);
/* Activate all Tx DMA/FIFO channels */
- priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+ priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
@@ -1909,7 +1922,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+ iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
@@ -2025,7 +2038,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status)?
+ info->flags |= iwl_is_tx_success(status) ?
IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
/* FIXME: code repetition end */
@@ -2322,7 +2335,7 @@ static struct iwl_ops iwl4965_ops = {
struct iwl_cfg iwl4965_agn_cfg = {
.name = "4965AGN",
- .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
+ .fw_name = IWL4965_MODULE_FIRMWARE,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
@@ -2332,7 +2345,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
};
/* Module firmware */
-MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE);
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index ee3613db3132..a738886b434f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -475,6 +475,9 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
index = IWL_CALIB_TX_IQ_PERD;
break;
+ case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+ index = IWL_CALIB_BASE_BAND;
+ break;
default:
IWL_ERROR("Unknown calibration notification %d\n",
hdr->op_code);
@@ -697,9 +700,10 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
static int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
- int i = 0;
unsigned long flags;
int ret;
+ int i, chan;
+ u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
@@ -722,6 +726,18 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
priv->scd_bc_tbls.dma >> 10);
+
+ /* Enable DMA channel */
+ for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+ iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+ /* Update FH chicken bits */
+ reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+ iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+ reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
@@ -841,8 +857,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
- BIT(IWL_CALIB_TX_IQ) |
- BIT(IWL_CALIB_TX_IQ_PERD);
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_TX_IQ_PERD) |
+ BIT(IWL_CALIB_BASE_BAND);
break;
case CSR_HW_REV_TYPE_5150:
priv->hw_params.calib_init_cfg = 0;
@@ -969,7 +986,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+ iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
@@ -1111,7 +1128,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status)?
+ info->flags |= iwl_is_tx_success(status) ?
IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 0332805cc630..3a2b81291d86 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -281,10 +281,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
u32 time_diff;
s32 index;
struct iwl_traffic_load *tl = NULL;
- __le16 fc = hdr->frame_control;
u8 tid;
- if (ieee80211_is_data_qos(fc)) {
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
} else
@@ -773,7 +772,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
int status;
u8 retries;
int rs_index, index = 0;
- struct iwl_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
@@ -785,12 +784,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct iwl_scale_tbl_info tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
u8 active_index = 0;
- __le16 fc = hdr->frame_control;
s32 tpt = 0;
IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1))
return;
/* This packet was aggregated but doesn't carry rate scale info */
@@ -803,8 +802,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
if (retries > 15)
retries = 15;
- lq_sta = (struct iwl_lq_sta *)priv_sta;
-
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added)
goto out;
@@ -1675,7 +1672,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
int high_tpt = IWL_INVALID_VALUE;
u32 fail_count;
s8 scale_action = 0;
- __le16 fc;
u16 rate_mask;
u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1;
@@ -1690,13 +1686,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
- fc = hdr->frame_control;
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
- /* Send management frames and broadcast/multicast data using
- * lowest rate. */
- /* TODO: this could probably be improved.. */
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1))
return;
- }
if (!sta || !lq_sta)
return;
@@ -2095,29 +2090,26 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate_control *txrc)
{
- int i;
struct sk_buff *skb = txrc->skb;
struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- __le16 fc;
- struct iwl_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
+ int rate_idx;
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
/* Send management frames and broadcast/multicast data using lowest
* rate. */
- fc = hdr->frame_control;
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
- !sta || !priv_sta) {
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) {
info->control.rates[0].idx = rate_lowest_index(sband, sta);
return;
}
- lq_sta = (struct iwl_lq_sta *)priv_sta;
- i = lq_sta->last_txrate_idx;
+ rate_idx = lq_sta->last_txrate_idx;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) {
@@ -2137,14 +2129,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
}
}
- if ((i < 0) || (i > IWL_RATE_COUNT)) {
- info->control.rates[0].idx = rate_lowest_index(sband, sta);
- return;
- }
+ if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+ rate_idx = rate_lowest_index(sband, sta);
+ else if (sband->band == IEEE80211_BAND_5GHZ)
+ rate_idx -= IWL_FIRST_OFDM_RATE;
- if (sband->band == IEEE80211_BAND_5GHZ)
- i -= IWL_FIRST_OFDM_RATE;
- info->control.rates[0].idx = i;
+ info->control.rates[0].idx = rate_idx;
}
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
@@ -2525,7 +2515,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
for (i = 0; i < LQ_SIZE; i++) {
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
"rate=0x%X\n",
- lq_sta->active_tbl == i?"*":"x",
+ lq_sta->active_tbl == i ? "*" : "x",
lq_sta->lq_info[i].lq_type,
lq_sta->lq_info[i].is_SGI,
lq_sta->lq_info[i].is_fat,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 8fa4f7a2dc1a..c8ce84a1eef4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -466,9 +466,9 @@ static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
/* Set rate mask*/
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
- rate_mask = priv->active_rate_basic & 0xF;
+ rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
else
- rate_mask = priv->active_rate_basic & 0xFF0;
+ rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
/* Find lowest valid rate */
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
@@ -1492,7 +1492,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
hw_rf_kill = 1;
IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio":"enable radio");
+ hw_rf_kill ? "disable radio" : "enable radio");
/* driver only loads ucode once setting the interface up.
* the driver as well won't allow loading if RFKILL is set
@@ -2224,27 +2224,6 @@ static void iwl_bg_rf_kill(struct work_struct *work)
iwl_rfkill_set_hw_state(priv);
}
-static void iwl_bg_set_monitor(struct work_struct *work)
-{
- struct iwl_priv *priv = container_of(work,
- struct iwl_priv, set_monitor);
- int ret;
-
- IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
- mutex_lock(&priv->mutex);
-
- ret = iwl_set_mode(priv, NL80211_IFTYPE_MONITOR);
- if (ret) {
- if (ret == -EAGAIN)
- IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
- else
- IWL_ERROR("iwl_set_mode() failed ret = %d\n", ret);
- }
-
- mutex_unlock(&priv->mutex);
-}
-
static void iwl_bg_run_time_calib_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2890,16 +2869,43 @@ static void iwl_configure_filter(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mc_list)
{
struct iwl_priv *priv = hw->priv;
+ __le32 *filter_flags = &priv->staging_rxon.filter_flags;
+
+ IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+ changed_flags, *total_flags);
- if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
- IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- NL80211_IFTYPE_MONITOR,
- changed_flags, *total_flags);
- /* queue work 'cuz mac80211 is holding a lock which
- * prevents us from issuing (synchronous) f/w cmds */
- queue_work(priv->workqueue, &priv->set_monitor);
+ if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+ if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+ *filter_flags |= RXON_FILTER_PROMISC_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
+ }
+ if (changed_flags & FIF_ALLMULTI) {
+ if (*total_flags & FIF_ALLMULTI)
+ *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+ }
+ if (changed_flags & FIF_CONTROL) {
+ if (*total_flags & FIF_CONTROL)
+ *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+ }
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
}
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+
+ /* We avoid iwl_commit_rxon here to commit the new filter flags
+ * since mac80211 will call ieee80211_hw_config immediately.
+ * (mc_list is not supported at this time). Otherwise, we need to
+ * queue a background iwl_commit_rxon work.
+ */
+
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -3058,49 +3064,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *keyconf, const u8 *addr,
u32 iv32, u16 *phase1key)
{
- struct iwl_priv *priv = hw->priv;
- u8 sta_id = IWL_INVALID_STATION;
- unsigned long flags;
- __le16 key_flags = 0;
- int i;
+ struct iwl_priv *priv = hw->priv;
IWL_DEBUG_MAC80211("enter\n");
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
- addr);
- return;
- }
-
- if (iwl_scan_cancel(priv)) {
- /* cancel scan failed, just live w/ bad key and rely
- briefly on SW decryption */
- return;
- }
-
- key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (sta_id == priv->hw_params.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
-
- for (i = 0; i < 5; i++)
- priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
- cpu_to_le16(phase1key[i]);
-
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
IWL_DEBUG_MAC80211("leave\n");
}
@@ -3239,10 +3207,10 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT("start Rx\n");
- return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
+ return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT("stop Rx\n");
- return iwl_rx_agg_stop(priv, sta->addr, tid);
+ return iwl_sta_rx_agg_stop(priv, sta->addr, tid);
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT("start Tx\n");
return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
@@ -3256,6 +3224,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
}
return 0;
}
+
static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats)
{
@@ -3694,7 +3663,8 @@ static ssize_t show_power_level(struct device *d,
break;
}
- p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto");
+ p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
+ "fixed" : "auto");
p += sprintf(p, "\tINDEX:%d", level);
p += sprintf(p, "\n");
return p - buf + 1;
@@ -3832,7 +3802,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
- INIT_WORK(&priv->set_monitor, iwl_bg_set_monitor);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8bd4d087d4e2..6aa332bebc5f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -37,6 +37,7 @@
#include "iwl-io.h"
#include "iwl-rfkill.h"
#include "iwl-power.h"
+#include "iwl-sta.h"
MODULE_DESCRIPTION("iwl core");
@@ -237,28 +238,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_hw_nic_init);
-/**
- * iwl_clear_stations_table - Clear the driver's station table
- *
- * NOTE: This does not clear or otherwise alter the device's station table.
- */
-void iwl_clear_stations_table(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- if (iwl_is_alive(priv) &&
- !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
- iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
- IWL_ERROR("Couldn't clear the station table\n");
-
- priv->num_stations = 0;
- memset(priv->stations, 0, sizeof(priv->stations));
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-EXPORT_SYMBOL(iwl_clear_stations_table);
void iwl_reset_qos(struct iwl_priv *priv)
{
@@ -832,6 +811,9 @@ int iwl_setup_mac(struct iwl_priv *priv)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
+
+ hw->wiphy->fw_handles_regulatory = true;
+
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
/* queues to support 11n aggregation */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index ff966b8a0c6d..82bf263b6f5a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -182,7 +182,6 @@ struct iwl_cfg {
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops);
void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_clear_stations_table(struct iwl_priv *priv);
void iwl_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
@@ -206,8 +205,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn);
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index bd3df55e4953..4da988e0eae0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -574,11 +574,6 @@ struct iwl_hw_params {
* iwl4965_mac_ <-- mac80211 callback
*
****************************************************************************/
-struct iwl_addsta_cmd;
-extern int iwl_send_add_sta(struct iwl_priv *priv,
- struct iwl_addsta_cmd *sta, u8 flags);
-extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
- int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
extern void iwl_update_chain_flags(struct iwl_priv *priv);
extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
extern const u8 iwl_bcast_addr[ETH_ALEN];
@@ -700,6 +695,7 @@ enum iwl_calib {
IWL_CALIB_LO,
IWL_CALIB_TX_IQ,
IWL_CALIB_TX_IQ_PERD,
+ IWL_CALIB_BASE_BAND,
IWL_CALIB_MAX
};
@@ -990,7 +986,6 @@ struct iwl_priv {
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
- struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index e46300c28a8f..c3dadb03701c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -72,7 +72,7 @@
* Addresses are offsets from device's PCI hardware base address.
*/
#define FH_MEM_LOWER_BOUND (0x1000)
-#define FH_MEM_UPPER_BOUND (0x1EF0)
+#define FH_MEM_UPPER_BOUND (0x2000)
/**
* Keep-Warm (KW) buffer base address.
@@ -268,6 +268,8 @@
#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000)
+#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
+
/**
* Rx Shared Status Registers (RSSR)
@@ -294,6 +296,13 @@
#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28
+/* TFDB Area - TFDs buffer table */
+#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF)
+#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900)
+#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958)
+#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
+#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+
/**
* Transmit DMA Channel Control/Status Registers (TCSR)
*
@@ -323,6 +332,7 @@
#define FH49_TCSR_CHNL_NUM (7)
#define FH50_TCSR_CHNL_NUM (8)
+/* TCSR: tx_config register values */
#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
@@ -379,31 +389,18 @@
(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
-
-
-#define FH_REGS_LOWER_BOUND (0x1000)
-#define FH_REGS_UPPER_BOUND (0x2000)
-
/* Tx service channels */
-#define FH_SRVC_CHNL (9)
-#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8)
-#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0)
+#define FH_SRVC_CHNL (9)
+#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8)
+#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
-/* TFDB Area - TFDs buffer table */
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF)
-#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900)
-#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958)
-#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
-#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
-
-/* TCSR: tx_config register values */
-#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
-
-#define TFD_QUEUE_SIZE_MAX (256)
-#define TFD_QUEUE_SIZE_BC_DUP (64)
-#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
+#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98)
+/* Instruct FH to increment the retry count of a packet when
+ * it is brought from the memory to TX-FIFO
+ */
+#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002)
/**
* struct iwl_rb_status - reseve buffer status
@@ -423,9 +420,10 @@ struct iwl_rb_status {
} __attribute__ ((packed));
-
+#define TFD_QUEUE_SIZE_MAX (256)
+#define TFD_QUEUE_SIZE_BC_DUP (64)
+#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
#define IWL_TX_DMA_MASK DMA_BIT_MASK(36)
-
#define IWL_NUM_OF_TBS 20
static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
@@ -440,7 +438,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
* @lo: low [31:0] portion of the dma address of TX buffer
* every even is unaligned on 16 bit boundary
* @hi_n_len 0-3 [35:32] portion of dma
- * 4-16 length of the tx buffer
+ * 4-15 length of the tx buffer
*/
struct iwl_tfd_tb {
__le32 lo;
@@ -453,7 +451,8 @@ struct iwl_tfd_tb {
* Transmit Frame Descriptor (TFD)
*
* @ __reserved1[3] reserved
- * @ num_tbs 0-5 number of active tbs
+ * @ num_tbs 0-4 number of active tbs
+ * 5 reserved
* 6-7 padding (not used)
* @ tbs[20] transmit frame buffer descriptors
* @ __pad padding
@@ -473,8 +472,6 @@ struct iwl_tfd_tb {
* Tx frame, up to 8 KBytes in size.
*
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
- *
- * Bit fields in the control dword (val0):
*/
struct iwl_tfd {
u8 __reserved1[3];
@@ -485,6 +482,6 @@ struct iwl_tfd {
/* Keep Warm Size */
-#define IWL_KW_SIZE 0x1000 /*4k */
+#define IWL_KW_SIZE 0x1000 /* 4k */
#endif /* !__iwl_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 8300f3d00a06..0008a35232b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -36,7 +36,7 @@
#include "iwl-core.h"
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
const char *get_cmd_string(u8 cmd)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 40e0050b7536..bc10435d96e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -109,7 +109,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l,
int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask,
- unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
+ unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret;
}
#define iwl_poll_bit(priv, addr, bits, mask, timeout) \
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 876afd4cab9e..8d2b73e194da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -499,49 +499,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn)
-{
- unsigned long flags;
- int sta_id;
-
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.station_flags_msk = 0;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
- priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
- priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_start);
-
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
-{
- unsigned long flags;
- int sta_id;
-
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.station_flags_msk = 0;
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
- priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_stop);
-
/* Calculate noise level, based on measurements during network silence just
* before arriving beacon. This measurement can be done only if we know
@@ -1017,38 +974,6 @@ static inline int iwl_calc_rssi(struct iwl_priv *priv,
}
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.sta.modify_mask = 0;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
-{
- /* FIXME: need locking over ps_status ??? */
- u8 sta_id = iwl_find_station(priv, addr);
-
- if (sta_id != IWL_INVALID_STATION) {
- u8 sta_awake = priv->stations[sta_id].
- ps_status == STA_PS_STATUS_WAKE;
-
- if (sta_awake && ps_bit)
- priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
- else if (!sta_awake && !ps_bit) {
- iwl_sta_modify_ps_wake(priv, sta_id);
- priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
- }
- }
-}
-
/* This is necessary only for a number of statistics, see the caller. */
static int iwl_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header)
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 0c5f1221b8f3..f86a8ca2aa3b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -132,7 +132,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
return 1;
}
-int iwl_send_add_sta(struct iwl_priv *priv,
+static int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags)
{
struct iwl_rx_packet *res = NULL;
@@ -180,7 +180,6 @@ int iwl_send_add_sta(struct iwl_priv *priv,
return ret;
}
-EXPORT_SYMBOL(iwl_send_add_sta);
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_sta_ht_cap *sta_ht_inf)
@@ -464,6 +463,29 @@ out:
}
EXPORT_SYMBOL(iwl_remove_station);
+/**
+ * iwl_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE: This does not clear or otherwise alter the device's station table.
+ */
+void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (iwl_is_alive(priv) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
+ iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
+ IWL_ERROR("Couldn't clear the station table\n");
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+EXPORT_SYMBOL(iwl_clear_stations_table);
+
static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{
int i;
@@ -703,6 +725,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
return ret;
}
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ const u8 *addr, u32 iv32, u16 *phase1key)
+{
+ u8 sta_id = IWL_INVALID_STATION;
+ unsigned long flags;
+ __le16 key_flags = 0;
+ int i;
+ DECLARE_MAC_BUF(mac);
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+ addr);
+ return;
+ }
+
+ if (iwl_scan_cancel(priv)) {
+ /* cancel scan failed, just live w/ bad key and rely
+ briefly on SW decryption */
+ return;
+ }
+
+ key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == priv->hw_params.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+ for (i = 0; i < 5; i++)
+ priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+ cpu_to_le16(phase1key[i]);
+
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+}
+EXPORT_SYMBOL(iwl_update_tkip_key);
+
int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
@@ -989,9 +1060,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
EXPORT_SYMBOL(iwl_get_sta_id);
/**
- * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
*/
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
{
unsigned long flags;
@@ -1004,5 +1075,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
-EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+ const u8 *addr, int tid, u16 ssn)
+{
+ unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+ priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_start);
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+{
+ unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+ priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask = 0;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+ /* FIXME: need locking over ps_status ??? */
+ u8 sta_id = iwl_find_station(priv, addr);
+
+ if (sta_id != IWL_INVALID_STATION) {
+ u8 sta_awake = priv->stations[sta_id].
+ ps_status == STA_PS_STATUS_WAKE;
+
+ if (sta_awake && ps_bit)
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+ else if (!sta_awake && !ps_bit) {
+ iwl_sta_modify_ps_wake(priv, sta_id);
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+ }
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 221b93e670a6..7b98ea4dfbc0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id);
int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ const u8 *addr, u32 iv32, u16 *phase1key);
+
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+void iwl_clear_stations_table(struct iwl_priv *priv);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+ int is_ap, u8 flags,
+ struct ieee80211_sta_ht_cap *ht_info);
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+ const u8 *addr, int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 166f0001e01d..e045dfeaa1fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -449,11 +449,6 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
- /* Enable DMA channel, using same id as for TFD queue */
- iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -587,8 +582,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
-
-
/* Alloc and init all Tx queues, including the command queue (#4) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
@@ -618,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
*/
void iwl_txq_ctx_stop(struct iwl_priv *priv)
{
-
int txq_id;
unsigned long flags;
-
/* Turn off all Tx DMA fifos */
spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) {
@@ -1498,7 +1489,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
ack = bitmap & (1ULL << i);
successes += !!ack;
IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
- ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+ ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
agg->start_idx + i);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 3344841b7662..69fda64c6503 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -519,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
static const char *get_cmd_string(u8 cmd)
{
@@ -1425,9 +1425,9 @@ static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv)
/* Set rate mask*/
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
- rate_mask = priv->active_rate_basic & 0xF;
+ rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
else
- rate_mask = priv->active_rate_basic & 0xFF0;
+ rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
i = iwl3945_rates[i].next_ieee) {
@@ -4320,7 +4320,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
"RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio":"enable radio");
+ hw_rf_kill ? "disable radio" : "enable radio");
/* Queue restart only if RF_KILL switch was set to "kill"
* when we loaded driver, and is now set to "enable".
@@ -5996,24 +5996,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
iwl3945_rfkill_set_hw_state(priv);
}
-static void iwl3945_bg_set_monitor(struct work_struct *work)
-{
- struct iwl3945_priv *priv = container_of(work,
- struct iwl3945_priv, set_monitor);
-
- IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
- mutex_lock(&priv->mutex);
-
- if (!iwl3945_is_ready(priv))
- IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
- else
- if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
- IWL_ERROR("iwl3945_set_mode() failed\n");
-
- mutex_unlock(&priv->mutex);
-}
-
#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6339,10 +6321,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
case NL80211_IFTYPE_ADHOC:
- /* clear out the station table */
- iwl3945_clear_stations_table(priv);
-
- iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+ priv->assoc_id = 1;
iwl3945_add_station(priv, priv->bssid, 0, 0);
iwl3945_sync_sta(priv, IWL_STA_ID,
(priv->band == IEEE80211_BAND_5GHZ) ?
@@ -6830,16 +6809,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mc_list)
{
struct iwl3945_priv *priv = hw->priv;
+ __le32 *filter_flags = &priv->staging_rxon.filter_flags;
+
+ IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+ changed_flags, *total_flags);
- if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
- IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- NL80211_IFTYPE_MONITOR,
- changed_flags, *total_flags);
- /* queue work 'cuz mac80211 is holding a lock which
- * prevents us from issuing (synchronous) f/w cmds */
- queue_work(priv->workqueue, &priv->set_monitor);
+ if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+ if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+ *filter_flags |= RXON_FILTER_PROMISC_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
+ }
+ if (changed_flags & FIF_ALLMULTI) {
+ if (*total_flags & FIF_ALLMULTI)
+ *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
}
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+ if (changed_flags & FIF_CONTROL) {
+ if (*total_flags & FIF_CONTROL)
+ *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+ }
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+ }
+
+ /* We avoid iwl_commit_rxon here to commit the new filter flags
+ * since mac80211 will call ieee80211_hw_config immediately.
+ * (mc_list is not supported at this time). Otherwise, we need to
+ * queue a background iwl_commit_rxon work.
+ */
+
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -7715,7 +7721,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
- INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
@@ -7787,6 +7792,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
unsigned long flags;
+ /***********************
+ * 1. Allocating HW data
+ * ********************/
+
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (iwl3945_param_disable_hw_scan) {
@@ -7810,27 +7819,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
err = -ENOMEM;
goto out;
}
- SET_IEEE80211_DEV(hw, &pdev->dev);
- hw->rate_control_algorithm = "iwl-3945-rs";
- hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+ SET_IEEE80211_DEV(hw, &pdev->dev);
- IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
priv = hw->priv;
priv->hw = hw;
-
priv->pci_dev = pdev;
priv->cfg = cfg;
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ hw->rate_control_algorithm = "iwl-3945-rs";
+ hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+
/* Select antenna (may be helpful if only one antenna is connected) */
priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
#ifdef CONFIG_IWL3945_DEBUG
iwl3945_debug_level = iwl3945_param_debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
- priv->retry_rate = 1;
-
- priv->ibss_beacon = NULL;
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
@@ -7841,17 +7847,14 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
+ hw->wiphy->fw_handles_regulatory = true;
+
/* 4 EDCA QOS priorities */
hw->queues = 4;
- spin_lock_init(&priv->lock);
- spin_lock_init(&priv->power_data.lock);
- spin_lock_init(&priv->sta_lock);
- spin_lock_init(&priv->hcmd_lock);
-
- INIT_LIST_HEAD(&priv->free_frames);
-
- mutex_init(&priv->mutex);
+ /***************************
+ * 2. Initializing PCI bus
+ * *************************/
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_ieee80211_free_hw;
@@ -7859,14 +7862,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_set_master(pdev);
- /* Clear the driver's (not device's) station table */
- iwl3945_clear_stations_table(priv);
-
- priv->data_retry_limit = -1;
- priv->ieee_channels = NULL;
- priv->ieee_rates = NULL;
- priv->band = IEEE80211_BAND_2GHZ;
-
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err)
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
@@ -7880,10 +7875,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (err)
goto out_pci_disable_device;
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_write_config_byte(pdev, 0x41, 0x00);
-
+ /***********************
+ * 3. Read REV Register
+ * ********************/
priv->hw_base = pci_iomap(pdev, 0, 0);
if (!priv->hw_base) {
err = -ENODEV;
@@ -7894,25 +7888,70 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
(unsigned long long) pci_resource_len(pdev, 0));
IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
- /* Initialize module parameter values here */
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
- /* Disable radio (SW RF KILL) via parameter when loading driver */
- if (iwl3945_param_disable) {
- set_bit(STATUS_RF_KILL_SW, &priv->status);
- IWL_DEBUG_INFO("Radio disabled.\n");
- }
+ /* nic init */
+ iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
- priv->iw_mode = NL80211_IFTYPE_STATION;
+ iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (err < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ goto out_remove_sysfs;
+ }
- printk(KERN_INFO DRV_NAME
- ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+ /***********************
+ * 4. Read EEPROM
+ * ********************/
+ /* Read the EEPROM */
+ err = iwl3945_eeprom_init(priv);
+ if (err) {
+ IWL_ERROR("Unable to init EEPROM\n");
+ goto out_remove_sysfs;
+ }
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ /***********************
+ * 5. Setup HW Constants
+ * ********************/
/* Device-specific setup */
if (iwl3945_hw_set_hw_setting(priv)) {
IWL_ERROR("failed to set hw settings\n");
goto out_iounmap;
}
+ /***********************
+ * 6. Setup priv
+ * ********************/
+ priv->retry_rate = 1;
+ priv->ibss_beacon = NULL;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+ mutex_init(&priv->mutex);
+
+ /* Clear the driver's (not device's) station table */
+ iwl3945_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->band = IEEE80211_BAND_2GHZ;
+
+ priv->iw_mode = NL80211_IFTYPE_STATION;
+
if (iwl3945_param_qos_enable)
priv->qos_data.qos_enable = 1;
@@ -7921,70 +7960,76 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->qos_data.qos_active = 0;
priv->qos_data.qos_cap.val = 0;
- iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
- iwl3945_setup_deferred_work(priv);
- iwl3945_setup_rx_handlers(priv);
priv->rates_mask = IWL_RATES_MASK;
/* If power management is turned on, default to AC mode */
priv->power_mode = IWL_POWER_AC;
priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
- spin_lock_irqsave(&priv->lock, flags);
- iwl3945_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+ err = iwl3945_init_channel_map(priv);
if (err) {
- IWL_ERROR("failed to create sysfs device attributes\n");
+ IWL_ERROR("initializing regulatory failed: %d\n", err);
goto out_release_irq;
}
- /* nic init */
- iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (err < 0) {
- IWL_DEBUG_INFO("Failed to init the card\n");
- goto out_remove_sysfs;
- }
- /* Read the EEPROM */
- err = iwl3945_eeprom_init(priv);
+ err = iwl3945_init_geos(priv);
if (err) {
- IWL_ERROR("Unable to init EEPROM\n");
- goto out_remove_sysfs;
+ IWL_ERROR("initializing geos failed: %d\n", err);
+ goto out_free_channel_map;
}
- /* MAC Address location in EEPROM same for 3945/4965 */
- get_eeprom_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
- err = iwl3945_init_channel_map(priv);
- if (err) {
- IWL_ERROR("initializing regulatory failed: %d\n", err);
- goto out_remove_sysfs;
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+
+ /***********************************
+ * 7. Initialize Module Parameters
+ * **********************************/
+
+ /* Initialize module parameter values here */
+ /* Disable radio (SW RF KILL) via parameter when loading driver */
+ if (iwl3945_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
}
- err = iwl3945_init_geos(priv);
+
+ /***********************
+ * 8. Setup Services
+ * ********************/
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl3945_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
if (err) {
- IWL_ERROR("initializing geos failed: %d\n", err);
- goto out_free_channel_map;
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ goto out_free_geos;
}
+ iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+ iwl3945_setup_deferred_work(priv);
+ iwl3945_setup_rx_handlers(priv);
+
+ /***********************
+ * 9. Conclude
+ * ********************/
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ /*********************************
+ * 10. Setup and Register mac80211
+ * *******************************/
+
err = ieee80211_register_hw(priv->hw);
if (err) {
IWL_ERROR("Failed to register network device (error %d)\n", err);
- goto out_free_geos;
+ goto out_remove_sysfs;
}
priv->hw->conf.beacon_int = 100;
priv->mac80211_registered = 1;
- pci_save_state(pdev);
- pci_disable_device(pdev);
+
err = iwl3945_rfkill_init(priv);
if (err)
@@ -7993,12 +8038,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
return 0;
+ out_remove_sysfs:
+ sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
out_free_geos:
iwl3945_free_geos(priv);
out_free_channel_map:
iwl3945_free_channel_map(priv);
- out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
out_release_irq:
destroy_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index d8b5cf389405..530648b39935 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -452,9 +452,9 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
hwsim_check_magic(vif);
if (conf->changed & IEEE80211_IFCC_BSSID) {
DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n",
+ printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
wiphy_name(hw->wiphy), __func__,
- print_mac(mac, conf->bssid));
+ conf->bssid);
memcpy(vp->bssid, conf->bssid, ETH_ALEN);
}
return 0;
@@ -612,9 +612,8 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
if (!vp->assoc)
return;
- printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n",
- wiphy_name(data->hw->wiphy), __func__,
- print_mac(buf, vp->bssid), vp->aid);
+ printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
+ wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
skb = dev_alloc_skb(sizeof(*pspoll));
if (!skb)
@@ -644,9 +643,8 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
if (!vp->assoc)
return;
- printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n",
- wiphy_name(data->hw->wiphy), __func__,
- print_mac(buf, vp->bssid), ps);
+ printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
+ wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
skb = dev_alloc_skb(sizeof(*hdr));
if (!skb)
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
index fd9263980d69..171bfa03868e 100644
--- a/drivers/net/wireless/orinoco/orinoco.c
+++ b/drivers/net/wireless/orinoco/orinoco.c
@@ -84,6 +84,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/firmware.h>
+#include <linux/suspend.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
@@ -431,9 +432,9 @@ struct fw_info {
};
const static struct fw_info orinoco_fw[] = {
- { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
- { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
- { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+ { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+ { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+ { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
};
/* Structure used to access fields in FW
@@ -487,18 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- if (priv->cached_fw)
- fw_entry = priv->cached_fw;
- else {
+ if (!priv->cached_fw) {
err = request_firmware(&fw_entry, firmware, priv->dev);
+
if (err) {
printk(KERN_ERR "%s: Cannot find firmware %s\n",
dev->name, firmware);
err = -ENOENT;
goto free;
}
- priv->cached_fw = fw_entry;
- }
+ } else
+ fw_entry = priv->cached_fw;
hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -540,11 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- /* In case of error, assume firmware was bogus and release it */
- if (err) {
- priv->cached_fw = NULL;
+ /* If we requested the firmware, release it. */
+ if (!priv->cached_fw)
release_firmware(fw_entry);
- }
free:
kfree(pda);
@@ -648,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv,
int ret;
const struct firmware *fw_entry;
- if (request_firmware(&fw_entry, fw->pri_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
- return -ENOENT;
- }
+ if (!priv->cached_pri_fw) {
+ if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->pri_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_pri_fw;
/* Load primary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 0);
- release_firmware(fw_entry);
+
+ if (!priv->cached_pri_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Primary firmware download failed\n",
dev->name);
return ret;
}
- if (request_firmware(&fw_entry, fw->sta_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
- return -ENOENT;
- }
+ if (!priv->cached_fw) {
+ if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->sta_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_fw;
/* Load secondary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 1);
- release_firmware(fw_entry);
+ if (!priv->cached_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Secondary firmware download failed\n",
dev->name);
@@ -708,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv)
return err;
}
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+static void orinoco_cache_fw(struct orinoco_private *priv, int ap)
+{
+ const struct firmware *fw_entry = NULL;
+ const char *pri_fw;
+ const char *fw;
+
+ pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+ if (ap)
+ fw = orinoco_fw[priv->firmware_type].ap_fw;
+ else
+ fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+ if (pri_fw) {
+ if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+ priv->cached_pri_fw = fw_entry;
+ }
+
+ if (fw) {
+ if (request_firmware(&fw_entry, fw, priv->dev) == 0)
+ priv->cached_fw = fw_entry;
+ }
+}
+
+static void orinoco_uncache_fw(struct orinoco_private *priv)
+{
+ if (priv->cached_pri_fw)
+ release_firmware(priv->cached_pri_fw);
+ if (priv->cached_fw)
+ release_firmware(priv->cached_fw);
+
+ priv->cached_pri_fw = NULL;
+ priv->cached_fw = NULL;
+}
+#else
+#define orinoco_cache_fw(priv, ap)
+#define orinoco_uncache_fw(priv)
+#endif
+
/********************************************************************/
/* Device methods */
/********************************************************************/
@@ -809,7 +853,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
wstats->qual.qual = (int)le16_to_cpu(cq.qual);
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
- wstats->qual.updated = 7;
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
}
}
@@ -1168,7 +1212,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
wstats.level = level - 0x95;
wstats.noise = noise - 0x95;
wstats.qual = (level > noise) ? (level - noise) : 0;
- wstats.updated = 7;
+ wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
/* Update spy records */
wireless_spy_update(dev, mac, &wstats);
}
@@ -3062,6 +3106,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
}
/********************************************************************/
+/* Power management */
+/********************************************************************/
+#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+ unsigned long pm_event,
+ void *unused)
+{
+ struct orinoco_private *priv = container_of(notifier,
+ struct orinoco_private,
+ pm_notifier);
+
+ /* All we need to do is cache the firmware before suspend, and
+ * release it when we come out.
+ *
+ * Only need to do this if we're downloading firmware. */
+ if (!priv->do_fw_download)
+ return NOTIFY_DONE;
+
+ switch (pm_event) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ orinoco_cache_fw(priv, 0);
+ break;
+
+ case PM_POST_RESTORE:
+ /* Restore from hibernation failed. We need to clean
+ * up in exactly the same way, so fall through. */
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ orinoco_uncache_fw(priv);
+ break;
+
+ case PM_RESTORE_PREPARE:
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
+#define orinoco_pm_notifier NULL
+#endif
+
+/********************************************************************/
/* Initialization */
/********************************************************************/
@@ -3304,6 +3392,10 @@ static int orinoco_init(struct net_device *dev)
}
if (priv->do_fw_download) {
+#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
+ orinoco_cache_fw(priv, 0);
+#endif
+
err = orinoco_download(priv);
if (err)
priv->do_fw_download = 0;
@@ -3540,8 +3632,13 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
+ priv->cached_pri_fw = NULL;
priv->cached_fw = NULL;
+ /* Register PM notifiers */
+ priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+ register_pm_notifier(&priv->pm_notifier);
+
return dev;
}
@@ -3553,9 +3650,10 @@ void free_orinocodev(struct net_device *dev)
* when we call tasklet_kill it will run one final time,
* emptying the list */
tasklet_kill(&priv->rx_tasklet);
- if (priv->cached_fw)
- release_firmware(priv->cached_fw);
- priv->cached_fw = NULL;
+
+ unregister_pm_notifier(&priv->pm_notifier);
+ orinoco_uncache_fw(priv);
+
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 8c2953834923..00750c8ba7db 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -10,6 +10,7 @@
#define DRIVER_VERSION "0.15"
#include <linux/interrupt.h>
+#include <linux/suspend.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
@@ -167,8 +168,11 @@ struct orinoco_private {
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
- /* Cached in memory firmware to use in ->resume */
+ /* Cached in memory firmware to use during ->resume. */
+ const struct firmware *cached_pri_fw;
const struct firmware *cached_fw;
+
+ struct notifier_block pm_notifier;
};
#ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 0bae3dcf9d50..a2764764c1c0 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -450,10 +450,29 @@ spectrum_cs_resume(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ err = orinoco_reinit_firmware(dev);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable--;
- schedule_work(&priv->reset_work);
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(dev);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index b585ff65e0e4..491ab96c7b67 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -102,6 +102,9 @@ struct p54_common {
unsigned int output_power;
u32 tsf_low32;
u32 tsf_high32;
+ u64 basic_rate_mask;
+ u16 wakeup_timer;
+ u16 aid;
struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
struct ieee80211_low_level_stats stats;
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 1796b8c6c5b8..602392628e4e 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -530,6 +530,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.noise = priv->noise;
/* XX correct? */
rx_status.qual = (100 * hdr->rssi) / 127;
+ if (hdr->rate & 0x10)
+ rx_status.flag |= RX_FLAG_SHORTPRE;
rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
hdr->rate : (hdr->rate - 4)) & 0xf;
rx_status.freq = freq;
@@ -576,7 +578,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
unsigned long flags;
u32 freed = 0, last_addr = priv->rx_start;
- if (!skb || !dev)
+ if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
return;
spin_lock_irqsave(&priv->tx_queue.lock, flags);
@@ -1058,6 +1060,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
*aid = 0;
*queue = 3;
@@ -1198,7 +1201,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
txhdr->key_type = 0;
txhdr->key_len = 0;
txhdr->hw_queue = queue;
- txhdr->backlog = 32;
+ if (current_queue)
+ txhdr->backlog = current_queue->len;
+ else
+ txhdr->backlog = 0;
memset(txhdr->durations, 0, sizeof(txhdr->durations));
txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
2 : info->antenna_sel_tx - 1;
@@ -1243,20 +1249,20 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
setup->rx_antenna = priv->rx_antenna;
setup->rx_align = 0;
if (priv->fw_var < 0x500) {
- setup->v1.basic_rate_mask = cpu_to_le32(0x15f);
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
memset(setup->v1.rts_rates, 0, 8);
setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
setup->v1.rxhw = cpu_to_le16(priv->rxhw);
- setup->v1.wakeup_timer = cpu_to_le16(500);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
setup->v1.unalloc0 = cpu_to_le16(0);
} else {
setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
setup->v2.rxhw = cpu_to_le16(priv->rxhw);
- setup->v2.timer = cpu_to_le16(1000);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
setup->v2.truncate = cpu_to_le16(48896);
- setup->v2.basic_rate_mask = cpu_to_le32(0x15f);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
setup->v2.sbss_offset = 0;
setup->v2.mcast_window = 0;
setup->v2.rx_rssi_threshold = 0;
@@ -1342,7 +1348,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency)
} else {
chan->v2.rssical_mul = cpu_to_le16(130);
chan->v2.rssical_add = cpu_to_le16(0xfe70);
- chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
+ chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
memset(chan->v2.rts_rates, 0, 8);
}
priv->tx(dev, skb, 1);
@@ -1518,16 +1524,24 @@ static int p54_start(struct ieee80211_hw *dev)
mutex_lock(&priv->conf_mutex);
err = priv->open(dev);
- if (!err)
- priv->mode = NL80211_IFTYPE_MONITOR;
+ if (err)
+ goto out;
P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
err = p54_set_edcf(dev);
- if (!err)
- err = p54_init_stats(dev);
+ if (err)
+ goto out;
+ err = p54_init_stats(dev);
+ if (err)
+ goto out;
+ err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
+ if (err)
+ goto out;
+ priv->mode = NL80211_IFTYPE_MONITOR;
+out:
mutex_unlock(&priv->conf_mutex);
return err;
}
@@ -1547,7 +1561,6 @@ static void p54_stop(struct ieee80211_hw *dev)
while ((skb = skb_dequeue(&priv->tx_queue)))
kfree_skb(skb);
- kfree(priv->cached_beacon);
priv->cached_beacon = NULL;
priv->stop(dev);
priv->tsf_high32 = priv->tsf_low32 = 0;
@@ -1570,6 +1583,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
priv->mode = conf->type;
break;
default:
@@ -1589,6 +1603,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
break;
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
break;
default:
@@ -1653,6 +1668,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
ret = p54_set_freq(dev, dev->conf.channel->center_freq);
if (ret)
@@ -1712,10 +1728,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
if ((params) && !(queue > 4)) {
P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(dev);
} else
ret = -EINVAL;
- if (!ret)
- ret = p54_set_edcf(dev);
mutex_unlock(&priv->conf_mutex);
return ret;
}
@@ -1792,6 +1807,24 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
priv->use_short_slot = info->use_short_slot;
p54_set_edcf(dev);
}
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+ if (priv->fw_var >= 0x500)
+ p54_set_freq(dev, dev->conf.channel->center_freq);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+ }
+ }
+
}
static const struct ieee80211_ops p54_ops = {
@@ -1821,14 +1854,16 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
priv = dev->priv;
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
skb_queue_head_init(&priv->tx_queue);
dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION |
- NL80211_IFTYPE_ADHOC |
- NL80211_IFTYPE_AP);
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
dev->channel_change_time = 1000; /* TODO: find actual value */
priv->tx_stats[0].limit = 1; /* Beacon queue */
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 8c8793cb2d79..3419f16be938 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -259,7 +259,7 @@ enum p54_rx_decrypt_status {
P54_DECRYPT_NOCKIPMIC,
P54_DECRYPT_FAIL_WEP,
P54_DECRYPT_FAIL_TKIP,
- P54_DECRYPT_FAIL_MICAHEL,
+ P54_DECRYPT_FAIL_MICHAEL,
P54_DECRYPT_FAIL_CKIPKP,
P54_DECRYPT_FAIL_CKIPMIC,
P54_DECRYPT_FAIL_AESCCMP
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index c4a868ae6d6b..d21c509325fe 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table);
static int p54p_upload_firmware(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
- const struct firmware *fw_entry = NULL;
__le32 reg;
int err;
__le32 *data;
@@ -73,23 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_WRITE(ctrl_stat, reg);
wmb();
- err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev);
- if (err) {
- printk(KERN_ERR "%s (p54pci): cannot find firmware "
- "(isl3886pci)\n", pci_name(priv->pdev));
- err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
- if (err)
- return err;
- }
+ /* wait for the firmware to reset properly */
+ mdelay(10);
- err = p54_parse_firmware(dev, fw_entry);
- if (err) {
- release_firmware(fw_entry);
+ err = p54_parse_firmware(dev, priv->firmware);
+ if (err)
return err;
- }
- data = (__le32 *) fw_entry->data;
- remains = fw_entry->size;
+ data = (__le32 *) priv->firmware->data;
+ remains = priv->firmware->size;
device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
while (remains) {
u32 i = 0;
@@ -107,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_READ(int_enable);
}
- release_firmware(fw_entry);
-
reg = P54P_READ(ctrl_stat);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
@@ -500,15 +489,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
if (mem_len < sizeof(struct p54p_csr)) {
printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
pci_name(pdev));
- pci_disable_device(pdev);
- return err;
+ goto err_disable_dev;
}
err = pci_request_regions(pdev, "p54pci");
if (err) {
printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
pci_name(pdev));
- return err;
+ goto err_disable_dev;
}
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
@@ -561,6 +549,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
+ err = request_firmware(&priv->firmware, "isl3886pci",
+ &priv->pdev->dev);
+ if (err) {
+ printk(KERN_ERR "%s (p54pci): cannot find firmware "
+ "(isl3886pci)\n", pci_name(priv->pdev));
+ err = request_firmware(&priv->firmware, "isl3886",
+ &priv->pdev->dev);
+ if (err)
+ goto err_free_common;
+ }
+
err = p54p_open(dev);
if (err)
goto err_free_common;
@@ -579,6 +578,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
return 0;
err_free_common:
+ release_firmware(priv->firmware);
p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -592,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_reg:
pci_release_regions(pdev);
+ err_disable_dev:
pci_disable_device(pdev);
return err;
}
@@ -606,6 +607,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
ieee80211_unregister_hw(dev);
priv = dev->priv;
+ release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
p54_free_common(dev);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 4a6778070afc..fbb683953fb2 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -93,7 +93,7 @@ struct p54p_priv {
struct pci_dev *pdev;
struct p54p_csr __iomem *map;
struct tasklet_struct rx_tasklet;
-
+ const struct firmware *firmware;
spinlock_t lock;
struct p54p_ring_control *ring_control;
dma_addr_t ring_control_dma;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 78fca1bcc544..6a977679124d 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -49,20 +49,10 @@
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
- if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -72,31 +62,20 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
}
static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -107,75 +86,55 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- /*
- * Write the request into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- *value = 0xff;
}
static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
mutex_lock(&rt2x00dev->csr_mutex);
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
- if (!rt2x00_get_field32(reg, RFCSR_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
}
mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, RFCSR_VALUE, value);
- rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
- rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
- rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 972b5a5c3864..d3bc218ec85c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -49,20 +49,10 @@
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
- if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -72,31 +62,20 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
-
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
}
static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -107,75 +86,55 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- /*
- * Write the request into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
-
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY))
- goto exit_fail;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- *value = 0xff;
}
static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
mutex_lock(&rt2x00dev->csr_mutex);
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
- if (!rt2x00_get_field32(reg, RFCSR_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
}
mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, RFCSR_VALUE, value);
- rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
- rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
- rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
-
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index e6bae4ae4c47..0447e93306ad 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -57,7 +57,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
__le16 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg);
}
@@ -68,7 +68,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
__le16 reg;
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg);
}
@@ -89,7 +89,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
__le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
}
static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
@@ -99,7 +99,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
__le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
}
static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
@@ -112,21 +112,32 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
REGISTER_TIMEOUT16(length));
}
-static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field16 field,
+ u16 *reg)
{
- u16 reg;
unsigned int i;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
- if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- break;
+ rt2500usb_register_read_lock(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field16(*reg, field))
+ return 1;
udelay(REGISTER_BUSY_DELAY);
}
- return reg;
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg))
+
static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
@@ -135,30 +146,19 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
- rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
- rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
-
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
- return;
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
}
static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -169,77 +169,57 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
-
- /*
- * Write the request into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
- rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg))
+ rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
+ }
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- *value = 0xff;
}
static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u16 reg;
- unsigned int i;
if (!word)
return;
mutex_lock(&rt2x00dev->csr_mutex);
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
- if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -1128,7 +1108,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
int length;
u16 reg;
@@ -1154,7 +1134,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
*/
- length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
entry->skb->data, length, rt2500usb_beacondone,
@@ -1176,8 +1156,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
}
-static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb)
+static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -1185,8 +1164,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
* The length _must_ be a multiple of 2,
* but it must _not_ be a multiple of the USB packet size.
*/
- length = roundup(skb->len, 2);
- length += (2 * !(length % rt2x00dev->usb_maxpacket));
+ length = roundup(entry->skb->len, 2);
+ length += (2 * !(length % entry->queue->usb_maxpacket));
return length;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index fee61bee1e7e..780ba7365810 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -555,8 +555,7 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry);
void (*write_beacon) (struct queue_entry *entry);
- int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb);
+ int (*get_tx_data_len) (struct queue_entry *entry);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue);
@@ -799,11 +798,6 @@ struct rt2x00_dev {
short lna_gain;
/*
- * USB Max frame size (for rt2500usb & rt73usb).
- */
- u16 usb_maxpacket;
-
- /*
* Current TX power value.
*/
u16 tx_power;
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index 66c61b1eca5d..68f4e0fc35b9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -111,12 +111,6 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
led->led_dev.name = name;
led->led_dev.brightness = LED_OFF;
- /*
- * Ensure the LED is off, it might have been enabled
- * by the hardware when the device was powered on.
- */
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
-
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
ERROR(rt2x00dev, "Failed to register led handler.\n");
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 48636b0dd895..4c0395729066 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -132,8 +132,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n", qid, DRV_PROJECT);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ goto exit_fail;
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index e33bd0f150c5..d52b22b82d1f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -32,6 +32,31 @@
#include "rt2x00pci.h"
/*
+ * Register access.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
+
+/*
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct queue_entry *entry)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 96a2082a3532..9c0a4d77bc1b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -77,6 +77,24 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
}
/**
+ * rt2x00pci_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg);
+
+/**
* rt2x00pci_write_tx_data - Initialize data for TX operation
* @entry: The entry where the frame is located
*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index d7752dbd2023..b8de9d2750e4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -386,7 +386,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
u8 rate_idx, rate_flags;
if (unlikely(rt2x00queue_full(queue)))
- return -EINVAL;
+ return -ENOBUFS;
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(queue->rt2x00dev,
@@ -415,7 +415,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
tx_info = IEEE80211_SKB_CB(skb);
rate_idx = tx_info->control.rates[0].idx;
rate_flags = tx_info->control.rates[0].flags;
- skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
skbdesc->tx_rate_idx = rate_idx;
@@ -427,20 +427,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
* the frame so we can provide it to the driver seperately.
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
- !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
+ !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags))
rt2x00crypto_tx_remove_iv(skb, iv_len);
- }
/*
* It could be possible that the queue was corrupted and this
- * call failed. Just drop the frame, we cannot rollback and pass
- * the frame to mac80211 because the skb->cb has now been tainted.
+ * call failed. Since we always return NETDEV_TX_OK to mac80211,
+ * this frame will simply be dropped.
*/
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
- return 0;
+ return -EIO;
}
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 4d3c7246f9ae..2e99ab53ec65 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -380,6 +380,8 @@ enum queue_index {
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
* @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data in this queue.
+ * @usb_endpoint: Device endpoint used for communication (USB only)
+ * @usb_maxpacket: Max packet size for given endpoint (USB only)
*/
struct data_queue {
struct rt2x00_dev *rt2x00dev;
@@ -401,6 +403,9 @@ struct data_queue {
unsigned short data_size;
unsigned short desc_size;
+
+ unsigned short usb_endpoint;
+ unsigned short usb_maxpacket;
};
/**
@@ -444,6 +449,19 @@ struct data_queue_desc {
&(__dev)->tx[(__dev)->ops->tx_queues]
/**
+ * queue_next - Return pointer to next queue in list (HELPER MACRO).
+ * @__queue: Current queue for which we need the next queue
+ *
+ * Using the current queue address we take the address directly
+ * after the queue to take the next queue. Note that this macro
+ * should be used carefully since it does not protect against
+ * moving past the end of the list. (See macros &queue_end and
+ * &tx_queue_end for determining the end of the queue).
+ */
+#define queue_next(__queue) \
+ &(__queue)[1]
+
+/**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO).
* @__entry: Pointer where the current queue entry will be stored in.
* @__start: Start queue pointer.
@@ -453,8 +471,8 @@ struct data_queue_desc {
*/
#define queue_loop(__entry, __start, __end) \
for ((__entry) = (__start); \
- prefetch(&(__entry)[1]), (__entry) != (__end); \
- (__entry) = &(__entry)[1])
+ prefetch(queue_next(__entry)), (__entry) != (__end);\
+ (__entry) = queue_next(__entry))
/**
* queue_for_each - Loop through all queues
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index c507b0d9409f..83df312ac56f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -154,6 +154,28 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
/*
* TX data handlers.
*/
@@ -212,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
*/
- length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, 1),
+ usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
@@ -356,10 +378,11 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
struct usb_device *usb_dev =
to_usb_device_intf(entry->queue->rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ int pipe;
if (entry->queue->qid == QID_RX) {
- usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_rcvbulkpipe(usb_dev, 1),
+ pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
@@ -371,6 +394,76 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+ struct usb_endpoint_descriptor *ep_desc)
+{
+ struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+ int pipe;
+
+ queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+ if (queue->qid == QID_RX) {
+ pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+ } else {
+ pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+ }
+
+ if (!queue->usb_maxpacket)
+ queue->usb_maxpacket = 1;
+}
+
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
+{
+ struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+ struct usb_host_interface *intf_desc = intf->cur_altsetting;
+ struct usb_endpoint_descriptor *ep_desc;
+ struct data_queue *queue = rt2x00dev->tx;
+ struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+ unsigned int i;
+
+ /*
+ * Walk through all available endpoints to search for "bulk in"
+ * and "bulk out" endpoints. When we find such endpoints collect
+ * the information we need from the descriptor and assign it
+ * to the queue.
+ */
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &intf_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc)) {
+ rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+ } else if (usb_endpoint_is_bulk_out(ep_desc)) {
+ rt2x00usb_assign_endpoint(queue, ep_desc);
+
+ if (queue != queue_end(rt2x00dev))
+ queue = queue_next(queue);
+ tx_ep_desc = ep_desc;
+ }
+ }
+
+ /*
+ * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+ */
+ if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+ ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+ return -EPIPE;
+ }
+
+ /*
+ * It might be possible not all queues have a dedicated endpoint.
+ * Loop through all TX queues and copy the endpoint information
+ * which we have gathered from already assigned endpoints.
+ */
+ txall_queue_for_each(rt2x00dev, queue) {
+ if (!queue->usb_endpoint)
+ rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+ }
+
+ return 0;
+}
+
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
@@ -442,6 +535,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
int status;
/*
+ * Find endpoints for each queue
+ */
+ status = rt2x00usb_find_endpoints(rt2x00dev);
+ if (status)
+ goto exit;
+
+ /*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
@@ -532,11 +632,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
- rt2x00dev->usb_maxpacket =
- usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
- if (!rt2x00dev->usb_maxpacket)
- rt2x00dev->usb_maxpacket = 1;
-
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 4104f0e8fa48..2bd4ac855f52 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
REGISTER_TIMEOUT16(length));
}
+/**
+ * rt2x00usb_regbusy_read - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_read_lock - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_multiread - Read 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length,
+ REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_register_write - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_write_lock - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_multiwrite - Write 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length,
+ REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field32 field,
+ u32 *reg);
+
/*
* Radio handlers
*/
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 89ac34fbadf2..d54443c25fe3 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -55,20 +55,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+ H2M_MAILBOX_CSR_OWNER, (__reg))
static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -78,30 +71,20 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
- */
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
- mutex_unlock(&rt2x00dev->csr_mutex);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
- return;
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
}
static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -112,72 +95,53 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
- /*
- * Write the request into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
-
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
}
static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
mutex_lock(&rt2x00dev->csr_mutex);
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
- rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
- rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -196,32 +160,25 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
- rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
-
- if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER))
- goto exit_fail;
-
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
-
- rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
- rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
- rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
- rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
+ /*
+ * Wait until the MCU becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
- return;
+ rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev,
- "mcu request error. Request 0x%02x failed for token 0x%02x.\n",
- command, token);
}
#endif /* CONFIG_RT2X00_LIB_LEDS */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index d1a63e0017da..37a782dc8080 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
* Register access.
* All access to the CSR registers will go through the methods
- * rt73usb_register_read and rt73usb_register_write.
+ * rt2x00usb_register_read and rt2x00usb_register_write.
* BBP and RF register require indirect register access,
* and use the CSR registers BBPCSR and RFCSR to achieve this.
* These indirect registers work with busy bits,
@@ -57,78 +57,10 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* and we will print an error.
* The _lock versions must be used if you already hold the csr_mutex
*/
-static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 *value)
-{
- __le32 reg;
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
- *value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 *value)
-{
- __le32 reg;
- rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
- *value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- value, length,
- REGISTER_TIMEOUT32(length));
-}
-
-static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 value)
-{
- __le32 reg = cpu_to_le32(value);
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 value)
-{
- __le32 reg = cpu_to_le32(value);
- rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- value, length,
- REGISTER_TIMEOUT32(length));
-}
-
-static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -138,30 +70,20 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+ }
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
}
static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -172,79 +94,59 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
- /*
- * Write the request into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
-
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
- mutex_unlock(&rt2x00dev->csr_mutex);
- return;
-
-exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
}
static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
mutex_lock(&rt2x00dev->csr_mutex);
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- mutex_unlock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
-
/*
- * RF5225 and RF2527 contain 21 bits per RF register value,
- * all others contain 20 bits.
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
- 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527)));
- rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
- rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
-
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ /*
+ * RF5225 and RF2527 contain 21 bits per RF register value,
+ * all others contain 20 bits.
+ */
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+ 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527)));
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -253,8 +155,8 @@ rf_write:
static const struct rt2x00debug rt73usb_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt73usb_register_read,
- .write = rt73usb_register_write,
+ .read = rt2x00usb_register_read,
+ .write = rt2x00usb_register_write,
.flags = RT2X00DEBUGFS_OFFSET,
.word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
@@ -333,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg;
- rt73usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
+ rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
- rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
+ rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
return 0;
}
@@ -379,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = (0xf << crypto->bssidx);
- rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
reg &= mask;
if (reg && reg == mask)
@@ -416,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
field.bit_offset = (3 * key->hw_key_idx);
field.bit_mask = 0x7 << field.bit_offset;
- rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR1, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg);
} else {
field.bit_offset = (3 * (key->hw_key_idx - 8));
field.bit_mask = 0x7 << field.bit_offset;
- rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR5, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg);
}
/*
@@ -448,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = 1 << key->hw_key_idx;
- rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg);
return 0;
}
@@ -478,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* When both registers are full, we drop the key,
* otherwise we use the first invalid entry.
*/
- rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
if (reg && reg == ~0) {
key->hw_key_idx = 32;
- rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
if (reg && reg == ~0)
return -ENOSPC;
}
@@ -509,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* Send the address and cipher type to the hardware register.
* This data fits within the CSR cache size, so we can use
- * rt73usb_register_multiwrite() directly.
+ * rt2x00usb_register_multiwrite() directly.
*/
memset(&addr_entry, 0, sizeof(addr_entry));
memcpy(&addr_entry, crypto->address, ETH_ALEN);
addr_entry.cipher = crypto->cipher;
reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
- rt73usb_register_multiwrite(rt2x00dev, reg,
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
&addr_entry, sizeof(addr_entry));
/*
@@ -524,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* without this received frames will not be decrypted
* by the hardware.
*/
- rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR4, &reg);
reg |= (1 << crypto->bssidx);
- rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg);
/*
* The driver does not support the IV/EIV generation
@@ -549,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
if (key->hw_key_idx < 32) {
mask = 1 << key->hw_key_idx;
- rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg);
} else {
mask = 1 << (key->hw_key_idx - 32);
- rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg);
}
return 0;
@@ -580,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
* and broadcast frames will always be accepted since
* there is no filter for it at this time.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
@@ -598,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
!(filter_flags & FIF_CONTROL));
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -617,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
* bits which (when set to 0) will invalidate the entire beacon.
*/
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt73usb_register_write(rt2x00dev, beacon_base, 0);
+ rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
/*
* Enable synchronisation.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
@@ -634,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg);
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
+ rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2,
conf->mac, sizeof(conf->mac));
}
@@ -643,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg);
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
+ rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4,
conf->bssid, sizeof(conf->bssid));
}
}
@@ -653,26 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
- rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
- rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
- rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
- rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR8, &reg);
rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
- rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
}
static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -818,14 +720,14 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
- rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, PHY_CSR0, &reg);
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
(rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
(rt2x00dev->curr_band == IEEE80211_BAND_5GHZ));
- rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
rt2x00_rf(&rt2x00dev->chip, RF5225))
@@ -915,12 +817,12 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
libconf->conf->short_frame_max_tx_count);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
}
static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -928,18 +830,18 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
libconf->conf->beacon_int * 16);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
@@ -972,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update FCS error count from register.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
/*
* Update False CCA count from register.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
@@ -1138,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
* Wait for stable hardware.
*/
for (i = 0; i < 100; i++) {
- rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg)
break;
msleep(1);
@@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
@@ -1195,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg);
/*
* CCK TXD BBP registers
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
@@ -1209,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg);
/*
* OFDM TXD BBP registers
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
- rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
- rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
- rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
- rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR6, &reg);
rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
- rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg);
- rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY;
- rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
/*
* Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
*/
- rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
- rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
- rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
reg = 0x000023b0;
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527))
rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
- rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
- rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
- rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
- rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
- rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
- rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
/*
* Clear all beacons
@@ -1287,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
* the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon.
*/
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
/*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
- rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
- rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR2, &reg);
/*
* Reset MAC and BBP registers.
*/
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
return 0;
}
@@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
(state == STATE_RADIO_RX_OFF) ||
(state == STATE_RADIO_RX_OFF_LINK));
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1415,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
/*
* Disable synchronisation.
*/
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0);
rt2x00usb_disable_radio(rt2x00dev);
}
@@ -1433,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
put_to_sleep = (state != STATE_AWAKE);
- rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
- rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg);
/*
* Device is not guaranteed to be in the requested state yet.
@@ -1444,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
* device has entered the correct state.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
if (state == !put_to_sleep)
return 0;
@@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Write entire beacon with descriptor to register.
@@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
entry->skb = NULL;
}
-static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb)
+static int rt73usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -1615,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
* The length _must_ be a multiple of 4,
* but it must _not_ be a multiple of the USB packet size.
*/
- length = roundup(skb->len, 4);
- length += (4 * !(length % rt2x00dev->usb_maxpacket));
+ length = roundup(entry->skb->len, 4);
+ length += (4 * !(length % entry->queue->usb_maxpacket));
return length;
}
@@ -1635,14 +1536,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
* For Wi-Fi faily generated beacons between participating stations.
* Set TBTT phase adaptive adjustment step to 8us (default 16us)
*/
- rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
}
@@ -1881,7 +1782,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
- rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) {
@@ -2235,33 +2136,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
field.bit_offset = queue_idx * 16;
field.bit_mask = 0xffff << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
- rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
} else if (queue_idx < 4) {
field.bit_offset = (queue_idx - 2) * 16;
field.bit_mask = 0xffff << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
- rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
}
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->aifs);
- rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg);
- rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_min);
- rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg);
- rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_max);
- rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0;
}
@@ -2279,9 +2180,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
u64 tsf;
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
- rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
return tsf;
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 33725d0978b3..c385407a9941 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -111,6 +111,13 @@ struct rtl8187_priv {
u8 signal;
u8 quality;
u8 noise;
+ u8 slot_time;
+ u8 aifsn[4];
+ struct {
+ __le64 buf;
+ struct urb *urb;
+ struct sk_buff_head queue;
+ } b_tx_status;
};
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 4a9f76f46f77..69ea5222f163 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -176,8 +176,27 @@ static void rtl8187_tx_cb(struct urb *urb)
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
sizeof(struct rtl8187_tx_hdr));
ieee80211_tx_info_clear_status(info);
- info->flags |= IEEE80211_TX_STAT_ACK;
- ieee80211_tx_status_irqsafe(hw, skb);
+
+ if (!urb->status &&
+ !(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ priv->is_rtl8187b) {
+ skb_queue_tail(&priv->b_tx_status.queue, skb);
+
+ /* queue is "full", discard last items */
+ while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
+ struct sk_buff *old_skb;
+
+ dev_dbg(&priv->udev->dev,
+ "transmit status queue full\n");
+
+ old_skb = skb_dequeue(&priv->b_tx_status.queue);
+ ieee80211_tx_status_irqsafe(hw, old_skb);
+ }
+ } else {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status_irqsafe(hw, skb);
+ }
}
static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -219,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
hdr->flags = cpu_to_le32(flags);
hdr->len = 0;
hdr->rts_duration = rts_dur;
- hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+ hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
buf = hdr;
ep = 2;
@@ -237,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
memset(hdr, 0, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags);
hdr->rts_duration = rts_dur;
- hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
+ hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
hdr->tx_duration =
ieee80211_generic_frame_duration(dev, priv->vif,
skb->len, txrate);
@@ -403,6 +422,109 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
return 0;
}
+static void rtl8187b_status_cb(struct urb *urb)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context;
+ struct rtl8187_priv *priv = hw->priv;
+ u64 val;
+ unsigned int cmd_type;
+
+ if (unlikely(urb->status)) {
+ usb_free_urb(urb);
+ return;
+ }
+
+ /*
+ * Read from status buffer:
+ *
+ * bits [30:31] = cmd type:
+ * - 0 indicates tx beacon interrupt
+ * - 1 indicates tx close descriptor
+ *
+ * In the case of tx beacon interrupt:
+ * [0:9] = Last Beacon CW
+ * [10:29] = reserved
+ * [30:31] = 00b
+ * [32:63] = Last Beacon TSF
+ *
+ * If it's tx close descriptor:
+ * [0:7] = Packet Retry Count
+ * [8:14] = RTS Retry Count
+ * [15] = TOK
+ * [16:27] = Sequence No
+ * [28] = LS
+ * [29] = FS
+ * [30:31] = 01b
+ * [32:47] = unused (reserved?)
+ * [48:63] = MAC Used Time
+ */
+ val = le64_to_cpu(priv->b_tx_status.buf);
+
+ cmd_type = (val >> 30) & 0x3;
+ if (cmd_type == 1) {
+ unsigned int pkt_rc, seq_no;
+ bool tok;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *ieee80211hdr;
+ unsigned long flags;
+
+ pkt_rc = val & 0xFF;
+ tok = val & (1 << 15);
+ seq_no = (val >> 16) & 0xFFF;
+
+ spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
+ skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) {
+ ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+
+ /*
+ * While testing, it was discovered that the seq_no
+ * doesn't actually contains the sequence number.
+ * Instead of returning just the 12 bits of sequence
+ * number, hardware is returning entire sequence control
+ * (fragment number plus sequence number) in a 12 bit
+ * only field overflowing after some time. As a
+ * workaround, just consider the lower bits, and expect
+ * it's unlikely we wrongly ack some sent data
+ */
+ if ((le16_to_cpu(ieee80211hdr->seq_ctrl)
+ & 0xFFF) == seq_no)
+ break;
+ }
+ if (skb != (struct sk_buff *) &priv->b_tx_status.queue) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ __skb_unlink(skb, &priv->b_tx_status.queue);
+ if (tok)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.rates[0].count = pkt_rc + 1;
+
+ ieee80211_tx_status_irqsafe(hw, skb);
+ }
+ spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ struct urb *entry;
+
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ priv->b_tx_status.urb = entry;
+
+ usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
+ &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
+ rtl8187b_status_cb, dev);
+
+ usb_submit_urb(entry, GFP_KERNEL);
+
+ return 0;
+}
+
static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
@@ -712,6 +834,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1);
+ priv->slot_time = 0x9;
+ priv->aifsn[0] = 2; /* AIFSN[AC_VO] */
+ priv->aifsn[1] = 2; /* AIFSN[AC_VI] */
+ priv->aifsn[2] = 7; /* AIFSN[AC_BK] */
+ priv->aifsn[3] = 3; /* AIFSN[AC_BE] */
+ rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
+
return 0;
}
@@ -748,6 +877,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 0 /* long retry limit */) |
(7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev);
+ rtl8187b_init_status_urb(dev);
mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -824,6 +954,9 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
usb_kill_urb(info->urb);
kfree_skb(skb);
}
+ while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
+ dev_kfree_skb_any(skb);
+ usb_kill_urb(priv->b_tx_status.urb);
mutex_unlock(&priv->conf_mutex);
}
@@ -919,24 +1052,38 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
return 0;
}
+/*
+ * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for
+ * example. Thus we have to use raw values for AC_*_PARAM register addresses.
+ */
+static __le32 *rtl8187b_ac_addr[4] = {
+ (__le32 *) 0xFFF0, /* AC_VO */
+ (__le32 *) 0xFFF4, /* AC_VI */
+ (__le32 *) 0xFFFC, /* AC_BK */
+ (__le32 *) 0xFFF8, /* AC_BE */
+};
+
+#define SIFS_TIME 0xa
+
static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
bool use_short_preamble)
{
if (priv->is_rtl8187b) {
- u8 difs, eifs, slot_time;
+ u8 difs, eifs;
u16 ack_timeout;
+ int queue;
if (use_short_slot) {
- slot_time = 0x9;
+ priv->slot_time = 0x9;
difs = 0x1c;
eifs = 0x53;
} else {
- slot_time = 0x14;
+ priv->slot_time = 0x14;
difs = 0x32;
eifs = 0x5b;
}
- rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa);
- rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time);
+ rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+ rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
rtl818x_iowrite8(priv, &priv->map->DIFS, difs);
/*
@@ -957,18 +1104,21 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
ack_timeout += 144;
rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER,
DIV_ROUND_UP(ack_timeout, 4));
+
+ for (queue = 0; queue < 4; queue++)
+ rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue],
+ priv->aifsn[queue] * priv->slot_time +
+ SIFS_TIME);
} else {
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
if (use_short_slot) {
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
} else {
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
}
}
}
@@ -1017,6 +1167,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
}
+static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u8 cw_min, cw_max;
+
+ if (queue > 3)
+ return -EINVAL;
+
+ cw_min = fls(params->cw_min);
+ cw_max = fls(params->cw_max);
+
+ if (priv->is_rtl8187b) {
+ priv->aifsn[queue] = params->aifs;
+
+ /*
+ * This is the structure of AC_*_PARAM registers in 8187B:
+ * - TXOP limit field, bit offset = 16
+ * - ECWmax, bit offset = 12
+ * - ECWmin, bit offset = 8
+ * - AIFS, bit offset = 0
+ */
+ rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue],
+ (params->txop << 16) | (cw_max << 12) |
+ (cw_min << 8) | (params->aifs *
+ priv->slot_time + SIFS_TIME));
+ } else {
+ if (queue != 0)
+ return -EINVAL;
+
+ rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+ cw_min | (cw_max << 4));
+ }
+ return 0;
+}
+
static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx,
.start = rtl8187_start,
@@ -1027,6 +1213,7 @@ static const struct ieee80211_ops rtl8187_ops = {
.config_interface = rtl8187_config_interface,
.bss_info_changed = rtl8187_bss_info_changed,
.configure_filter = rtl8187_configure_filter,
+ .conf_tx = rtl8187_conf_tx
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1222,9 +1409,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
}
if (priv->is_rtl8187b) {
- printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
- "is EXPERIMENTAL, and could damage your\n"
- " hardware, use at your own risk\n");
+ printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
dev->flags |= IEEE80211_HW_SIGNAL_DBM;
} else {
dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
@@ -1256,6 +1441,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
goto err_free_dev;
}
mutex_init(&priv->conf_mutex);
+ skb_queue_head_init(&priv->b_tx_status.queue);
printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
index 69030be62b36..4e75e8e7fa90 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -878,12 +878,6 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
-
rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 56b0eb25d927..a6ec928186ad 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1042,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode {
WLAN_ACTION_SPCT_CHL_SWITCH = 4,
};
+/*
+ * IEEE 802.11-2007 7.3.2.9 Country information element
+ *
+ * Minimum length is 8 octets, ie len must be evenly
+ * divisible by 2
+ */
+
+/* Although the spec says 8 I'm seeing 6 in practice */
+#define IEEE80211_COUNTRY_IE_MIN_LEN 6
+
+/*
+ * For regulatory extension stuff see IEEE 802.11-2007
+ * Annex I (page 1141) and Annex J (page 1147). Also
+ * review 7.3.2.9.
+ *
+ * When dot11RegulatoryClassesRequired is true and the
+ * first_channel/reg_extension_id is >= 201 then the IE
+ * compromises of the 'ext' struct represented below:
+ *
+ * - Regulatory extension ID - when generating IE this just needs
+ * to be monotonically increasing for each triplet passed in
+ * the IE
+ * - Regulatory class - index into set of rules
+ * - Coverage class - index into air propagation time (Table 7-27),
+ * in microseconds, you can compute the air propagation time from
+ * the index by multiplying by 3, so index 10 yields a propagation
+ * of 10 us. Valid values are 0-31, values 32-255 are not defined
+ * yet. A value of 0 inicates air propagation of <= 1 us.
+ *
+ * See also Table I.2 for Emission limit sets and table
+ * I.3 for Behavior limit sets. Table J.1 indicates how to map
+ * a reg_class to an emission limit set and behavior limit set.
+ */
+#define IEEE80211_COUNTRY_EXTENSION_ID 201
+
+/*
+ * Channels numbers in the IE must be monotonically increasing
+ * if dot11RegulatoryClassesRequired is not true.
+ *
+ * If dot11RegulatoryClassesRequired is true consecutive
+ * subband triplets following a regulatory triplet shall
+ * have monotonically increasing first_channel number fields.
+ *
+ * Channel numbers shall not overlap.
+ *
+ * Note that max_power is signed.
+ */
+struct ieee80211_country_ie_triplet {
+ union {
+ struct {
+ u8 first_channel;
+ u8 num_channels;
+ s8 max_power;
+ } __attribute__ ((packed)) chans;
+ struct {
+ u8 reg_extension_id;
+ u8 reg_class;
+ u8 coverage_class;
+ } __attribute__ ((packed)) ext;
+ };
+} __attribute__ ((packed));
+
/* BACK action code */
enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 79827345351d..e08c8bcfb78d 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -508,6 +508,8 @@ enum nl80211_band_attr {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ * (100 * dBm).
*/
enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
@@ -516,12 +518,15 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
};
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
/**
* enum nl80211_bitrate_attr - bitrate attributes
* @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 4cd64b0d9825..f376a93927f7 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -108,6 +108,7 @@ struct rfkill {
struct device dev;
struct list_head node;
+ enum rfkill_state state_for_resume;
};
#define to_rfkill(d) container_of(d, struct rfkill, dev)
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 412351560b76..21c5d966142d 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -181,6 +181,11 @@ struct ieee80211_supported_band {
* struct wiphy - wireless hardware description
* @idx: the wiphy index assigned to this item
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @fw_handles_regulatory: tells us the firmware for this device
+ * has its own regulatory solution and cannot identify the
+ * ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ * we will disregard the first regulatory hint (when the
+ * initiator is %REGDOM_SET_BY_CORE).
* @reg_notifier: the driver's regulatory notification callback
*/
struct wiphy {
@@ -192,6 +197,8 @@ struct wiphy {
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
+ bool fw_handles_regulatory;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
@@ -373,4 +380,19 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
* for a regulatory domain structure for the respective country.
*/
extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ * conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+extern void regulatory_hint_11d(struct wiphy *wiphy,
+ u8 *country_ie,
+ u8 country_ie_len);
#endif /* __NET_WIRELESS_H */
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 7f710a27e91c..60c16162474c 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -16,20 +16,20 @@ menu "Rate control algorithm selection"
config MAC80211_RC_PID
bool "PID controller based rate control algorithm" if EMBEDDED
- default y
---help---
This option enables a TX rate control algorithm for
mac80211 that uses a PID controller to select the TX
rate.
config MAC80211_RC_MINSTREL
- bool "Minstrel"
+ bool "Minstrel" if EMBEDDED
+ default y
---help---
This option enables the 'minstrel' TX rate control algorithm
choice
prompt "Default rate control algorithm"
- default MAC80211_RC_DEFAULT_PID
+ default MAC80211_RC_DEFAULT_MINSTREL
---help---
This option selects the default rate control algorithm
mac80211 will use. Note that this default can still be
@@ -55,8 +55,8 @@ endchoice
config MAC80211_RC_DEFAULT
string
- default "pid" if MAC80211_RC_DEFAULT_PID
default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
+ default "pid" if MAC80211_RC_DEFAULT_PID
default ""
endmenu
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 3e231d756776..a1eed7032c9b 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -36,7 +36,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
ht_cap->ht_supported = true;
- ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
+ ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d631dc96c323..cec9b6d3e1ce 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -722,7 +722,6 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
- const char *name;
int result;
enum ieee80211_band band;
struct net_device *mdev;
@@ -787,8 +786,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list;
- name = wiphy_dev(local->hw.wiphy)->driver->name;
- local->hw.workqueue = create_freezeable_workqueue(name);
+ local->hw.workqueue =
+ create_freezeable_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
result = -ENOMEM;
goto fail_workqueue;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d81a4d2cd3aa..7600ac9b87fe 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -802,6 +802,10 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
}
+/*
+ * The disassoc 'reason' argument can be either our own reason
+ * if self disconnected or a reason code from the AP.
+ */
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta, bool deauth,
bool self_disconnected, u16 reason)
@@ -848,7 +852,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_send_apinfo(sdata, ifsta);
- if (self_disconnected)
+ if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
ifsta->state = IEEE80211_STA_MLME_DISABLED;
sta_info_unlink(&sta);
@@ -1163,7 +1167,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
IEEE80211_RETRY_AUTH_INTERVAL);
}
- ieee80211_set_disassoc(sdata, ifsta, false, false, 0);
+ ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);
}
@@ -1736,6 +1740,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ap_ht_cap_flags);
}
+ if (elems.country_elem) {
+ /* Note we are only reviewing this on beacons
+ * for the BSSID we are associated to */
+ regulatory_hint_11d(local->hw.wiphy,
+ elems.country_elem, elems.country_elem_len);
+ }
+
ieee80211_bss_info_change_notify(sdata, changed);
}
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 96ceb7e86c5c..b16801cde06f 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -256,7 +256,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba
if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
spinfo->tx_num_failed += 2;
spinfo->tx_num_xmit++;
- } else if (info->status.rates[0].count) {
+ } else if (info->status.rates[0].count > 1) {
spinfo->tx_num_failed++;
spinfo->tx_num_xmit++;
}
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 7bbb98e846a3..7043ddc75498 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
+#include <asm/unaligned.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
@@ -125,10 +126,10 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
{
struct blkcipher_desc desc = { .tfm = tfm };
struct scatterlist sg;
- __le32 *icv;
+ __le32 icv;
- icv = (__le32 *)(data + data_len);
- *icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+ icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+ put_unaligned(icv, (__le32 *)(data + data_len));
crypto_blkcipher_setkey(tfm, rc4key, klen);
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index ec26eae8004d..051d2c9ea66b 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -565,16 +565,22 @@ static void rfkill_release(struct device *dev)
#ifdef CONFIG_PM
static int rfkill_suspend(struct device *dev, pm_message_t state)
{
+ struct rfkill *rfkill = to_rfkill(dev);
+
/* mark class device as suspended */
if (dev->power.power_state.event != state.event)
dev->power.power_state = state;
+ /* store state for the resume handler */
+ rfkill->state_for_resume = rfkill->state;
+
return 0;
}
static int rfkill_resume(struct device *dev)
{
struct rfkill *rfkill = to_rfkill(dev);
+ enum rfkill_state newstate;
if (dev->power.power_state.event != PM_EVENT_ON) {
mutex_lock(&rfkill->mutex);
@@ -582,6 +588,15 @@ static int rfkill_resume(struct device *dev)
dev->power.power_state.event = PM_EVENT_ON;
/*
+ * rfkill->state could have been modified before we got
+ * called, and won't be updated by rfkill_toggle_radio()
+ * in force mode. Sync it FIRST.
+ */
+ if (rfkill->get_state &&
+ !rfkill->get_state(rfkill->data, &newstate))
+ rfkill->state = newstate;
+
+ /*
* If we are under EPO, kick transmitter offline,
* otherwise restore to pre-suspend state.
*
@@ -590,7 +605,7 @@ static int rfkill_resume(struct device *dev)
rfkill_toggle_radio(rfkill,
rfkill_epo_lock_active ?
RFKILL_STATE_SOFT_BLOCKED :
- rfkill->state,
+ rfkill->state_for_resume,
1);
mutex_unlock(&rfkill->mutex);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index f7c64dbe86cc..e28e2b8fa436 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,6 +1,15 @@
config CFG80211
tristate "Improved wireless configuration API"
+config CFG80211_REG_DEBUG
+ bool "cfg80211 regulatory debugging"
+ depends on CFG80211
+ default n
+ ---help---
+ You can enable this if you want to debug regulatory changes.
+
+ If unsure, say N.
+
config NL80211
bool "nl80211 new netlink interface support"
depends on CFG80211
@@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY
ieee80211_regdom module parameter. This is being phased out and you
should stop using them ASAP.
+ Note: You will need CRDA if you want 802.11d support
+
Say Y unless you have installed a new userspace application.
Also say Y if have one currently depending on the ieee80211_regdom
module parameter and cannot port it to use the new userspace
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 39e3d10fccde..b96fc0c3f1c4 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -19,7 +19,6 @@
#include "nl80211.h"
#include "core.h"
#include "sysfs.h"
-#include "reg.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -348,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy)
/* unlock again before freeing */
mutex_unlock(&drv->mtx);
+ /* If this device got a regulatory hint tell core its
+ * free to listen now to a new shiny device regulatory hint */
+ reg_device_remove(wiphy);
+
list_del(&drv->list);
device_del(&drv->wiphy.dev);
debugfs_remove(drv->wiphy.debugfsdir);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 771cc5cc7658..f7fb9f413028 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -11,6 +11,7 @@
#include <net/genetlink.h>
#include <net/wireless.h>
#include <net/cfg80211.h>
+#include "reg.h"
struct cfg80211_registered_device {
struct cfg80211_ops *ops;
@@ -21,6 +22,18 @@ struct cfg80211_registered_device {
* any call is in progress */
struct mutex mtx;
+ /* ISO / IEC 3166 alpha2 for which this device is receiving
+ * country IEs on, this can help disregard country IEs from APs
+ * on the same alpha2 quickly. The alpha2 may differ from
+ * cfg80211_regdomain's alpha2 when an intersection has occurred.
+ * If the AP is reconfigured this can also be used to tell us if
+ * the country on the country IE changed. */
+ char country_ie_alpha2[2];
+
+ /* If a Country IE has been received this tells us the environment
+ * which its telling us its in. This defaults to ENVIRON_ANY */
+ enum environment_cap env;
+
/* wiphy index, internal only */
int idx;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e3e1494e769a..c9141e3df9ba 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -198,6 +198,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (chan->flags & IEEE80211_CHAN_RADAR)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+ NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ DBM_TO_MBM(chan->max_power));
+
nla_nest_end(msg, nl_freq);
}
@@ -1760,7 +1763,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
#endif
mutex_lock(&cfg80211_drv_mutex);
- r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data);
+ r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
mutex_unlock(&cfg80211_drv_mutex);
return r;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 4c7e39d466c4..0990059f7e48 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -60,12 +60,18 @@
* @intersect: indicates whether the wireless core should intersect
* the requested regulatory domain with the presently set regulatory
* domain.
+ * @country_ie_checksum: checksum of the last processed and accepted
+ * country IE
+ * @country_ie_env: lets us know if the AP is telling us we are outdoor,
+ * indoor, or if it doesn't matter
*/
struct regulatory_request {
struct wiphy *wiphy;
enum reg_set_by initiator;
char alpha2[2];
bool intersect;
+ u32 country_ie_checksum;
+ enum environment_cap country_ie_env;
};
/* Receipt of information from last regulatory request */
@@ -85,6 +91,11 @@ static u32 supported_bandwidths[] = {
* information to give us an alpha2 */
static const struct ieee80211_regdomain *cfg80211_regdomain;
+/* We use this as a place for the rd structure built from the
+ * last parsed country IE to rest until CRDA gets back to us with
+ * what it thinks should apply for the same country */
+static const struct ieee80211_regdomain *country_ie_regdomain;
+
/* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 1,
@@ -264,6 +275,18 @@ static bool is_unknown_alpha2(const char *alpha2)
return false;
}
+static bool is_intersected_alpha2(const char *alpha2)
+{
+ if (!alpha2)
+ return false;
+ /* Special case where regulatory domain is the
+ * result of an intersection between two regulatory domain
+ * structures */
+ if (alpha2[0] == '9' && alpha2[1] == '8')
+ return true;
+ return false;
+}
+
static bool is_an_alpha2(const char *alpha2)
{
if (!alpha2)
@@ -292,6 +315,25 @@ static bool regdom_changed(const char *alpha2)
return true;
}
+/**
+ * country_ie_integrity_changes - tells us if the country IE has changed
+ * @checksum: checksum of country IE of fields we are interested in
+ *
+ * If the country IE has not changed you can ignore it safely. This is
+ * useful to determine if two devices are seeing two different country IEs
+ * even on the same alpha2. Note that this will return false if no IE has
+ * been set on the wireless core yet.
+ */
+static bool country_ie_integrity_changes(u32 checksum)
+{
+ /* If no IE has been set then the checksum doesn't change */
+ if (unlikely(!last_request->country_ie_checksum))
+ return false;
+ if (unlikely(last_request->country_ie_checksum != checksum))
+ return true;
+ return false;
+}
+
/* This lets us keep regulatory code which is updated on a regulatory
* basis in userspace. */
static int call_crda(const char *alpha2)
@@ -330,7 +372,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
const struct ieee80211_freq_range *freq_range = &rule->freq_range;
u32 freq_diff;
- if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
+ if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0)
return false;
if (freq_range->start_freq_khz > freq_range->end_freq_khz)
@@ -352,6 +394,9 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
if (!rd->n_reg_rules)
return false;
+ if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
+ return false;
+
for (i = 0; i < rd->n_reg_rules; i++) {
reg_rule = &rd->reg_rules[i];
if (!is_valid_reg_rule(reg_rule))
@@ -376,6 +421,174 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
return 0;
}
+/* Converts a country IE to a regulatory domain. A regulatory domain
+ * structure has a lot of information which the IE doesn't yet have,
+ * so for the other values we use upper max values as we will intersect
+ * with our userspace regulatory agent to get lower bounds. */
+static struct ieee80211_regdomain *country_ie_2_rd(
+ u8 *country_ie,
+ u8 country_ie_len,
+ u32 *checksum)
+{
+ struct ieee80211_regdomain *rd = NULL;
+ unsigned int i = 0;
+ char alpha2[2];
+ u32 flags = 0;
+ u32 num_rules = 0, size_of_regd = 0;
+ u8 *triplets_start = NULL;
+ u8 len_at_triplet = 0;
+ /* the last channel we have registered in a subband (triplet) */
+ int last_sub_max_channel = 0;
+
+ *checksum = 0xDEADBEEF;
+
+ /* Country IE requirements */
+ BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN ||
+ country_ie_len & 0x01);
+
+ alpha2[0] = country_ie[0];
+ alpha2[1] = country_ie[1];
+
+ /*
+ * Third octet can be:
+ * 'I' - Indoor
+ * 'O' - Outdoor
+ *
+ * anything else we assume is no restrictions
+ */
+ if (country_ie[2] == 'I')
+ flags = NL80211_RRF_NO_OUTDOOR;
+ else if (country_ie[2] == 'O')
+ flags = NL80211_RRF_NO_INDOOR;
+
+ country_ie += 3;
+ country_ie_len -= 3;
+
+ triplets_start = country_ie;
+ len_at_triplet = country_ie_len;
+
+ *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
+
+ /* We need to build a reg rule for each triplet, but first we must
+ * calculate the number of reg rules we will need. We will need one
+ * for each channel subband */
+ while (country_ie_len >= 3) {
+ struct ieee80211_country_ie_triplet *triplet =
+ (struct ieee80211_country_ie_triplet *) country_ie;
+ int cur_sub_max_channel = 0, cur_channel = 0;
+
+ if (triplet->ext.reg_extension_id >=
+ IEEE80211_COUNTRY_EXTENSION_ID) {
+ country_ie += 3;
+ country_ie_len -= 3;
+ continue;
+ }
+
+ cur_channel = triplet->chans.first_channel;
+ cur_sub_max_channel = ieee80211_channel_to_frequency(
+ cur_channel + triplet->chans.num_channels);
+
+ /* Basic sanity check */
+ if (cur_sub_max_channel < cur_channel)
+ return NULL;
+
+ /* Do not allow overlapping channels. Also channels
+ * passed in each subband must be monotonically
+ * increasing */
+ if (last_sub_max_channel) {
+ if (cur_channel <= last_sub_max_channel)
+ return NULL;
+ if (cur_sub_max_channel <= last_sub_max_channel)
+ return NULL;
+ }
+
+ /* When dot11RegulatoryClassesRequired is supported
+ * we can throw ext triplets as part of this soup,
+ * for now we don't care when those change as we
+ * don't support them */
+ *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
+ ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
+ ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
+
+ last_sub_max_channel = cur_sub_max_channel;
+
+ country_ie += 3;
+ country_ie_len -= 3;
+ num_rules++;
+
+ /* Note: this is not a IEEE requirement but
+ * simply a memory requirement */
+ if (num_rules > NL80211_MAX_SUPP_REG_RULES)
+ return NULL;
+ }
+
+ country_ie = triplets_start;
+ country_ie_len = len_at_triplet;
+
+ size_of_regd = sizeof(struct ieee80211_regdomain) +
+ (num_rules * sizeof(struct ieee80211_reg_rule));
+
+ rd = kzalloc(size_of_regd, GFP_KERNEL);
+ if (!rd)
+ return NULL;
+
+ rd->n_reg_rules = num_rules;
+ rd->alpha2[0] = alpha2[0];
+ rd->alpha2[1] = alpha2[1];
+
+ /* This time around we fill in the rd */
+ while (country_ie_len >= 3) {
+ struct ieee80211_country_ie_triplet *triplet =
+ (struct ieee80211_country_ie_triplet *) country_ie;
+ struct ieee80211_reg_rule *reg_rule = NULL;
+ struct ieee80211_freq_range *freq_range = NULL;
+ struct ieee80211_power_rule *power_rule = NULL;
+
+ /* Must parse if dot11RegulatoryClassesRequired is true,
+ * we don't support this yet */
+ if (triplet->ext.reg_extension_id >=
+ IEEE80211_COUNTRY_EXTENSION_ID) {
+ country_ie += 3;
+ country_ie_len -= 3;
+ continue;
+ }
+
+ reg_rule = &rd->reg_rules[i];
+ freq_range = &reg_rule->freq_range;
+ power_rule = &reg_rule->power_rule;
+
+ reg_rule->flags = flags;
+
+ /* The +10 is since the regulatory domain expects
+ * the actual band edge, not the center of freq for
+ * its start and end freqs, assuming 20 MHz bandwidth on
+ * the channels passed */
+ freq_range->start_freq_khz =
+ MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+ triplet->chans.first_channel) - 10);
+ freq_range->end_freq_khz =
+ MHZ_TO_KHZ(ieee80211_channel_to_frequency(
+ triplet->chans.first_channel +
+ triplet->chans.num_channels) + 10);
+
+ /* Large arbitrary values, we intersect later */
+ /* Increment this if we ever support >= 40 MHz channels
+ * in IEEE 802.11 */
+ freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
+ power_rule->max_antenna_gain = DBI_TO_MBI(100);
+ power_rule->max_eirp = DBM_TO_MBM(100);
+
+ country_ie += 3;
+ country_ie_len -= 3;
+ i++;
+
+ BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
+ }
+
+ return rd;
+}
+
+
/* Helper for regdom_intersect(), this does the real
* mathematical intersection fun */
static int reg_rules_intersect(
@@ -603,12 +816,23 @@ static void handle_band(struct ieee80211_supported_band *sband)
handle_channel(&sband->channels[i]);
}
+static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
+{
+ if (!last_request)
+ return true;
+ if (setby == REGDOM_SET_BY_CORE &&
+ wiphy->fw_handles_regulatory)
+ return true;
+ return false;
+}
+
static void update_all_wiphy_regulatory(enum reg_set_by setby)
{
struct cfg80211_registered_device *drv;
list_for_each_entry(drv, &cfg80211_drv_list, list)
- wiphy_update_regulatory(&drv->wiphy, setby);
+ if (!ignore_reg_update(&drv->wiphy, setby))
+ wiphy_update_regulatory(&drv->wiphy, setby);
}
void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
@@ -660,16 +884,14 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
return -EOPNOTSUPP;
return -EALREADY;
}
- /* Two consecutive Country IE hints on the same wiphy */
- if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+ /* Two consecutive Country IE hints on the same wiphy.
+ * This should be picked up early by the driver/stack */
+ if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
+ alpha2)))
return 0;
return -EALREADY;
}
- /*
- * Ignore Country IE hints for now, need to think about
- * what we need to do to support multi-domain operation.
- */
- return -EOPNOTSUPP;
+ return REG_INTERSECT;
case REGDOM_SET_BY_DRIVER:
if (last_request->initiator == REGDOM_SET_BY_DRIVER)
return -EALREADY;
@@ -677,6 +899,11 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
case REGDOM_SET_BY_USER:
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT;
+ /* If the user knows better the user should set the regdom
+ * to their country before the IE is picked up */
+ if (last_request->initiator == REGDOM_SET_BY_USER &&
+ last_request->intersect)
+ return -EOPNOTSUPP;
return 0;
}
@@ -685,7 +912,9 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
/* Caller must hold &cfg80211_drv_mutex */
int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
- const char *alpha2)
+ const char *alpha2,
+ u32 country_ie_checksum,
+ enum environment_cap env)
{
struct regulatory_request *request;
bool intersect = false;
@@ -698,36 +927,32 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
else if (r)
return r;
- switch (set_by) {
- case REGDOM_SET_BY_CORE:
- case REGDOM_SET_BY_COUNTRY_IE:
- case REGDOM_SET_BY_DRIVER:
- case REGDOM_SET_BY_USER:
- request = kzalloc(sizeof(struct regulatory_request),
- GFP_KERNEL);
- if (!request)
- return -ENOMEM;
-
- request->alpha2[0] = alpha2[0];
- request->alpha2[1] = alpha2[1];
- request->initiator = set_by;
- request->wiphy = wiphy;
- request->intersect = intersect;
-
- kfree(last_request);
- last_request = request;
- r = call_crda(alpha2);
-#ifndef CONFIG_WIRELESS_OLD_REGULATORY
- if (r)
- printk(KERN_ERR "cfg80211: Failed calling CRDA\n");
-#endif
- break;
- default:
- r = -ENOTSUPP;
- break;
- }
+ request = kzalloc(sizeof(struct regulatory_request),
+ GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
- return r;
+ request->alpha2[0] = alpha2[0];
+ request->alpha2[1] = alpha2[1];
+ request->initiator = set_by;
+ request->wiphy = wiphy;
+ request->intersect = intersect;
+ request->country_ie_checksum = country_ie_checksum;
+ request->country_ie_env = env;
+
+ kfree(last_request);
+ last_request = request;
+ /*
+ * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
+ * AND if CRDA is NOT present nothing will happen, if someone
+ * wants to bother with 11d with OLD_REG you can add a timer.
+ * If after x amount of time nothing happens you can call:
+ *
+ * return set_regdom(country_ie_regdomain);
+ *
+ * to intersect with the static rd
+ */
+ return call_crda(alpha2);
}
void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
@@ -735,11 +960,120 @@ void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
BUG_ON(!alpha2);
mutex_lock(&cfg80211_drv_mutex);
- __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2);
+ __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY);
mutex_unlock(&cfg80211_drv_mutex);
}
EXPORT_SYMBOL(regulatory_hint);
+static bool reg_same_country_ie_hint(struct wiphy *wiphy,
+ u32 country_ie_checksum)
+{
+ if (!last_request->wiphy)
+ return false;
+ if (likely(last_request->wiphy != wiphy))
+ return !country_ie_integrity_changes(country_ie_checksum);
+ /* We should not have let these through at this point, they
+ * should have been picked up earlier by the first alpha2 check
+ * on the device */
+ if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
+ return true;
+ return false;
+}
+
+void regulatory_hint_11d(struct wiphy *wiphy,
+ u8 *country_ie,
+ u8 country_ie_len)
+{
+ struct ieee80211_regdomain *rd = NULL;
+ char alpha2[2];
+ u32 checksum = 0;
+ enum environment_cap env = ENVIRON_ANY;
+
+ mutex_lock(&cfg80211_drv_mutex);
+
+ /* IE len must be evenly divisible by 2 */
+ if (country_ie_len & 0x01)
+ goto out;
+
+ if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
+ goto out;
+
+ /* Pending country IE processing, this can happen after we
+ * call CRDA and wait for a response if a beacon was received before
+ * we were able to process the last regulatory_hint_11d() call */
+ if (country_ie_regdomain)
+ goto out;
+
+ alpha2[0] = country_ie[0];
+ alpha2[1] = country_ie[1];
+
+ if (country_ie[2] == 'I')
+ env = ENVIRON_INDOOR;
+ else if (country_ie[2] == 'O')
+ env = ENVIRON_OUTDOOR;
+
+ /* We will run this for *every* beacon processed for the BSSID, so
+ * we optimize an early check to exit out early if we don't have to
+ * do anything */
+ if (likely(last_request->wiphy)) {
+ struct cfg80211_registered_device *drv_last_ie;
+
+ drv_last_ie = wiphy_to_dev(last_request->wiphy);
+
+ /* Lets keep this simple -- we trust the first AP
+ * after we intersect with CRDA */
+ if (likely(last_request->wiphy == wiphy)) {
+ /* Ignore IEs coming in on this wiphy with
+ * the same alpha2 and environment cap */
+ if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+ alpha2) &&
+ env == drv_last_ie->env)) {
+ goto out;
+ }
+ /* the wiphy moved on to another BSSID or the AP
+ * was reconfigured. XXX: We need to deal with the
+ * case where the user suspends and goes to goes
+ * to another country, and then gets IEs from an
+ * AP with different settings */
+ goto out;
+ } else {
+ /* Ignore IEs coming in on two separate wiphys with
+ * the same alpha2 and environment cap */
+ if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
+ alpha2) &&
+ env == drv_last_ie->env)) {
+ goto out;
+ }
+ /* We could potentially intersect though */
+ goto out;
+ }
+ }
+
+ rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
+ if (!rd)
+ goto out;
+
+ /* This will not happen right now but we leave it here for the
+ * the future when we want to add suspend/resume support and having
+ * the user move to another country after doing so, or having the user
+ * move to another AP. Right now we just trust the first AP. This is why
+ * this is marked as likley(). If we hit this before we add this support
+ * we want to be informed of it as it would indicate a mistake in the
+ * current design */
+ if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
+ goto out;
+
+ /* We keep this around for when CRDA comes back with a response so
+ * we can intersect with that */
+ country_ie_regdomain = rd;
+
+ __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
+ country_ie_regdomain->alpha2, checksum, env);
+
+out:
+ mutex_unlock(&cfg80211_drv_mutex);
+}
+EXPORT_SYMBOL(regulatory_hint_11d);
static void print_rd_rules(const struct ieee80211_regdomain *rd)
{
@@ -779,7 +1113,25 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
static void print_regdomain(const struct ieee80211_regdomain *rd)
{
- if (is_world_regdom(rd->alpha2))
+ if (is_intersected_alpha2(rd->alpha2)) {
+ struct wiphy *wiphy = NULL;
+ struct cfg80211_registered_device *drv;
+
+ if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+ if (last_request->wiphy) {
+ wiphy = last_request->wiphy;
+ drv = wiphy_to_dev(wiphy);
+ printk(KERN_INFO "cfg80211: Current regulatory "
+ "domain updated by AP to: %c%c\n",
+ drv->country_ie_alpha2[0],
+ drv->country_ie_alpha2[1]);
+ } else
+ printk(KERN_INFO "cfg80211: Current regulatory "
+ "domain intersected: \n");
+ } else
+ printk(KERN_INFO "cfg80211: Current regulatory "
+ "intersected: \n");
+ } else if (is_world_regdom(rd->alpha2))
printk(KERN_INFO "cfg80211: World regulatory "
"domain updated:\n");
else {
@@ -802,10 +1154,39 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
print_rd_rules(rd);
}
+#ifdef CONFIG_CFG80211_REG_DEBUG
+static void reg_country_ie_process_debug(
+ const struct ieee80211_regdomain *rd,
+ const struct ieee80211_regdomain *country_ie_regdomain,
+ const struct ieee80211_regdomain *intersected_rd)
+{
+ printk(KERN_DEBUG "cfg80211: Received country IE:\n");
+ print_regdomain_info(country_ie_regdomain);
+ printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n");
+ print_regdomain_info(rd);
+ if (intersected_rd) {
+ printk(KERN_DEBUG "cfg80211: We intersect both of these "
+ "and get:\n");
+ print_regdomain_info(rd);
+ return;
+ }
+ printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");
+}
+#else
+static inline void reg_country_ie_process_debug(
+ const struct ieee80211_regdomain *rd,
+ const struct ieee80211_regdomain *country_ie_regdomain,
+ const struct ieee80211_regdomain *intersected_rd)
+{
+}
+#endif
+
/* Takes ownership of rd only if it doesn't fail */
static int __set_regdom(const struct ieee80211_regdomain *rd)
{
const struct ieee80211_regdomain *intersected_rd = NULL;
+ struct cfg80211_registered_device *drv = NULL;
+ struct wiphy *wiphy = NULL;
/* Some basic sanity checks first */
if (is_world_regdom(rd->alpha2)) {
@@ -822,10 +1203,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!last_request)
return -EINVAL;
- /* allow overriding the static definitions if CRDA is present */
- if (!is_old_static_regdom(cfg80211_regdomain) &&
- !regdom_changed(rd->alpha2))
- return -EINVAL;
+ /* Lets only bother proceeding on the same alpha2 if the current
+ * rd is non static (it means CRDA was present and was used last)
+ * and the pending request came in from a country IE */
+ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+ /* If someone else asked us to change the rd lets only bother
+ * checking if the alpha2 changes if CRDA was already called */
+ if (!is_old_static_regdom(cfg80211_regdomain) &&
+ !regdom_changed(rd->alpha2))
+ return -EINVAL;
+ }
+
+ wiphy = last_request->wiphy;
/* Now lets set the regulatory domain, update all driver channels
* and finally inform them of what we have done, in case they want
@@ -835,36 +1224,78 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
return -EINVAL;
- reset_regdomains();
+ if (!is_valid_rd(rd)) {
+ printk(KERN_ERR "cfg80211: Invalid "
+ "regulatory domain detected:\n");
+ print_regdomain_info(rd);
+ return -EINVAL;
+ }
- /* Country IE parsing coming soon */
- switch (last_request->initiator) {
- case REGDOM_SET_BY_CORE:
- case REGDOM_SET_BY_DRIVER:
- case REGDOM_SET_BY_USER:
- if (!is_valid_rd(rd)) {
- printk(KERN_ERR "cfg80211: Invalid "
- "regulatory domain detected:\n");
- print_regdomain_info(rd);
- return -EINVAL;
- }
- break;
- case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */
- WARN_ON(1);
- default:
- return -EOPNOTSUPP;
+ if (!last_request->intersect) {
+ reset_regdomains();
+ cfg80211_regdomain = rd;
+ return 0;
}
- if (unlikely(last_request->intersect)) {
+ /* Intersection requires a bit more work */
+
+ if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+
intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
if (!intersected_rd)
return -EINVAL;
+
+ /* We can trash what CRDA provided now */
kfree(rd);
- rd = intersected_rd;
+ rd = NULL;
+
+ reset_regdomains();
+ cfg80211_regdomain = intersected_rd;
+
+ return 0;
}
- /* Tada! */
- cfg80211_regdomain = rd;
+ /*
+ * Country IE requests are handled a bit differently, we intersect
+ * the country IE rd with what CRDA believes that country should have
+ */
+
+ BUG_ON(!country_ie_regdomain);
+
+ if (rd != country_ie_regdomain) {
+ /* Intersect what CRDA returned and our what we
+ * had built from the Country IE received */
+
+ intersected_rd = regdom_intersect(rd, country_ie_regdomain);
+
+ reg_country_ie_process_debug(rd, country_ie_regdomain,
+ intersected_rd);
+
+ kfree(country_ie_regdomain);
+ country_ie_regdomain = NULL;
+ } else {
+ /* This would happen when CRDA was not present and
+ * OLD_REGULATORY was enabled. We intersect our Country
+ * IE rd and what was set on cfg80211 originally */
+ intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+ }
+
+ if (!intersected_rd)
+ return -EINVAL;
+
+ drv = wiphy_to_dev(wiphy);
+
+ drv->country_ie_alpha2[0] = rd->alpha2[0];
+ drv->country_ie_alpha2[1] = rd->alpha2[1];
+ drv->env = last_request->country_ie_env;
+
+ BUG_ON(intersected_rd == rd);
+
+ kfree(rd);
+ rd = NULL;
+
+ reset_regdomains();
+ cfg80211_regdomain = intersected_rd;
return 0;
}
@@ -885,16 +1316,28 @@ int set_regdom(const struct ieee80211_regdomain *rd)
}
/* This would make this whole thing pointless */
- BUG_ON(rd != cfg80211_regdomain);
+ if (!last_request->intersect)
+ BUG_ON(rd != cfg80211_regdomain);
/* update all wiphys now with the new established regulatory domain */
update_all_wiphy_regulatory(last_request->initiator);
- print_regdomain(rd);
+ print_regdomain(cfg80211_regdomain);
return r;
}
+/* Caller must hold cfg80211_drv_mutex */
+void reg_device_remove(struct wiphy *wiphy)
+{
+ if (!last_request->wiphy)
+ return;
+ if (last_request->wiphy != wiphy)
+ return;
+ last_request->wiphy = NULL;
+ last_request->country_ie_env = ENVIRON_ANY;
+}
+
int regulatory_init(void)
{
int err;
@@ -914,11 +1357,11 @@ int regulatory_init(void)
* that is not a valid ISO / IEC 3166 alpha2 */
if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
- ieee80211_regdom);
+ ieee80211_regdom, 0, ENVIRON_ANY);
#else
cfg80211_regdomain = cfg80211_world_regdom;
- err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00");
+ err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
if (err)
printk(KERN_ERR "cfg80211: calling CRDA failed - "
"unable to update world regulatory domain, "
@@ -934,6 +1377,9 @@ void regulatory_exit(void)
reset_regdomains();
+ kfree(country_ie_regdomain);
+ country_ie_regdomain = NULL;
+
kfree(last_request);
platform_device_unregister(reg_pdev);
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index c9b6b6358bbe..a76ea3ff7cd6 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -4,28 +4,41 @@
bool is_world_regdom(const char *alpha2);
bool reg_is_valid_request(const char *alpha2);
+void reg_device_remove(struct wiphy *wiphy);
+
int regulatory_init(void);
void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd);
+enum environment_cap {
+ ENVIRON_ANY,
+ ENVIRON_INDOOR,
+ ENVIRON_OUTDOOR,
+};
+
+
/**
* __regulatory_hint - hint to the wireless core a regulatory domain
* @wiphy: if the hint comes from country information from an AP, this
* is required to be set to the wiphy that received the information
* @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
* should be in.
+ * @country_ie_checksum: checksum of processed country IE, set this to 0
+ * if the hint did not come from a country IE
+ * @country_ie_env: the environment the IE told us we are in, %ENVIRON_*
*
* The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain by
- * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory
- * domain should be in.
+ * what it believes should be the current regulatory domain by giving it an
+ * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
+ * in.
*
* Returns zero if all went fine, %-EALREADY if a regulatory domain had
* already been set or other standard error codes.
*
*/
extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
- const char *alpha2);
+ const char *alpha2, u32 country_ie_checksum,
+ enum environment_cap country_ie_env);
#endif /* __NET_WIRELESS_REG_H */