Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2008-11-26 15:28:40 -08:00
commit b5ddedc9cc
83 changed files with 6683 additions and 6066 deletions

View File

@ -214,6 +214,21 @@ config HERMES
configure your card and that /etc/pcmcia/wireless.opts works : configure your card and that /etc/pcmcia/wireless.opts works :
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> <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 config APPLE_AIRPORT
tristate "Apple Airport support (built-in)" tristate "Apple Airport support (built-in)"
depends on PPC_PMAC && HERMES depends on PPC_PMAC && HERMES
@ -508,7 +523,7 @@ config RTL8180
config RTL8187 config RTL8187
tristate "Realtek 8187 and 8187B USB support" tristate "Realtek 8187 and 8187B USB support"
depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL depends on MAC80211 && USB && WLAN_80211
select EEPROM_93CX6 select EEPROM_93CX6
---help--- ---help---
This is a driver for RTL8187 and RTL8187B based cards. This is a driver for RTL8187 and RTL8187B based cards.

View File

@ -821,13 +821,6 @@ struct ath5k_athchan_2ghz {
return (false); \ return (false); \
} while (0) } 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 * Hardware interrupt abstraction
*/ */

View File

@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
{ {
struct ath5k_hw *ah; struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev; struct pci_dev *pdev = sc->pdev;
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN] = {};
int ret; int ret;
u32 srev; u32 srev;
@ -317,15 +317,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free; goto err_free;
} }
/* Set MAC address */ /* MAC address is cleared until add_interface */
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;
}
ath5k_hw_set_lladdr(ah, mac); ath5k_hw_set_lladdr(ah, mac);
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
memset(ah->ah_bssid, 0xff, ETH_ALEN); memset(ah->ah_bssid, 0xff, ETH_ALEN);
ath5k_hw_set_associd(ah, ah->ah_bssid, 0); ath5k_hw_set_associd(ah, ah->ah_bssid, 0);

View File

@ -200,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static struct pci_driver ath5k_pci_driver = { static struct pci_driver ath5k_pci_driver = {
.name = "ath5k_pci", .name = KBUILD_MODNAME,
.id_table = ath5k_pci_id_table, .id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe, .probe = ath5k_pci_probe,
.remove = __devexit_p(ath5k_pci_remove), .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_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah; struct ath5k_hw *ah = sc->ah;
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN] = {};
int ret; int ret;
ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); 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); tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
setup_timer(&sc->calib_tim, ath5k_calibrate, (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); SET_IEEE80211_PERM_ADDR(hw, mac);
/* All MAC address bits matter for ACKs */ /* All MAC address bits matter for ACKs */
memset(sc->bssidmask, 0xff, ETH_ALEN); 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 /* Set to a reasonable value. Note that this will
* be set to mac80211's value at ath5k_config(). */ * be set to mac80211's value at ath5k_config(). */
sc->bintval = 1000; sc->bintval = 1000;
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
ret = 0; ret = 0;
end: end:
@ -2777,11 +2784,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf) struct ieee80211_if_init_conf *conf)
{ {
struct ath5k_softc *sc = hw->priv; struct ath5k_softc *sc = hw->priv;
u8 mac[ETH_ALEN] = {};
mutex_lock(&sc->lock); mutex_lock(&sc->lock);
if (sc->vif != conf->vif) if (sc->vif != conf->vif)
goto end; goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
sc->vif = NULL; sc->vif = NULL;
end: end:
mutex_unlock(&sc->lock); mutex_unlock(&sc->lock);

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,128 @@
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
#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
#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */
#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */
#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_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 /* 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 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
#define AR5K_EEPROM_MODE_11G 2
#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
#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_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
#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
/* Newer EEPROMs are using a different offset */
#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
(((_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) ((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
#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ #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_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_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
@ -42,72 +164,6 @@
#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 #define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ #define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 #define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
#define AR5K_EEPROM_INFO_CKSUM 0xffff
#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */
#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */
#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_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_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_MODE_11A 0
#define AR5K_EEPROM_MODE_11B 1
#define AR5K_EEPROM_MODE_11G 2
#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
#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_RFKILL_GPIO_SEL 0x0000001c
#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
/* Newer EEPROMs are using a different offset */
#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
(((_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))
/* 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 */
/* [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)
/* Some EEPROM defines */ /* Some EEPROM defines */
#define AR5K_EEPROM_EEP_SCALE 100 #define AR5K_EEPROM_EEP_SCALE 100
@ -115,8 +171,11 @@
#define AR5K_EEPROM_N_MODES 3 #define AR5K_EEPROM_N_MODES 3
#define AR5K_EEPROM_N_5GHZ_CHAN 10 #define AR5K_EEPROM_N_5GHZ_CHAN 10
#define AR5K_EEPROM_N_2GHZ_CHAN 3 #define AR5K_EEPROM_N_2GHZ_CHAN 3
#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
#define AR5K_EEPROM_MAX_CHAN 10 #define AR5K_EEPROM_MAX_CHAN 10
#define AR5K_EEPROM_N_PWR_POINTS_5111 11
#define AR5K_EEPROM_N_PCDAC 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_TEST_FREQ 8
#define AR5K_EEPROM_N_EDGES 8 #define AR5K_EEPROM_N_EDGES 8
#define AR5K_EEPROM_N_INTERCEPTS 11 #define AR5K_EEPROM_N_INTERCEPTS 11
@ -136,6 +195,8 @@
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 #define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
#define AR5K_EEPROM_N_XPD0_POINTS 4 #define AR5K_EEPROM_N_XPD0_POINTS 4
#define AR5K_EEPROM_N_XPD3_POINTS 3 #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_2GHZ 35
#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
#define AR5K_EEPROM_POWER_M 0x3f #define AR5K_EEPROM_POWER_M 0x3f
@ -158,8 +219,99 @@
#define AR5K_EEPROM_READ_HDR(_o, _v) \ #define AR5K_EEPROM_READ_HDR(_o, _v) \
AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._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 { struct ath5k_eeprom_info {
/* Header information */
u16 ee_magic; u16 ee_magic;
u16 ee_protect; u16 ee_protect;
u16 ee_regdomain; u16 ee_regdomain;
@ -168,6 +320,11 @@ struct ath5k_eeprom_info {
u16 ee_ant_gain; u16 ee_ant_gain;
u16 ee_misc0; u16 ee_misc0;
u16 ee_misc1; 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_gain_delta;
u16 ee_cck_ofdm_power_delta; u16 ee_cck_ofdm_power_delta;
u16 ee_scaled_cck_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_turbo_max_power[AR5K_EEPROM_N_MODES];
u16 ee_xr_power[AR5K_EEPROM_N_MODES]; u16 ee_xr_power[AR5K_EEPROM_N_MODES];
u16 ee_switch_settling[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_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
u16 ee_db[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_x_gain[AR5K_EEPROM_N_MODES];
u16 ee_i_gain[AR5K_EEPROM_N_MODES]; u16 ee_i_gain[AR5K_EEPROM_N_MODES];
u16 ee_margin_tx_rx[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_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) */ /* Conformance test limits (Unused) */
u16 ee_ctls; u16 ee_ctls;
u16 ee_ctl[AR5K_EEPROM_MAX_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 */ /* Noise Floor Calibration settings */
s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES];
s8 ee_pga_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];
}; };

View File

@ -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, (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
0xffffc07f); 0xffffc07f);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, 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); 0xfffc0fff);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
(ee->ee_adc_desired_size[ee_mode] & 0x00ff) | (ee->ee_adc_desired_size[ee_mode] & 0x00ff) |

View File

@ -9,7 +9,6 @@ ath9k-y += hw.o \
main.o \ main.o \
recv.o \ recv.o \
xmit.o \ xmit.o \
rc.o \ rc.o
core.o
obj-$(CONFIG_ATH9K) += ath9k.o obj-$(CONFIG_ATH9K) += ath9k.o

View File

@ -401,22 +401,6 @@ enum ath9k_int {
ATH9K_INT_NOCARD = 0xffffffff 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_RTS_CTS 0x0001
#define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_2040 0x0002
#define ATH9K_RATESERIES_HALFGI 0x0004 #define ATH9K_RATESERIES_HALFGI 0x0004
@ -492,12 +476,10 @@ struct ath9k_channel {
(((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
(((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
(((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) (((_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) || \ #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
(((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
(((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
(((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) (((_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_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 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) #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
/* These macros check chanmode and not channelFlags */ /* 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) || \ #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \
((_c)->chanmode == CHANNEL_G_HT20)) ((_c)->chanmode == CHANNEL_G_HT20))
#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \
@ -702,13 +685,19 @@ enum ath9k_ani_cmd {
ATH9K_ANI_ALL = 0xff ATH9K_ANI_ALL = 0xff
}; };
enum phytype { enum {
PHY_DS, WLAN_RC_PHY_OFDM,
PHY_FH, WLAN_RC_PHY_CCK,
PHY_OFDM, WLAN_RC_PHY_HT_20_SS,
PHY_HT, 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 { enum ath9k_tp_scale {
ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_MAX = 0,
@ -828,6 +817,8 @@ struct chan_centers {
u16 ext_center; u16 ext_center;
}; };
struct ath_rate_table;
/* Helpers */ /* Helpers */
enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, 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 flags, u16 *low,
u16 *high); u16 *high);
u16 ath9k_hw_computetxtime(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, u32 frameLen, u16 rateix,
bool shortPreamble); bool shortPreamble);
u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); 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_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
const struct ath9k_beacon_state *bs); const struct ath9k_beacon_state *bs);
/* Rate table */
const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
u32 mode);
/* HW Capabilities */ /* HW Capabilities */
bool ath9k_hw_fill_cap_info(struct ath_hal *ah); 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, void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
u32 ah_signal_type); u32 ah_signal_type);
void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val); 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); void ath9k_enable_rfkill(struct ath_hal *ah);
#endif #endif
int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);

View File

@ -14,13 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/* Implementation of beacon processing. */
#include "core.h" #include "core.h"
/* /*
* Configure parameters for the beacon queue
*
* This function will modify certain transmit queue properties depending on * This function will modify certain transmit queue properties depending on
* the operating mode of the station (AP or AdHoc). Parameters are AIFS * the operating mode of the station (AP or AdHoc). Parameters are AIFS
* settings and channel width min/max * 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 * Associates the beacon frame buffer with a transmit descriptor. Will set
* up all required antenna switch parameters, rate codes, and channel flags. * up all required antenna switch parameters, rate codes, and channel flags.
* Beacons are always sent out at the lowest rate, and are not retried. * 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_hal *ah = sc->sc_ah;
struct ath_desc *ds; struct ath_desc *ds;
struct ath9k_11n_rate_series series[4]; struct ath9k_11n_rate_series series[4];
const struct ath9k_rate_table *rt; struct ath_rate_table *rt;
int flags, antenna; int flags, antenna;
u8 rix, rate; u8 rix, rate;
int ctsrate = 0; int ctsrate = 0;
@ -106,10 +108,10 @@ static void ath_beacon_setup(struct ath_softc *sc,
* XXX everything at min xmit rate * XXX everything at min xmit rate
*/ */
rix = 0; rix = 0;
rt = sc->sc_currates; rt = sc->hw_rate_table[sc->sc_curmode];
rate = rt->info[rix].rateCode; rate = rt->info[rix].ratecode;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) 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, ath9k_hw_set11n_txdesc(ah, ds,
skb->len + FCS_LEN, /* frame length */ skb->len + FCS_LEN, /* frame length */
@ -138,14 +140,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
ctsrate, ctsduration, series, 4, 0); ctsrate, ctsduration, series, 4, 0);
} }
/* /* Generate beacon frame and queue cab data for a vap */
* 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.
*/
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
{ {
struct ath_buf *bf; 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); 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) int ath_beaconq_setup(struct ath_hal *ah)
{ {
struct ath9k_tx_queue_info qi; 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); 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) int ath_beacon_alloc(struct ath_softc *sc, int if_id)
{ {
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
@ -321,7 +300,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
if (!avp->av_bcbuf) { if (!avp->av_bcbuf) {
/* Allocate beacon state for hostap/ibss. We know /* Allocate beacon state for hostap/ibss. We know
* a buffer is available. */ * a buffer is available. */
avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
struct ath_buf, list); struct ath_buf, list);
list_del(&avp->av_bcbuf->list); list_del(&avp->av_bcbuf->list);
@ -427,12 +405,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
return 0; 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) void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
{ {
if (avp->av_bcbuf != NULL) { 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) void ath9k_beacon_tasklet(unsigned long data)
{ {
struct ath_softc *sc = (struct ath_softc *)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) { if (sc->sc_flags & SC_OP_NO_RESET) {
show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
&rx_clear, &rx_clear, &rx_frame, &tx_frame);
&rx_frame,
&tx_frame);
} }
/* /*
@ -605,9 +568,10 @@ void ath9k_beacon_tasklet(unsigned long data)
if (sc->sc_updateslot == UPDATE) { if (sc->sc_updateslot == UPDATE) {
sc->sc_updateslot = COMMIT; /* commit next beacon */ sc->sc_updateslot = COMMIT; /* commit next beacon */
sc->sc_slotupdate = slot; sc->sc_slotupdate = slot;
} else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) {
ath_setslottime(sc); /* commit change to hardware */ ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
sc->sc_updateslot = OK;
}
if (bfaddr != 0) { if (bfaddr != 0) {
/* /*
* Stop any current dma and put the new frame(s) on the queue. * Stop any current dma and put the new frame(s) on the queue.
@ -629,20 +593,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. * Configure the beacon and sleep timers.
* *
@ -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) void ath_beacon_sync(struct ath_softc *sc, int if_id)
{ {
/* /*

View File

@ -176,14 +176,14 @@ static bool getNoiseFloorThresh(struct ath_hal *ah,
case CHANNEL_A_HT20: case CHANNEL_A_HT20:
case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS: 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; break;
case CHANNEL_B: case CHANNEL_B:
case CHANNEL_G: case CHANNEL_G:
case CHANNEL_G_HT20: case CHANNEL_G_HT20:
case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40PLUS:
case CHANNEL_G_HT40MINUS: 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; break;
default: default:
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,

File diff suppressed because it is too large Load Diff

View File

@ -47,10 +47,6 @@
struct ath_node; struct ath_node;
/******************/
/* Utility macros */
/******************/
/* Macro to expand scalars to 64-bit objects */ /* Macro to expand scalars to 64-bit objects */
#define ito64(x) (sizeof(x) == 8) ? \ #define ito64(x) (sizeof(x) == 8) ? \
@ -86,11 +82,6 @@ struct ath_node;
#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i)) #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}; 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) */ 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 */ /* Descriptor Management */
/*************************/ /*************************/
@ -203,7 +166,6 @@ struct ath_buf_state {
int bfs_seqno; /* sequence number */ int bfs_seqno; /* sequence number */
int bfs_tidno; /* tid of this frame */ int bfs_tidno; /* tid of this frame */
int bfs_retries; /* current retries */ int bfs_retries; /* current retries */
struct ath_rc_series bfs_rcs[4]; /* rate series */
u32 bf_type; /* BUF_* (enum buffer_type) */ u32 bf_type; /* BUF_* (enum buffer_type) */
/* key type use to encrypt this frame */ /* key type use to encrypt this frame */
u32 bfs_keyix; u32 bfs_keyix;
@ -241,7 +203,6 @@ struct ath_buf {
an aggregate) */ an aggregate) */
struct ath_buf *bf_lastfrm; /* last buf of this frame */ struct ath_buf *bf_lastfrm; /* last buf of this frame */
struct ath_buf *bf_next; /* next subframe in the aggregate */ 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 */ void *bf_mpdu; /* enclosing frame structure */
struct ath_desc *bf_desc; /* virtual addr of desc */ struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */
@ -279,80 +240,27 @@ struct ath_descdma {
dma_addr_t dd_dmacontext; dma_addr_t dd_dmacontext;
}; };
/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct list_head *head, const char *name,
struct ath_rx_context { int nbuf, int ndesc);
struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
};
#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,
struct list_head *head); struct list_head *head);
/******/ /***********/
/* RX */ /* RX / TX */
/******/ /***********/
#define ATH_MAX_ANTENNA 3 #define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512 #define ATH_RXBUF 512
#define WME_NUM_TID 16 #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); int ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc);
void ath_flushrecv(struct ath_softc *sc); void ath_flushrecv(struct ath_softc *sc);
u32 ath_calcrxfilter(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); int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc); void ath_rx_cleanup(struct ath_softc *sc);
int ath_rx_tasklet(struct ath_softc *sc, int flush); 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 #define ATH_TXBUF 512
/* max number of transmit attempts (tries) */ /* 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); void ath_tx_tasklet(struct ath_softc *sc);
u32 ath_txq_depth(struct ath_softc *sc, int qnum); u32 ath_txq_depth(struct ath_softc *sc, int qnum);
u32 ath_txq_aggr_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); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
/**********************/ /**********************/
@ -567,25 +472,41 @@ struct ath_node_aggr {
/* driver-specific node state */ /* driver-specific node state */
struct ath_node { struct ath_node {
struct ath_softc *an_sc; struct ath_softc *an_sc;
struct ath_chainmask_sel an_chainmask_sel;
struct ath_node_aggr an_aggr; struct ath_node_aggr an_aggr;
u16 maxampdu; u16 maxampdu;
u8 mpdudensity; u8 mpdudensity;
}; };
void ath_tx_resume_tid(struct ath_softc *sc, void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
struct ath_atx_tid *tid);
bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
void ath_tx_aggr_teardown(struct ath_softc *sc, void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno);
struct ath_node *an, u8 tidno);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn); u16 tid, u16 *ssn);
int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); 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_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); /* VAPs */
void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta); /********/
/*
* 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 */ /* Beacon Handling */
@ -620,80 +541,8 @@ void ath9k_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, int if_id); void ath_beacon_config(struct ath_softc *sc, int if_id);
int ath_beaconq_setup(struct ath_hal *ah); int ath_beaconq_setup(struct ath_hal *ah);
int ath_beacon_alloc(struct ath_softc *sc, int if_id); 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_return(struct ath_softc *sc, struct ath_vap *avp);
void ath_beacon_sync(struct ath_softc *sc, int if_id); 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 */ /* ANI */
@ -775,30 +624,8 @@ struct ath_rfkill {
#define ATH_IF_ID_ANY 0xff #define ATH_IF_ID_ANY 0xff
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RSSI_DUMMY_MARKER 0x127
#define RSSI_LPF_THRESHOLD -20 #define ATH_RATE_DUMMY_MARKER 0
#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)
enum PROT_MODE { enum PROT_MODE {
PROT_M_NONE = 0, PROT_M_NONE = 0,
@ -806,17 +633,6 @@ enum PROT_MODE {
PROT_M_CTSONLY 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_INVALID BIT(0)
#define SC_OP_BEACONS BIT(1) #define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2) #define SC_OP_RXAGGR BIT(2)
@ -839,7 +655,6 @@ struct ath_softc {
struct tasklet_struct bcon_tasklet; struct tasklet_struct bcon_tasklet;
struct ath_config sc_config; struct ath_config sc_config;
struct ath_hal *sc_ah; struct ath_hal *sc_ah;
struct ath_rate_softc *sc_rc;
void __iomem *mem; void __iomem *mem;
u8 sc_curbssid[ETH_ALEN]; u8 sc_curbssid[ETH_ALEN];
@ -871,8 +686,8 @@ struct ath_softc {
u8 sc_rxotherant; /* rx's on non-default antenna */ u8 sc_rxotherant; /* rx's on non-default antenna */
struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ 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_extprotspacing sc_ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width;
#ifdef CONFIG_SLOW_ANT_DIV #ifdef CONFIG_SLOW_ANT_DIV
struct ath_antdiv sc_antdiv; struct ath_antdiv sc_antdiv;
@ -914,13 +729,8 @@ struct ath_softc {
/* Rate */ /* Rate */
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
const struct ath9k_rate_table *sc_currates; struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */
u8 sc_protrix; /* protection rate index */ 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 */ /* Channel, Band */
struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
@ -945,27 +755,9 @@ struct ath_softc {
struct ath_ani sc_ani; 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_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_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 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 *); int ath_cabq_update(struct ath_softc *);
u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
#endif /* CORE_H */ #endif /* CORE_H */

View File

@ -1244,7 +1244,7 @@ bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; 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); REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
for (i = 0; i < AR5416_MAX_CHAINS; i++) { for (i = 0; i < AR5416_MAX_CHAINS; i++) {
@ -1551,9 +1551,9 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
switch (param) { switch (param) {
case EEP_NFTHRESH_5: case EEP_NFTHRESH_5:
return -pModal[0].noiseFloorThreshCh[0]; return pModal[0].noiseFloorThreshCh[0];
case EEP_NFTHRESH_2: case EEP_NFTHRESH_2:
return -pModal[1].noiseFloorThreshCh[0]; return pModal[1].noiseFloorThreshCh[0];
case AR_EEPROM_MAC(0): case AR_EEPROM_MAC(0):
return pBase->macAddr[0] << 8 | pBase->macAddr[1]; return pBase->macAddr[0] << 8 | pBase->macAddr[1];
case AR_EEPROM_MAC(1): case AR_EEPROM_MAC(1):
@ -1584,6 +1584,11 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
return pBase->txMask; return pBase->txMask;
case EEP_RX_MASK: case EEP_RX_MASK:
return pBase->rxMask; return pBase->rxMask;
case EEP_RXGAIN_TYPE:
return pBase->rxGainType;
case EEP_TXGAIN_TYPE:
return pBase->txGainType;
default: default:
return 0; return 0;
} }

View File

@ -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, enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
const struct ath9k_channel *chan) const struct ath9k_channel *chan)
{ {
if (IS_CHAN_CCK(chan)) if (IS_CHAN_B(chan))
return ATH9K_MODE_11A; return ATH9K_MODE_11B;
if (IS_CHAN_G(chan)) if (IS_CHAN_G(chan))
return ATH9K_MODE_11G; return ATH9K_MODE_11G;
return ATH9K_MODE_11A; 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, u16 ath9k_hw_computetxtime(struct ath_hal *ah,
const struct ath9k_rate_table *rates, struct ath_rate_table *rates,
u32 frameLen, u16 rateix, u32 frameLen, u16 rateix,
bool shortPreamble) bool shortPreamble)
{ {
u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
u32 kbps; u32 kbps;
kbps = rates->info[rateix].rateKbps; kbps = rates->info[rateix].ratekbps;
if (kbps == 0) if (kbps == 0)
return 0; return 0;
switch (rates->info[rateix].phy) { switch (rates->info[rateix].phy) {
case PHY_CCK: case WLAN_RC_PHY_CCK:
phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
if (shortPreamble && rates->info[rateix].shortPreamble) if (shortPreamble && rates->info[rateix].short_preamble)
phyTime >>= 1; phyTime >>= 1;
numBits = frameLen << 3; numBits = frameLen << 3;
txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
break; break;
case PHY_OFDM: case WLAN_RC_PHY_OFDM:
if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3); numBits = OFDM_PLCP_BITS + (frameLen << 3);
@ -557,6 +558,54 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah)
return 0; 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) static int ath9k_hw_post_attach(struct ath_hal *ah)
{ {
int ecode; int ecode;
@ -800,6 +849,14 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
if (ecode != 0) if (ecode != 0)
goto bad; 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 #ifndef CONFIG_SLOW_ANT_DIV
if (ah->ah_devid == AR9280_DEVID_PCI) { if (ah->ah_devid == AR9280_DEVID_PCI) {
for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { 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; u32 synthDelay;
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; 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; synthDelay = (4 * synthDelay) / 22;
else else
synthDelay /= 10; synthDelay /= 10;
@ -1258,6 +1315,12 @@ static int ath9k_hw_process_ini(struct ath_hal *ah,
DO_DELAY(regWrites); 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++) { for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); 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) && if (!IS_CHAN_OFDM(chan) &&
!IS_CHAN_CCK(chan) && !IS_CHAN_B(chan) &&
!IS_CHAN_HT20(chan) && !IS_CHAN_HT20(chan) &&
!IS_CHAN_HT40(chan)) { !IS_CHAN_HT40(chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, 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; 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; synthDelay = (4 * synthDelay) / 22;
else else
synthDelay /= 10; synthDelay /= 10;
@ -2169,8 +2232,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
((chan->channelFlags & CHANNEL_ALL) == ((chan->channelFlags & CHANNEL_ALL) ==
(ah->ah_curchan->channelFlags & CHANNEL_ALL)) && (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
(!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
!IS_CHAN_A_5MHZ_SPACED(ah-> !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
ah_curchan)))) {
if (ath9k_hw_channel_change(ah, chan, macmode)) { if (ath9k_hw_channel_change(ah, chan, macmode)) {
ath9k_hw_loadnf(ah, ah->ah_curchan); 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_interrupt_masks(ah, ah->ah_opmode);
ath9k_hw_init_qos(ah); 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) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
ath9k_enable_rfkill(ah); ath9k_enable_rfkill(ah);
#endif #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 */ /* HW Capabilities */
/*******************/ /*******************/
@ -3453,7 +3331,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; 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); ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
ah->ah_rfkill_gpio = 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)); AR_GPIO_BIT(gpio));
} }
#ifdef CONFIG_RFKILL #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
void ath9k_enable_rfkill(struct ath_hal *ah) void ath9k_enable_rfkill(struct ath_hal *ah)
{ {
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,

View File

@ -415,6 +415,9 @@ struct ar5416Stats {
#define AR5416_EEP_MINOR_VER_3 0x3 #define AR5416_EEP_MINOR_VER_3 0x3
#define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_7 0x7
#define AR5416_EEP_MINOR_VER_9 0x9 #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_5G_CAL_PIERS 8
#define AR5416_NUM_2G_CAL_PIERS 4 #define AR5416_NUM_2G_CAL_PIERS 4
@ -436,6 +439,16 @@ struct ar5416Stats {
#define AR5416_MAX_CHAINS 3 #define AR5416_MAX_CHAINS 3
#define AR5416_PWR_TABLE_OFFSET -5 #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 { enum eeprom_param {
EEP_NFTHRESH_5, EEP_NFTHRESH_5,
EEP_NFTHRESH_2, EEP_NFTHRESH_2,
@ -454,6 +467,8 @@ enum eeprom_param {
EEP_MINOR_REV, EEP_MINOR_REV,
EEP_TX_MASK, EEP_TX_MASK,
EEP_RX_MASK, EEP_RX_MASK,
EEP_RXGAIN_TYPE,
EEP_TXGAIN_TYPE,
}; };
enum ar5416_rates { enum ar5416_rates {
@ -485,7 +500,11 @@ struct base_eep_header {
u32 binBuildNumber; u32 binBuildNumber;
u8 deviceType; u8 deviceType;
u8 pwdclkind; u8 pwdclkind;
u8 futureBase[32]; u8 futureBase_1[2];
u8 rxGainType;
u8 futureBase_2[3];
u8 txGainType;
u8 futureBase_3[25];
} __packed; } __packed;
struct spur_chan { struct spur_chan {
@ -792,6 +811,8 @@ struct ath_hal_5416 {
struct ar5416IniArray ah_iniAddac; struct ar5416IniArray ah_iniAddac;
struct ar5416IniArray ah_iniPcieSerdes; struct ar5416IniArray ah_iniPcieSerdes;
struct ar5416IniArray ah_iniModesAdditional; struct ar5416IniArray ah_iniModesAdditional;
struct ar5416IniArray ah_iniModesRxGain;
struct ar5416IniArray ah_iniModesTxGain;
}; };
#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/* AR5416 to Fowl ar5146.ini */
static const u32 ar5416Modes_9100[][6] = { static const u32 ar5416Modes_9100[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 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 }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
{ 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
{ 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
{ 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x00008134, 0x00000000 }, { 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 }, { 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 }, { 0x0000813c, 0x00000000 },
{ 0x00008144, 0x00000000 }, { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 }, { 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 }, { 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 }, { 0x00008170, 0x32143320 },
@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x0000832c, 0x00000007 }, { 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 }, { 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 }, { 0x00008334, 0x00000e00 },
{ 0x00008338, 0x00000000 }, { 0x00008338, 0x00070000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff }, { 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 }, { 0x00009808, 0x00000000 },
@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = {
{0x000098c4, 0x00000000 }, {0x000098c4, 0x00000000 },
}; };
/* ar5416 - howl ar5416_howl.ini */
static const u32 ar5416Modes[][6] = { static const u32 ar5416Modes[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = {
{ 0x0000994c, 0x00020028 }, { 0x0000994c, 0x00020028 },
{ 0x0000c95c, 0x004b6a8e }, { 0x0000c95c, 0x004b6a8e },
{ 0x0000c968, 0x000003ce }, { 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb514 }, { 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 }, { 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 }, { 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 }, { 0x0000997c, 0x00000000 },
@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = {
{0x000098cc, 0x00000000 }, {0x000098cc, 0x00000000 },
}; };
/* AR5416 9160 Sowl ar5416_sowl.ini */
static const u32 ar5416Modes_9160[][6] = { static const u32 ar5416Modes_9160[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 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 }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
{ 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
{ 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
{ 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
{ 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
{ 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00008134, 0x00000000 }, { 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 }, { 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 }, { 0x0000813c, 0x00000000 },
{ 0x00008144, 0x00000000 }, { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 }, { 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 }, { 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 }, { 0x00008170, 0x32143320 },
@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000832c, 0x00000007 }, { 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 }, { 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 }, { 0x00008334, 0x00000e00 },
{ 0x00008338, 0x00000000 }, { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff }, { 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 }, { 0x00009808, 0x00000000 },
@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00009958, 0x2108ecff }, { 0x00009958, 0x2108ecff },
{ 0x00009940, 0x00750604 }, { 0x00009940, 0x00750604 },
{ 0x0000c95c, 0x004b6a8e }, { 0x0000c95c, 0x004b6a8e },
{ 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb515 }, { 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 }, { 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 }, { 0x00009978, 0x00000001 },
@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a244, 0x00007bb6 }, { 0x0000a244, 0x00007bb6 },
{ 0x0000a248, 0x0fff3ffc }, { 0x0000a248, 0x0fff3ffc },
{ 0x0000a24c, 0x00000001 }, { 0x0000a24c, 0x00000001 },
{ 0x0000a250, 0x0000a000 }, { 0x0000a250, 0x0000e000 },
{ 0x0000a254, 0x00000000 }, { 0x0000a254, 0x00000000 },
{ 0x0000a258, 0x0cc75380 }, { 0x0000a258, 0x0cc75380 },
{ 0x0000a25c, 0x0f0f0f01 }, { 0x0000a25c, 0x0f0f0f01 },
@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a34c, 0x3fffffff }, { 0x0000a34c, 0x3fffffff },
{ 0x0000a350, 0x3fffffff }, { 0x0000a350, 0x3fffffff },
{ 0x0000a354, 0x0003ffff }, { 0x0000a354, 0x0003ffff },
{ 0x0000a358, 0x79a8aa33 }, { 0x0000a358, 0x79bfaa03 },
{ 0x0000d35c, 0x07ffffef }, { 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 }, { 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 }, { 0x0000d364, 0x17ffffe5 },
@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = {
}; };
static const u32 ar5416Bank6_9160[][3] = { static const u32 ar5416Bank6_9160[][3] = {
{ 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 },
@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = {
{ 0x000098cc, 0x0000000e }, { 0x000098cc, 0x0000000e },
}; };
static u32 ar5416Addac_9160[][2] = { static u32 ar5416Addac_9160[][2] = {
{0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 },
@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = {
{0x000098cc, 0x00000000 }, {0x000098cc, 0x00000000 },
}; };
static u32 ar5416Addac_91601_1[][2] = { static u32 ar5416Addac_91601_1[][2] = {
{0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 },
@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = {
{0x000098cc, 0x00000000 }, {0x000098cc, 0x00000000 },
}; };
/* XXX 9280 1 */
static const u32 ar9280Modes_9280[][6] = { static const u32 ar9280Modes_9280[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = {
{ 0x00007898, 0x2a850160 }, { 0x00007898, 0x2a850160 },
}; };
/* XXX 9280 2 */
static const u32 ar9280Modes_9280_2[][6] = { static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e }, { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
{ 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
{ 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
{ 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
{ 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
{ 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
{ 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c }, { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
{ 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
{ 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x000099d8, 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 }, { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
{ 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
{ 0x0000b20c, 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 }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 }, { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
{ 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, { 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 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
{ 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008134, 0x00000000 }, { 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 }, { 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 }, { 0x0000813c, 0x00000000 },
{ 0x00008144, 0x00000000 }, { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 }, { 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 }, { 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 }, { 0x00008170, 0x32143320 },
@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008258, 0x00000000 }, { 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff }, { 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 }, { 0x00008260, 0x00080922 },
{ 0x00008264, 0xa8a00010 },
{ 0x00008270, 0x00000000 }, { 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 }, { 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 }, { 0x00008278, 0x003e4180 },
@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000832c, 0x00000007 }, { 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 }, { 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 }, { 0x00008334, 0x00000e00 },
{ 0x00008338, 0x00000000 }, { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff }, { 0x00008340, 0x000107ff },
{ 0x00008344, 0x00581043 }, { 0x00008344, 0x00581043 },
@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009958, 0x2108ecff }, { 0x00009958, 0x2108ecff },
{ 0x00009940, 0x14750604 }, { 0x00009940, 0x14750604 },
{ 0x0000c95c, 0x004b6a8e }, { 0x0000c95c, 0x004b6a8e },
{ 0x0000c968, 0x000003ce }, { 0x00009968, 0x000003ce },
{ 0x00009970, 0x190fb515 }, { 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 }, { 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 }, { 0x00009978, 0x00000001 },
@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x000099ec, 0x0cc80caa }, { 0x000099ec, 0x0cc80caa },
{ 0x000099f0, 0x00000000 }, { 0x000099f0, 0x00000000 },
{ 0x000099fc, 0x00001042 }, { 0x000099fc, 0x00001042 },
{ 0x0000a208, 0x803e4788 },
{ 0x0000a210, 0x4080a333 }, { 0x0000a210, 0x4080a333 },
{ 0x0000a214, 0x40206c10 }, { 0x0000a214, 0x40206c10 },
{ 0x0000a218, 0x009c4060 }, { 0x0000a218, 0x009c4060 },
{ 0x0000a220, 0x01834061 }, { 0x0000a220, 0x01834061 },
{ 0x0000a224, 0x00000400 }, { 0x0000a224, 0x00000400 },
{ 0x0000a228, 0x000003b5 }, { 0x0000a228, 0x000003b5 },
{ 0x0000a22c, 0x233f71c0 }, { 0x0000a22c, 0x233f7180 },
{ 0x0000a234, 0x20202020 }, { 0x0000a234, 0x20202020 },
{ 0x0000a238, 0x20202020 }, { 0x0000a238, 0x20202020 },
{ 0x0000a23c, 0x13c88000 }, { 0x0000a23c, 0x13c88000 },
@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000b26c, 0x0ebae9c6 }, { 0x0000b26c, 0x0ebae9c6 },
{ 0x0000d270, 0x00820820 }, { 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce }, { 0x0000a278, 0x1ce739ce },
{ 0x0000a27c, 0x050701ce },
{ 0x0000d35c, 0x07ffffef }, { 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 }, { 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 }, { 0x0000d364, 0x17ffffe5 },
@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00007808, 0x04924914 }, { 0x00007808, 0x04924914 },
{ 0x0000780c, 0x21084210 }, { 0x0000780c, 0x21084210 },
{ 0x00007810, 0x6d801300 }, { 0x00007810, 0x6d801300 },
{ 0x00007814, 0x0019beff },
{ 0x00007818, 0x07e41000 }, { 0x00007818, 0x07e41000 },
{ 0x0000781c, 0x00392000 }, { 0x0000781c, 0x00392000 },
{ 0x00007820, 0x92592480 }, { 0x00007820, 0x92592480 },
@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000782c, 0x04924914 }, { 0x0000782c, 0x04924914 },
{ 0x00007830, 0x21084210 }, { 0x00007830, 0x21084210 },
{ 0x00007834, 0x6d801300 }, { 0x00007834, 0x6d801300 },
{ 0x00007838, 0x0019beff },
{ 0x0000783c, 0x07e40000 }, { 0x0000783c, 0x07e40000 },
{ 0x00007840, 0x00392000 }, { 0x00007840, 0x00392000 },
{ 0x00007844, 0x92592480 }, { 0x00007844, 0x92592480 },
@ -3110,12 +2952,465 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
{ 0x00009828, 0x0b020001, 0x0b020001 }, { 0x00009828, 0x0b020001, 0x0b020001 },
{ 0x00009834, 0x00000f0f, 0x00000f0f }, { 0x00009834, 0x00000f0f, 0x00000f0f },
{ 0x00009844, 0x03721821, 0x03721821 }, { 0x00009844, 0x03721821, 0x03721821 },
{ 0x00009914, 0x00000898, 0x00000898 }, { 0x00009914, 0x00000898, 0x00001130 },
{ 0x00009918, 0x0000000b, 0x00000016 }, { 0x00009918, 0x0000000b, 0x00000016 },
{ 0x00009944, 0xdfbc1210, 0xdfbc1210 }, { 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] = { static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
{0x00004040, 0x9248fd00 }, {0x00004040, 0x9248fd00 },
@ -3123,23 +3418,21 @@ static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
{0x00004040, 0xa8000019 }, {0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 }, {0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 }, {0x00004040, 0xe5980560 },
{0x00004040, 0x401dcffc }, {0x00004040, 0xc01dcffc },
{0x00004040, 0x1aaabe40 }, {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 }, {0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 }, {0x00004040, 0x00043007 },
{0x00004044, 0x00000000 }, {0x00004044, 0x00000000 },
}; };
static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004040, 0x9248fd00 }, {0x00004040, 0x9248fd00 },
{0x00004040, 0x24924924 }, {0x00004040, 0x24924924 },
{0x00004040, 0xa8000019 }, {0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 }, {0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 }, {0x00004040, 0xe5980560 },
{0x00004040, 0x401dcffd }, {0x00004040, 0xc01dcffd },
{0x00004040, 0x1aaabe40 }, {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 }, {0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 }, {0x00004040, 0x00043007 },
{0x00004044, 0x00000000 }, {0x00004044, 0x00000000 },

View File

@ -293,8 +293,10 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
if (ads->ds_txstatus1 & AR_Filtered) if (ads->ds_txstatus1 & AR_Filtered)
ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; 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; ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
ath9k_hw_updatetxtriglevel(ah, true);
}
if (ads->ds_txstatus9 & AR_TxOpExceeded) if (ads->ds_txstatus9 & AR_TxOpExceeded)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
if (ads->ds_txstatus1 & AR_TxTimerExpired) if (ads->ds_txstatus1 & AR_TxTimerExpired)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,83 +20,24 @@
#define RC_H #define RC_H
#include "ath9k.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; struct ath_softc;
#define TRUE 1 #define ATH_RATE_MAX 30
#define FALSE 0 #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 { #define INVALID 0x0
IEEE80211_FIXED_RATE_NONE = 0, #define VALID 0x1
IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */ #define VALID_20 0x2
}; #define VALID_40 0x4
#define VALID_2040 (VALID_20|VALID_40)
/* #define VALID_ALL (VALID_2040|VALID)
* 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 WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ #define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \
@ -113,26 +54,22 @@ enum {
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) #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) ? \ #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 HT20 && client supports HT20 or
* return TRUE if flag supports HT40 && client supports HT40. * return TRUE if flag supports HT40 && client supports HT40.
* This is used becos some rates overlap between HT20/HT40. * This is used becos some rates overlap between HT20/HT40.
*/ */
#define WLAN_RC_PHY_HT_VALID(flag, capflag) \
#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \ (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
& WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \ ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
(capflag & WLAN_RC_40_FLAG)))
#define WLAN_RC_DS_FLAG (0x01) #define WLAN_RC_DS_FLAG (0x01)
#define WLAN_RC_40_FLAG (0x02) #define WLAN_RC_40_FLAG (0x02)
#define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_SGI_FLAG (0x04)
#define WLAN_RC_HT_FLAG (0x08) #define WLAN_RC_HT_FLAG (0x08)
#define RATE_TABLE_SIZE 64
/** /**
* struct ath_rate_table - Rate Control table * struct ath_rate_table - Rate Control table
* @valid: valid for use in rate control * @valid: valid for use in rate control
@ -149,10 +86,11 @@ enum {
* @max_4ms_framelen: maximum frame length(bytes) for tx duration * @max_4ms_framelen: maximum frame length(bytes) for tx duration
* @probe_interval: interval for rate control to probe for other rates * @probe_interval: interval for rate control to probe for other rates
* @rssi_reduce_interval: interval for rate control to reduce rssi * @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 { struct ath_rate_table {
int rate_cnt; int rate_cnt;
u8 rateCodeToIndex[256];
struct { struct {
int valid; int valid;
int valid_single_stream; int valid_single_stream;
@ -170,42 +108,26 @@ struct ath_rate_table {
u8 sgi_index; u8 sgi_index;
u8 ht_index; u8 ht_index;
u32 max_4ms_framelen; u32 max_4ms_framelen;
u16 lpAckDuration;
u16 spAckDuration;
} info[RATE_TABLE_SIZE]; } info[RATE_TABLE_SIZE];
u32 probe_interval; u32 probe_interval;
u32 rssi_reduce_interval; u32 rssi_reduce_interval;
u8 initial_ratemax; 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 { struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */ int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */ 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 * @state: RC state
* @rssi_last: last ACK rssi * @rssi_last: last ACK rssi
* @rssi_last_lookup: last ACK rssi used for lookup * @rssi_last_lookup: last ACK rssi used for lookup
@ -224,9 +146,13 @@ struct ath_tx_ratectrl_state {
* @valid_phy_ratecnt: valid rate count * @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate * @rate_max_phy: phy index for the max rate
* @probe_interval: interval for ratectrl to probe for other rates * @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_rate_priv {
struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
int8_t rssi_last; int8_t rssi_last;
int8_t rssi_last_lookup; int8_t rssi_last_lookup;
int8_t rssi_last_prev; int8_t rssi_last_prev;
@ -236,89 +162,40 @@ struct ath_tx_ratectrl {
int32_t rssi_sum; int32_t rssi_sum;
u8 rate_table_size; u8 rate_table_size;
u8 probe_rate; u8 probe_rate;
u8 hw_maxretry_pktcnt;
u8 max_valid_rate;
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][RATE_TABLE_SIZE];
u8 rc_phy_mode;
u8 rate_max_phy;
u32 rssi_time; u32 rssi_time;
u32 rssi_down_time; u32 rssi_down_time;
u32 probe_time; u32 probe_time;
u8 hw_maxretry_pktcnt;
u8 max_valid_rate;
u8 valid_rate_index[MAX_TX_RATE_TBL];
u32 per_down_time; u32 per_down_time;
/* 11n state */
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
u8 rc_phy_mode;
u8 rate_max_phy;
u32 probe_interval; 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; u32 prev_data_rix;
u32 tx_triglevel_max;
/* ht capabilities */ struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
u8 ht_cap;
/* When TRUE, only single stream Tx possible */
u8 single_stream;
/* Negotiated rates */
struct ath_rateset neg_rates; struct ath_rateset neg_rates;
/* Negotiated HT rates */
struct ath_rateset neg_ht_rates; struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc; struct ath_rate_softc *asc;
struct ath_vap *avp;
}; };
/* Driver data of ieee80211_tx_info */
struct ath_tx_info_priv { struct ath_tx_info_priv {
struct ath_rc_series rcs[4];
struct ath_tx_status tx; struct ath_tx_status tx;
int n_frames; int n_frames;
int n_bad_frames; int n_bad_frames;
u8 min_rate; bool update_rc;
}; };
/* #define ATH_TX_INFO_PRIV(tx_info) \
* Attach/detach a rate control module. ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
*/
struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
void ath_rate_detach(struct ath_rate_softc *asc);
/* void ath_rate_attach(struct ath_softc *sc);
* Update/reset rate control state for 802.11 state transitions. u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
* 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);
/* Routines to register/unregister rate control algorithm */
int ath_rate_control_register(void); int ath_rate_control_register(void);
void ath_rate_control_unregister(void); void ath_rate_control_unregister(void);

View File

@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/*
* Implementation of receive path.
*/
#include "core.h" #include "core.h"
/* /*
@ -27,10 +23,7 @@
* MAC acknowledges BA status as long as it copies frames to host * MAC acknowledges BA status as long as it copies frames to host
* buffer (or rx fifo). This can incorrectly acknowledge packets * buffer (or rx fifo). This can incorrectly acknowledge packets
* to a sender if last desc is self-linked. * 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) static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
{ {
struct ath_hal *ah = sc->sc_ah; 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); ATH_RXBUF_RESET(bf);
ds = bf->bf_desc; 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; 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; skb = bf->bf_mpdu;
ASSERT(skb != NULL); ASSERT(skb != NULL);
ds->ds_vdata = skb->data; ds->ds_vdata = skb->data;
/* setup rx descriptors */ /* setup rx descriptors */
ath9k_hw_setuprxdesc(ah, ath9k_hw_setuprxdesc(ah, ds,
ds, skb_tailroom(skb), /* buffer size */
skb_tailroom(skb), /* buffer size */
0); 0);
if (sc->sc_rxlink == NULL) 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); ath9k_hw_rxena(ah);
} }
static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
u32 len) {
/* 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; struct sk_buff *skb;
u32 off; u32 off;
@ -91,59 +103,133 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
return skb; 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); for (i = 0; i < n_rates; i++) {
if (bf->bf_status & ATH_BUFSTATUS_STALE) { if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
/* break;
* 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);
} }
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. * For Decrypt or Demic errors, we only mark packet status here and always push
* So we have to allocate a new one and queue it by ourselves. * 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, static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
struct sk_buff *skb, struct ieee80211_rx_status *rx_status, bool *decrypt_error,
struct ath_recv_status *status, struct ath_softc *sc)
u16 keyix)
{ {
struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode];
struct sk_buff *nskb; struct ieee80211_hdr *hdr;
int type; int ratekbps, rix;
u8 ratecode;
__le16 fc;
/* indicate frame to the stack, which will free the old skb. */ hdr = (struct ieee80211_hdr *)skb->data;
type = _ath_rx_indicate(sc, skb, status, keyix); fc = hdr->frame_control;
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
/* allocate a new skb and queue it to for H/W processing */ if (ds->ds_rxstat.rs_more) {
nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); /*
if (nskb != NULL) { * Frame spans multiple descriptors; this cannot happen yet
bf->bf_mpdu = nskb; * as we don't support jumbograms. If not in monitor mode,
bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, * discard the frame. Enable this if you want to see
skb_end_pointer(nskb) - nskb->head, * error frames in Monitor mode.
PCI_DMA_FROMDEVICE); */
bf->bf_dmacontext = bf->bf_buf_addr; if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; 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;
/* queue the new wbuf to H/W */ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
ath_rx_requeue(sc, nskb); *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) 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; sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->sc_rxbuflock); 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, sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(sc->sc_cachelsz, min(sc->sc_cachelsz,
(u16)64)); (u16)64));
@ -209,8 +289,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
break; break;
} }
/* Pre-allocate a wbuf for each rx buffer */
list_for_each_entry(bf, &sc->sc_rxbuf, list) { list_for_each_entry(bf, &sc->sc_rxbuf, list) {
skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
if (skb == NULL) { if (skb == NULL) {
@ -223,7 +301,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
skb_end_pointer(skb) - skb->head, skb_end_pointer(skb) - skb->head,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
bf->bf_dmacontext = bf->bf_buf_addr; bf->bf_dmacontext = bf->bf_buf_addr;
ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
} }
sc->sc_rxlink = NULL; sc->sc_rxlink = NULL;
@ -235,8 +312,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
return error; return error;
} }
/* Reclaim all rx queue resources */
void ath_rx_cleanup(struct ath_softc *sc) void ath_rx_cleanup(struct ath_softc *sc)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -248,8 +323,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
/* cleanup rx descriptors */
if (sc->sc_rxdma.dd_desc_len != 0) if (sc->sc_rxdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); 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 || 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; rfilt |= ATH9K_RX_FILTER_BEACON;
/* If in HOSTAP mode, want to enable reception of PSPOLL frames /* If in HOSTAP mode, want to enable reception of PSPOLL frames
& beacon frames */ & beacon frames */
if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
return rfilt; return rfilt;
#undef RX_FILTER_PRESERVE #undef RX_FILTER_PRESERVE
} }
/* Enable the receive h/w following a reset. */
int ath_startrecv(struct ath_softc *sc) int ath_startrecv(struct ath_softc *sc)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
@ -322,21 +394,6 @@ int ath_startrecv(struct ath_softc *sc)
sc->sc_rxlink = NULL; sc->sc_rxlink = NULL;
list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) { 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); 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); bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
ath9k_hw_putrxbuf(ah, bf->bf_daddr); ath9k_hw_putrxbuf(ah, bf->bf_daddr);
ath9k_hw_rxena(ah); /* enable recv descriptors */ ath9k_hw_rxena(ah);
start_recv: start_recv:
spin_unlock_bh(&sc->sc_rxbuflock); spin_unlock_bh(&sc->sc_rxbuflock);
ath_opmode_init(sc); /* set filters, etc. */ ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */ ath9k_hw_startpcureceive(ah);
return 0; return 0;
} }
/* Disable the receive h/w in preparation for a reset. */
bool ath_stoprecv(struct ath_softc *sc) bool ath_stoprecv(struct ath_softc *sc)
{ {
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
u64 tsf;
bool stopped; bool stopped;
ath9k_hw_stoppcurecv(ah); /* disable PCU */ ath9k_hw_stoppcurecv(ah);
ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */ ath9k_hw_setrxfilter(ah, 0);
stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */ stopped = ath9k_hw_stopdmarecv(ah);
mdelay(3); /* 3ms is long enough for 1 frame */ mdelay(3); /* 3ms is long enough for 1 frame */
tsf = ath9k_hw_gettsf64(ah); sc->sc_rxlink = NULL;
sc->sc_rxlink = NULL; /* just in case */
return stopped; return stopped;
} }
/* Flush receive queue */
void ath_flushrecv(struct ath_softc *sc) 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); spin_lock_bh(&sc->sc_rxflushlock);
sc->sc_flags |= SC_OP_RXFLUSH; sc->sc_flags |= SC_OP_RXFLUSH;
ath_rx_tasklet(sc, 1); ath_rx_tasklet(sc, 1);
sc->sc_flags &= ~SC_OP_RXFLUSH; sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_unlock_bh(&sc->sc_rxflushlock); spin_unlock_bh(&sc->sc_rxflushlock);
} }
/* Process receive queue, as well as LED, etc. */
int ath_rx_tasklet(struct ath_softc *sc, int flush) int ath_rx_tasklet(struct ath_softc *sc, int flush)
{ {
#define PA2DESC(_sc, _pa) \ #define PA2DESC(_sc, _pa) \
((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
struct ath_buf *bf, *bf_held = NULL; struct ath_buf *bf;
struct ath_desc *ds; struct ath_desc *ds;
struct ieee80211_hdr *hdr; struct sk_buff *skb = NULL, *requeue_skb;
struct sk_buff *skb = NULL; struct ieee80211_rx_status rx_status;
struct ath_recv_status rx_status;
struct ath_hal *ah = sc->sc_ah; struct ath_hal *ah = sc->sc_ah;
int type, rx_processed = 0; struct ieee80211_hdr *hdr;
u32 phyerr; int hdrlen, padsize, retval;
u8 chainreset = 0; bool decrypt_error = false;
int retval; u8 keyix;
__le16 fc;
spin_lock_bh(&sc->sc_rxbuflock);
do { do {
/* If handling rx interrupt and flush is in progress => exit */ /* If handling rx interrupt and flush is in progress => exit */
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
break; break;
spin_lock_bh(&sc->sc_rxbuflock);
if (list_empty(&sc->sc_rxbuf)) { if (list_empty(&sc->sc_rxbuf)) {
sc->sc_rxlink = NULL; sc->sc_rxlink = NULL;
spin_unlock_bh(&sc->sc_rxbuflock);
break; break;
} }
bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); 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; ds = bf->bf_desc;
++rx_processed;
/* /*
* Must provide the virtual address of the current * 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 * on. All this is necessary because of our use of
* a self-linked list to avoid rx overruns. * a self-linked list to avoid rx overruns.
*/ */
retval = ath9k_hw_rxprocdesc(ah, retval = ath9k_hw_rxprocdesc(ah, ds,
ds,
bf->bf_daddr, bf->bf_daddr,
PA2DESC(sc, ds->ds_link), PA2DESC(sc, ds->ds_link),
0); 0);
@ -482,7 +487,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ath_desc *tds; struct ath_desc *tds;
if (list_is_last(&bf->list, &sc->sc_rxbuf)) { if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
spin_unlock_bh(&sc->sc_rxbuflock); sc->sc_rxlink = NULL;
break; break;
} }
@ -500,215 +505,87 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/ */
tds = tbf->bf_desc; tds = tbf->bf_desc;
retval = ath9k_hw_rxprocdesc(ah, retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
tds, tbf->bf_daddr, PA2DESC(sc, tds->ds_link), 0);
PA2DESC(sc, tds->ds_link), 0);
if (retval == -EINPROGRESS) { if (retval == -EINPROGRESS) {
spin_unlock_bh(&sc->sc_rxbuflock);
break; break;
} }
} }
/* XXX: we do not support frames spanning
* multiple descriptors */
bf->bf_status |= ATH_BUFSTATUS_DONE;
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
if (skb == NULL) { /* XXX ??? can this happen */ if (!skb)
spin_unlock_bh(&sc->sc_rxbuflock);
continue; continue;
}
/* /*
* Now we know it's a completed frame, we can indicate the * If we're asked to flush receive queue, directly
* frame. Remove the previous holding descriptor and leave * chain it back at the queue without processing it.
* this one in the queue as the new holding descriptor.
*/ */
if (bf_held) { if (flush)
list_del(&bf_held->list); goto requeue;
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; if (!ds->ds_rxstat.rs_datalen)
bf_held = bf; goto requeue;
/*
* Release the lock here in case ieee80211_input() return
* the frame immediately by calling ath_rx_mpdu_requeue().
*/
spin_unlock_bh(&sc->sc_rxbuflock);
if (flush) { /* The status portion of the descriptor could get corrupted. */
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
*/
goto rx_next;
}
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
memset(&rx_status, 0, sizeof(struct ath_recv_status));
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 (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) if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
goto rx_next; goto requeue;
/*
* 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 (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
if (rx_status.ratecode & 0x80) { goto requeue;
/* 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;
}
/* sc_noise_floor is only available when the station /* Ensure we always have an skb to requeue once we are done
attaches to an AP, so we use a default value * processing the current buffer's skb */
if we are not yet attached. */ requeue_skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
rx_status.abs_rssi =
ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
pci_dma_sync_single_for_cpu(sc->pdev, /* If there is no memory we ignore the current RX'd frame,
bf->bf_buf_addr, * 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;
/* Sync and unmap the frame */
pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
skb_tailroom(skb), skb_tailroom(skb),
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
pci_unmap_single(sc->pdev, pci_unmap_single(sc->pdev, bf->bf_buf_addr,
bf->bf_buf_addr,
sc->sc_rxbufsize, sc->sc_rxbufsize,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
/* XXX: Ah! make me more readable, use a helper */ skb_put(skb, ds->ds_rxstat.rs_datalen);
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { skb->protocol = cpu_to_be16(ETH_P_CONTROL);
if (ds->ds_rxstat.rs_moreaggr == 0) {
rx_status.rssictl[0] = /* see if any padding is done by the hw and remove it */
ds->ds_rxstat.rs_rssi_ctl0; hdr = (struct ieee80211_hdr *)skb->data;
rx_status.rssictl[1] = hdrlen = ieee80211_get_hdrlen_from_skb(skb);
ds->ds_rxstat.rs_rssi_ctl1;
rx_status.rssictl[2] = if (hdrlen & 3) {
ds->ds_rxstat.rs_rssi_ctl2; padsize = hdrlen % 4;
rx_status.rssi = ds->ds_rxstat.rs_rssi; memmove(skb->data + padsize, skb->data, hdrlen);
if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { skb_pull(skb, padsize);
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;
} }
/* Pass frames up to the stack. */ keyix = ds->ds_rxstat.rs_keyix;
type = ath_rx_indicate(sc, skb, if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
&rx_status, ds->ds_rxstat.rs_keyix); 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 * 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_defant != ds->ds_rxstat.rs_antenna) {
if (++sc->sc_rxotherant >= 3) if (++sc->sc_rxotherant >= 3)
ath_setdefantenna(sc, ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
ds->ds_rxstat.rs_antenna);
} else { } else {
sc->sc_rxotherant = 0; 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 spin_unlock_bh(&sc->sc_rxbuflock);
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);
}
return 0; return 0;
#undef PA2DESC #undef PA2DESC

View File

@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/*
* Implementation of transmit path.
*/
#include "core.h" #include "core.h"
#define BITS_PER_BYTE 8 #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); ath9k_hw_txstart(ah, txq->axq_qnum);
} }
/* Get transmit rate index using rate in Kbps */ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ath_xmit_status *tx_status)
static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
{ {
int i; struct ieee80211_hw *hw = sc->hw;
int ndx = 0; 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++) { DPRINTF(sc, ATH_DBG_XMIT,
if (rt->info[i].rateKbps == rate) { "%s: TX complete: skb: %p\n", __func__, skb);
ndx = i;
break; 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 */ /* 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; 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 */ /* Calculate Atheros packet type from IEEE80211 packet header */
static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) 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; return htype;
} }
static bool check_min_rate(struct sk_buff *skb) static bool is_pae(struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
bool use_minrate = false;
__le16 fc; __le16 fc;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control; fc = hdr->frame_control;
if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { if (ieee80211_is_data(fc)) {
use_minrate = true;
} else if (ieee80211_is_data(fc)) {
if (ieee80211_is_nullfunc(fc) || if (ieee80211_is_nullfunc(fc) ||
/* Port Access Entity (IEEE 802.1X) */ /* Port Access Entity (IEEE 802.1X) */
(skb->protocol == cpu_to_be16(ETH_P_PAE))) { (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) 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; 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 */ /* Called only when tx aggregation is enabled and HT is supported */
static void assign_aggr_tid_seqno(struct sk_buff *skb, 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 */ /* 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. /* For HT capable stations, we save tidno for later use.
* We also override seqno set by upper layer with the one * We also override seqno set by upper layer with the one
* in tx aggregation state. * 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 * width - 0 for 20 MHz, 1 for 40 MHz
* half_gi - to use 4us v/s 3.6 us for symbol time * 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, static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
int width, int half_gi, bool shortPreamble) 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; u32 nbits, nsymbits, duration, nsymbols;
u8 rc; u8 rc;
int streams, pktlen; int streams, pktlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; 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)) if (!IS_HT_RATE(rc))
return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix, return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
shortPreamble); rix, shortPreamble);
/*
* find number of symbols: PLCP + data /* find number of symbols: PLCP + data */
*/
nbits = (pktlen << 3) + OFDM_PLCP_BITS; nbits = (pktlen << 3) + OFDM_PLCP_BITS;
nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
nsymbols = (nbits + nsymbits - 1) / nsymbits; 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 else
duration = SYMBOL_TIME_HALFGI(nsymbols); 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); streams = HT_RC_2_STREAMS(rc);
duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 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) static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{ {
struct ath_hal *ah = sc->sc_ah; 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 *ds = bf->bf_desc;
struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
struct ath9k_11n_rate_series series[4]; 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; int i, flags, rtsctsena = 0;
u32 ctsduration = 0; u32 ctsduration = 0;
u8 rix = 0, cix, ctsrate = 0; u8 rix = 0, cix, ctsrate = 0;
struct ath_node *an = NULL; __le16 fc;
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info; memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
skb = (struct sk_buff *)bf->bf_mpdu; skb = (struct sk_buff *)bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
rates = tx_info->control.rates;
if (tx_info->control.sta) if (ieee80211_has_morefrags(fc) ||
an = (struct ath_node *)tx_info->control.sta->drv_priv; (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 */
* get the cix for the lowest valid rix. rt = sc->hw_rate_table[sc->sc_curmode];
*/ for (i = 3; i >= 0; i--) {
rt = sc->sc_currates; if (rates[i].count && (rates[i].idx >= 0)) {
for (i = 4; i--;) { rix = rates[i].idx;
if (bf->bf_rcs[i].tries) {
rix = bf->bf_rcs[i].rix;
break; break;
} }
} }
flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)); 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 * If 802.11g protection is enabled, determine whether to use RTS/CTS or
* to use RTS/CTS or just CTS. Note that this is only * just CTS. Note that this is only done for OFDM/HT unicast frames.
* done for OFDM/HT unicast frames.
*/ */
if (sc->sc_protmode != PROT_M_NONE && if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
(rt->info[rix].phy == PHY_OFDM || && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
rt->info[rix].phy == PHY_HT) && WLAN_RC_PHY_HT(rt->info[rix].phy))) {
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
if (sc->sc_protmode == PROT_M_RTSCTS) if (sc->sc_protmode == PROT_M_RTSCTS)
flags = ATH9K_TXDESC_RTSENA; flags = ATH9K_TXDESC_RTSENA;
else if (sc->sc_protmode == PROT_M_CTSONLY) else if (sc->sc_protmode == PROT_M_CTSONLY)
flags = ATH9K_TXDESC_CTSENA; flags = ATH9K_TXDESC_CTSENA;
cix = rt->info[sc->sc_protrix].controlRate; cix = rt->info[sc->sc_protrix].ctrl_rate;
rtsctsena = 1; rtsctsena = 1;
} }
/* For 11n, the default behavior is to enable RTS for /* For 11n, the default behavior is to enable RTS for hw retried frames.
* hw retried frames. We enable the global flag here and * We enable the global flag here and let rate series flags determine
* let rate series flags determine which rates will actually * which rates will actually use RTS.
* use RTS.
*/ */
if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { 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) if (!rtsctsena)
flags = ATH9K_TXDESC_RTSENA; flags = ATH9K_TXDESC_RTSENA;
} }
/* /* Set protection if aggregate protection on */
* Set protection if aggregate protection on
*/
if (sc->sc_config.ath_aggr_prot && if (sc->sc_config.ath_aggr_prot &&
(!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
flags = ATH9K_TXDESC_RTSENA; flags = ATH9K_TXDESC_RTSENA;
cix = rt->info[sc->sc_protrix].controlRate; cix = rt->info[sc->sc_protrix].ctrl_rate;
rtsctsena = 1; rtsctsena = 1;
} }
/* /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
* 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))
*/
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.
*/
flags &= ~(ATH9K_TXDESC_RTSENA); flags &= ~(ATH9K_TXDESC_RTSENA);
}
/* /*
* CTS transmit rate is derived from the transmit rate * CTS transmit rate is derived from the transmit rate by looking in the
* by looking in the h/w rate table. We must also factor * h/w rate table. We must also factor in whether or not a short
* in whether or not a short preamble is to be used. * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
* NB: cix is set above where RTS/CTS is enabled
*/ */
BUG_ON(cix == 0xff); ctsrate = rt->info[cix].ratecode |
ctsrate = rt->info[cix].rateCode | (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
(bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
/*
* Setup HAL rate series
*/
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (!bf->bf_rcs[i].tries) if (!rates[i].count || (rates[i].idx < 0))
continue; continue;
rix = bf->bf_rcs[i].rix; rix = rates[i].idx;
series[i].Rate = rt->info[rix].rateCode | series[i].Rate = rt->info[rix].ratecode |
(bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); (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 = ( 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) | 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) | 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); ATH9K_RATESERIES_HALFGI : 0);
series[i].PktDuration = ath_pkt_duration(sc, rix, bf, series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
(bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
(bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
bf_isshpreamble(bf)); bf_isshpreamble(bf));
if (bf_isht(bf) && an) series[i].ChSel = sc->sc_tx_chainmask;
series[i].ChSel = ath_chainmask_sel_logic(sc, an);
else
series[i].ChSel = sc->sc_tx_chainmask;
if (rtsctsena) if (rtsctsena)
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
} }
/* /* set dur_update_en for l-sig computation except for PS-Poll frames */
* For non-HT devices, calculate RTS/CTS duration in software ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
* and disable multi-rate retry. ctsrate, ctsduration,
*/
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,
series, 4, flags); series, 4, flags);
if (sc->sc_config.ath_aggr_prot && 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 * Function to send a normal HT (non-AMPDU) frame
* NB: must be called with txq lock held * NB: must be called with txq lock held
*/ */
static int ath_tx_send_normal(struct ath_softc *sc, static int ath_tx_send_normal(struct ath_softc *sc,
struct ath_txq *txq, struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct list_head *bf_head) struct list_head *bf_head)
{ {
struct ath_buf *bf; 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)); BUG_ON(list_empty(bf_head));
bf = list_first_entry(bf_head, struct ath_buf, list); bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ 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 */ /* update starting sequence number for subsequent ADDBA request */
INCR(tid->seq_start, IEEE80211_SEQ_MAX); INCR(tid->seq_start, IEEE80211_SEQ_MAX);
@ -1051,18 +950,37 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
return; 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 */ /* 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_hal *ah = sc->sc_ah;
struct ath_buf *bf, *lastbf, *bf_held = NULL; struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head; struct list_head bf_head;
struct ath_desc *ds, *tmp_ds; struct ath_desc *ds;
struct sk_buff *skb; int txok, nbad = 0;
struct ieee80211_tx_info *tx_info;
struct ath_tx_info_priv *tx_info_priv;
int nacked, txok, nbad = 0, isrifs = 0;
int status; int status;
DPRINTF(sc, ATH_DBG_QUEUE, 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_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
txq->axq_link); txq->axq_link);
nacked = 0;
for (;;) { for (;;) {
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
if (list_empty(&txq->axq_q)) { if (list_empty(&txq->axq_q)) {
@ -1160,30 +1077,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
} else { } else {
nbad = ath_tx_num_badfrms(sc, bf, txok); nbad = ath_tx_num_badfrms(sc, bf, txok);
} }
skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
/* XXX: HACK! */ ath_tx_rc_status(bf, ds, nbad);
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;
}
}
/* /*
* Complete this transmit unit * 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); ath_txq_schedule(sc, txq);
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
} }
return nacked;
} }
static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) 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); spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, if (!ath9k_hw_reset(ah,
sc->sc_ah->ah_curchan, 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_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, true, &status)) { 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_tx_control *txctl)
{ {
struct ath_buf *bf; 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)); BUG_ON(list_empty(bf_head));
@ -1335,12 +1226,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
return 0; 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 */ /* Add sub-frame to BAW */
ath_tx_addto_baw(sc, tid, bf); 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_buf *bf,
struct ath_atx_tid *tid) 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 sk_buff *skb;
struct ieee80211_tx_info *tx_info; struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
struct ath_tx_info_priv *tx_info_priv; struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frame_length; u32 max_4ms_framelen, frame_length;
u16 aggr_limit, legacy = 0, maxampdu; 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; skb = (struct sk_buff *)bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
tx_info_priv = (struct ath_tx_info_priv *) rates = tx_info->control.rates;
tx_info->control.vif; /* XXX: HACK! */ tx_info_priv =
memcpy(bf->bf_rcs, (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
/* /*
* Find the lowest frame length among the rate series that will have a * 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; max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (bf->bf_rcs[i].tries) { if (rates[i].count) {
frame_length = bf->bf_rcs[i].max_4ms_framelen; if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
legacy = 1; legacy = 1;
break; break;
} }
frame_length =
rate_table->info[rates[i].idx].max_4ms_framelen;
max_4ms_framelen = min(max_4ms_framelen, frame_length); 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, struct ath_buf *bf,
u16 frmlen) 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; u32 nsymbits, nsymbols, mpdudensity;
u16 minlen; u16 minlen;
u8 rc, flags, rix; u8 rc, flags, rix;
@ -1464,11 +1351,11 @@ static int ath_compute_num_delims(struct ath_softc *sc,
if (mpdudensity == 0) if (mpdudensity == 0)
return ndelim; return ndelim;
rix = bf->bf_rcs[0].rix; rix = tx_info->control.rates[0].idx;
flags = bf->bf_rcs[0].flags; flags = tx_info->control.rates[0].flags;
rc = rt->info[rix].rateCode; rc = rt->info[rix].ratecode;
width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0; width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0; half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi) if (half_gi)
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); 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, u16 aggr_limit = 0, al = 0, bpad = 0,
al_delta, h_baw = tid->baw_size / 2; al_delta, h_baw = tid->baw_size / 2;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; 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); INIT_LIST_HEAD(&bf_head);
BUG_ON(list_empty(&tid->buf_q)); 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) { if (!rl) {
aggr_limit = ath_lookup_rate(sc, bf, tid); aggr_limit = ath_lookup_rate(sc, bf, tid);
rl = 1; 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, 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 ath_tx_control *txctl)
{ {
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_tx_info_priv *tx_info_priv; struct ath_tx_info_priv *tx_info_priv;
struct ath_rc_series *rcs;
int hdrlen; int hdrlen;
__le16 fc; __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); hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control; fc = hdr->frame_control;
rcs = tx_info_priv->rcs;
ATH_TXBUF_RESET(bf); 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) ? (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
(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)) ? (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ?
(bf->bf_state.bf_type |= BUF_HT) : (bf->bf_state.bf_type |= BUF_HT) :
(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; 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 */ /* Assign seqno, tidno */
if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) 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 */ /* FIXME: tx power */
static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, 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 ath_tx_control *txctl)
{ {
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; 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); bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
ath9k_hw_filltxdesc(ah, ds, ath9k_hw_filltxdesc(ah, ds,
sg_dma_len(sg), /* segment length */ skb->len, /* segment length */
true, /* first segment */ true, /* first segment */
(n_sg == 1) ? true : false, /* last segment */ true, /* last segment */
ds); /* first descriptor */ ds); /* first descriptor */
bf->bf_lastfrm = bf; 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_tx_control *txctl)
{ {
struct ath_buf *bf; struct ath_buf *bf;
struct scatterlist sg;
/* Check if a tx buffer is available */ /* 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; return -1;
} }
ath_tx_setup_buffer(sc, bf, skb, &sg, txctl); ath_tx_setup_buffer(sc, bf, skb, txctl);
ath_tx_start_dma(sc, bf, 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);
return 0; return 0;
} }

View File

@ -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); 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", IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask, addr, bits, mask,
unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret; return ret;
} }
#define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \ #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \

View File

@ -886,7 +886,6 @@ struct iwl3945_priv {
struct work_struct report_work; struct work_struct report_work;
struct work_struct request_scan; struct work_struct request_scan;
struct work_struct beacon_update; struct work_struct beacon_update;
struct work_struct set_monitor;
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;

View File

@ -53,6 +53,7 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
* is not compatible with earlier drivers. * is not compatible with earlier drivers.
* This number will also appear in << 8 position of 1st dword of uCode file */ * This number will also appear in << 8 position of 1st dword of uCode file */
#define IWL4965_UCODE_API "-2" #define IWL4965_UCODE_API "-2"
#define IWL4965_MODULE_FIRMWARE "iwlwifi-4965" IWL4965_UCODE_API ".ucode"
/* module parameters */ /* module parameters */
@ -661,7 +662,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
int txq_id = txq->q.id; int txq_id = txq->q.id;
/* Find out whether to activate Tx queue */ /* 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 */ /* Set up and activate */
iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), 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) static int iwl4965_alive_notify(struct iwl_priv *priv)
{ {
u32 a; u32 a;
int i = 0;
unsigned long flags; unsigned long flags;
int ret; int ret;
int i, chan;
u32 reg_val;
spin_lock_irqsave(&priv->lock, flags); 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, iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
priv->scd_bc_tbls.dma >> 10); 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 */ /* Disable chain mode for all queues */
iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); 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); (1 << priv->hw_params.max_txq_num) - 1);
/* Activate all Tx DMA/FIFO channels */ /* 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); 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); ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this 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); spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv); 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 = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1; info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU; 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; IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info); iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
/* FIXME: code repetition end */ /* FIXME: code repetition end */
@ -2322,7 +2335,7 @@ static struct iwl_ops iwl4965_ops = {
struct iwl_cfg iwl4965_agn_cfg = { struct iwl_cfg iwl4965_agn_cfg = {
.name = "4965AGN", .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, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.eeprom_size = IWL4965_EEPROM_IMG_SIZE, .eeprom_size = IWL4965_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_4965_EEPROM_VERSION, .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
@ -2332,7 +2345,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
}; };
/* Module firmware */ /* 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_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");

View File

@ -475,6 +475,9 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
index = IWL_CALIB_TX_IQ_PERD; index = IWL_CALIB_TX_IQ_PERD;
break; break;
case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
index = IWL_CALIB_BASE_BAND;
break;
default: default:
IWL_ERROR("Unknown calibration notification %d\n", IWL_ERROR("Unknown calibration notification %d\n",
hdr->op_code); 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) static int iwl5000_alive_notify(struct iwl_priv *priv)
{ {
u32 a; u32 a;
int i = 0;
unsigned long flags; unsigned long flags;
int ret; int ret;
int i, chan;
u32 reg_val;
spin_lock_irqsave(&priv->lock, flags); 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, iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
priv->scd_bc_tbls.dma >> 10); 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, iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); 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 = priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD); BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
break; break;
case CSR_HW_REV_TYPE_5150: case CSR_HW_REV_TYPE_5150:
priv->hw_params.calib_init_cfg = 0; 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); ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this 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); spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv); 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 = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.rates[0].count = tx_resp->failure_frame + 1; info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU; 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; IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info); iwl_hwrate_to_tx_control(priv, rate_n_flags, info);

View File

@ -281,10 +281,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
u32 time_diff; u32 time_diff;
s32 index; s32 index;
struct iwl_traffic_load *tl = NULL; struct iwl_traffic_load *tl = NULL;
__le16 fc = hdr->frame_control;
u8 tid; u8 tid;
if (ieee80211_is_data_qos(fc)) { if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr); u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf; tid = qc[0] & 0xf;
} else } else
@ -773,7 +772,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
int status; int status;
u8 retries; u8 retries;
int rs_index, index = 0; 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 iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r; 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 tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *search_tbl; struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
u8 active_index = 0; u8 active_index = 0;
__le16 fc = hdr->frame_control;
s32 tpt = 0; s32 tpt = 0;
IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); 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; return;
/* This packet was aggregated but doesn't carry rate scale info */ /* 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) if (retries > 15)
retries = 15; retries = 15;
lq_sta = (struct iwl_lq_sta *)priv_sta;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) !lq_sta->ibss_sta_added)
goto out; goto out;
@ -1675,7 +1672,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
int high_tpt = IWL_INVALID_VALUE; int high_tpt = IWL_INVALID_VALUE;
u32 fail_count; u32 fail_count;
s8 scale_action = 0; s8 scale_action = 0;
__le16 fc;
u16 rate_mask; u16 rate_mask;
u8 update_lq = 0; u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1; 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"); IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
fc = hdr->frame_control; /* Send management frames and broadcast/multicast data using
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { * lowest rate. */
/* Send management frames and broadcast/multicast data using /* TODO: this could probably be improved.. */
* lowest rate. */ if (!ieee80211_is_data(hdr->frame_control) ||
/* TODO: this could probably be improved.. */ is_multicast_ether_addr(hdr->addr1))
return; return;
}
if (!sta || !lq_sta) if (!sta || !lq_sta)
return; 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) struct ieee80211_tx_rate_control *txrc)
{ {
int i;
struct sk_buff *skb = txrc->skb; struct sk_buff *skb = txrc->skb;
struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_conf *conf = &priv->hw->conf;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
__le16 fc; struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_lq_sta *lq_sta; int rate_idx;
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
/* Send management frames and broadcast/multicast data using lowest /* Send management frames and broadcast/multicast data using lowest
* rate. */ * rate. */
fc = hdr->frame_control; if (!ieee80211_is_data(hdr->frame_control) ||
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) {
!sta || !priv_sta) {
info->control.rates[0].idx = rate_lowest_index(sband, sta); info->control.rates[0].idx = rate_lowest_index(sband, sta);
return; return;
} }
lq_sta = (struct iwl_lq_sta *)priv_sta; rate_idx = lq_sta->last_txrate_idx;
i = lq_sta->last_txrate_idx;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) { !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)) { if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
info->control.rates[0].idx = rate_lowest_index(sband, sta); rate_idx = rate_lowest_index(sband, sta);
return; else if (sband->band == IEEE80211_BAND_5GHZ)
} rate_idx -= IWL_FIRST_OFDM_RATE;
if (sband->band == IEEE80211_BAND_5GHZ) info->control.rates[0].idx = rate_idx;
i -= IWL_FIRST_OFDM_RATE;
info->control.rates[0].idx = i;
} }
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, 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++) { for (i = 0; i < LQ_SIZE; i++) {
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
"rate=0x%X\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].lq_type,
lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_SGI,
lq_sta->lq_info[i].is_fat, lq_sta->lq_info[i].is_fat,

View File

@ -466,9 +466,9 @@ static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
/* Set rate mask*/ /* Set rate mask*/
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) 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 else
rate_mask = priv->active_rate_basic & 0xFF0; rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
/* Find lowest valid rate */ /* Find lowest valid rate */
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; 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; hw_rf_kill = 1;
IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", 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. /* driver only loads ucode once setting the interface up.
* the driver as well won't allow loading if RFKILL is set * 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); 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) static void iwl_bg_run_time_calib_work(struct work_struct *work)
{ {
struct iwl_priv *priv = container_of(work, struct iwl_priv, 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) int mc_count, struct dev_addr_list *mc_list)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
__le32 *filter_flags = &priv->staging_rxon.filter_flags;
if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", changed_flags, *total_flags);
NL80211_IFTYPE_MONITOR,
changed_flags, *total_flags); if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
/* queue work 'cuz mac80211 is holding a lock which if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
* prevents us from issuing (synchronous) f/w cmds */ *filter_flags |= RXON_FILTER_PROMISC_MSK;
queue_work(priv->workqueue, &priv->set_monitor); else
*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
} }
*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | 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;
}
/* 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; 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, struct ieee80211_key_conf *keyconf, const u8 *addr,
u32 iv32, u16 *phase1key) 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"); IWL_DEBUG_MAC80211("enter\n");
sta_id = iwl_find_station(priv, addr); iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
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_DEBUG_MAC80211("leave\n"); IWL_DEBUG_MAC80211("leave\n");
} }
@ -3239,10 +3207,10 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) { switch (action) {
case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT("start Rx\n"); 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: case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT("stop Rx\n"); 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: case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT("start Tx\n"); IWL_DEBUG_HT("start Tx\n");
return iwl_tx_agg_start(priv, sta->addr, tid, ssn); 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; return 0;
} }
static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats) struct ieee80211_tx_queue_stats *stats)
{ {
@ -3694,7 +3663,8 @@ static ssize_t show_power_level(struct device *d,
break; 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, "\tINDEX:%d", level);
p += sprintf(p, "\n"); p += sprintf(p, "\n");
return p - buf + 1; 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->rx_replenish, iwl_bg_rx_replenish);
INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); 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_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->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);

View File

@ -37,6 +37,7 @@
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-rfkill.h" #include "iwl-rfkill.h"
#include "iwl-power.h" #include "iwl-power.h"
#include "iwl-sta.h"
MODULE_DESCRIPTION("iwl core"); MODULE_DESCRIPTION("iwl core");
@ -237,28 +238,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwl_hw_nic_init); 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) 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_AP) |
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->fw_handles_regulatory = true;
/* Default value; 4 EDCA QOS priorities */ /* Default value; 4 EDCA QOS priorities */
hw->queues = 4; hw->queues = 4;
/* queues to support 11n aggregation */ /* queues to support 11n aggregation */

View File

@ -182,7 +182,6 @@ struct iwl_cfg {
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops); struct ieee80211_ops *hw_ops);
void iwl_hw_detect(struct iwl_priv *priv); 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_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(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); 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_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv); void iwl_rx_replenish(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 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_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q); int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv); void iwl_rx_allocate(struct iwl_priv *priv);

View File

@ -574,11 +574,6 @@ struct iwl_hw_params {
* iwl4965_mac_ <-- mac80211 callback * 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 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 int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
extern const u8 iwl_bcast_addr[ETH_ALEN]; extern const u8 iwl_bcast_addr[ETH_ALEN];
@ -700,6 +695,7 @@ enum iwl_calib {
IWL_CALIB_LO, IWL_CALIB_LO,
IWL_CALIB_TX_IQ, IWL_CALIB_TX_IQ,
IWL_CALIB_TX_IQ_PERD, IWL_CALIB_TX_IQ_PERD,
IWL_CALIB_BASE_BAND,
IWL_CALIB_MAX IWL_CALIB_MAX
}; };
@ -990,7 +986,6 @@ struct iwl_priv {
struct work_struct report_work; struct work_struct report_work;
struct work_struct request_scan; struct work_struct request_scan;
struct work_struct beacon_update; struct work_struct beacon_update;
struct work_struct set_monitor;
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;

View File

@ -72,7 +72,7 @@
* Addresses are offsets from device's PCI hardware base address. * Addresses are offsets from device's PCI hardware base address.
*/ */
#define FH_MEM_LOWER_BOUND (0x1000) #define FH_MEM_LOWER_BOUND (0x1000)
#define FH_MEM_UPPER_BOUND (0x1EF0) #define FH_MEM_UPPER_BOUND (0x2000)
/** /**
* Keep-Warm (KW) buffer base address. * Keep-Warm (KW) buffer base address.
@ -268,6 +268,8 @@
#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000) #define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000)
#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
/** /**
* Rx Shared Status Registers (RSSR) * Rx Shared Status Registers (RSSR)
@ -294,6 +296,13 @@
#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 #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) * Transmit DMA Channel Control/Status Registers (TCSR)
* *
@ -323,6 +332,7 @@
#define FH49_TCSR_CHNL_NUM (7) #define FH49_TCSR_CHNL_NUM (7)
#define FH50_TCSR_CHNL_NUM (8) #define FH50_TCSR_CHNL_NUM (8)
/* TCSR: tx_config register values */
#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ #define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
#define FH_TCSR_CHNL_TX_CREDIT_REG(_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_BUFS_EMPTY(_chnl) | \
FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_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 */ /* Tx service channels */
#define FH_SRVC_CHNL (9) #define FH_SRVC_CHNL (9)
#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) #define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8)
#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) #define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
/* TFDB Area - TFDs buffer table */ #define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98)
#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) /* Instruct FH to increment the retry count of a packet when
#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) * it is brought from the memory to TX-FIFO
#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) */
#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) #define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002)
#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)
/** /**
* struct iwl_rb_status - reseve buffer status * struct iwl_rb_status - reseve buffer status
@ -423,9 +420,10 @@ struct iwl_rb_status {
} __attribute__ ((packed)); } __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_TX_DMA_MASK DMA_BIT_MASK(36)
#define IWL_NUM_OF_TBS 20 #define IWL_NUM_OF_TBS 20
static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) 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 * @lo: low [31:0] portion of the dma address of TX buffer
* every even is unaligned on 16 bit boundary * every even is unaligned on 16 bit boundary
* @hi_n_len 0-3 [35:32] portion of dma * @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 { struct iwl_tfd_tb {
__le32 lo; __le32 lo;
@ -453,7 +451,8 @@ struct iwl_tfd_tb {
* Transmit Frame Descriptor (TFD) * Transmit Frame Descriptor (TFD)
* *
* @ __reserved1[3] reserved * @ __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) * 6-7 padding (not used)
* @ tbs[20] transmit frame buffer descriptors * @ tbs[20] transmit frame buffer descriptors
* @ __pad padding * @ __pad padding
@ -473,8 +472,6 @@ struct iwl_tfd_tb {
* Tx frame, up to 8 KBytes in size. * Tx frame, up to 8 KBytes in size.
* *
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. * 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 { struct iwl_tfd {
u8 __reserved1[3]; u8 __reserved1[3];
@ -485,6 +482,6 @@ struct iwl_tfd {
/* Keep Warm Size */ /* Keep Warm Size */
#define IWL_KW_SIZE 0x1000 /*4k */ #define IWL_KW_SIZE 0x1000 /* 4k */
#endif /* !__iwl_fh_h__ */ #endif /* !__iwl_fh_h__ */

View File

@ -36,7 +36,7 @@
#include "iwl-core.h" #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) const char *get_cmd_string(u8 cmd)
{ {

View File

@ -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); 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", IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask, addr, bits, mask,
unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret; return ret;
} }
#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ #define iwl_poll_bit(priv, addr, bits, mask, timeout) \

View File

@ -499,49 +499,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
} }
EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); 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 /* Calculate noise level, based on measurements during network silence just
* before arriving beacon. This measurement can be done only if we know * 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. */ /* This is necessary only for a number of statistics, see the caller. */
static int iwl_is_network_packet(struct iwl_priv *priv, static int iwl_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header) struct ieee80211_hdr *header)

View File

@ -132,7 +132,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
return 1; 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_addsta_cmd *sta, u8 flags)
{ {
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *res = NULL;
@ -180,7 +180,6 @@ int iwl_send_add_sta(struct iwl_priv *priv,
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_send_add_sta);
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_sta_ht_cap *sta_ht_inf) struct ieee80211_sta_ht_cap *sta_ht_inf)
@ -464,6 +463,29 @@ out:
} }
EXPORT_SYMBOL(iwl_remove_station); 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) static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{ {
int i; int i;
@ -703,6 +725,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
return ret; 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, int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf, struct ieee80211_key_conf *keyconf,
u8 sta_id) 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); 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; 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); 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;
}
}
}

View File

@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id); struct ieee80211_key_conf *key, u8 sta_id);
int iwl_remove_dynamic_key(struct iwl_priv *priv, int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id); 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_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); 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); 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); 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__ */ #endif /* __iwl_sta_h__ */

View File

@ -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), iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8); 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); iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
@ -587,8 +582,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
/* Alloc and init all Tx queues, including the command queue (#4) */ /* 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++) { for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? 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) void iwl_txq_ctx_stop(struct iwl_priv *priv)
{ {
int txq_id; int txq_id;
unsigned long flags; unsigned long flags;
/* Turn off all Tx DMA fifos */ /* Turn off all Tx DMA fifos */
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) { 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); ack = bitmap & (1ULL << i);
successes += !!ack; successes += !!ack;
IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", 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); agg->start_idx + i);
} }

View File

@ -519,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
/*************** HOST COMMAND QUEUE FUNCTIONS *****/ /*************** 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) 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*/ /* Set rate mask*/
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) 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 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; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
i = iwl3945_rates[i].next_ieee) { 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, IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
"RF_KILL bit toggled to %s.\n", "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" /* Queue restart only if RF_KILL switch was set to "kill"
* when we loaded driver, and is now set to "enable". * 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); 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) #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl3945_bg_scan_check(struct work_struct *data) 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: case NL80211_IFTYPE_ADHOC:
/* clear out the station table */ priv->assoc_id = 1;
iwl3945_clear_stations_table(priv);
iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_add_station(priv, priv->bssid, 0, 0);
iwl3945_sync_sta(priv, IWL_STA_ID, iwl3945_sync_sta(priv, IWL_STA_ID,
(priv->band == IEEE80211_BAND_5GHZ) ? (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) int mc_count, struct dev_addr_list *mc_list)
{ {
struct iwl3945_priv *priv = hw->priv; struct iwl3945_priv *priv = hw->priv;
__le32 *filter_flags = &priv->staging_rxon.filter_flags;
if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", changed_flags, *total_flags);
NL80211_IFTYPE_MONITOR,
changed_flags, *total_flags); if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
/* queue work 'cuz mac80211 is holding a lock which if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
* prevents us from issuing (synchronous) f/w cmds */ *filter_flags |= RXON_FILTER_PROMISC_MSK;
queue_work(priv->workqueue, &priv->set_monitor); else
*filter_flags &= ~RXON_FILTER_PROMISC_MSK;
} }
*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | 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;
}
/* 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; 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->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); 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->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); 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); struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
unsigned long flags; unsigned long flags;
/***********************
* 1. Allocating HW data
* ********************/
/* Disabling hardware scan means that mac80211 will perform scans /* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */ * "the hard way", rather than using device's scan. */
if (iwl3945_param_disable_hw_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; err = -ENOMEM;
goto out; goto out;
} }
SET_IEEE80211_DEV(hw, &pdev->dev); SET_IEEE80211_DEV(hw, &pdev->dev);
hw->rate_control_algorithm = "iwl-3945-rs";
hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
priv = hw->priv; priv = hw->priv;
priv->hw = hw; priv->hw = hw;
priv->pci_dev = pdev; priv->pci_dev = pdev;
priv->cfg = cfg; 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) */ /* Select antenna (may be helpful if only one antenna is connected) */
priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
#ifdef CONFIG_IWL3945_DEBUG #ifdef CONFIG_IWL3945_DEBUG
iwl3945_debug_level = iwl3945_param_debug; iwl3945_debug_level = iwl3945_param_debug;
atomic_set(&priv->restrict_refcnt, 0); atomic_set(&priv->restrict_refcnt, 0);
#endif #endif
priv->retry_rate = 1;
priv->ibss_beacon = NULL;
/* Tell mac80211 our characteristics */ /* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM | 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_STATION) |
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->fw_handles_regulatory = true;
/* 4 EDCA QOS priorities */ /* 4 EDCA QOS priorities */
hw->queues = 4; hw->queues = 4;
spin_lock_init(&priv->lock); /***************************
spin_lock_init(&priv->power_data.lock); * 2. Initializing PCI bus
spin_lock_init(&priv->sta_lock); * *************************/
spin_lock_init(&priv->hcmd_lock);
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
if (pci_enable_device(pdev)) { if (pci_enable_device(pdev)) {
err = -ENODEV; err = -ENODEV;
goto out_ieee80211_free_hw; 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); 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); err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err) if (!err)
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 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) if (err)
goto out_pci_disable_device; goto out_pci_disable_device;
/* We disable the RETRY_TIMEOUT register (0x41) to keep /***********************
* PCI Tx retries from interfering with C3 CPU state */ * 3. Read REV Register
pci_write_config_byte(pdev, 0x41, 0x00); * ********************/
priv->hw_base = pci_iomap(pdev, 0, 0); priv->hw_base = pci_iomap(pdev, 0, 0);
if (!priv->hw_base) { if (!priv->hw_base) {
err = -ENODEV; err = -ENODEV;
@ -7894,51 +7888,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
(unsigned long long) pci_resource_len(pdev, 0)); (unsigned long long) pci_resource_len(pdev, 0));
IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); 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 */
/* Disable radio (SW RF KILL) via parameter when loading driver */ pci_write_config_byte(pdev, 0x41, 0x00);
if (iwl3945_param_disable) {
set_bit(STATUS_RF_KILL_SW, &priv->status);
IWL_DEBUG_INFO("Radio disabled.\n");
}
priv->iw_mode = NL80211_IFTYPE_STATION;
printk(KERN_INFO DRV_NAME
": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
/* Device-specific setup */
if (iwl3945_hw_set_hw_setting(priv)) {
IWL_ERROR("failed to set hw settings\n");
goto out_iounmap;
}
if (iwl3945_param_qos_enable)
priv->qos_data.qos_enable = 1;
iwl3945_reset_qos(priv);
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);
if (err) {
IWL_ERROR("failed to create sysfs device attributes\n");
goto out_release_irq;
}
/* nic init */ /* nic init */
iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
@ -7952,6 +7904,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO("Failed to init the card\n"); IWL_DEBUG_INFO("Failed to init the card\n");
goto out_remove_sysfs; goto out_remove_sysfs;
} }
/***********************
* 4. Read EEPROM
* ********************/
/* Read the EEPROM */ /* Read the EEPROM */
err = iwl3945_eeprom_init(priv); err = iwl3945_eeprom_init(priv);
if (err) { if (err) {
@ -7963,10 +7919,57 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
SET_IEEE80211_PERM_ADDR(priv->hw, 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;
iwl3945_reset_qos(priv);
priv->qos_data.qos_active = 0;
priv->qos_data.qos_cap.val = 0;
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;
err = iwl3945_init_channel_map(priv); err = iwl3945_init_channel_map(priv);
if (err) { if (err) {
IWL_ERROR("initializing regulatory failed: %d\n", err); IWL_ERROR("initializing regulatory failed: %d\n", err);
goto out_remove_sysfs; goto out_release_irq;
} }
err = iwl3945_init_geos(priv); err = iwl3945_init_geos(priv);
@ -7975,16 +7978,58 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
goto out_free_channel_map; goto out_free_channel_map;
} }
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");
}
/***********************
* 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("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); err = ieee80211_register_hw(priv->hw);
if (err) { if (err) {
IWL_ERROR("Failed to register network device (error %d)\n", 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->hw->conf.beacon_int = 100;
priv->mac80211_registered = 1; priv->mac80211_registered = 1;
pci_save_state(pdev);
pci_disable_device(pdev);
err = iwl3945_rfkill_init(priv); err = iwl3945_rfkill_init(priv);
if (err) if (err)
@ -7993,12 +8038,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
return 0; return 0;
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
out_free_geos: out_free_geos:
iwl3945_free_geos(priv); iwl3945_free_geos(priv);
out_free_channel_map: out_free_channel_map:
iwl3945_free_channel_map(priv); iwl3945_free_channel_map(priv);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
out_release_irq: out_release_irq:
destroy_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue);

View File

@ -452,9 +452,9 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
hwsim_check_magic(vif); hwsim_check_magic(vif);
if (conf->changed & IEEE80211_IFCC_BSSID) { if (conf->changed & IEEE80211_IFCC_BSSID) {
DECLARE_MAC_BUF(mac); 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__, wiphy_name(hw->wiphy), __func__,
print_mac(mac, conf->bssid)); conf->bssid);
memcpy(vp->bssid, conf->bssid, ETH_ALEN); memcpy(vp->bssid, conf->bssid, ETH_ALEN);
} }
return 0; return 0;
@ -612,9 +612,8 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
if (!vp->assoc) if (!vp->assoc)
return; return;
printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n", printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
wiphy_name(data->hw->wiphy), __func__, wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
print_mac(buf, vp->bssid), vp->aid);
skb = dev_alloc_skb(sizeof(*pspoll)); skb = dev_alloc_skb(sizeof(*pspoll));
if (!skb) if (!skb)
@ -644,9 +643,8 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
if (!vp->assoc) if (!vp->assoc)
return; return;
printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n", printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
wiphy_name(data->hw->wiphy), __func__, wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
print_mac(buf, vp->bssid), ps);
skb = dev_alloc_skb(sizeof(*hdr)); skb = dev_alloc_skb(sizeof(*hdr));
if (!skb) if (!skb)

View File

@ -84,6 +84,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/suspend.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
@ -431,9 +432,9 @@ struct fw_info {
}; };
const static struct fw_info orinoco_fw[] = { const static struct fw_info orinoco_fw[] = {
{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
}; };
/* Structure used to access fields in FW /* Structure used to access fields in FW
@ -487,18 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err) if (err)
goto free; goto free;
if (priv->cached_fw) if (!priv->cached_fw) {
fw_entry = priv->cached_fw;
else {
err = request_firmware(&fw_entry, firmware, priv->dev); err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) { if (err) {
printk(KERN_ERR "%s: Cannot find firmware %s\n", printk(KERN_ERR "%s: Cannot find firmware %s\n",
dev->name, firmware); dev->name, firmware);
err = -ENOENT; err = -ENOENT;
goto free; goto free;
} }
priv->cached_fw = fw_entry; } else
} fw_entry = priv->cached_fw;
hdr = (const struct orinoco_fw_header *) fw_entry->data; 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)); dev->name, hermes_present(hw));
abort: abort:
/* In case of error, assume firmware was bogus and release it */ /* If we requested the firmware, release it. */
if (err) { if (!priv->cached_fw)
priv->cached_fw = NULL;
release_firmware(fw_entry); release_firmware(fw_entry);
}
free: free:
kfree(pda); kfree(pda);
@ -648,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv,
int ret; int ret;
const struct firmware *fw_entry; const struct firmware *fw_entry;
if (request_firmware(&fw_entry, fw->pri_fw, if (!priv->cached_pri_fw) {
priv->dev) != 0) { if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
printk(KERN_ERR "%s: Cannot find firmware: %s\n", printk(KERN_ERR "%s: Cannot find firmware: %s\n",
dev->name, fw->pri_fw); dev->name, fw->pri_fw);
return -ENOENT; return -ENOENT;
} }
} else
fw_entry = priv->cached_pri_fw;
/* Load primary firmware */ /* Load primary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data, ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 0); fw_entry->data + fw_entry->size, 0);
release_firmware(fw_entry);
if (!priv->cached_pri_fw)
release_firmware(fw_entry);
if (ret) { if (ret) {
printk(KERN_ERR "%s: Primary firmware download failed\n", printk(KERN_ERR "%s: Primary firmware download failed\n",
dev->name); dev->name);
return ret; return ret;
} }
if (request_firmware(&fw_entry, fw->sta_fw, if (!priv->cached_fw) {
priv->dev) != 0) { if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
printk(KERN_ERR "%s: Cannot find firmware: %s\n", printk(KERN_ERR "%s: Cannot find firmware: %s\n",
dev->name, fw->sta_fw); dev->name, fw->sta_fw);
return -ENOENT; return -ENOENT;
} }
} else
fw_entry = priv->cached_fw;
/* Load secondary firmware */ /* Load secondary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data, ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 1); fw_entry->data + fw_entry->size, 1);
release_firmware(fw_entry); if (!priv->cached_fw)
release_firmware(fw_entry);
if (ret) { if (ret) {
printk(KERN_ERR "%s: Secondary firmware download failed\n", printk(KERN_ERR "%s: Secondary firmware download failed\n",
dev->name); dev->name);
@ -708,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv)
return err; 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 */ /* 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.qual = (int)le16_to_cpu(cq.qual);
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 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.level = level - 0x95;
wstats.noise = noise - 0x95; wstats.noise = noise - 0x95;
wstats.qual = (level > noise) ? (level - noise) : 0; wstats.qual = (level > noise) ? (level - noise) : 0;
wstats.updated = 7; wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
/* Update spy records */ /* Update spy records */
wireless_spy_update(dev, mac, &wstats); wireless_spy_update(dev, mac, &wstats);
} }
@ -3061,6 +3105,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/********************************************************************/
/* 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 */ /* Initialization */
/********************************************************************/ /********************************************************************/
@ -3304,6 +3392,10 @@ static int orinoco_init(struct net_device *dev)
} }
if (priv->do_fw_download) { if (priv->do_fw_download) {
#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
orinoco_cache_fw(priv, 0);
#endif
err = orinoco_download(priv); err = orinoco_download(priv);
if (err) if (err)
priv->do_fw_download = 0; priv->do_fw_download = 0;
@ -3540,8 +3632,13 @@ struct net_device
netif_carrier_off(dev); netif_carrier_off(dev);
priv->last_linkstatus = 0xffff; priv->last_linkstatus = 0xffff;
priv->cached_pri_fw = NULL;
priv->cached_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; return dev;
} }
@ -3553,9 +3650,10 @@ void free_orinocodev(struct net_device *dev)
* when we call tasklet_kill it will run one final time, * when we call tasklet_kill it will run one final time,
* emptying the list */ * emptying the list */
tasklet_kill(&priv->rx_tasklet); tasklet_kill(&priv->rx_tasklet);
if (priv->cached_fw)
release_firmware(priv->cached_fw); unregister_pm_notifier(&priv->pm_notifier);
priv->cached_fw = NULL; orinoco_uncache_fw(priv);
priv->wpa_ie_len = 0; priv->wpa_ie_len = 0;
kfree(priv->wpa_ie); kfree(priv->wpa_ie);
orinoco_mic_free(priv); orinoco_mic_free(priv);

View File

@ -10,6 +10,7 @@
#define DRIVER_VERSION "0.15" #define DRIVER_VERSION "0.15"
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
@ -167,8 +168,11 @@ struct orinoco_private {
unsigned int tkip_cm_active:1; unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3; 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; const struct firmware *cached_fw;
struct notifier_block pm_notifier;
}; };
#ifdef ORINOCO_DEBUG #ifdef ORINOCO_DEBUG

View File

@ -450,10 +450,29 @@ spectrum_cs_resume(struct pcmcia_device *link)
{ {
struct net_device *dev = link->priv; struct net_device *dev = link->priv;
struct orinoco_private *priv = netdev_priv(dev); 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); netif_device_attach(dev);
priv->hw_unavailable--; 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; return 0;
} }

View File

@ -102,6 +102,9 @@ struct p54_common {
unsigned int output_power; unsigned int output_power;
u32 tsf_low32; u32 tsf_low32;
u32 tsf_high32; u32 tsf_high32;
u64 basic_rate_mask;
u16 wakeup_timer;
u16 aid;
struct ieee80211_tx_queue_stats tx_stats[8]; struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8]; struct p54_edcf_queue_param qos_params[8];
struct ieee80211_low_level_stats stats; struct ieee80211_low_level_stats stats;

View File

@ -530,6 +530,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.noise = priv->noise; rx_status.noise = priv->noise;
/* XX correct? */ /* XX correct? */
rx_status.qual = (100 * hdr->rssi) / 127; 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 ? rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
hdr->rate : (hdr->rate - 4)) & 0xf; hdr->rate : (hdr->rate - 4)) & 0xf;
rx_status.freq = freq; rx_status.freq = freq;
@ -576,7 +578,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
unsigned long flags; unsigned long flags;
u32 freed = 0, last_addr = priv->rx_start; u32 freed = 0, last_addr = priv->rx_start;
if (!skb || !dev) if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
return; return;
spin_lock_irqsave(&priv->tx_queue.lock, flags); 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; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
*aid = 0; *aid = 0;
*queue = 3; *queue = 3;
@ -1198,7 +1201,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
txhdr->key_type = 0; txhdr->key_type = 0;
txhdr->key_len = 0; txhdr->key_len = 0;
txhdr->hw_queue = queue; 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)); memset(txhdr->durations, 0, sizeof(txhdr->durations));
txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
2 : info->antenna_sel_tx - 1; 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_antenna = priv->rx_antenna;
setup->rx_align = 0; setup->rx_align = 0;
if (priv->fw_var < 0x500) { 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); memset(setup->v1.rts_rates, 0, 8);
setup->v1.rx_addr = cpu_to_le32(priv->rx_end); setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
setup->v1.rxhw = cpu_to_le16(priv->rxhw); 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); setup->v1.unalloc0 = cpu_to_le16(0);
} else { } else {
setup->v2.rx_addr = cpu_to_le32(priv->rx_end); setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
setup->v2.rxhw = cpu_to_le16(priv->rxhw); 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.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.sbss_offset = 0;
setup->v2.mcast_window = 0; setup->v2.mcast_window = 0;
setup->v2.rx_rssi_threshold = 0; setup->v2.rx_rssi_threshold = 0;
@ -1342,7 +1348,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency)
} else { } else {
chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_mul = cpu_to_le16(130);
chan->v2.rssical_add = cpu_to_le16(0xfe70); 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); memset(chan->v2.rts_rates, 0, 8);
} }
priv->tx(dev, skb, 1); priv->tx(dev, skb, 1);
@ -1518,16 +1524,24 @@ static int p54_start(struct ieee80211_hw *dev)
mutex_lock(&priv->conf_mutex); mutex_lock(&priv->conf_mutex);
err = priv->open(dev); err = priv->open(dev);
if (!err) if (err)
priv->mode = NL80211_IFTYPE_MONITOR; goto out;
P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); 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[1], 0x0002, 0x0007, 0x000f, 94);
P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
err = p54_set_edcf(dev); err = p54_set_edcf(dev);
if (!err) if (err)
err = p54_init_stats(dev); 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); mutex_unlock(&priv->conf_mutex);
return err; return err;
} }
@ -1547,7 +1561,6 @@ static void p54_stop(struct ieee80211_hw *dev)
while ((skb = skb_dequeue(&priv->tx_queue))) while ((skb = skb_dequeue(&priv->tx_queue)))
kfree_skb(skb); kfree_skb(skb);
kfree(priv->cached_beacon);
priv->cached_beacon = NULL; priv->cached_beacon = NULL;
priv->stop(dev); priv->stop(dev);
priv->tsf_high32 = priv->tsf_low32 = 0; 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_STATION:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
priv->mode = conf->type; priv->mode = conf->type;
break; break;
default: 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); p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
break; break;
default: default:
@ -1653,6 +1668,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
memcpy(priv->bssid, conf->bssid, ETH_ALEN); memcpy(priv->bssid, conf->bssid, ETH_ALEN);
ret = p54_set_freq(dev, dev->conf.channel->center_freq); ret = p54_set_freq(dev, dev->conf.channel->center_freq);
if (ret) if (ret)
@ -1712,10 +1728,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
if ((params) && !(queue > 4)) { if ((params) && !(queue > 4)) {
P54_SET_QUEUE(priv->qos_params[queue], params->aifs, P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
params->cw_min, params->cw_max, params->txop); params->cw_min, params->cw_max, params->txop);
ret = p54_set_edcf(dev);
} else } else
ret = -EINVAL; ret = -EINVAL;
if (!ret)
ret = p54_set_edcf(dev);
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return ret; return ret;
} }
@ -1792,6 +1807,24 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
priv->use_short_slot = info->use_short_slot; priv->use_short_slot = info->use_short_slot;
p54_set_edcf(dev); 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 = { 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 = dev->priv;
priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->basic_rate_mask = 0x15f;
skb_queue_head_init(&priv->tx_queue); skb_queue_head_init(&priv->tx_queue);
dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM; IEEE80211_HW_NOISE_DBM;
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
NL80211_IFTYPE_ADHOC | BIT(NL80211_IFTYPE_ADHOC) |
NL80211_IFTYPE_AP); BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
dev->channel_change_time = 1000; /* TODO: find actual value */ dev->channel_change_time = 1000; /* TODO: find actual value */
priv->tx_stats[0].limit = 1; /* Beacon queue */ priv->tx_stats[0].limit = 1; /* Beacon queue */

View File

@ -259,7 +259,7 @@ enum p54_rx_decrypt_status {
P54_DECRYPT_NOCKIPMIC, P54_DECRYPT_NOCKIPMIC,
P54_DECRYPT_FAIL_WEP, P54_DECRYPT_FAIL_WEP,
P54_DECRYPT_FAIL_TKIP, P54_DECRYPT_FAIL_TKIP,
P54_DECRYPT_FAIL_MICAHEL, P54_DECRYPT_FAIL_MICHAEL,
P54_DECRYPT_FAIL_CKIPKP, P54_DECRYPT_FAIL_CKIPKP,
P54_DECRYPT_FAIL_CKIPMIC, P54_DECRYPT_FAIL_CKIPMIC,
P54_DECRYPT_FAIL_AESCCMP P54_DECRYPT_FAIL_AESCCMP

View File

@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table);
static int p54p_upload_firmware(struct ieee80211_hw *dev) static int p54p_upload_firmware(struct ieee80211_hw *dev)
{ {
struct p54p_priv *priv = dev->priv; struct p54p_priv *priv = dev->priv;
const struct firmware *fw_entry = NULL;
__le32 reg; __le32 reg;
int err; int err;
__le32 *data; __le32 *data;
@ -73,23 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_WRITE(ctrl_stat, reg); P54P_WRITE(ctrl_stat, reg);
wmb(); wmb();
err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev); /* wait for the firmware to reset properly */
if (err) { mdelay(10);
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;
}
err = p54_parse_firmware(dev, fw_entry); err = p54_parse_firmware(dev, priv->firmware);
if (err) { if (err)
release_firmware(fw_entry);
return err; return err;
}
data = (__le32 *) fw_entry->data; data = (__le32 *) priv->firmware->data;
remains = fw_entry->size; remains = priv->firmware->size;
device_addr = ISL38XX_DEV_FIRMWARE_ADDR; device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
while (remains) { while (remains) {
u32 i = 0; u32 i = 0;
@ -107,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_READ(int_enable); P54P_READ(int_enable);
} }
release_firmware(fw_entry);
reg = P54P_READ(ctrl_stat); reg = P54P_READ(ctrl_stat);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); 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)) { if (mem_len < sizeof(struct p54p_csr)) {
printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
pci_name(pdev)); pci_name(pdev));
pci_disable_device(pdev); goto err_disable_dev;
return err;
} }
err = pci_request_regions(pdev, "p54pci"); err = pci_request_regions(pdev, "p54pci");
if (err) { if (err) {
printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
pci_name(pdev)); pci_name(pdev));
return err; goto err_disable_dev;
} }
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 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); spin_lock_init(&priv->lock);
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); 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); err = p54p_open(dev);
if (err) if (err)
goto err_free_common; goto err_free_common;
@ -579,6 +578,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
return 0; return 0;
err_free_common: err_free_common:
release_firmware(priv->firmware);
p54_free_common(dev); p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control), pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma); priv->ring_control, priv->ring_control_dma);
@ -592,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_reg: err_free_reg:
pci_release_regions(pdev); pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev); pci_disable_device(pdev);
return err; return err;
} }
@ -606,6 +607,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
ieee80211_unregister_hw(dev); ieee80211_unregister_hw(dev);
priv = dev->priv; priv = dev->priv;
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control), pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma); priv->ring_control, priv->ring_control_dma);
p54_free_common(dev); p54_free_common(dev);

View File

@ -93,7 +93,7 @@ struct p54p_priv {
struct pci_dev *pdev; struct pci_dev *pdev;
struct p54p_csr __iomem *map; struct p54p_csr __iomem *map;
struct tasklet_struct rx_tasklet; struct tasklet_struct rx_tasklet;
const struct firmware *firmware;
spinlock_t lock; spinlock_t lock;
struct p54p_ring_control *ring_control; struct p54p_ring_control *ring_control;
dma_addr_t ring_control_dma; dma_addr_t ring_control_dma;

View File

@ -49,20 +49,10 @@
* the access attempt is considered to have failed, * the access attempt is considered to have failed,
* and we will print an error. * and we will print an error.
*/ */
static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev) #define WAIT_FOR_BBP(__dev, __reg) \
{ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
u32 reg; #define WAIT_FOR_RF(__dev, __reg) \
unsigned int i; rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
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;
}
static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value) 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); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
} }
static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@ -107,74 +86,54 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); WAIT_FOR_BBP(rt2x00dev, &reg);
}
/*
* Wait until the BBP becomes ready.
*/
reg = rt2400pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY))
goto exit_fail;
*value = rt2x00_get_field32(reg, BBPCSR_VALUE); *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex); 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, static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value) const unsigned int word, const u32 value)
{ {
u32 reg; u32 reg;
unsigned int i;
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex); mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { /*
rt2x00pci_register_read(rt2x00dev, RFCSR, &reg); * Wait until the RF becomes available, afterwards we
if (!rt2x00_get_field32(reg, RFCSR_BUSY)) * can safely write the new data into the register.
goto rf_write; */
udelay(REGISTER_BUSY_DELAY); 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); mutex_unlock(&rt2x00dev->csr_mutex);
} }

View File

@ -49,20 +49,10 @@
* the access attempt is considered to have failed, * the access attempt is considered to have failed,
* and we will print an error. * and we will print an error.
*/ */
static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev) #define WAIT_FOR_BBP(__dev, __reg) \
{ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
u32 reg; #define WAIT_FOR_RF(__dev, __reg) \
unsigned int i; rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
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;
}
static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value) 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); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); mutex_unlock(&rt2x00dev->csr_mutex);
return;
exit_fail:
mutex_unlock(&rt2x00dev->csr_mutex);
ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
} }
static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@ -107,74 +86,54 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, BBPCSR_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); WAIT_FOR_BBP(rt2x00dev, &reg);
}
/*
* Wait until the BBP becomes ready.
*/
reg = rt2500pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, BBPCSR_BUSY))
goto exit_fail;
*value = rt2x00_get_field32(reg, BBPCSR_VALUE); *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex); 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, static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value) const unsigned int word, const u32 value)
{ {
u32 reg; u32 reg;
unsigned int i;
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex); mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { /*
rt2x00pci_register_read(rt2x00dev, RFCSR, &reg); * Wait until the RF becomes available, afterwards we
if (!rt2x00_get_field32(reg, RFCSR_BUSY)) * can safely write the new data into the register.
goto rf_write; */
udelay(REGISTER_BUSY_DELAY); 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); mutex_unlock(&rt2x00dev->csr_mutex);
} }

View File

@ -57,7 +57,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
__le16 reg; __le16 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset, USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(u16), REGISTER_TIMEOUT); &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg); *value = le16_to_cpu(reg);
} }
@ -68,7 +68,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
__le16 reg; __le16 reg;
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset, USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(u16), REGISTER_TIMEOUT); &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg); *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); __le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset, 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, 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); __le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset, 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, 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)); 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; unsigned int i;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg); rt2500usb_register_read_lock(rt2x00dev, offset, reg);
if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) if (!rt2x00_get_field16(*reg, field))
break; return 1;
udelay(REGISTER_BUSY_DELAY); 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, static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value) 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); 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 = rt2500usb_bbp_check(rt2x00dev); if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) reg = 0;
goto exit_fail; 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);
* Write the data into the BBP. }
*/
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); mutex_unlock(&rt2x00dev->csr_mutex);
return;
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, static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@ -169,78 +169,58 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex); 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 = rt2500usb_bbp_check(rt2x00dev); if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) reg = 0;
goto exit_fail; 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);
* Write the request into the BBP.
*/
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); if (WAIT_FOR_BBP(rt2x00dev, &reg))
rt2500usb_register_read_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;
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
mutex_unlock(&rt2x00dev->csr_mutex); 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, static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value) const unsigned int word, const u32 value)
{ {
u16 reg; u16 reg;
unsigned int i;
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex); mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { /*
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg); * Wait until the RF becomes available, afterwards we
if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) * can safely write the new data into the register.
goto rf_write; */
udelay(REGISTER_BUSY_DELAY); 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);
rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
rt2x00_rf_write(rt2x00dev, word, value);
} }
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);
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);
mutex_unlock(&rt2x00dev->csr_mutex); 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 usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 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; int length;
u16 reg; 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 * length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be. * 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, usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
entry->skb->data, length, rt2500usb_beacondone, 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); usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
} }
static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
struct sk_buff *skb)
{ {
int length; 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, * The length _must_ be a multiple of 2,
* but it must _not_ be a multiple of the USB packet size. * but it must _not_ be a multiple of the USB packet size.
*/ */
length = roundup(skb->len, 2); length = roundup(entry->skb->len, 2);
length += (2 * !(length % rt2x00dev->usb_maxpacket)); length += (2 * !(length % entry->queue->usb_maxpacket));
return length; return length;
} }

View File

@ -555,8 +555,7 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc); struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry); int (*write_tx_data) (struct queue_entry *entry);
void (*write_beacon) (struct queue_entry *entry); void (*write_beacon) (struct queue_entry *entry);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int (*get_tx_data_len) (struct queue_entry *entry);
struct sk_buff *skb);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue); const enum data_queue_qid queue);
@ -798,11 +797,6 @@ struct rt2x00_dev {
*/ */
short lna_gain; short lna_gain;
/*
* USB Max frame size (for rt2500usb & rt73usb).
*/
u16 usb_maxpacket;
/* /*
* Current TX power value. * Current TX power value.
*/ */

View File

@ -111,12 +111,6 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
led->led_dev.name = name; led->led_dev.name = name;
led->led_dev.brightness = LED_OFF; 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); retval = led_classdev_register(device, &led->led_dev);
if (retval) { if (retval) {
ERROR(rt2x00dev, "Failed to register led handler.\n"); ERROR(rt2x00dev, "Failed to register led handler.\n");

View File

@ -132,8 +132,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ERROR(rt2x00dev, ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n" "Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n", qid, DRV_PROJECT); "Please file bug report to %s.\n", qid, DRV_PROJECT);
dev_kfree_skb_any(skb); goto exit_fail;
return NETDEV_TX_OK;
} }
/* /*

View File

@ -31,6 +31,31 @@
#include "rt2x00.h" #include "rt2x00.h"
#include "rt2x00pci.h" #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. * TX data handlers.
*/ */

View File

@ -76,6 +76,24 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
memcpy_toio(rt2x00dev->csr.base + offset, value, length); memcpy_toio(rt2x00dev->csr.base + offset, value, length);
} }
/**
* 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 * rt2x00pci_write_tx_data - Initialize data for TX operation
* @entry: The entry where the frame is located * @entry: The entry where the frame is located

View File

@ -386,7 +386,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
u8 rate_idx, rate_flags; u8 rate_idx, rate_flags;
if (unlikely(rt2x00queue_full(queue))) if (unlikely(rt2x00queue_full(queue)))
return -EINVAL; return -ENOBUFS;
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(queue->rt2x00dev, 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); tx_info = IEEE80211_SKB_CB(skb);
rate_idx = tx_info->control.rates[0].idx; rate_idx = tx_info->control.rates[0].idx;
rate_flags = tx_info->control.rates[0].flags; 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)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry; skbdesc->entry = entry;
skbdesc->tx_rate_idx = rate_idx; 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. * the frame so we can provide it to the driver seperately.
*/ */
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && 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); rt2x00crypto_tx_remove_iv(skb, iv_len);
}
/* /*
* It could be possible that the queue was corrupted and this * It could be possible that the queue was corrupted and this
* call failed. Just drop the frame, we cannot rollback and pass * call failed. Since we always return NETDEV_TX_OK to mac80211,
* the frame to mac80211 because the skb->cb has now been tainted. * this frame will simply be dropped.
*/ */
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
dev_kfree_skb_any(entry->skb);
entry->skb = NULL; entry->skb = NULL;
return 0; return -EIO;
} }
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))

View File

@ -380,6 +380,8 @@ enum queue_index {
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue). * @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. * @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data 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 data_queue {
struct rt2x00_dev *rt2x00dev; struct rt2x00_dev *rt2x00dev;
@ -401,6 +403,9 @@ struct data_queue {
unsigned short data_size; unsigned short data_size;
unsigned short desc_size; unsigned short desc_size;
unsigned short usb_endpoint;
unsigned short usb_maxpacket;
}; };
/** /**
@ -443,6 +448,19 @@ struct data_queue_desc {
#define tx_queue_end(__dev) \ #define tx_queue_end(__dev) \
&(__dev)->tx[(__dev)->ops->tx_queues] &(__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). * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
* @__entry: Pointer where the current queue entry will be stored in. * @__entry: Pointer where the current queue entry will be stored in.
@ -453,8 +471,8 @@ struct data_queue_desc {
*/ */
#define queue_loop(__entry, __start, __end) \ #define queue_loop(__entry, __start, __end) \
for ((__entry) = (__start); \ for ((__entry) = (__start); \
prefetch(&(__entry)[1]), (__entry) != (__end); \ prefetch(queue_next(__entry)), (__entry) != (__end);\
(__entry) = &(__entry)[1]) (__entry) = queue_next(__entry))
/** /**
* queue_for_each - Loop through all queues * queue_for_each - Loop through all queues

View File

@ -154,6 +154,28 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
} }
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); 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. * 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 * length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be. * 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_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, entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry); rt2x00usb_interrupt_txdone, entry);
@ -356,10 +378,11 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
struct usb_device *usb_dev = struct usb_device *usb_dev =
to_usb_device_intf(entry->queue->rt2x00dev->dev); to_usb_device_intf(entry->queue->rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;
if (entry->queue->qid == QID_RX) { if (entry->queue->qid == QID_RX) {
usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
usb_rcvbulkpipe(usb_dev, 1), usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
entry->skb->data, entry->skb->len, entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry); rt2x00usb_interrupt_rxdone, entry);
@ -371,6 +394,76 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
} }
EXPORT_SYMBOL_GPL(rt2x00usb_clear_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, static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
@ -441,6 +534,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue; struct data_queue *queue;
int status; int status;
/*
* Find endpoints for each queue
*/
status = rt2x00usb_find_endpoints(rt2x00dev);
if (status)
goto exit;
/* /*
* Allocate DMA * Allocate DMA
*/ */
@ -532,11 +632,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->ops = ops; rt2x00dev->ops = ops;
rt2x00dev->hw = hw; 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); retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval) if (retval)
goto exit_free_device; goto exit_free_device;

View File

@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
REGISTER_TIMEOUT16(length)); 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 * Radio handlers
*/ */

View File

@ -55,20 +55,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* the access attempt is considered to have failed, * the access attempt is considered to have failed,
* and we will print an error. * and we will print an error.
*/ */
static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev) #define WAIT_FOR_BBP(__dev, __reg) \
{ rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
u32 reg; #define WAIT_FOR_RF(__dev, __reg) \
unsigned int i; rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
#define WAIT_FOR_MCU(__dev, __reg) \
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg); H2M_MAILBOX_CSR_OWNER, (__reg))
if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
break;
udelay(REGISTER_BUSY_DELAY);
}
return reg;
}
static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value) 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); 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 = rt61pci_bbp_check(rt2x00dev); if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) reg = 0;
goto exit_fail; 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);
* 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);
rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
mutex_unlock(&rt2x00dev->csr_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
return;
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, static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@ -112,73 +95,54 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); WAIT_FOR_BBP(rt2x00dev, &reg);
}
/*
* Wait until the BBP becomes ready.
*/
reg = rt61pci_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
goto exit_fail;
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex); 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, static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value) const unsigned int word, const u32 value)
{ {
u32 reg; u32 reg;
unsigned int i;
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex); mutex_lock(&rt2x00dev->csr_mutex);
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { /*
rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg); * Wait until the RF becomes available, afterwards we
if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) * can safely write the new data into the register.
goto rf_write; */
udelay(REGISTER_BUSY_DELAY); 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);
} }
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);
rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
rt2x00_rf_write(rt2x00dev, word, value);
mutex_unlock(&rt2x00dev->csr_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
} }
@ -196,32 +160,25 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
mutex_lock(&rt2x00dev->csr_mutex); mutex_lock(&rt2x00dev->csr_mutex);
rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg); /*
* 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);
if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
goto exit_fail; rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1); rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
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); mutex_unlock(&rt2x00dev->csr_mutex);
return;
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 */ #endif /* CONFIG_RT2X00_LIB_LEDS */

View File

@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/* /*
* Register access. * Register access.
* All access to the CSR registers will go through the methods * 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, * BBP and RF register require indirect register access,
* and use the CSR registers BBPCSR and RFCSR to achieve this. * and use the CSR registers BBPCSR and RFCSR to achieve this.
* These indirect registers work with busy bits, * These indirect registers work with busy bits,
@ -57,78 +57,10 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* and we will print an error. * and we will print an error.
* The _lock versions must be used if you already hold the csr_mutex * The _lock versions must be used if you already hold the csr_mutex
*/ */
static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, #define WAIT_FOR_BBP(__dev, __reg) \
const unsigned int offset, u32 *value) rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
{ #define WAIT_FOR_RF(__dev, __reg) \
__le32 reg; rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__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;
}
static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value) 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); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) reg = 0;
goto exit_fail; 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);
* 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); mutex_unlock(&rt2x00dev->csr_mutex);
return;
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, 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); 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 (WAIT_FOR_BBP(rt2x00dev, &reg)) {
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) reg = 0;
goto exit_fail; 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);
* 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);
rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); WAIT_FOR_BBP(rt2x00dev, &reg);
}
/*
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
goto exit_fail;
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
mutex_unlock(&rt2x00dev->csr_mutex); 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, static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value) const unsigned int word, const u32 value)
{ {
u32 reg; u32 reg;
unsigned int i;
if (!word) if (!word)
return; return;
mutex_lock(&rt2x00dev->csr_mutex); 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, * Wait until the RF becomes available, afterwards we
* all others contain 20 bits. * can safely write the new data into the register.
*/ */
rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, if (WAIT_FOR_RF(rt2x00dev, &reg)) {
20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || reg = 0;
rt2x00_rf(&rt2x00dev->chip, RF2527))); rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0); /*
rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1); * 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);
rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
rt2x00_rf_write(rt2x00dev, word, value); rt2x00_rf_write(rt2x00dev, word, value);
}
mutex_unlock(&rt2x00dev->csr_mutex); mutex_unlock(&rt2x00dev->csr_mutex);
} }
@ -253,8 +155,8 @@ rf_write:
static const struct rt2x00debug rt73usb_rt2x00debug = { static const struct rt2x00debug rt73usb_rt2x00debug = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.csr = { .csr = {
.read = rt73usb_register_read, .read = rt2x00usb_register_read,
.write = rt73usb_register_write, .write = rt2x00usb_register_write,
.flags = RT2X00DEBUGFS_OFFSET, .flags = RT2X00DEBUGFS_OFFSET,
.word_base = CSR_REG_BASE, .word_base = CSR_REG_BASE,
.word_size = sizeof(u32), .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); container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg; 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_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off); 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; return 0;
} }
@ -379,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/ */
mask = (0xf << crypto->bssidx); mask = (0xf << crypto->bssidx);
rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg); rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
reg &= mask; reg &= mask;
if (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_offset = (3 * key->hw_key_idx);
field.bit_mask = 0x7 << field.bit_offset; 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); rt2x00_set_field32(&reg, field, crypto->cipher);
rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg);
} else { } else {
field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_offset = (3 * (key->hw_key_idx - 8));
field.bit_mask = 0x7 << field.bit_offset; 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); 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; 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) if (crypto->cmd == SET_KEY)
reg |= mask; reg |= mask;
else if (crypto->cmd == DISABLE_KEY) else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask; reg &= ~mask;
rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg);
return 0; 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, * When both registers are full, we drop the key,
* otherwise we use the first invalid entry. * 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) { if (reg && reg == ~0) {
key->hw_key_idx = 32; key->hw_key_idx = 32;
rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg); rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
if (reg && reg == ~0) if (reg && reg == ~0)
return -ENOSPC; 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. * Send the address and cipher type to the hardware register.
* This data fits within the CSR cache size, so we can use * 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)); memset(&addr_entry, 0, sizeof(addr_entry));
memcpy(&addr_entry, crypto->address, ETH_ALEN); memcpy(&addr_entry, crypto->address, ETH_ALEN);
addr_entry.cipher = crypto->cipher; addr_entry.cipher = crypto->cipher;
reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
rt73usb_register_multiwrite(rt2x00dev, reg, rt2x00usb_register_multiwrite(rt2x00dev, reg,
&addr_entry, sizeof(addr_entry)); &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 * without this received frames will not be decrypted
* by the hardware. * by the hardware.
*/ */
rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg); rt2x00usb_register_read(rt2x00dev, SEC_CSR4, &reg);
reg |= (1 << crypto->bssidx); 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 * 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) { if (key->hw_key_idx < 32) {
mask = 1 << key->hw_key_idx; 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) if (crypto->cmd == SET_KEY)
reg |= mask; reg |= mask;
else if (crypto->cmd == DISABLE_KEY) else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask; reg &= ~mask;
rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg);
} else { } else {
mask = 1 << (key->hw_key_idx - 32); 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) if (crypto->cmd == SET_KEY)
reg |= mask; reg |= mask;
else if (crypto->cmd == DISABLE_KEY) else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask; reg &= ~mask;
rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg);
} }
return 0; return 0;
@ -580,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
* and broadcast frames will always be accepted since * and broadcast frames will always be accepted since
* there is no filter for it at this time. * 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, rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL)); !(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL, 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_BROADCAST, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
!(filter_flags & FIF_CONTROL)); !(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, 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. * bits which (when set to 0) will invalidate the entire beacon.
*/ */
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); 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. * 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_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1); 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) { 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); rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg); conf->mac[1] = cpu_to_le32(reg);
rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2,
conf->mac, sizeof(conf->mac)); 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); rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg); conf->bssid[1] = cpu_to_le32(reg);
rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4,
conf->bssid, sizeof(conf->bssid)); conf->bssid, sizeof(conf->bssid));
} }
} }
@ -653,26 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; 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); 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, rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!erp->short_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); 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, erp->sifs);
rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs); 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, 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++) for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); 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, rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
(rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
(rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); (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) || if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
rt2x00_rf(&rt2x00dev->chip, RF5225)) rt2x00_rf(&rt2x00dev->chip, RF5225))
@ -915,12 +817,12 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; 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, rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
libconf->conf->long_frame_max_tx_count); libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
libconf->conf->short_frame_max_tx_count); 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, static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
@ -928,18 +830,18 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; 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); 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); 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, rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
libconf->conf->beacon_int * 16); 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, 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. * 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); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
/* /*
* Update False CCA count from register. * 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); 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. * Wait for stable hardware.
*/ */
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg); rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg) if (reg)
break; break;
msleep(1); msleep(1);
@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
{ {
u32 reg; 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_AUTO_TX_SEQ, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 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, 47); /* CCK Signal */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ 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_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1); 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 * 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, 13);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12); 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_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10); rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1); 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 * 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, 7);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1); 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, 6);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1); 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, 5);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1); 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_6MBS, 59);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53); 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_12MBS, 49);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46); 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_24MBS, 44);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42); 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_48MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 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_BEACON_INTERVAL, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 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_TSF_SYNC, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 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_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 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); 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)) if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY; return -EBUSY;
rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
/* /*
* Invalidate all Shared Keys (SEC_CSR0), * Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
*/ */
rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
reg = 0x000023b0; reg = 0x000023b0;
if (rt2x00_rf(&rt2x00dev->chip, RF5225) || if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527)) rt2x00_rf(&rt2x00dev->chip, RF2527))
rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1); 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); rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); 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); 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 * 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 * the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon. * bits which (when set to 0) will invalidate the entire beacon.
*/ */
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
/* /*
* We must clear the error counters. * We must clear the error counters.
* These registers are cleared on read, * These registers are cleared on read,
* so we may pass a useless variable to store the value. * so we may pass a useless variable to store the value.
*/ */
rt73usb_register_read(rt2x00dev, STA_CSR0, &reg); rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
rt73usb_register_read(rt2x00dev, STA_CSR1, &reg); rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
rt73usb_register_read(rt2x00dev, STA_CSR2, &reg); rt2x00usb_register_read(rt2x00dev, STA_CSR2, &reg);
/* /*
* Reset MAC and BBP registers. * 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_SOFT_RESET, 1);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_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_SOFT_RESET, 0);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_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); 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; return 0;
} }
@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
{ {
u32 reg; u32 reg;
rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg); rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
(state == STATE_RADIO_RX_OFF) || (state == STATE_RADIO_RX_OFF) ||
(state == STATE_RADIO_RX_OFF_LINK)); (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) 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) 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. * Disable synchronisation.
*/ */
rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0);
rt2x00usb_disable_radio(rt2x00dev); 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); 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_FORCE_WAKEUP, !put_to_sleep);
rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, 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. * 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. * device has entered the correct state.
*/ */
for (i = 0; i < REGISTER_BUSY_COUNT; i++) { 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); state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
if (state == !put_to_sleep) if (state == !put_to_sleep)
return 0; return 0;
@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
* Disable beaconing while we are reloading the beacon data, * Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid 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_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 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_BEACON_GEN, 0);
rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/* /*
* Write entire beacon with descriptor to register. * Write entire beacon with descriptor to register.
@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
entry->skb = NULL; entry->skb = NULL;
} }
static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, static int rt73usb_get_tx_data_len(struct queue_entry *entry)
struct sk_buff *skb)
{ {
int length; 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, * The length _must_ be a multiple of 4,
* but it must _not_ be a multiple of the USB packet size. * but it must _not_ be a multiple of the USB packet size.
*/ */
length = roundup(skb->len, 4); length = roundup(entry->skb->len, 4);
length += (4 * !(length % rt2x00dev->usb_maxpacket)); length += (4 * !(length % entry->queue->usb_maxpacket));
return length; 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. * For Wi-Fi faily generated beacons between participating stations.
* Set TBTT phase adaptive adjustment step to 8us (default 16us) * 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)) { if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 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. * Identify RF chipset.
*/ */
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); 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); rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { 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_offset = queue_idx * 16;
field.bit_mask = 0xffff << field.bit_offset; 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); 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) { } else if (queue_idx < 4) {
field.bit_offset = (queue_idx - 2) * 16; field.bit_offset = (queue_idx - 2) * 16;
field.bit_mask = 0xffff << field.bit_offset; 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); 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 */ /* Update WMM registers */
field.bit_offset = queue_idx * 4; field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset; 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); 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); 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); rt2x00_set_field32(&reg, field, queue->cw_max);
rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0; return 0;
} }
@ -2279,9 +2180,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
u64 tsf; u64 tsf;
u32 reg; 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; 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); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
return tsf; return tsf;

View File

@ -111,6 +111,13 @@ struct rtl8187_priv {
u8 signal; u8 signal;
u8 quality; u8 quality;
u8 noise; 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); void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);

View File

@ -176,8 +176,27 @@ static void rtl8187_tx_cb(struct urb *urb)
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
sizeof(struct rtl8187_tx_hdr)); sizeof(struct rtl8187_tx_hdr));
ieee80211_tx_info_clear_status(info); 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) 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->flags = cpu_to_le32(flags);
hdr->len = 0; hdr->len = 0;
hdr->rts_duration = rts_dur; 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; buf = hdr;
ep = 2; ep = 2;
@ -237,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
memset(hdr, 0, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags); hdr->flags = cpu_to_le32(flags);
hdr->rts_duration = rts_dur; 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 = hdr->tx_duration =
ieee80211_generic_frame_duration(dev, priv->vif, ieee80211_generic_frame_duration(dev, priv->vif,
skb->len, txrate); skb->len, txrate);
@ -403,6 +422,109 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
return 0; 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) static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
{ {
struct rtl8187_priv *priv = dev->priv; 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); 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; return 0;
} }
@ -748,6 +877,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 0 /* long retry limit */) | (7 << 0 /* long retry limit */) |
(7 << 21 /* MAX TX DMA */)); (7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev); rtl8187_init_urbs(dev);
rtl8187b_init_status_urb(dev);
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return 0; return 0;
} }
@ -824,6 +954,9 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
usb_kill_urb(info->urb); usb_kill_urb(info->urb);
kfree_skb(skb); 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); mutex_unlock(&priv->conf_mutex);
} }
@ -919,24 +1052,38 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
return 0; 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, static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
bool use_short_preamble) bool use_short_preamble)
{ {
if (priv->is_rtl8187b) { if (priv->is_rtl8187b) {
u8 difs, eifs, slot_time; u8 difs, eifs;
u16 ack_timeout; u16 ack_timeout;
int queue;
if (use_short_slot) { if (use_short_slot) {
slot_time = 0x9; priv->slot_time = 0x9;
difs = 0x1c; difs = 0x1c;
eifs = 0x53; eifs = 0x53;
} else { } else {
slot_time = 0x14; priv->slot_time = 0x14;
difs = 0x32; difs = 0x32;
eifs = 0x5b; eifs = 0x5b;
} }
rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
rtl818x_iowrite8(priv, &priv->map->DIFS, difs); 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; ack_timeout += 144;
rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER,
DIV_ROUND_UP(ack_timeout, 4)); 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 { } else {
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
if (use_short_slot) { if (use_short_slot) {
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
} else { } else {
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 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); 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 = { static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx, .tx = rtl8187_tx,
.start = rtl8187_start, .start = rtl8187_start,
@ -1027,6 +1213,7 @@ static const struct ieee80211_ops rtl8187_ops = {
.config_interface = rtl8187_config_interface, .config_interface = rtl8187_config_interface,
.bss_info_changed = rtl8187_bss_info_changed, .bss_info_changed = rtl8187_bss_info_changed,
.configure_filter = rtl8187_configure_filter, .configure_filter = rtl8187_configure_filter,
.conf_tx = rtl8187_conf_tx
}; };
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) 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) { if (priv->is_rtl8187b) {
printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
"is EXPERIMENTAL, and could damage your\n"
" hardware, use at your own risk\n");
dev->flags |= IEEE80211_HW_SIGNAL_DBM; dev->flags |= IEEE80211_HW_SIGNAL_DBM;
} else { } else {
dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
@ -1256,6 +1441,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
goto err_free_dev; goto err_free_dev;
} }
mutex_init(&priv->conf_mutex); 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", printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
wiphy_name(dev->wiphy), dev->wiphy->perm_addr, wiphy_name(dev->wiphy), dev->wiphy->perm_addr,

View File

@ -878,12 +878,6 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
rtl8225_write_phy_ofdm(dev, i, 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, 0x97, 0x46);
rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);

View File

@ -1042,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode {
WLAN_ACTION_SPCT_CHL_SWITCH = 4, 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 */ /* BACK action code */
enum ieee80211_back_actioncode { enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0, WLAN_ACTION_ADDBA_REQ = 0,

View File

@ -508,6 +508,8 @@ enum nl80211_band_attr {
* on this channel in current regulatory domain. * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
* on this channel in current regulatory domain. * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
*/ */
enum nl80211_frequency_attr { enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID, __NL80211_FREQUENCY_ATTR_INVALID,
@ -516,12 +518,15 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
/* keep last */ /* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST, __NL80211_FREQUENCY_ATTR_AFTER_LAST,
NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 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 * enum nl80211_bitrate_attr - bitrate attributes
* @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps

View File

@ -108,6 +108,7 @@ struct rfkill {
struct device dev; struct device dev;
struct list_head node; struct list_head node;
enum rfkill_state state_for_resume;
}; };
#define to_rfkill(d) container_of(d, struct rfkill, dev) #define to_rfkill(d) container_of(d, struct rfkill, dev)

View File

@ -181,6 +181,11 @@ struct ieee80211_supported_band {
* struct wiphy - wireless hardware description * struct wiphy - wireless hardware description
* @idx: the wiphy index assigned to this item * @idx: the wiphy index assigned to this item
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name> * @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 * @reg_notifier: the driver's regulatory notification callback
*/ */
struct wiphy { struct wiphy {
@ -192,6 +197,8 @@ struct wiphy {
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes; u16 interface_modes;
bool fw_handles_regulatory;
/* If multiple wiphys are registered and you're handed e.g. /* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't * a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered * 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. * for a regulatory domain structure for the respective country.
*/ */
extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2); 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 */ #endif /* __NET_WIRELESS_H */

View File

@ -16,20 +16,20 @@ menu "Rate control algorithm selection"
config MAC80211_RC_PID config MAC80211_RC_PID
bool "PID controller based rate control algorithm" if EMBEDDED bool "PID controller based rate control algorithm" if EMBEDDED
default y
---help--- ---help---
This option enables a TX rate control algorithm for This option enables a TX rate control algorithm for
mac80211 that uses a PID controller to select the TX mac80211 that uses a PID controller to select the TX
rate. rate.
config MAC80211_RC_MINSTREL config MAC80211_RC_MINSTREL
bool "Minstrel" bool "Minstrel" if EMBEDDED
default y
---help--- ---help---
This option enables the 'minstrel' TX rate control algorithm This option enables the 'minstrel' TX rate control algorithm
choice choice
prompt "Default rate control algorithm" prompt "Default rate control algorithm"
default MAC80211_RC_DEFAULT_PID default MAC80211_RC_DEFAULT_MINSTREL
---help--- ---help---
This option selects the default rate control algorithm This option selects the default rate control algorithm
mac80211 will use. Note that this default can still be mac80211 will use. Note that this default can still be
@ -55,8 +55,8 @@ endchoice
config MAC80211_RC_DEFAULT config MAC80211_RC_DEFAULT
string string
default "pid" if MAC80211_RC_DEFAULT_PID
default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
default "pid" if MAC80211_RC_DEFAULT_PID
default "" default ""
endmenu endmenu

View File

@ -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->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 &= ~IEEE80211_HT_CAP_SM_PS;
ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;

View File

@ -722,7 +722,6 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
int ieee80211_register_hw(struct ieee80211_hw *hw) int ieee80211_register_hw(struct ieee80211_hw *hw)
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
const char *name;
int result; int result;
enum ieee80211_band band; enum ieee80211_band band;
struct net_device *mdev; struct net_device *mdev;
@ -787,8 +786,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
mdev->header_ops = &ieee80211_header_ops; mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list; mdev->set_multicast_list = ieee80211_master_set_multicast_list;
name = wiphy_dev(local->hw.wiphy)->driver->name; local->hw.workqueue =
local->hw.workqueue = create_freezeable_workqueue(name); create_freezeable_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) { if (!local->hw.workqueue) {
result = -ENOMEM; result = -ENOMEM;
goto fail_workqueue; goto fail_workqueue;

View File

@ -802,6 +802,10 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); 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, static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta, bool deauth, struct ieee80211_if_sta *ifsta, bool deauth,
bool self_disconnected, u16 reason) 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); 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; ifsta->state = IEEE80211_STA_MLME_DISABLED;
sta_info_unlink(&sta); 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_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); 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); ieee80211_bss_info_change_notify(sdata, changed);
} }

View File

@ -256,7 +256,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba
if (!(info->flags & IEEE80211_TX_STAT_ACK)) { if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
spinfo->tx_num_failed += 2; spinfo->tx_num_failed += 2;
spinfo->tx_num_xmit++; 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_failed++;
spinfo->tx_num_xmit++; spinfo->tx_num_xmit++;
} }

View File

@ -17,6 +17,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <asm/unaligned.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "ieee80211_i.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 blkcipher_desc desc = { .tfm = tfm };
struct scatterlist sg; 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); crypto_blkcipher_setkey(tfm, rc4key, klen);
sg_init_one(&sg, data, data_len + WEP_ICV_LEN); sg_init_one(&sg, data, data_len + WEP_ICV_LEN);

View File

@ -565,22 +565,37 @@ static void rfkill_release(struct device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int rfkill_suspend(struct device *dev, pm_message_t state) static int rfkill_suspend(struct device *dev, pm_message_t state)
{ {
struct rfkill *rfkill = to_rfkill(dev);
/* mark class device as suspended */ /* mark class device as suspended */
if (dev->power.power_state.event != state.event) if (dev->power.power_state.event != state.event)
dev->power.power_state = state; dev->power.power_state = state;
/* store state for the resume handler */
rfkill->state_for_resume = rfkill->state;
return 0; return 0;
} }
static int rfkill_resume(struct device *dev) static int rfkill_resume(struct device *dev)
{ {
struct rfkill *rfkill = to_rfkill(dev); struct rfkill *rfkill = to_rfkill(dev);
enum rfkill_state newstate;
if (dev->power.power_state.event != PM_EVENT_ON) { if (dev->power.power_state.event != PM_EVENT_ON) {
mutex_lock(&rfkill->mutex); mutex_lock(&rfkill->mutex);
dev->power.power_state.event = PM_EVENT_ON; 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, * If we are under EPO, kick transmitter offline,
* otherwise restore to pre-suspend state. * otherwise restore to pre-suspend state.
@ -590,7 +605,7 @@ static int rfkill_resume(struct device *dev)
rfkill_toggle_radio(rfkill, rfkill_toggle_radio(rfkill,
rfkill_epo_lock_active ? rfkill_epo_lock_active ?
RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_SOFT_BLOCKED :
rfkill->state, rfkill->state_for_resume,
1); 1);
mutex_unlock(&rfkill->mutex); mutex_unlock(&rfkill->mutex);

View File

@ -1,6 +1,15 @@
config CFG80211 config CFG80211
tristate "Improved wireless configuration API" 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 config NL80211
bool "nl80211 new netlink interface support" bool "nl80211 new netlink interface support"
depends on CFG80211 depends on CFG80211
@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY
ieee80211_regdom module parameter. This is being phased out and you ieee80211_regdom module parameter. This is being phased out and you
should stop using them ASAP. 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. Say Y unless you have installed a new userspace application.
Also say Y if have one currently depending on the ieee80211_regdom Also say Y if have one currently depending on the ieee80211_regdom
module parameter and cannot port it to use the new userspace module parameter and cannot port it to use the new userspace

View File

@ -19,7 +19,6 @@
#include "nl80211.h" #include "nl80211.h"
#include "core.h" #include "core.h"
#include "sysfs.h" #include "sysfs.h"
#include "reg.h"
/* name for sysfs, %d is appended */ /* name for sysfs, %d is appended */
#define PHY_NAME "phy" #define PHY_NAME "phy"
@ -348,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy)
/* unlock again before freeing */ /* unlock again before freeing */
mutex_unlock(&drv->mtx); 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); list_del(&drv->list);
device_del(&drv->wiphy.dev); device_del(&drv->wiphy.dev);
debugfs_remove(drv->wiphy.debugfsdir); debugfs_remove(drv->wiphy.debugfsdir);

View File

@ -11,6 +11,7 @@
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/wireless.h> #include <net/wireless.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "reg.h"
struct cfg80211_registered_device { struct cfg80211_registered_device {
struct cfg80211_ops *ops; struct cfg80211_ops *ops;
@ -21,6 +22,18 @@ struct cfg80211_registered_device {
* any call is in progress */ * any call is in progress */
struct mutex mtx; 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 */ /* wiphy index, internal only */
int idx; int idx;

View File

@ -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) if (chan->flags & IEEE80211_CHAN_RADAR)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_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); 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; return -EINVAL;
#endif #endif
mutex_lock(&cfg80211_drv_mutex); 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); mutex_unlock(&cfg80211_drv_mutex);
return r; return r;
} }

View File

@ -60,12 +60,18 @@
* @intersect: indicates whether the wireless core should intersect * @intersect: indicates whether the wireless core should intersect
* the requested regulatory domain with the presently set regulatory * the requested regulatory domain with the presently set regulatory
* domain. * 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 regulatory_request {
struct wiphy *wiphy; struct wiphy *wiphy;
enum reg_set_by initiator; enum reg_set_by initiator;
char alpha2[2]; char alpha2[2];
bool intersect; bool intersect;
u32 country_ie_checksum;
enum environment_cap country_ie_env;
}; };
/* Receipt of information from last regulatory request */ /* Receipt of information from last regulatory request */
@ -85,6 +91,11 @@ static u32 supported_bandwidths[] = {
* information to give us an alpha2 */ * information to give us an alpha2 */
static const struct ieee80211_regdomain *cfg80211_regdomain; 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 */ /* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = { static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 1, .n_reg_rules = 1,
@ -264,6 +275,18 @@ static bool is_unknown_alpha2(const char *alpha2)
return false; 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) static bool is_an_alpha2(const char *alpha2)
{ {
if (!alpha2) if (!alpha2)
@ -292,6 +315,25 @@ static bool regdom_changed(const char *alpha2)
return true; 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 /* This lets us keep regulatory code which is updated on a regulatory
* basis in userspace. */ * basis in userspace. */
static int call_crda(const char *alpha2) 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; const struct ieee80211_freq_range *freq_range = &rule->freq_range;
u32 freq_diff; 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; return false;
if (freq_range->start_freq_khz > freq_range->end_freq_khz) 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) if (!rd->n_reg_rules)
return false; 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++) { for (i = 0; i < rd->n_reg_rules; i++) {
reg_rule = &rd->reg_rules[i]; reg_rule = &rd->reg_rules[i];
if (!is_valid_reg_rule(reg_rule)) 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; 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 /* Helper for regdom_intersect(), this does the real
* mathematical intersection fun */ * mathematical intersection fun */
static int reg_rules_intersect( static int reg_rules_intersect(
@ -603,12 +816,23 @@ static void handle_band(struct ieee80211_supported_band *sband)
handle_channel(&sband->channels[i]); 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) static void update_all_wiphy_regulatory(enum reg_set_by setby)
{ {
struct cfg80211_registered_device *drv; struct cfg80211_registered_device *drv;
list_for_each_entry(drv, &cfg80211_drv_list, list) 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) 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 -EOPNOTSUPP;
return -EALREADY; return -EALREADY;
} }
/* Two consecutive Country IE hints on the same wiphy */ /* Two consecutive Country IE hints on the same wiphy.
if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) * This should be picked up early by the driver/stack */
if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
alpha2)))
return 0; return 0;
return -EALREADY; return -EALREADY;
} }
/* return REG_INTERSECT;
* Ignore Country IE hints for now, need to think about
* what we need to do to support multi-domain operation.
*/
return -EOPNOTSUPP;
case REGDOM_SET_BY_DRIVER: case REGDOM_SET_BY_DRIVER:
if (last_request->initiator == REGDOM_SET_BY_DRIVER) if (last_request->initiator == REGDOM_SET_BY_DRIVER)
return -EALREADY; return -EALREADY;
@ -677,6 +899,11 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
case REGDOM_SET_BY_USER: case REGDOM_SET_BY_USER:
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT; 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; 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 */ /* Caller must hold &cfg80211_drv_mutex */
int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, 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; struct regulatory_request *request;
bool intersect = false; bool intersect = false;
@ -698,36 +927,32 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
else if (r) else if (r)
return r; return r;
switch (set_by) { request = kzalloc(sizeof(struct regulatory_request),
case REGDOM_SET_BY_CORE: GFP_KERNEL);
case REGDOM_SET_BY_COUNTRY_IE: if (!request)
case REGDOM_SET_BY_DRIVER: return -ENOMEM;
case REGDOM_SET_BY_USER:
request = kzalloc(sizeof(struct regulatory_request),
GFP_KERNEL);
if (!request)
return -ENOMEM;
request->alpha2[0] = alpha2[0]; request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1]; request->alpha2[1] = alpha2[1];
request->initiator = set_by; request->initiator = set_by;
request->wiphy = wiphy; request->wiphy = wiphy;
request->intersect = intersect; request->intersect = intersect;
request->country_ie_checksum = country_ie_checksum;
request->country_ie_env = env;
kfree(last_request); kfree(last_request);
last_request = request; last_request = request;
r = call_crda(alpha2); /*
#ifndef CONFIG_WIRELESS_OLD_REGULATORY * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
if (r) * AND if CRDA is NOT present nothing will happen, if someone
printk(KERN_ERR "cfg80211: Failed calling CRDA\n"); * wants to bother with 11d with OLD_REG you can add a timer.
#endif * If after x amount of time nothing happens you can call:
break; *
default: * return set_regdom(country_ie_regdomain);
r = -ENOTSUPP; *
break; * to intersect with the static rd
} */
return call_crda(alpha2);
return r;
} }
void regulatory_hint(struct wiphy *wiphy, const char *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); BUG_ON(!alpha2);
mutex_lock(&cfg80211_drv_mutex); 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); mutex_unlock(&cfg80211_drv_mutex);
} }
EXPORT_SYMBOL(regulatory_hint); 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) 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) 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 " printk(KERN_INFO "cfg80211: World regulatory "
"domain updated:\n"); "domain updated:\n");
else { else {
@ -802,10 +1154,39 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
print_rd_rules(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 */ /* Takes ownership of rd only if it doesn't fail */
static int __set_regdom(const struct ieee80211_regdomain *rd) static int __set_regdom(const struct ieee80211_regdomain *rd)
{ {
const struct ieee80211_regdomain *intersected_rd = NULL; const struct ieee80211_regdomain *intersected_rd = NULL;
struct cfg80211_registered_device *drv = NULL;
struct wiphy *wiphy = NULL;
/* Some basic sanity checks first */ /* Some basic sanity checks first */
if (is_world_regdom(rd->alpha2)) { if (is_world_regdom(rd->alpha2)) {
@ -822,10 +1203,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!last_request) if (!last_request)
return -EINVAL; return -EINVAL;
/* allow overriding the static definitions if CRDA is present */ /* Lets only bother proceeding on the same alpha2 if the current
if (!is_old_static_regdom(cfg80211_regdomain) && * rd is non static (it means CRDA was present and was used last)
!regdom_changed(rd->alpha2)) * and the pending request came in from a country IE */
return -EINVAL; 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 /* Now lets set the regulatory domain, update all driver channels
* and finally inform them of what we have done, in case they want * 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))) if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
return -EINVAL; return -EINVAL;
reset_regdomains(); if (!is_valid_rd(rd)) {
printk(KERN_ERR "cfg80211: Invalid "
/* Country IE parsing coming soon */ "regulatory domain detected:\n");
switch (last_request->initiator) { print_regdomain_info(rd);
case REGDOM_SET_BY_CORE: return -EINVAL;
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 (unlikely(last_request->intersect)) { if (!last_request->intersect) {
reset_regdomains();
cfg80211_regdomain = rd;
return 0;
}
/* Intersection requires a bit more work */
if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
intersected_rd = regdom_intersect(rd, cfg80211_regdomain); intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
if (!intersected_rd) if (!intersected_rd)
return -EINVAL; return -EINVAL;
/* We can trash what CRDA provided now */
kfree(rd); 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; return 0;
} }
@ -885,16 +1316,28 @@ int set_regdom(const struct ieee80211_regdomain *rd)
} }
/* This would make this whole thing pointless */ /* 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 wiphys now with the new established regulatory domain */
update_all_wiphy_regulatory(last_request->initiator); update_all_wiphy_regulatory(last_request->initiator);
print_regdomain(rd); print_regdomain(cfg80211_regdomain);
return r; 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 regulatory_init(void)
{ {
int err; int err;
@ -914,11 +1357,11 @@ int regulatory_init(void)
* that is not a valid ISO / IEC 3166 alpha2 */ * that is not a valid ISO / IEC 3166 alpha2 */
if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
ieee80211_regdom); ieee80211_regdom, 0, ENVIRON_ANY);
#else #else
cfg80211_regdomain = cfg80211_world_regdom; 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) if (err)
printk(KERN_ERR "cfg80211: calling CRDA failed - " printk(KERN_ERR "cfg80211: calling CRDA failed - "
"unable to update world regulatory domain, " "unable to update world regulatory domain, "
@ -934,6 +1377,9 @@ void regulatory_exit(void)
reset_regdomains(); reset_regdomains();
kfree(country_ie_regdomain);
country_ie_regdomain = NULL;
kfree(last_request); kfree(last_request);
platform_device_unregister(reg_pdev); platform_device_unregister(reg_pdev);

View File

@ -4,28 +4,41 @@
bool is_world_regdom(const char *alpha2); bool is_world_regdom(const char *alpha2);
bool reg_is_valid_request(const char *alpha2); bool reg_is_valid_request(const char *alpha2);
void reg_device_remove(struct wiphy *wiphy);
int regulatory_init(void); int regulatory_init(void);
void regulatory_exit(void); void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd); 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 * __regulatory_hint - hint to the wireless core a regulatory domain
* @wiphy: if the hint comes from country information from an AP, this * @wiphy: if the hint comes from country information from an AP, this
* is required to be set to the wiphy that received the information * is required to be set to the wiphy that received the information
* @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
* should be in. * 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 * The Wireless subsystem can use this function to hint to the wireless core
* what it believes should be the current regulatory domain by * what it believes should be the current regulatory domain by giving it an
* giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
* domain should be in. * in.
* *
* Returns zero if all went fine, %-EALREADY if a regulatory domain had * Returns zero if all went fine, %-EALREADY if a regulatory domain had
* already been set or other standard error codes. * already been set or other standard error codes.
* *
*/ */
extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, 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 */ #endif /* __NET_WIRELESS_REG_H */