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

Conflicts:
	drivers/net/wireless/wl12xx/wl1271_cmd.h
This commit is contained in:
John W. Linville 2010-07-13 15:57:29 -04:00
commit e300d955de
106 changed files with 9726 additions and 8521 deletions

View File

@ -313,11 +313,9 @@ S: Maintained
F: drivers/hwmon/adm1029.c
ADM8211 WIRELESS DRIVER
M: Michael Wu <flamingice@sourmilk.net>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
S: Maintained
S: Orphan
F: drivers/net/wireless/adm8211.*
ADT746X FAN DRIVER
@ -4251,10 +4249,9 @@ F: include/scsi/osd_*
F: fs/exofs/
P54 WIRELESS DRIVER
M: Michael Wu <flamingice@sourmilk.net>
M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
W: http://prism54.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
W: http://wireless.kernel.org/en/users/Drivers/p54
S: Maintained
F: drivers/net/wireless/p54/

View File

@ -1903,7 +1903,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
if (err) {
printk(KERN_ERR "%s (adm8211): Cannot register device\n",
pci_name(pdev));
goto err_free_desc;
goto err_free_eeprom;
}
printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n",
@ -1912,6 +1912,9 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
return 0;
err_free_eeprom:
kfree(priv->eeprom);
err_free_desc:
pci_free_consistent(pdev,
sizeof(struct adm8211_desc) * priv->rx_ring_size +

File diff suppressed because it is too large Load Diff

View File

@ -1495,121 +1495,25 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
static void ar5008_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 0] is %d\n", nf);
nfarray[0] = nf;
nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
nfarray[1] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 2] is %d\n", nf);
nfarray[2] = nf;
nfarray[2] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[3] = nf;
nfarray[3] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
nfarray[4] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 2] is %d\n", nf);
nfarray[5] = nf;
}
static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_nfcal_hist *h;
int i, j;
int32_t val;
const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
AR_PHY_CH2_CCA,
AR_PHY_EXT_CCA,
AR_PHY_CH1_EXT_CCA,
AR_PHY_CH2_EXT_CCA
};
u8 chainmask, rx_chain_status;
rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
chainmask = 0x9;
else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
chainmask = 0x1B;
else
chainmask = 0x09;
} else {
if (rx_chain_status & 0x4)
chainmask = 0x3F;
else if (rx_chain_status & 0x2)
chainmask = 0x1B;
else
chainmask = 0x09;
}
h = ah->nfCalHist;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ar5416_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
REG_WRITE(ah, ar5416_cca_regs[i], val);
}
}
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_ENABLE_NF);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
for (j = 0; j < 5; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
udelay(50);
}
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ar5416_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (-50) << 1) & 0x1ff);
REG_WRITE(ah, ar5416_cca_regs[i], val);
}
}
REGWRITE_BUFFER_FLUSH(ah);
DISABLE_REGWRITE_BUFFER(ah);
nfarray[5] = sign_extend(nf, 9);
}
/*
@ -1676,10 +1580,27 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
aniState->cycleCount = 0;
}
static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
{
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
}
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
AR_PHY_CH2_CCA,
AR_PHY_EXT_CCA,
AR_PHY_CH1_EXT_CCA,
AR_PHY_CH2_EXT_CCA
};
priv_ops->rf_set_freq = ar5008_hw_set_channel;
priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
@ -1699,7 +1620,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->restore_chainmask = ar5008_restore_chainmask;
priv_ops->set_diversity = ar5008_set_diversity;
priv_ops->do_getnf = ar5008_hw_do_getnf;
priv_ops->loadnf = ar5008_hw_loadnf;
if (modparam_force_new_ani) {
priv_ops->ani_control = ar5008_hw_ani_control_new;
@ -1713,4 +1633,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
else
priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
ar5008_hw_set_nf_limits(ah);
memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
}

File diff suppressed because it is too large Load Diff

View File

@ -239,7 +239,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
if (qCoff > 15)
qCoff = 15;
else if (qCoff <= -16)
qCoff = 16;
qCoff = -16;
ath_print(common, ATH_DBG_CALIBRATE,
"Chn %d : iCoff = 0x%x qCoff = 0x%x\n",

View File

@ -179,8 +179,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar5416Bank7_9160), 2);
if (AR_SREV_9160_11(ah)) {
INIT_INI_ARRAY(&ah->iniAddac,
ar5416Addac_91601_1,
ARRAY_SIZE(ar5416Addac_91601_1), 2);
ar5416Addac_9160_1_1,
ARRAY_SIZE(ar5416Addac_9160_1_1), 2);
} else {
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
ARRAY_SIZE(ar5416Addac_9160), 2);
@ -239,12 +239,12 @@ void ar9002_hw_cck_chan14_spread(struct ath_hw *ah)
{
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniCckfirNormal,
ar9287Common_normal_cck_fir_coeff_92871_1,
ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1),
ar9287Common_normal_cck_fir_coeff_9287_1_1,
ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1),
2);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9287Common_japan_2484_cck_fir_coeff_92871_1,
ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1),
ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1),
2);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -287,6 +287,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
ts->tid = MS(ads->ds_txstatus9, AR_TxTid);
ts->ts_antenna = 0;
return 0;

View File

@ -471,52 +471,45 @@ static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
static void ar9002_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 0] is %d\n", nf);
if (AR_SREV_9271(ah) && (nf >= -114))
nf = -116;
nfarray[0] = nf;
if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
AR9280_PHY_CH1_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
}
nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[3] = sign_extend(nf, 9);
if (AR_SREV_9271(ah) && (nf >= -114))
nf = -116;
if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
return;
nfarray[3] = nf;
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
nfarray[1] = sign_extend(nf, 9);
if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
AR9280_PHY_CH1_EXT_MINCCA_PWR);
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR);
nfarray[4] = sign_extend(nf, 9);
}
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
{
if (AR_SREV_9285(ah)) {
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ;
} else if (AR_SREV_9287(ah)) {
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ;
} else if (AR_SREV_9271(ah)) {
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9271_2GHZ;
} else {
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ;
ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ;
ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ;
ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ;
}
}
@ -532,4 +525,6 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->olc_init = ar9002_olc_init;
priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
priv_ops->do_getnf = ar9002_hw_do_getnf;
ar9002_hw_set_nf_limits(ah);
}

View File

@ -576,4 +576,30 @@
#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000
#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
#define AR_PHY_CCA_NOM_VAL_5416_2GHZ -90
#define AR_PHY_CCA_NOM_VAL_5416_5GHZ -100
#define AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ -100
#define AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ -110
#define AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ -80
#define AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ -90
#define AR_PHY_CCA_NOM_VAL_9280_2GHZ -112
#define AR_PHY_CCA_NOM_VAL_9280_5GHZ -112
#define AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ -127
#define AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ -122
#define AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ -97
#define AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ -102
#define AR_PHY_CCA_NOM_VAL_9285_2GHZ -118
#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ -127
#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ -108
#define AR_PHY_CCA_NOM_VAL_9271_2GHZ -118
#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127
#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116
#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120
#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127
#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110
#endif

View File

@ -951,7 +951,7 @@ static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
return 1;
}
static u16 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
static u32 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
return -EINVAL;

View File

@ -33,9 +33,6 @@
#define AR_TxDescId_S 16
#define AR_TxPtrChkSum 0x0000ffff
#define AR_TxTid 0xf0000000
#define AR_TxTid_S 28
#define AR_LowRxChain 0x00004000
#define AR_Not_Sounding 0x20000000

View File

@ -1015,213 +1015,38 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
return true;
}
static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf)
{
struct ath_common *common = ath9k_hw_common(ah);
if (*nf > ah->nf_2g_max) {
ath_print(common, ATH_DBG_CALIBRATE,
"2 GHz NF (%d) > MAX (%d), "
"correcting to MAX",
*nf, ah->nf_2g_max);
*nf = ah->nf_2g_max;
} else if (*nf < ah->nf_2g_min) {
ath_print(common, ATH_DBG_CALIBRATE,
"2 GHz NF (%d) < MIN (%d), "
"correcting to MIN",
*nf, ah->nf_2g_min);
*nf = ah->nf_2g_min;
}
}
static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf)
{
struct ath_common *common = ath9k_hw_common(ah);
if (*nf > ah->nf_5g_max) {
ath_print(common, ATH_DBG_CALIBRATE,
"5 GHz NF (%d) > MAX (%d), "
"correcting to MAX",
*nf, ah->nf_5g_max);
*nf = ah->nf_5g_max;
} else if (*nf < ah->nf_5g_min) {
ath_print(common, ATH_DBG_CALIBRATE,
"5 GHz NF (%d) < MIN (%d), "
"correcting to MIN",
*nf, ah->nf_5g_min);
*nf = ah->nf_5g_min;
}
}
static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
{
if (IS_CHAN_2GHZ(ah->curchan))
ar9003_hw_nf_sanitize_2g(ah, nf);
else
ar9003_hw_nf_sanitize_5g(ah, nf);
}
static void ar9003_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 0] is %d\n", nf);
nfarray[0] = nf;
nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
nfarray[1] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ctl] [chain 2] is %d\n", nf);
nfarray[2] = nf;
nfarray[2] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[3] = nf;
nfarray[3] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
nfarray[4] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
ar9003_hw_nf_sanitize(ah, &nf);
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [ext] [chain 2] is %d\n", nf);
nfarray[5] = nf;
nfarray[5] = sign_extend(nf, 9);
}
void ar9003_hw_set_nf_limits(struct ath_hw *ah)
static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
{
ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
}
/*
* Find out which of the RX chains are enabled
*/
static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
{
u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
/*
* The bits [2:0] indicate the rx chain mask and are to be
* interpreted as follows:
* 00x => Only chain 0 is enabled
* 01x => Chain 1 and 0 enabled
* 1xx => Chain 2,1 and 0 enabled
*/
return chain & 0x7;
}
static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_nfcal_hist *h;
unsigned i, j;
int32_t val;
const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
AR_PHY_CCA_2,
AR_PHY_EXT_CCA,
AR_PHY_EXT_CCA_1,
AR_PHY_EXT_CCA_2,
};
u8 chainmask, rx_chain_status;
struct ath_common *common = ath9k_hw_common(ah);
rx_chain_status = ar9003_hw_get_rx_chainmask(ah);
chainmask = 0x3F;
h = ah->nfCalHist;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ar9300_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
REG_WRITE(ah, ar9300_cca_regs[i], val);
}
}
/*
* Load software filtered NF value into baseband internal minCCApwr
* variable.
*/
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_ENABLE_NF);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
/*
* Wait for load to complete, should be fast, a few 10s of us.
* The max delay was changed from an original 250us to 10000us
* since 250us often results in NF load timeout and causes deaf
* condition during stress testing 12/12/2009
*/
for (j = 0; j < 1000; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
udelay(10);
}
/*
* We timed out waiting for the noisefloor to load, probably due to an
* in-progress rx. Simply return here and allow the load plenty of time
* to complete before the next calibration interval. We need to avoid
* trying to load -50 (which happens below) while the previous load is
* still in progress as this can cause rx deafness. Instead by returning
* here, the baseband nf cal will just be capped by our present
* noisefloor until the next calibration timer.
*/
if (j == 1000) {
ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
"to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));
return;
}
/*
* Restore maxCCAPower register parameter again so that we're not capped
* by the median we just loaded. This will be initial (and max) value
* of next noise floor calibration the baseband does.
*/
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ar9300_cca_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (-50) << 1) & 0x1ff);
REG_WRITE(ah, ar9300_cca_regs[i], val);
}
}
ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
}
/*
@ -1291,6 +1116,14 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
AR_PHY_CCA_2,
AR_PHY_EXT_CCA,
AR_PHY_EXT_CCA_1,
AR_PHY_EXT_CCA_2,
};
priv_ops->rf_set_freq = ar9003_hw_set_channel;
priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
@ -1307,8 +1140,10 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->set_diversity = ar9003_hw_set_diversity;
priv_ops->ani_control = ar9003_hw_ani_control;
priv_ops->do_getnf = ar9003_hw_do_getnf;
priv_ops->loadnf = ar9003_hw_loadnf;
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
ar9003_hw_set_nf_limits(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
}
void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)

View File

@ -428,6 +428,7 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
void ath_hw_check(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
@ -562,6 +563,7 @@ struct ath_softc {
spinlock_t sc_pm_lock;
struct mutex mutex;
struct work_struct paprd_work;
struct work_struct hw_check_work;
struct completion paprd_complete;
u32 intrstatus;

View File

@ -74,13 +74,8 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
h[i].currIndex = 0;
if (h[i].invalidNFcount > 0) {
if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
} else {
h[i].invalidNFcount--;
h[i].privNF = nfarray[i];
}
h[i].invalidNFcount--;
h[i].privNF = nfarray[i];
} else {
h[i].privNF =
ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
@ -172,6 +167,133 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_nfcal_hist *h;
unsigned i, j;
int32_t val;
u8 chainmask;
struct ath_common *common = ath9k_hw_common(ah);
if (AR_SREV_9300_20_OR_LATER(ah))
chainmask = 0x3F;
else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
chainmask = 0x9;
else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
if ((ah->rxchainmask & 0x2) || (ah->rxchainmask & 0x4))
chainmask = 0x1B;
else
chainmask = 0x09;
} else {
if (ah->rxchainmask & 0x4)
chainmask = 0x3F;
else if (ah->rxchainmask & 0x2)
chainmask = 0x1B;
else
chainmask = 0x09;
}
h = ah->nfCalHist;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ah->nf_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
REG_WRITE(ah, ah->nf_regs[i], val);
}
}
/*
* Load software filtered NF value into baseband internal minCCApwr
* variable.
*/
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_ENABLE_NF);
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
/*
* Wait for load to complete, should be fast, a few 10s of us.
* The max delay was changed from an original 250us to 10000us
* since 250us often results in NF load timeout and causes deaf
* condition during stress testing 12/12/2009
*/
for (j = 0; j < 1000; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
udelay(10);
}
/*
* We timed out waiting for the noisefloor to load, probably due to an
* in-progress rx. Simply return here and allow the load plenty of time
* to complete before the next calibration interval. We need to avoid
* trying to load -50 (which happens below) while the previous load is
* still in progress as this can cause rx deafness. Instead by returning
* here, the baseband nf cal will just be capped by our present
* noisefloor until the next calibration timer.
*/
if (j == 1000) {
ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
"to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));
return;
}
/*
* Restore maxCCAPower register parameter again so that we're not capped
* by the median we just loaded. This will be initial (and max) value
* of next noise floor calibration the baseband does.
*/
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ah->nf_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (-50) << 1) & 0x1ff);
REG_WRITE(ah, ah->nf_regs[i], val);
}
}
REGWRITE_BUFFER_FLUSH(ah);
DISABLE_REGWRITE_BUFFER(ah);
}
static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath_nf_limits *limit;
int i;
if (IS_CHAN_2GHZ(ah->curchan))
limit = &ah->nf_2g;
else
limit = &ah->nf_5g;
for (i = 0; i < NUM_NF_READINGS; i++) {
if (!nf[i])
continue;
ath_print(common, ATH_DBG_CALIBRATE,
"NF calibrated [%s] [chain %d] is %d\n",
(i > 3 ? "ext" : "ctl"), i % 3, nf[i]);
if (nf[i] > limit->max) {
ath_print(common, ATH_DBG_CALIBRATE,
"NF[%d] (%d) > MAX (%d), correcting to MAX",
i, nf[i], limit->max);
nf[i] = limit->max;
} else if (nf[i] < limit->min) {
ath_print(common, ATH_DBG_CALIBRATE,
"NF[%d] (%d) < MIN (%d), correcting to NOM",
i, nf[i], limit->min);
nf[i] = limit->nominal;
}
}
}
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -190,6 +312,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
return chan->rawNoiseFloor;
} else {
ath9k_hw_do_getnf(ah, nfarray);
ath9k_hw_nf_sanitize(ah, nfarray);
nf = nfarray[0];
if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
&& nf > nfThresh) {
@ -211,25 +334,21 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
struct ath_nf_limits *limit;
int i, j;
s16 noise_floor;
if (AR_SREV_9280(ah))
noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
else if (AR_SREV_9287(ah))
noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
limit = &ah->nf_2g;
else
noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
limit = &ah->nf_5g;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].privNF = limit->nominal;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
}
}
}

View File

@ -19,12 +19,6 @@
#include "hw.h"
#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_AR9287_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5
@ -115,6 +109,7 @@ struct ath9k_pacal_info{
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);

View File

@ -319,6 +319,10 @@ int ath9k_cmn_key_config(struct ath_common *common,
idx = ath_reserve_key_cache_slot(common, key->alg);
break;
case NL80211_IFTYPE_ADHOC:
if (!sta) {
idx = key->keyidx;
break;
}
memcpy(gmac, sta->addr, ETH_ALEN);
gmac[0] |= 0x01;
mac = gmac;

View File

@ -670,7 +670,7 @@ struct eeprom_ops {
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);

View File

@ -1150,13 +1150,13 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
}
}
static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct modal_eep_4k_header *pModal = &eep->modalHeader;
return pModal->antCtrlCommon & 0xFFFF;
return pModal->antCtrlCommon;
}
static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,

View File

@ -1130,13 +1130,13 @@ static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
return 1;
}
static u16 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
static u32 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
return pModal->antCtrlCommon & 0xFFFF;
return pModal->antCtrlCommon;
}
static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,

View File

@ -730,7 +730,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
vpdTableI[i][sizeCurrVpdTable - 2]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
if (tgtIndex > maxIndex) {
if (tgtIndex >= maxIndex) {
while ((ss <= tgtIndex) &&
(k < (AR5416_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
@ -1438,14 +1438,14 @@ static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
return num_ant_config;
}
static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
static u32 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct modal_eep_header *pModal =
&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
return pModal->antCtrlCommon & 0xFFFF;
return pModal->antCtrlCommon;
}
static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)

View File

@ -745,13 +745,17 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
/* RX */
if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0)
goto err;
goto err_rx;
/* Register Read */
if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
goto err;
goto err_reg;
return 0;
err_reg:
ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
err_rx:
ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
err:
return -ENOMEM;
}

View File

@ -264,12 +264,6 @@ static inline void ath9k_hw_do_getnf(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
}
static inline void ath9k_hw_loadnf(struct ath_hw *ah,
struct ath9k_channel *chan)
{
ath9k_hw_private_ops(ah)->loadnf(ah, chan);
}
static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{

View File

@ -609,9 +609,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
else
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
if (AR_SREV_9300_20_OR_LATER(ah))
ar9003_hw_set_nf_limits(ah);
ath9k_init_nfcal_hist_buffer(ah);
ah->bb_watchdog_timeout_ms = 25;
@ -1235,9 +1232,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!ah->chip_fullsleep) {
ath9k_hw_abortpcurecv(ah);
if (!ath9k_hw_stopdmarecv(ah))
if (!ath9k_hw_stopdmarecv(ah)) {
ath_print(common, ATH_DBG_XMIT,
"Failed to stop receive dma\n");
bChannelChange = false;
}
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))

View File

@ -510,7 +510,6 @@ struct ath_gen_timer_table {
* AR_RTC_PLL_CONTROL for a given channel
* @setup_calibration: set up calibration
* @iscal_supported: used to query if a type of calibration is supported
* @loadnf: load noise floor read from each chain on the CCA registers
*
* @ani_reset: reset ANI parameters to default values
* @ani_lower_immunity: lower the noise immunity level. The level controls
@ -564,7 +563,6 @@ struct ath_hw_private_ops {
bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
int param);
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan);
/* ANI */
void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
@ -630,6 +628,12 @@ struct ath_hw_ops {
void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
};
struct ath_nf_limits {
s16 max;
s16 min;
s16 nominal;
};
struct ath_hw {
struct ieee80211_hw *hw;
struct ath_common common;
@ -651,10 +655,10 @@ struct ath_hw {
bool is_pciexpress;
bool need_an_top2_fixup;
u16 tx_trig_level;
s16 nf_2g_max;
s16 nf_2g_min;
s16 nf_5g_max;
s16 nf_5g_min;
u32 nf_regs[6];
struct ath_nf_limits nf_2g;
struct ath_nf_limits nf_5g;
u16 rfsilent;
u32 rfkill_gpio;
u32 rfkill_polarity;
@ -848,6 +852,12 @@ static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah)
return &ah->ops;
}
static inline int sign_extend(int val, const int nbits)
{
int order = BIT(nbits-1);
return (val ^ order) - order;
}
/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_deinit(struct ath_hw *ah);
@ -943,7 +953,6 @@ void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
* Code specific to AR9003, we stuff these here to avoid callbacks
* for older families
*/
void ar9003_hw_set_nf_limits(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);

View File

@ -718,6 +718,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
goto error_world;
}
INIT_WORK(&sc->hw_check_work, ath_hw_check);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);

View File

@ -485,6 +485,9 @@ struct ar5416_desc {
#define AR_TxRSSICombined 0xff000000
#define AR_TxRSSICombined_S 24
#define AR_TxTid 0xf0000000
#define AR_TxTid_S 28
#define AR_TxEVM0 ds_txstatus5
#define AR_TxEVM1 ds_txstatus6
#define AR_TxEVM2 ds_txstatus7

View File

@ -515,6 +515,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
ath_tx_node_cleanup(sc, an);
}
void ath_hw_check(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
int i;
ath9k_ps_wakeup(sc);
for (i = 0; i < 3; i++) {
if (ath9k_hw_check_alive(sc->sc_ah))
goto out;
msleep(1);
}
ath_reset(sc, false);
out:
ath9k_ps_restore(sc);
}
void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@ -526,13 +545,15 @@ void ath9k_tasklet(unsigned long data)
ath9k_ps_wakeup(sc);
if ((status & ATH9K_INT_FATAL) ||
!ath9k_hw_check_alive(ah)) {
if (status & ATH9K_INT_FATAL) {
ath_reset(sc, false);
ath9k_ps_restore(sc);
return;
}
if (!ath9k_hw_check_alive(ah))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
ATH9K_INT_RXORN);
@ -1253,6 +1274,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
cancel_delayed_work_sync(&sc->tx_complete_work);
cancel_work_sync(&sc->paprd_work);
cancel_work_sync(&sc->hw_check_work);
if (!sc->num_sec_wiphy) {
cancel_delayed_work_sync(&sc->wiphy_work);
@ -1976,6 +1998,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
sc->sc_flags |= SC_OP_SCANNING;
del_timer_sync(&common->ani.timer);
cancel_work_sync(&sc->paprd_work);
cancel_work_sync(&sc->hw_check_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
mutex_unlock(&sc->mutex);
}

View File

@ -329,6 +329,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
struct ieee80211_tx_rate rates[4];
unsigned long flags;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@ -344,12 +345,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
if (!sta) {
rcu_read_unlock();
spin_lock_irqsave(&sc->tx.txbuflock, flags);
list_splice_tail_init(bf_q, &sc->tx.txbuf);
spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
return;
}
an = (struct ath_node *)sta->drv_priv;
tid = ATH_AN_2_TID(an, bf->bf_tidno);
/*
* The hardware occasionally sends a tx status for the wrong TID.
* In this case, the BA status cannot be considered valid and all
* subframes need to be retransmitted
*/
if (bf->bf_tidno != ts->tid)
txok = false;
isaggr = bf_isaggr(bf);
memset(ba, 0, WME_BA_BMP_SIZE >> 3);
@ -2430,37 +2443,37 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
{
int i;
struct ath_atx_ac *ac, *ac_tmp;
struct ath_atx_tid *tid, *tid_tmp;
struct ath_atx_ac *ac;
struct ath_atx_tid *tid;
struct ath_txq *txq;
int i, tidno;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
txq = &sc->tx.txq[i];
for (tidno = 0, tid = &an->tid[tidno];
tidno < WME_NUM_TID; tidno++, tid++) {
i = tid->ac->qnum;
spin_lock_bh(&txq->axq_lock);
if (!ATH_TXQ_SETUP(sc, i))
continue;
list_for_each_entry_safe(ac,
ac_tmp, &txq->axq_acq, list) {
tid = list_first_entry(&ac->tid_q,
struct ath_atx_tid, list);
if (tid && tid->an != an)
continue;
list_del(&ac->list);
ac->sched = false;
txq = &sc->tx.txq[i];
ac = tid->ac;
list_for_each_entry_safe(tid,
tid_tmp, &ac->tid_q, list) {
list_del(&tid->list);
tid->sched = false;
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
}
}
spin_lock_bh(&txq->axq_lock);
spin_unlock_bh(&txq->axq_lock);
if (tid->sched) {
list_del(&tid->list);
tid->sched = false;
}
if (ac->sched) {
list_del(&ac->list);
tid->ac->sched = false;
}
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
spin_unlock_bh(&txq->axq_lock);
}
}

View File

@ -186,7 +186,7 @@ int prism2_wds_add(local_info_t *local, u8 *remote_addr,
return -ENOBUFS;
/* verify that there is room for wds# postfix in the interface name */
if (strlen(local->dev->name) > IFNAMSIZ - 5) {
if (strlen(local->dev->name) >= IFNAMSIZ - 5) {
printk(KERN_DEBUG "'%s' too long base device name\n",
local->dev->name);
return -EINVAL;

View File

@ -87,10 +87,15 @@ config IWL4965
This option enables support for Intel Wireless WiFi Link 4965AGN
config IWL5000
bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 1000, 6000, and 6050 Series"
bool "Intel Wireless-N/Advanced-N/Ultimate-N WiFi Link"
depends on IWLAGN
---help---
This option enables support for Intel Wireless WiFi Link 5000AGN Family
This option enables support for use with the following hardware:
Intel Wireless WiFi Link 6250AGN Adapter
Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN)
Intel WiFi Link 1000BGN
Intel Wireless WiFi 5150AGN
Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"

View File

@ -129,8 +129,8 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@ -226,6 +226,8 @@ static struct iwl_lib_ops iwl1000_lib = {
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl1000_ops = {

View File

@ -179,8 +179,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@ -226,8 +226,8 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@ -402,6 +402,8 @@ static struct iwl_lib_ops iwl5000_lib = {
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static struct iwl_lib_ops iwl5150_lib = {
@ -465,6 +467,8 @@ static struct iwl_lib_ops iwl5150_lib = {
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl5000_ops = {

View File

@ -160,8 +160,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
@ -327,6 +327,8 @@ static struct iwl_lib_ops iwl6000_lib = {
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl6000_ops = {
@ -827,6 +829,44 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.need_dc_calib = true,
};
struct iwl_cfg iwl6050g2_bgn_cfg = {
.name = "6050 Series 1x2 BGN Gen2",
.fw_name_pre = IWL6050_FW_PRE,
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.mod_params = &iwlagn_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
.pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
.use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1500,
.monitor_recover_period = IWL_MONITORING_PERIOD,
.max_event_log_size = 1024,
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
.need_dc_calib = true,
};
struct iwl_cfg iwl6050_2abg_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
.fw_name_pre = IWL6050_FW_PRE,

View File

@ -409,10 +409,50 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
return 0;
}
static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
struct iwl_sensitivity_data *data,
__le16 *tbl)
{
tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm);
tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_x1);
tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck);
tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck_mrc);
tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_cck);
tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_ofdm);
tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
cpu_to_le16(data->barker_corr_th_min);
tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16(data->barker_corr_th_min_mrc);
tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
data->nrg_th_ofdm);
IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
data->auto_corr_cck, data->auto_corr_cck_mrc,
data->nrg_th_cck);
}
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
static int iwl_sensitivity_write(struct iwl_priv *priv)
{
struct iwl_sensitivity_cmd cmd ;
struct iwl_sensitivity_cmd cmd;
struct iwl_sensitivity_data *data = NULL;
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
@ -425,40 +465,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
memset(&cmd, 0, sizeof(cmd));
cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm);
cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_x1);
cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck);
cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck_mrc);
cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_cck);
cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_ofdm);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
cpu_to_le16(data->barker_corr_th_min);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16(data->barker_corr_th_min_mrc);
cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
data->nrg_th_ofdm);
IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
data->auto_corr_cck, data->auto_corr_cck_mrc,
data->nrg_th_cck);
iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
@ -477,6 +484,70 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
return iwl_send_cmd(priv, &cmd_out);
}
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
{
struct iwl_enhance_sensitivity_cmd cmd;
struct iwl_sensitivity_data *data = NULL;
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
.len = sizeof(struct iwl_enhance_sensitivity_cmd),
.flags = CMD_ASYNC,
.data = &cmd,
};
data = &(priv->sensitivity_data);
memset(&cmd, 0, sizeof(cmd));
iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
HD_INA_NON_SQUARE_DET_OFDM_DATA;
cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
HD_INA_NON_SQUARE_DET_CCK_DATA;
cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA;
cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA;
cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
HD_OFDM_NON_SQUARE_DET_SLOPE_DATA;
cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA;
cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA;
cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
HD_CCK_NON_SQUARE_DET_SLOPE_DATA;
cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA;
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
/* Don't send command to uCode if nothing has changed */
if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]),
sizeof(u16)*HD_TABLE_SIZE) &&
!memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
&(priv->enhance_sensitivity_tbl[0]),
sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
return 0;
}
/* Copy table for comparison next time */
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]),
sizeof(u16)*HD_TABLE_SIZE);
memcpy(&(priv->enhance_sensitivity_tbl[0]),
&(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
return iwl_send_cmd(priv, &cmd_out);
}
void iwl_init_sensitivity(struct iwl_priv *priv)
{
int ret = 0;
@ -527,7 +598,10 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
data->last_bad_plcp_cnt_cck = 0;
data->last_fa_cnt_cck = 0;
ret |= iwl_sensitivity_write(priv);
if (priv->enhance_sensitivity_table)
ret |= iwl_enhance_sensitivity_write(priv);
else
ret |= iwl_sensitivity_write(priv);
IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
}
@ -633,7 +707,10 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
iwl_sensitivity_write(priv);
if (priv->enhance_sensitivity_table)
iwl_enhance_sensitivity_write(priv);
else
iwl_sensitivity_write(priv);
}
static inline u8 find_first_chain(u8 mask)

View File

@ -205,7 +205,9 @@ void iwl_check_abort_status(struct iwl_priv *priv,
u8 frame_count, u32 status)
{
if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
IWL_ERR(priv, "Tx flush command to flush out all frames\n");
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
queue_work(priv->workqueue, &priv->tx_flush);
}
}
@ -1435,3 +1437,81 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
}
}
#define IWL_FLUSH_WAIT_MS 2000
int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
{
struct iwl_tx_queue *txq;
struct iwl_queue *q;
int cnt;
unsigned long now = jiffies;
int ret = 0;
/* waiting for all the tx frames complete might take a while */
for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
if (cnt == IWL_CMD_QUEUE_NUM)
continue;
txq = &priv->txq[cnt];
q = &txq->q;
while (q->read_ptr != q->write_ptr && !time_after(jiffies,
now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
msleep(1);
if (q->read_ptr != q->write_ptr) {
IWL_ERR(priv, "fail to flush all tx fifo queues\n");
ret = -ETIMEDOUT;
break;
}
}
return ret;
}
#define IWL_TX_QUEUE_MSK 0xfffff
/**
* iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
*
* pre-requirements:
* 1. acquire mutex before calling
* 2. make sure rf is on and not in exit state
*/
int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
{
struct iwl_txfifo_flush_cmd flush_cmd;
struct iwl_host_cmd cmd = {
.id = REPLY_TXFIFO_FLUSH,
.len = sizeof(struct iwl_txfifo_flush_cmd),
.flags = CMD_SYNC,
.data = &flush_cmd,
};
might_sleep();
memset(&flush_cmd, 0, sizeof(flush_cmd));
flush_cmd.fifo_control = IWL_TX_FIFO_VO_MSK | IWL_TX_FIFO_VI_MSK |
IWL_TX_FIFO_BE_MSK | IWL_TX_FIFO_BK_MSK;
if (priv->cfg->sku & IWL_SKU_N)
flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
flush_cmd.fifo_control);
flush_cmd.flush_control = cpu_to_le16(flush_control);
return iwl_send_cmd(priv, &cmd);
}
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
{
mutex_lock(&priv->mutex);
ieee80211_stop_queues(priv->hw);
if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
IWL_ERR(priv, "flush request fail\n");
goto done;
}
IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
iwlagn_wait_tx_queue_empty(priv);
done:
ieee80211_wake_queues(priv->hw);
mutex_unlock(&priv->mutex);
}

View File

@ -950,9 +950,12 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
/* Stop each Tx DMA channel, and wait for it to be idle */
for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
1000);
1000))
IWL_ERR(priv, "Failing on timeout while stopping"
" DMA channel %d [0x%08x]", ch,
iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
}
spin_unlock_irqrestore(&priv->lock, flags);
}

View File

@ -859,6 +859,24 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
return 0;
}
static void iwl_bg_tx_flush(struct work_struct *work)
{
struct iwl_priv *priv =
container_of(work, struct iwl_priv, tx_flush);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
/* do nothing if rf-kill is on */
if (!iwl_is_ready_rf(priv))
return;
if (priv->cfg->ops->lib->txfifo_flush) {
IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
}
}
/**
* iwl_setup_rx_handlers - Initialize Rx handler callbacks
*
@ -1806,12 +1824,21 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
const u8 *data;
int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
u64 alternatives;
u32 tlv_len;
enum iwl_ucode_tlv_type tlv_type;
const u8 *tlv_data;
int ret = 0;
if (len < sizeof(*ucode))
if (len < sizeof(*ucode)) {
IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
return -EINVAL;
}
if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
le32_to_cpu(ucode->magic));
return -EINVAL;
}
/*
* Check which alternatives are present, and "downgrade"
@ -1836,11 +1863,9 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
len -= sizeof(*ucode);
while (len >= sizeof(*tlv)) {
u32 tlv_len;
enum iwl_ucode_tlv_type tlv_type;
while (len >= sizeof(*tlv) && !ret) {
u16 tlv_alt;
const u8 *tlv_data;
u32 fixed_tlv_size = 4;
len -= sizeof(*tlv);
tlv = (void *)data;
@ -1850,8 +1875,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
tlv_alt = le16_to_cpu(tlv->alternative);
tlv_data = tlv->data;
if (len < tlv_len)
if (len < tlv_len) {
IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
len, tlv_len);
return -EINVAL;
}
len -= ALIGN(tlv_len, 4);
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
@ -1885,56 +1913,77 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
pieces->boot_size = tlv_len;
break;
case IWL_UCODE_TLV_PROBE_MAX_LEN:
if (tlv_len != 4)
return -EINVAL;
capa->max_probe_length =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
capa->max_probe_length =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->init_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->init_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
if (tlv_len != 4)
return -EINVAL;
pieces->init_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->init_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->init_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->init_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->inst_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->inst_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
if (tlv_len != fixed_tlv_size)
ret = -EINVAL;
else
pieces->inst_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
if (tlv_len)
ret = -EINVAL;
else
priv->enhance_sensitivity_table = true;
break;
default:
IWL_WARN(priv, "unknown TLV: %d\n", tlv_type);
break;
}
}
if (len)
return -EINVAL;
if (len) {
IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
ret = -EINVAL;
} else if (ret) {
IWL_ERR(priv, "TLV %d has invalid size: %u\n",
tlv_type, tlv_len);
iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)tlv_data, tlv_len);
}
return 0;
return ret;
}
/**
@ -2247,17 +2296,41 @@ static const char *desc_lookup_text[] = {
"DEBUG_1",
"DEBUG_2",
"DEBUG_3",
"ADVANCED SYSASSERT"
};
static const char *desc_lookup(int i)
static struct { char *name; u8 num; } advanced_lookup[] = {
{ "NMI_INTERRUPT_WDG", 0x34 },
{ "SYSASSERT", 0x35 },
{ "UCODE_VERSION_MISMATCH", 0x37 },
{ "BAD_COMMAND", 0x38 },
{ "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
{ "FATAL_ERROR", 0x3D },
{ "NMI_TRM_HW_ERR", 0x46 },
{ "NMI_INTERRUPT_TRM", 0x4C },
{ "NMI_INTERRUPT_BREAK_POINT", 0x54 },
{ "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
{ "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
{ "NMI_INTERRUPT_HOST", 0x66 },
{ "NMI_INTERRUPT_ACTION_PT", 0x7C },
{ "NMI_INTERRUPT_UNKNOWN", 0x84 },
{ "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
{ "ADVANCED_SYSASSERT", 0 },
};
static const char *desc_lookup(u32 num)
{
int max = ARRAY_SIZE(desc_lookup_text) - 1;
int i;
int max = ARRAY_SIZE(desc_lookup_text);
if (i < 0 || i > max)
i = max;
if (num < max)
return desc_lookup_text[num];
return desc_lookup_text[i];
max = ARRAY_SIZE(advanced_lookup) - 1;
for (i = 0; i < max; i++) {
if (advanced_lookup[i].num == num)
break;;
}
return advanced_lookup[i].name;
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
@ -3614,6 +3687,44 @@ out_exit:
IWL_DEBUG_MAC80211(priv, "leave\n");
}
static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct iwl_priv *priv = hw->priv;
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "enter\n");
/* do not support "flush" */
if (!priv->cfg->ops->lib->txfifo_flush)
goto done;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
goto done;
}
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
goto done;
}
/*
* mac80211 will not push any more frames for transmit
* until the flush is completed
*/
if (drop) {
IWL_DEBUG_MAC80211(priv, "send flush command\n");
if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
IWL_ERR(priv, "flush request fail\n");
goto done;
}
}
IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
iwlagn_wait_tx_queue_empty(priv);
done:
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
/*****************************************************************************
*
* driver setup and teardown
@ -3630,6 +3741,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@ -3787,6 +3899,7 @@ static struct ieee80211_ops iwl_hw_ops = {
.sta_add = iwlagn_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
.channel_switch = iwl_mac_channel_switch,
.flush = iwl_mac_flush,
};
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@ -4234,6 +4347,14 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
/* 6x50 WiFi/WiMax Series Gen2 */
{IWL_PCI_DEVICE(0x0885, 0x1305, iwl6050g2_bgn_cfg)},
{IWL_PCI_DEVICE(0x0885, 0x1306, iwl6050g2_bgn_cfg)},
{IWL_PCI_DEVICE(0x0885, 0x1325, iwl6050g2_bgn_cfg)},
{IWL_PCI_DEVICE(0x0885, 0x1326, iwl6050g2_bgn_cfg)},
{IWL_PCI_DEVICE(0x0886, 0x1315, iwl6050g2_bgn_cfg)},
{IWL_PCI_DEVICE(0x0886, 0x1316, iwl6050g2_bgn_cfg)},
/* 1000 Series WiFi */
{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
{IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},

View File

@ -89,6 +89,7 @@ extern struct iwl_cfg iwl6000i_2bg_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_2abg_cfg;
extern struct iwl_cfg iwl6050g2_bgn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
extern struct iwl_cfg iwl1000_bg_cfg;
@ -147,6 +148,9 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwlagn_hw_nic_init(struct iwl_priv *priv);
int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
/* rx */
void iwlagn_rx_queue_restock(struct iwl_priv *priv);

View File

@ -97,6 +97,7 @@ enum {
REPLY_ADD_STA = 0x18,
REPLY_REMOVE_STA = 0x19,
REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
REPLY_TXFIFO_FLUSH = 0x1e,
/* Security */
REPLY_WEPKEY = 0x20,
@ -957,8 +958,8 @@ struct iwl_qosparam_cmd {
#define IWL3945_STATION_COUNT 25
#define IWL4965_BROADCAST_ID 31
#define IWL4965_STATION_COUNT 32
#define IWL5000_BROADCAST_ID 15
#define IWL5000_STATION_COUNT 16
#define IWLAGN_BROADCAST_ID 15
#define IWLAGN_STATION_COUNT 16
#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
#define IWL_INVALID_STATION 255
@ -1209,6 +1210,43 @@ struct iwl_rem_sta_cmd {
u8 reserved2[2];
} __packed;
#define IWL_TX_FIFO_BK_MSK cpu_to_le32(BIT(0))
#define IWL_TX_FIFO_BE_MSK cpu_to_le32(BIT(1))
#define IWL_TX_FIFO_VI_MSK cpu_to_le32(BIT(2))
#define IWL_TX_FIFO_VO_MSK cpu_to_le32(BIT(3))
#define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00)
#define IWL_DROP_SINGLE 0
#define IWL_DROP_SELECTED 1
#define IWL_DROP_ALL 2
/*
* REPLY_TXFIFO_FLUSH = 0x1e(command and response)
*
* When using full FIFO flush this command checks the scheduler HW block WR/RD
* pointers to check if all the frames were transferred by DMA into the
* relevant TX FIFO queue. Only when the DMA is finished and the queue is
* empty the command can finish.
* This command is used to flush the TXFIFO from transmit commands, it may
* operate on single or multiple queues, the command queue can't be flushed by
* this command. The command response is returned when all the queue flush
* operations are done. Each TX command flushed return response with the FLUSH
* status set in the TX response status. When FIFO flush operation is used,
* the flush operation ends when both the scheduler DMA done and TXFIFO empty
* are set.
*
* @fifo_control: bit mask for which queues to flush
* @flush_control: flush controls
* 0: Dump single MSDU
* 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
* 2: Dump all FIFO
*/
struct iwl_txfifo_flush_cmd {
__le32 fifo_control;
__le16 flush_control;
__le16 reserved;
} __attribute__ ((packed));
/*
* REPLY_WEP_KEY = 0x20
*/
@ -3452,6 +3490,41 @@ struct iwl_missed_beacon_notif {
#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
/*
* Additional table entries in enhance SENSITIVITY_CMD
*/
#define HD_INA_NON_SQUARE_DET_OFDM_INDEX (11)
#define HD_INA_NON_SQUARE_DET_CCK_INDEX (12)
#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX (13)
#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX (14)
#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX (15)
#define HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX (16)
#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX (17)
#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX (18)
#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX (19)
#define HD_CCK_NON_SQUARE_DET_SLOPE_INDEX (20)
#define HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX (21)
#define HD_RESERVED (22)
/* number of entries for enhanced tbl */
#define ENHANCE_HD_TABLE_SIZE (23)
/* number of additional entries for enhanced tbl */
#define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
#define HD_INA_NON_SQUARE_DET_OFDM_DATA cpu_to_le16(0)
#define HD_INA_NON_SQUARE_DET_CCK_DATA cpu_to_le16(0)
#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA cpu_to_le16(0)
#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(668)
#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(486)
#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(37)
#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(853)
#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(476)
#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(99)
/* Control field in struct iwl_sensitivity_cmd */
#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0)
#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1)
@ -3468,6 +3541,14 @@ struct iwl_sensitivity_cmd {
__le16 table[HD_TABLE_SIZE]; /* use HD_* as index */
} __packed;
/*
*
*/
struct iwl_enhance_sensitivity_cmd {
__le16 control; /* always use "1" */
__le16 enhance_table[ENHANCE_HD_TABLE_SIZE]; /* use HD_* as index */
} __attribute__ ((packed));
/**
* REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)

View File

@ -2627,7 +2627,7 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)
}
int iwl_force_reset(struct iwl_priv *priv, int mode)
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
{
struct iwl_force_reset *force_reset;
@ -2640,12 +2640,14 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
}
force_reset = &priv->force_reset[mode];
force_reset->reset_request_count++;
if (force_reset->last_force_reset_jiffies &&
time_after(force_reset->last_force_reset_jiffies +
force_reset->reset_duration, jiffies)) {
IWL_DEBUG_INFO(priv, "force reset rejected\n");
force_reset->reset_reject_count++;
return -EAGAIN;
if (!external) {
if (force_reset->last_force_reset_jiffies &&
time_after(force_reset->last_force_reset_jiffies +
force_reset->reset_duration, jiffies)) {
IWL_DEBUG_INFO(priv, "force reset rejected\n");
force_reset->reset_reject_count++;
return -EAGAIN;
}
}
force_reset->reset_success_count++;
force_reset->last_force_reset_jiffies = jiffies;
@ -2655,6 +2657,19 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
iwl_force_rf_reset(priv);
break;
case IWL_FW_RESET:
/*
* if the request is from external(ex: debugfs),
* then always perform the request in regardless the module
* parameter setting
* if the request is from internal (uCode error or driver
* detect failure), then fw_restart module parameter
* need to be check before performing firmware reload
*/
if (!external && !priv->cfg->mod_params->restart_fw) {
IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
"module parameter setting\n");
break;
}
IWL_ERR(priv, "On demand firmware reload\n");
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
@ -2713,7 +2728,7 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
"queue %d stuck %d time. Fw reload.\n",
q->id, q->repeat_same_read_ptr);
q->repeat_same_read_ptr = 0;
iwl_force_reset(priv, IWL_FW_RESET);
iwl_force_reset(priv, IWL_FW_RESET, false);
} else {
q->repeat_same_read_ptr++;
IWL_DEBUG_RADIO(priv,

View File

@ -205,6 +205,9 @@ struct iwl_lib_ops {
/* check for ack health */
bool (*check_ack_health)(struct iwl_priv *priv,
struct iwl_rx_packet *pkt);
int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
struct iwl_debugfs_ops debugfs_ops;
};
@ -525,7 +528,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req);
void iwl_bg_start_internal_scan(struct work_struct *work);
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
int iwl_force_reset(struct iwl_priv *priv, int mode);
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ta, const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);

View File

@ -298,6 +298,7 @@
#define CSR_HW_REV_TYPE_1000 (0x0000060)
#define CSR_HW_REV_TYPE_6x00 (0x0000070)
#define CSR_HW_REV_TYPE_6x50 (0x0000080)
#define CSR_HW_REV_TYPE_6x50g2 (0x0000084)
#define CSR_HW_REV_TYPE_6x00g2 (0x00000B0)
#define CSR_HW_REV_TYPE_NONE (0x00000F0)

View File

@ -1487,7 +1487,7 @@ static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
switch (reset) {
case IWL_RF_RESET:
case IWL_FW_RESET:
ret = iwl_force_reset(priv, reset);
ret = iwl_force_reset(priv, reset, true);
break;
default:
return -EINVAL;
@ -1495,6 +1495,30 @@ static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
return ret ? ret : count;
}
static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
int flush;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d", &flush) != 1)
return -EINVAL;
if (iwl_is_rfkill(priv))
return -EFAULT;
priv->cfg->ops->lib->dev_txfifo_flush(priv, IWL_DROP_ALL);
return count;
}
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@ -1516,6 +1540,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
DEBUGFS_READ_FILE_OPS(rxon_flags);
DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
/*
* Create the debugfs files and directories
@ -1574,6 +1599,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
if (priv->cfg->ops->lib->dev_txfifo_flush)
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
if (priv->cfg->sensitivity_calib_by_driver)
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);

View File

@ -570,6 +570,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11,
IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12,
IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13,
IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14,
};
struct iwl_ucode_tlv {
@ -1193,7 +1194,9 @@ struct iwl_priv {
u8 start_calib;
struct iwl_sensitivity_data sensitivity_data;
struct iwl_chain_noise_data chain_noise_data;
bool enhance_sensitivity_table;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
__le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
struct iwl_ht_config current_ht_config;
@ -1345,6 +1348,7 @@ struct iwl_priv {
struct work_struct ct_enter;
struct work_struct ct_exit;
struct work_struct start_internal_scan;
struct work_struct tx_flush;
struct tasklet_struct irq_tasklet;

View File

@ -276,6 +276,10 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_6050_TX_POWER_VERSION (4)
#define EEPROM_6050_EEPROM_VERSION (0x532)
/* 6x50g2 Specific */
#define EEPROM_6050G2_TX_POWER_VERSION (6)
#define EEPROM_6050G2_EEPROM_VERSION (0x553)
/* 6x00g2 Specific */
#define EEPROM_6000G2_TX_POWER_VERSION (6)
#define EEPROM_6000G2_EEPROM_VERSION (0x709)

View File

@ -398,12 +398,7 @@
*/
#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018)
#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
/* Tx service channels */
#define FH_SRVC_CHNL (9)

View File

@ -49,6 +49,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_ADD_STA);
IWL_CMD(REPLY_REMOVE_STA);
IWL_CMD(REPLY_REMOVE_ALL_STA);
IWL_CMD(REPLY_TXFIFO_FLUSH);
IWL_CMD(REPLY_WEPKEY);
IWL_CMD(REPLY_3945_RX);
IWL_CMD(REPLY_TX);

View File

@ -238,7 +238,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
*/
IWL_ERR(priv, "low ack count detected, "
"restart firmware\n");
if (!iwl_force_reset(priv, IWL_FW_RESET))
if (!iwl_force_reset(priv, IWL_FW_RESET, false))
return;
}
}
@ -249,7 +249,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
* high plcp error detected
* reset Radio
*/
iwl_force_reset(priv, IWL_RF_RESET);
iwl_force_reset(priv, IWL_RF_RESET, false);
}
}
}

View File

@ -98,6 +98,17 @@ static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
spin_lock_irqsave(&priv->sta_lock, flags);
memset(priv->stations, 0, sizeof(priv->stations));
priv->num_stations = 0;
/*
* Remove all key information that is not stored as part of station
* information since mac80211 may not have had a
* chance to remove all the keys. When device is reconfigured by
* mac80211 after an error all keys will be reconfigured.
*/
priv->ucode_key_table = 0;
priv->key_mapping_key = 0;
memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
spin_unlock_irqrestore(&priv->sta_lock, flags);
}

View File

@ -226,6 +226,18 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
hostsleep
This command is used to enable/disable host sleep.
Note: Host sleep parameters should be configured using
"ethtool -s ethX wol X" command before enabling host sleep.
Path: /sys/kernel/debug/libertas_wireless/ethX/
Usage:
cat hostsleep: reads the current hostsleep state
echo "1" > hostsleep : enable host sleep.
echo "0" > hostsleep : disable host sleep
========================
IWCONFIG COMMANDS
========================

View File

@ -181,7 +181,7 @@ static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
struct cmd_header *resp)
{
lbs_deb_enter(LBS_DEB_CMD);
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
if (priv->is_host_sleep_activated) {
priv->is_host_sleep_configured = 0;
if (priv->psstate == PS_STATE_FULL_POWER) {
priv->is_host_sleep_activated = 0;
@ -361,6 +361,65 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
return ret;
}
static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
unsigned long dummy,
struct cmd_header *cmd)
{
lbs_deb_enter(LBS_DEB_FW);
priv->is_host_sleep_activated = 1;
wake_up_interruptible(&priv->host_sleep_q);
lbs_deb_leave(LBS_DEB_FW);
return 0;
}
int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
{
struct cmd_header cmd;
int ret = 0;
uint32_t criteria = EHS_REMOVE_WAKEUP;
lbs_deb_enter(LBS_DEB_CMD);
if (host_sleep) {
if (priv->is_host_sleep_activated != 1) {
memset(&cmd, 0, sizeof(cmd));
ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
(struct wol_config *)NULL);
if (ret) {
lbs_pr_info("Host sleep configuration failed: "
"%d\n", ret);
return ret;
}
if (priv->psstate == PS_STATE_FULL_POWER) {
ret = __lbs_cmd(priv,
CMD_802_11_HOST_SLEEP_ACTIVATE,
&cmd,
sizeof(cmd),
lbs_ret_host_sleep_activate, 0);
if (ret)
lbs_pr_info("HOST_SLEEP_ACTIVATE "
"failed: %d\n", ret);
}
if (!wait_event_interruptible_timeout(
priv->host_sleep_q,
priv->is_host_sleep_activated,
(10 * HZ))) {
lbs_pr_err("host_sleep_q: timer expired\n");
ret = -1;
}
} else {
lbs_pr_err("host sleep: already enabled\n");
}
} else {
if (priv->is_host_sleep_activated)
ret = lbs_host_sleep_cfg(priv, criteria,
(struct wol_config *)NULL);
}
return ret;
}
/**
* @brief Set an SNMP MIB value
*

View File

@ -127,4 +127,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
#endif /* _LBS_CMD_H */

View File

@ -124,6 +124,70 @@ out_unlock:
return ret;
}
static ssize_t lbs_host_sleep_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t buf_size, ret;
int host_sleep;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
ret = -EFAULT;
goto out_unlock;
}
ret = sscanf(buf, "%d", &host_sleep);
if (ret != 1) {
ret = -EINVAL;
goto out_unlock;
}
if (host_sleep == 0)
ret = lbs_set_host_sleep(priv, 0);
else if (host_sleep == 1) {
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
lbs_pr_info("wake parameters not configured");
ret = -EINVAL;
goto out_unlock;
}
ret = lbs_set_host_sleep(priv, 1);
} else {
lbs_pr_err("invalid option\n");
ret = -EINVAL;
}
if (!ret)
ret = count;
out_unlock:
free_page(addr);
return ret;
}
static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t ret;
size_t pos = 0;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
free_page(addr);
return ret;
}
/*
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@ -675,6 +739,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
lbs_sleepparams_write), },
{ "hostsleep", 0644, FOPS(lbs_host_sleep_read,
lbs_host_sleep_write), },
};
static const struct lbs_debugfs_files debugfs_events_files[] = {

View File

@ -544,20 +544,8 @@ static int lbs_thread(void *data)
return 0;
}
static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
unsigned long dummy,
struct cmd_header *cmd)
{
lbs_deb_enter(LBS_DEB_FW);
priv->is_host_sleep_activated = 1;
wake_up_interruptible(&priv->host_sleep_q);
lbs_deb_leave(LBS_DEB_FW);
return 0;
}
int lbs_suspend(struct lbs_private *priv)
{
struct cmd_header cmd;
int ret;
lbs_deb_enter(LBS_DEB_FW);
@ -571,25 +559,8 @@ int lbs_suspend(struct lbs_private *priv)
priv->deep_sleep_required = 1;
}
memset(&cmd, 0, sizeof(cmd));
ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
(struct wol_config *)NULL);
if (ret) {
lbs_pr_info("Host sleep configuration failed: %d\n", ret);
return ret;
}
if (priv->psstate == PS_STATE_FULL_POWER) {
ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
sizeof(cmd), lbs_ret_host_sleep_activate, 0);
if (ret)
lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
}
ret = lbs_set_host_sleep(priv, 1);
if (!wait_event_interruptible_timeout(priv->host_sleep_q,
priv->is_host_sleep_activated, (10 * HZ))) {
lbs_pr_err("host_sleep_q: timer expired\n");
ret = -1;
}
netif_device_detach(priv->dev);
if (priv->mesh_dev)
netif_device_detach(priv->mesh_dev);
@ -602,11 +573,10 @@ EXPORT_SYMBOL_GPL(lbs_suspend);
int lbs_resume(struct lbs_private *priv)
{
int ret;
uint32_t criteria = EHS_REMOVE_WAKEUP;
lbs_deb_enter(LBS_DEB_FW);
ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
ret = lbs_set_host_sleep(priv, 0);
netif_device_attach(priv->dev);
if (priv->mesh_dev)

View File

@ -2067,7 +2067,7 @@ send_simple_event(islpci_private *priv, const char *str)
memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
if (!memptr)
return;
BUG_ON(n > IW_CUSTOM_MAX);
BUG_ON(n >= IW_CUSTOM_MAX);
wrqu.data.pointer = memptr;
wrqu.data.length = n;
strcpy(memptr, str);

View File

@ -586,9 +586,11 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, u8 vgc_level)
{
rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
if (qual->vgc_level_reg != vgc_level) {
rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
}
}
static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
@ -877,7 +879,8 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int mask = (state == STATE_RADIO_IRQ_OFF);
int mask = (state == STATE_RADIO_IRQ_OFF) ||
(state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@ -978,7 +981,9 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2400pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
rt2400pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@ -1233,23 +1238,10 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
u32 reg = rt2x00dev->irqvalue[0];
/*
* Handle interrupts, walk through all bits
@ -1287,9 +1279,40 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
rt2400pci_txdone(rt2x00dev, QID_AC_BK);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/* Store irqvalues for use in the interrupt thread. */
rt2x00dev->irqvalue[0] = reg;
/* Disable interrupts, will be enabled again in the interrupt thread. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_OFF_ISR);
return IRQ_WAKE_THREAD;
}
/*
* Device probe functions.
*/
@ -1399,8 +1422,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Check if the BBP tuning should be enabled.
*/
if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
return 0;
}
@ -1566,7 +1589,8 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
@ -1577,6 +1601,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.irq_handler = rt2400pci_interrupt,
.irq_handler_thread = rt2400pci_interrupt_thread,
.probe_hw = rt2400pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,

View File

@ -626,6 +626,7 @@ static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev,
{
if (qual->vgc_level_reg != vgc_level) {
rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
}
}
@ -700,13 +701,10 @@ dynamic_cca_tune:
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40)
rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
qual->vgc_level = qual->vgc_level_reg;
} else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32)
rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
qual->vgc_level = qual->vgc_level_reg;
}
}
/*
@ -1035,7 +1033,8 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int mask = (state == STATE_RADIO_IRQ_OFF);
int mask = (state == STATE_RADIO_IRQ_OFF) ||
(state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@ -1136,7 +1135,9 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
rt2500pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@ -1369,23 +1370,10 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
u32 reg = rt2x00dev->irqvalue[0];
/*
* Handle interrupts, walk through all bits
@ -1423,9 +1411,41 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
rt2500pci_txdone(rt2x00dev, QID_AC_BK);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/* Store irqvalues for use in the interrupt thread. */
rt2x00dev->irqvalue[0] = reg;
/* Disable interrupts, will be enabled again in the interrupt thread. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_OFF_ISR);
return IRQ_WAKE_THREAD;
}
/*
* Device probe functions.
*/
@ -1557,9 +1577,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Check if the BBP tuning should be enabled.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Read the RSSI <-> dBm offset information.
@ -1864,7 +1883,8 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
@ -1875,6 +1895,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.irq_handler = rt2500pci_interrupt,
.irq_handler_thread = rt2500pci_interrupt_thread,
.probe_hw = rt2500pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,

View File

@ -1004,7 +1004,9 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@ -1470,13 +1472,6 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Check if the BBP tuning should be disabled.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
/*
* Read the RSSI <-> dBm offset information.
*/
@ -1743,7 +1738,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
}
__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -1763,6 +1758,8 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
@ -1778,6 +1775,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.rfkill_poll = rt2500usb_rfkill_poll,
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,

View File

@ -74,7 +74,7 @@
* Signal information.
* Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120 /* FIXME */
#define DEFAULT_RSSI_OFFSET 120
/*
* Register layout information.
@ -719,14 +719,20 @@
#define TBTT_TIMER 0x1124
/*
* INT_TIMER_CFG:
* INT_TIMER_CFG: timer configuration
* PRE_TBTT_TIMER: leadtime to tbtt for pretbtt interrupt in units of 1/16 TU
* GP_TIMER: period of general purpose timer in units of 1/16 TU
*/
#define INT_TIMER_CFG 0x1128
#define INT_TIMER_CFG_PRE_TBTT_TIMER FIELD32(0x0000ffff)
#define INT_TIMER_CFG_GP_TIMER FIELD32(0xffff0000)
/*
* INT_TIMER_EN: GP-timer and pre-tbtt Int enable
*/
#define INT_TIMER_EN 0x112c
#define INT_TIMER_EN_PRE_TBTT_TIMER FIELD32(0x00000001)
#define INT_TIMER_EN_GP_TIMER FIELD32(0x00000002)
/*
* CH_IDLE_STA: channel idle time
@ -802,6 +808,18 @@
*/
#define EDCA_TID_AC_MAP 0x1310
/*
* TX_PWR_CFG:
*/
#define TX_PWR_CFG_RATE0 FIELD32(0x0000000f)
#define TX_PWR_CFG_RATE1 FIELD32(0x000000f0)
#define TX_PWR_CFG_RATE2 FIELD32(0x00000f00)
#define TX_PWR_CFG_RATE3 FIELD32(0x0000f000)
#define TX_PWR_CFG_RATE4 FIELD32(0x000f0000)
#define TX_PWR_CFG_RATE5 FIELD32(0x00f00000)
#define TX_PWR_CFG_RATE6 FIELD32(0x0f000000)
#define TX_PWR_CFG_RATE7 FIELD32(0xf0000000)
/*
* TX_PWR_CFG_0:
*/
@ -1853,9 +1871,15 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
/*
* EEPROM TXpower byrate: 20MHZ power
* EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
*/
#define EEPROM_TXPOWER_BYRATE 0x006f
#define EEPROM_TXPOWER_BYRATE_SIZE 9
#define EEPROM_TXPOWER_BYRATE_RATE0 FIELD16(0x000f)
#define EEPROM_TXPOWER_BYRATE_RATE1 FIELD16(0x00f0)
#define EEPROM_TXPOWER_BYRATE_RATE2 FIELD16(0x0f00)
#define EEPROM_TXPOWER_BYRATE_RATE3 FIELD16(0xf000)
/*
* EEPROM BBP.

View File

@ -33,6 +33,7 @@
Abstract: rt2800 generic device routines.
*/
#include <linux/crc-ccitt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@ -272,6 +273,160 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
static bool rt2800_check_firmware_crc(const u8 *data, const size_t len)
{
u16 fw_crc;
u16 crc;
/*
* The last 2 bytes in the firmware array are the crc checksum itself,
* this means that we should never pass those 2 bytes to the crc
* algorithm.
*/
fw_crc = (data[len - 2] << 8 | data[len - 1]);
/*
* Use the crc ccitt algorithm.
* This will return the same value as the legacy driver which
* used bit ordering reversion on the both the firmware bytes
* before input input as well as on the final output.
* Obviously using crc ccitt directly is much more efficient.
*/
crc = crc_ccitt(~0, data, len - 2);
/*
* There is a small difference between the crc-itu-t + bitrev and
* the crc-ccitt crc calculation. In the latter method the 2 bytes
* will be swapped, use swab16 to convert the crc to the correct
* value.
*/
crc = swab16(crc);
return fw_crc == crc;
}
int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
size_t offset = 0;
size_t fw_len;
bool multiple;
/*
* PCI(e) & SOC devices require firmware with a length
* of 8kb. USB devices require firmware files with a length
* of 4kb. Certain USB chipsets however require different firmware,
* which Ralink only provides attached to the original firmware
* file. Thus for USB devices, firmware files have a length
* which is a multiple of 4kb.
*/
if (rt2x00_is_usb(rt2x00dev)) {
fw_len = 4096;
multiple = true;
} else {
fw_len = 8192;
multiple = true;
}
/*
* Validate the firmware length
*/
if (len != fw_len && (!multiple || (len % fw_len) != 0))
return FW_BAD_LENGTH;
/*
* Check if the chipset requires one of the upper parts
* of the firmware.
*/
if (rt2x00_is_usb(rt2x00dev) &&
!rt2x00_rt(rt2x00dev, RT2860) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT3070) &&
((len / fw_len) == 1))
return FW_BAD_VERSION;
/*
* 8kb firmware files must be checked as if it were
* 2 separate firmware files.
*/
while (offset < len) {
if (!rt2800_check_firmware_crc(data + offset, fw_len))
return FW_BAD_CRC;
offset += fw_len;
}
return FW_OK;
}
EXPORT_SYMBOL_GPL(rt2800_check_firmware);
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
unsigned int i;
u32 reg;
/*
* Wait for stable hardware.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg && reg != ~0)
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "Unstable hardware.\n");
return -EBUSY;
}
if (rt2x00_is_pci(rt2x00dev))
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
/*
* Disable DMA, will be reenabled later when enabling
* the radio.
*/
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
/*
* Write firmware to the device.
*/
rt2800_drv_write_firmware(rt2x00dev, data, len);
/*
* Wait for device to stabilize.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "PBF system register not ready.\n");
return -EBUSY;
}
/*
* Initialize firmware.
*/
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
msleep(1);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_load_firmware);
void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
{
u32 word;
@ -325,9 +480,53 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
}
EXPORT_SYMBOL_GPL(rt2800_write_txwi);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
{
__le32 *rxwi = (__le32 *) skb->data;
int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
int rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
u16 eeprom;
u8 offset0;
u8 offset1;
u8 offset2;
if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
} else {
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
}
/*
* Convert the value from the descriptor into the RSSI value
* If the value in the descriptor is 0, it is considered invalid
* and the default (extremely low) rssi value is assumed
*/
rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
/*
* mac80211 only accepts a single RSSI value. Calculating the
* average doesn't deliver a fair answer either since -60:-60 would
* be considered equally good as -50:-70 while the second is the one
* which gives less energy...
*/
rssi0 = max(rssi0, rssi1);
return max(rssi0, rssi2);
}
void rt2800_process_rxwi(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
__le32 *rxwi = (__le32 *) entry->skb->data;
u32 word;
rt2x00_desc_read(rxwi, 0, &word);
@ -358,14 +557,15 @@ void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
rt2x00_desc_read(rxwi, 2, &word);
rxdesc->rssi =
(rt2x00_get_field32(word, RXWI_W2_RSSI0) +
rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
/*
* Convert descriptor AGC value to RSSI value.
*/
rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
/*
* Remove RXWI descriptor from start of buffer.
*/
skb_pull(skb, RXWI_DESC_SIZE);
skb_pull(entry->skb, RXWI_DESC_SIZE);
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
@ -428,7 +628,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
}
EXPORT_SYMBOL(rt2800_write_beacon);
EXPORT_SYMBOL_GPL(rt2800_write_beacon);
static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
unsigned int beacon_base)
@ -760,8 +960,18 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
(conf->sync == TSF_SYNC_BEACON));
(conf->sync == TSF_SYNC_ADHOC ||
conf->sync == TSF_SYNC_AP_NONE));
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Enable pre tbtt interrupt for beaconing modes
*/
rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER,
(conf->sync == TSF_SYNC_AP_NONE));
rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
@ -1086,66 +1296,115 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
}
static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
const int txpower)
const int max_txpower)
{
u8 txpower;
u8 max_value = (u8)max_txpower;
u16 eeprom;
int i;
u32 reg;
u32 value = TXPOWER_G_TO_DEV(txpower);
u8 r1;
u32 offset;
/*
* set to normal tx power mode: +/- 0dBm
*/
rt2800_bbp_read(rt2x00dev, 1, &r1);
rt2x00_set_field8(&r1, BBP1_TX_POWER, 0);
rt2800_bbp_write(rt2x00dev, 1, r1);
rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_1MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_2MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_55MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_11MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_6MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_9MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_12MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_0_18MBS, value);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg);
/*
* The eeprom contains the tx power values for each rate. These
* values map to 100% tx power. Each 16bit word contains four tx
* power values and the order is the same as used in the TX_PWR_CFG
* registers.
*/
offset = TX_PWR_CFG_0;
rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, &reg);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_24MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_36MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_48MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_54MBS, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS0, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS1, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS2, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS3, value);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg);
for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) {
/* just to be safe */
if (offset > TX_PWR_CFG_4)
break;
rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, &reg);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS4, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS5, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS6, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS7, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS8, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS9, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS10, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS11, value);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
rt2800_register_read(rt2x00dev, offset, &reg);
rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, &reg);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS12, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS13, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS14, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS15, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN1, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN2, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN3, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN4, value);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg);
/* read the next four txpower values */
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i,
&eeprom);
rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, &reg);
rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN5, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN6, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN7, value);
rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN8, value);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg);
/* TX_PWR_CFG_0: 1MBS, TX_PWR_CFG_1: 24MBS,
* TX_PWR_CFG_2: MCS4, TX_PWR_CFG_3: MCS12,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE0);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0,
min(txpower, max_value));
/* TX_PWR_CFG_0: 2MBS, TX_PWR_CFG_1: 36MBS,
* TX_PWR_CFG_2: MCS5, TX_PWR_CFG_3: MCS13,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE1);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1,
min(txpower, max_value));
/* TX_PWR_CFG_0: 55MBS, TX_PWR_CFG_1: 48MBS,
* TX_PWR_CFG_2: MCS6, TX_PWR_CFG_3: MCS14,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE2);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2,
min(txpower, max_value));
/* TX_PWR_CFG_0: 11MBS, TX_PWR_CFG_1: 54MBS,
* TX_PWR_CFG_2: MCS7, TX_PWR_CFG_3: MCS15,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE3);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3,
min(txpower, max_value));
/* read the next four txpower values */
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1,
&eeprom);
/* TX_PWR_CFG_0: 6MBS, TX_PWR_CFG_1: MCS0,
* TX_PWR_CFG_2: MCS8, TX_PWR_CFG_3: unknown,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE0);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4,
min(txpower, max_value));
/* TX_PWR_CFG_0: 9MBS, TX_PWR_CFG_1: MCS1,
* TX_PWR_CFG_2: MCS9, TX_PWR_CFG_3: unknown,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE1);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5,
min(txpower, max_value));
/* TX_PWR_CFG_0: 12MBS, TX_PWR_CFG_1: MCS2,
* TX_PWR_CFG_2: MCS10, TX_PWR_CFG_3: unknown,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE2);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6,
min(txpower, max_value));
/* TX_PWR_CFG_0: 18MBS, TX_PWR_CFG_1: MCS3,
* TX_PWR_CFG_2: MCS11, TX_PWR_CFG_3: unknown,
* TX_PWR_CFG_4: unknown */
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE3);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7,
min(txpower, max_value));
rt2800_register_write(rt2x00dev, offset, reg);
/* next TX_PWR_CFG register */
offset += 4;
}
}
static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
@ -1316,7 +1575,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 1600);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
@ -1638,6 +1897,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg);
rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg);
/*
* Setup leadtime for pre tbtt interrupt to 6ms
*/
rt2800_register_read(rt2x00dev, INT_TIMER_CFG, &reg);
rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_init_registers);
@ -2630,8 +2896,8 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
/*
* IEEE80211 stack callback functions.
*/
static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
u32 *iv32, u16 *iv16)
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u16 *iv16)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct mac_iveiv_entry iveiv_entry;
@ -2644,8 +2910,9 @@ static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
}
EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u32 reg;
@ -2681,9 +2948,10 @@ static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
@ -2748,8 +3016,9 @@ static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_conf_tx);
static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
u64 rt2800_get_tsf(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
@ -2762,12 +3031,11 @@ static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
EXPORT_SYMBOL_GPL(rt2800_get_tsf);
static int rt2800_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta,
u16 tid, u16 *ssn)
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
int ret = 0;
@ -2791,27 +3059,7 @@ static int rt2800_ampdu_action(struct ieee80211_hw *hw,
return ret;
}
const struct ieee80211_ops rt2800_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
.stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800_get_tkip_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
};
EXPORT_SYMBOL_GPL(rt2800_mac80211_ops);
EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
MODULE_VERSION(DRV_VERSION);

View File

@ -41,6 +41,8 @@ struct rt2800_ops {
const unsigned int offset,
const struct rt2x00_field32 field, u32 *reg);
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
};
@ -48,7 +50,7 @@ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_read(rt2x00dev, offset, value);
}
@ -57,7 +59,7 @@ static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_read_lock(rt2x00dev, offset, value);
}
@ -66,7 +68,7 @@ static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write(rt2x00dev, offset, value);
}
@ -75,7 +77,7 @@ static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write_lock(rt2x00dev, offset, value);
}
@ -84,7 +86,7 @@ static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiread(rt2x00dev, offset, value, length);
}
@ -94,7 +96,7 @@ static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const void *value,
const u32 length)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiwrite(rt2x00dev, offset, value, length);
}
@ -104,14 +106,22 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
const struct rt2x00_field32 field,
u32 *reg)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
}
static inline int rt2800_drv_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->drv_write_firmware(rt2x00dev, data, len);
}
static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->drv_init_registers(rt2x00dev);
}
@ -120,8 +130,13 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
@ -159,6 +174,14 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
extern const struct ieee80211_ops rt2800_mac80211_ops;
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u16 *iv16);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params);
u64 rt2800_get_tsf(struct ieee80211_hw *hw);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
#endif /* RT2800LIB_H */

View File

@ -31,7 +31,6 @@
Supported chipsets: RT2800E & RT2800ED.
*/
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
@ -192,81 +191,13 @@ static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
return FIRMWARE_RT2860;
}
static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
u16 fw_crc;
u16 crc;
/*
* Only support 8kb firmware files.
*/
if (len != 8192)
return FW_BAD_LENGTH;
/*
* The last 2 bytes in the firmware array are the crc checksum itself,
* this means that we should never pass those 2 bytes to the crc
* algorithm.
*/
fw_crc = (data[len - 2] << 8 | data[len - 1]);
/*
* Use the crc ccitt algorithm.
* This will return the same value as the legacy driver which
* used bit ordering reversion on the both the firmware bytes
* before input input as well as on the final output.
* Obviously using crc ccitt directly is much more efficient.
*/
crc = crc_ccitt(~0, data, len - 2);
/*
* There is a small difference between the crc-itu-t + bitrev and
* the crc-ccitt crc calculation. In the latter method the 2 bytes
* will be swapped, use swab16 to convert the crc to the correct
* value.
*/
crc = swab16(crc);
return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
}
static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
unsigned int i;
u32 reg;
/*
* Wait for stable hardware.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg && reg != ~0)
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "Unstable hardware.\n");
return -EBUSY;
}
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
/*
* Disable DMA, will be reenabled later when enabling
* the radio.
*/
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
/*
* enable Host program ram write selection
*/
@ -278,34 +209,11 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
* Write firmware to device.
*/
rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
data, len);
data, len);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
/*
* Wait for device to stabilize.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "PBF system register not ready.\n");
return -EBUSY;
}
/*
* Disable interrupts
*/
rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
/*
* Initialize BBP R/W access agent
*/
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
@ -422,7 +330,8 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int mask = (state == STATE_RADIO_IRQ_ON);
int mask = (state == STATE_RADIO_IRQ_ON) ||
(state == STATE_RADIO_IRQ_ON_ISR);
u32 reg;
/*
@ -631,7 +540,9 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
rt2800pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@ -805,7 +716,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
/*
* Process the RXWI structure that is at the start of the buffer.
*/
rt2800_process_rxwi(entry->skb, rxdesc);
rt2800_process_rxwi(entry, rxdesc);
/*
* Set RX IDX in register to inform hardware that we have handled
@ -929,6 +840,48 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg = rt2x00dev->irqvalue[0];
/*
* 1 - Pre TBTT interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
rt2x00lib_pretbtt(rt2x00dev);
/*
* 2 - Beacondone interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
rt2x00lib_beacondone(rt2x00dev);
/*
* 3 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
rt2x00pci_rxdone(rt2x00dev);
/*
* 4 - Tx done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
rt2800pci_txdone(rt2x00dev);
/*
* 5 - Auto wakeup interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
rt2800pci_wakeup(rt2x00dev);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
@ -944,25 +897,15 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/*
* 1 - Rx ring done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
rt2x00pci_rxdone(rt2x00dev);
/* Store irqvalue for use in the interrupt thread. */
rt2x00dev->irqvalue[0] = reg;
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
rt2800pci_txdone(rt2x00dev);
/* Disable interrupts, will be enabled again in the interrupt thread. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_OFF_ISR);
/*
* Current beacon was sent out, fetch the next one
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
rt2x00lib_beacondone(rt2x00dev);
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
rt2800pci_wakeup(rt2x00dev);
return IRQ_HANDLED;
return IRQ_WAKE_THREAD;
}
/*
@ -983,26 +926,10 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
return rt2800_validate_eeprom(rt2x00dev);
}
static const struct rt2800_ops rt2800pci_rt2800_ops = {
.register_read = rt2x00pci_register_read,
.register_read_lock = rt2x00pci_register_read, /* same for PCI */
.register_write = rt2x00pci_register_write,
.register_write_lock = rt2x00pci_register_write, /* same for PCI */
.register_multiread = rt2x00pci_register_multiread,
.register_multiwrite = rt2x00pci_register_multiwrite,
.regbusy_read = rt2x00pci_regbusy_read,
.drv_init_registers = rt2800pci_init_registers,
};
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops;
/*
* Allocate eeprom data.
*/
@ -1028,6 +955,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
/*
* This device has a pre tbtt interrupt and thus fetches
* a new beacon directly prior to transmission.
*/
__set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
/*
* This device requires firmware.
*/
@ -1037,6 +970,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -1046,12 +980,46 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return 0;
}
static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
.stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800_get_tkip_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
.register_read = rt2x00pci_register_read,
.register_read_lock = rt2x00pci_register_read, /* same for PCI */
.register_write = rt2x00pci_register_write,
.register_write_lock = rt2x00pci_register_write, /* same for PCI */
.register_multiread = rt2x00pci_register_multiread,
.register_multiwrite = rt2x00pci_register_multiwrite,
.regbusy_read = rt2x00pci_regbusy_read,
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800pci_init_registers,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.irq_handler = rt2800pci_interrupt,
.irq_handler_thread = rt2800pci_interrupt_thread,
.probe_hw = rt2800pci_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
.check_firmware = rt2800pci_check_firmware,
.load_firmware = rt2800pci_load_firmware,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
.get_entry_state = rt2800pci_get_entry_state,
@ -1109,7 +1077,8 @@ static const struct rt2x00_ops rt2800pci_ops = {
.tx = &rt2800pci_queue_tx,
.bcn = &rt2800pci_queue_bcn,
.lib = &rt2800pci_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
.drv = &rt2800pci_rt2800_ops,
.hw = &rt2800pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */

View File

@ -28,7 +28,6 @@
Supported chipsets: RT2800U.
*/
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
@ -57,84 +56,10 @@ static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
return FIRMWARE_RT2870;
}
static bool rt2800usb_check_crc(const u8 *data, const size_t len)
{
u16 fw_crc;
u16 crc;
/*
* The last 2 bytes in the firmware array are the crc checksum itself,
* this means that we should never pass those 2 bytes to the crc
* algorithm.
*/
fw_crc = (data[len - 2] << 8 | data[len - 1]);
/*
* Use the crc ccitt algorithm.
* This will return the same value as the legacy driver which
* used bit ordering reversion on the both the firmware bytes
* before input input as well as on the final output.
* Obviously using crc ccitt directly is much more efficient.
*/
crc = crc_ccitt(~0, data, len - 2);
/*
* There is a small difference between the crc-itu-t + bitrev and
* the crc-ccitt crc calculation. In the latter method the 2 bytes
* will be swapped, use swab16 to convert the crc to the correct
* value.
*/
crc = swab16(crc);
return fw_crc == crc;
}
static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
size_t offset = 0;
/*
* Firmware files:
* There are 2 variations of the rt2870 firmware.
* a) size: 4kb
* b) size: 8kb
* Note that (b) contains 2 separate firmware blobs of 4k
* within the file. The first blob is the same firmware as (a),
* but the second blob is for the additional chipsets.
*/
if (len != 4096 && len != 8192)
return FW_BAD_LENGTH;
/*
* Check if we need the upper 4kb firmware data or not.
*/
if ((len == 4096) &&
!rt2x00_rt(rt2x00dev, RT2860) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT3070))
return FW_BAD_VERSION;
/*
* 8kb firmware files must be checked as if it were
* 2 separate firmware files.
*/
while (offset < len) {
if (!rt2800usb_check_crc(data + offset, 4096))
return FW_BAD_CRC;
offset += 4096;
}
return FW_OK;
}
static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
unsigned int i;
int status;
u32 reg;
u32 offset;
u32 length;
@ -151,21 +76,6 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
length = 4096;
}
/*
* Wait for stable hardware.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg && reg != ~0)
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "Unstable hardware.\n");
return -EBUSY;
}
/*
* Write firmware to device.
*/
@ -203,28 +113,6 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
udelay(10);
}
/*
* Wait for device to stabilize.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
break;
msleep(1);
}
if (i == REGISTER_BUSY_COUNT) {
ERROR(rt2x00dev, "PBF system register not ready.\n");
return -EBUSY;
}
/*
* Initialize firmware.
*/
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
msleep(1);
return 0;
}
@ -406,7 +294,9 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@ -563,7 +453,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
/*
* Process the RXWI structure.
*/
rt2800_process_rxwi(entry->skb, rxdesc);
rt2800_process_rxwi(entry, rxdesc);
}
/*
@ -580,26 +470,10 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
return rt2800_validate_eeprom(rt2x00dev);
}
static const struct rt2800_ops rt2800usb_rt2800_ops = {
.register_read = rt2x00usb_register_read,
.register_read_lock = rt2x00usb_register_read_lock,
.register_write = rt2x00usb_register_write,
.register_write_lock = rt2x00usb_register_write_lock,
.register_multiread = rt2x00usb_register_multiread,
.register_multiwrite = rt2x00usb_register_multiwrite,
.regbusy_read = rt2x00usb_regbusy_read,
.drv_init_registers = rt2800usb_init_registers,
};
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops;
/*
* Allocate eeprom data.
*/
@ -632,6 +506,8 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -641,11 +517,45 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return 0;
}
static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
.stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800_get_tkip_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
};
static const struct rt2800_ops rt2800usb_rt2800_ops = {
.register_read = rt2x00usb_register_read,
.register_read_lock = rt2x00usb_register_read_lock,
.register_write = rt2x00usb_register_write,
.register_write_lock = rt2x00usb_register_write_lock,
.register_multiread = rt2x00usb_register_multiread,
.register_multiwrite = rt2x00usb_register_multiwrite,
.regbusy_read = rt2x00usb_regbusy_read,
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.probe_hw = rt2800usb_probe_hw,
.get_firmware_name = rt2800usb_get_firmware_name,
.check_firmware = rt2800usb_check_firmware,
.load_firmware = rt2800usb_load_firmware,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
.initialize = rt2x00usb_initialize,
.uninitialize = rt2x00usb_uninitialize,
.clear_entry = rt2x00usb_clear_entry,
@ -654,6 +564,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
@ -703,7 +614,8 @@ static const struct rt2x00_ops rt2800usb_ops = {
.tx = &rt2800usb_queue_tx,
.bcn = &rt2800usb_queue_bcn,
.lib = &rt2800usb_rt2x00_ops,
.hw = &rt2800_mac80211_ops,
.drv = &rt2800usb_rt2800_ops,
.hw = &rt2800usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */

View File

@ -332,6 +332,11 @@ struct link {
* Work structure for scheduling periodic link tuning.
*/
struct delayed_work work;
/*
* Work structure for scheduling periodic watchdog monitoring.
*/
struct delayed_work watchdog_work;
};
/*
@ -509,6 +514,11 @@ struct rt2x00lib_ops {
*/
irq_handler_t irq_handler;
/*
* Threaded Interrupt handlers.
*/
irq_handler_t irq_handler_thread;
/*
* Device init handlers.
*/
@ -543,6 +553,7 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
void (*watchdog) (struct rt2x00_dev *rt2x00dev);
/*
* TX control handlers
@ -610,6 +621,7 @@ struct rt2x00_ops {
const struct data_queue_desc *bcn;
const struct data_queue_desc *atim;
const struct rt2x00lib_ops *lib;
const void *drv;
const struct ieee80211_ops *hw;
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug *debugfs;
@ -628,6 +640,7 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_SCANNING,
/*
* Driver requirements
@ -646,6 +659,9 @@ enum rt2x00_flags {
CONFIG_SUPPORT_HW_CRYPTO,
DRIVER_SUPPORT_CONTROL_FILTERS,
DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
DRIVER_SUPPORT_LINK_TUNING,
DRIVER_SUPPORT_WATCHDOG,
/*
* Driver configuration
@ -655,7 +671,6 @@ enum rt2x00_flags {
CONFIG_EXTERNAL_LNA_A,
CONFIG_EXTERNAL_LNA_BG,
CONFIG_DOUBLE_ANTENNA,
CONFIG_DISABLE_LINK_TUNING,
CONFIG_CHANNEL_HT40,
};
@ -863,9 +878,10 @@ struct rt2x00_dev {
const struct firmware *fw;
/*
* Driver specific data.
* Interrupt values, stored between interrupt service routine
* and interrupt thread routine.
*/
void *priv;
u32 irqvalue[2];
};
/*
@ -1052,6 +1068,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
@ -1081,6 +1098,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
#else
#define rt2x00mac_set_key NULL
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw);
void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw);
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,

View File

@ -41,10 +41,12 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
switch (type) {
case NL80211_IFTYPE_ADHOC:
conf.sync = TSF_SYNC_ADHOC;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_WDS:
conf.sync = TSF_SYNC_BEACON;
conf.sync = TSF_SYNC_AP_NONE;
break;
case NL80211_IFTYPE_STATION:
conf.sync = TSF_SYNC_INFRA;

View File

@ -69,6 +69,11 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
/*
* Start watchdog monitoring.
*/
rt2x00link_start_watchdog(rt2x00dev);
/*
* Start the TX queues.
*/
@ -88,6 +93,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
ieee80211_stop_queues(rt2x00dev->hw);
rt2x00queue_stop_queues(rt2x00dev);
/*
* Stop watchdog monitoring.
*/
rt2x00link_stop_watchdog(rt2x00dev);
/*
* Disable RX.
*/
@ -168,10 +178,32 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
/*
* Interrupt context handlers.
*/
static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_intf *intf = vif_to_intf(vif);
struct rt2x00_dev *rt2x00dev = data;
struct sk_buff *skb;
/*
* Only AP mode interfaces do broad- and multicast buffering
*/
if (vif->type != NL80211_IFTYPE_AP)
return;
/*
* Send out buffered broad- and multicast frames
*/
skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
while (skb) {
rt2x00mac_tx(rt2x00dev->hw, skb);
skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
}
}
static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
@ -179,9 +211,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
spin_lock(&intf->lock);
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
spin_unlock(&intf->lock);
rt2x00queue_update_beacon(rt2x00dev, vif, true);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
@ -189,14 +219,37 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00lib_beacondone_iter,
rt2x00dev);
/* send buffered bc/mc frames out for every bssid */
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_bc_buffer_iter,
rt2x00dev);
/*
* Devices with pre tbtt interrupt don't need to update the beacon
* here as they will fetch the next beacon directly prior to
* transmission.
*/
if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
return;
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
/* fetch next beacon */
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_beaconupdate_iter,
rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
{
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/* fetch next beacon */
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
rt2x00lib_beaconupdate_iter,
rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
@ -330,9 +383,17 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Only PCI and SOC devices process the tx status in process
* context. Hence use ieee80211_tx_status for PCI and SOC
* devices and stick to ieee80211_tx_status_irqsafe for USB.
*/
if (rt2x00_is_usb(rt2x00dev))
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
else
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
dev_kfree_skb_irq(entry->skb);
dev_kfree_skb_any(entry->skb);
/*
* Make this entry available for reuse.
@ -479,7 +540,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Currently only PCI and SOC devices handle rx interrupts in process
* context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
* for PCI and SOC devices.
*/
if (rt2x00_is_usb(rt2x00dev))
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
else
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.

View File

@ -30,6 +30,7 @@
/*
* Interval defines
*/
#define WATCHDOG_INTERVAL round_jiffies_relative(HZ)
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
/*
@ -257,11 +258,30 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev);
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
/**
* rt2x00link_register - Initialize link tuning functionality
* rt2x00link_start_watchdog - Start periodic watchdog monitoring
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* Initialize work structure and all link tuning related
* parameters. This will not start the link tuning process itself.
* This start the watchdog periodic work, this work will
*be executed periodically until &rt2x00link_stop_watchdog has
* been called.
*/
void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_stop_watchdog - Stop periodic watchdog monitoring
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* After this function completed the watchdog monitoring will not
* be running until &rt2x00link_start_watchdog is called.
*/
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_register - Initialize link tuning & watchdog functionality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* Initialize work structure and all link tuning and watchdog related
* parameters. This will not start the periodic work itself.
*/
void rt2x00link_register(struct rt2x00_dev *rt2x00dev);

View File

@ -278,6 +278,15 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->intf_sta_count)
return;
/**
* While scanning, link tuning is disabled. By default
* the most sensitive settings will be used to make sure
* that all beacons and probe responses will be recieved
* during the scan.
*/
if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@ -293,6 +302,7 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
{
struct link_qual *qual = &rt2x00dev->link.qual;
u8 vgc_level = qual->vgc_level_reg;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
@ -308,6 +318,13 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
rt2x00dev->link.count = 0;
memset(qual, 0, sizeof(*qual));
/*
* Restore the VGC level as stored in the registers,
* the driver can use this to determine if the register
* must be updated during reset or not.
*/
qual->vgc_level_reg = vgc_level;
/*
* Reset the link tuner.
*/
@ -338,7 +355,8 @@ static void rt2x00link_tuner(struct work_struct *work)
* When the radio is shutting down we should
* immediately cease all link tuning.
*/
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
/*
@ -359,10 +377,11 @@ static void rt2x00link_tuner(struct work_struct *work)
qual->rssi = link->avg_rssi.avg;
/*
* Only perform the link tuning when Link tuning
* has been enabled (This could have been disabled from the EEPROM).
* Check if link tuning is supported by the hardware, some hardware
* do not support link tuning at all, while other devices can disable
* the feature from the EEPROM.
*/
if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
@ -388,7 +407,45 @@ static void rt2x00link_tuner(struct work_struct *work)
&link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
return;
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work, WATCHDOG_INTERVAL);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
{
cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
}
static void rt2x00link_watchdog(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, link.watchdog_work.work);
struct link *link = &rt2x00dev->link;
/*
* When the radio is shutting down we should
* immediately cease the watchdog monitoring.
*/
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
rt2x00dev->ops->lib->watchdog(rt2x00dev);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work, WATCHDOG_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
}

View File

@ -347,9 +347,11 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
/*
* Some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled, but do require the RX to
* be off.
* be off. During this period we should keep link tuning enabled,
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
/*
* When we've just turned on the radio, we want to reprogram
@ -367,7 +369,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
return 0;
}
@ -431,12 +433,36 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_intf *intf = vif_to_intf(vif);
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
vif->type != NL80211_IFTYPE_MESH_POINT &&
vif->type != NL80211_IFTYPE_WDS)
return;
spin_lock(&intf->lock);
intf->delayed_flags |= DELAYED_UPDATE_BEACON;
spin_unlock(&intf->lock);
}
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
rt2x00lib_beacondone(rt2x00dev);
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
rt2x00mac_set_tim_iter,
rt2x00dev);
/* queue work to upodate the beacon template */
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
@ -540,6 +566,22 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
__set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_stop_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
__clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_start_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{

View File

@ -153,8 +153,10 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
/*
* Register interrupt handler.
*/
status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler,
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
status = request_threaded_irq(rt2x00dev->irq,
rt2x00dev->ops->lib->irq_handler,
rt2x00dev->ops->lib->irq_handler_thread,
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
if (status) {
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
rt2x00dev->irq, status);

View File

@ -688,9 +688,11 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
if (index == Q_INDEX) {
queue->length++;
queue->last_index = jiffies;
} else if (index == Q_INDEX_DONE) {
queue->length--;
queue->count++;
queue->last_index_done = jiffies;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
@ -704,6 +706,8 @@ static void rt2x00queue_reset(struct data_queue *queue)
queue->count = 0;
queue->length = 0;
queue->last_index = jiffies;
queue->last_index_done = jiffies;
memset(queue->index, 0, sizeof(queue->index));
spin_unlock_irqrestore(&queue->lock, irqflags);

View File

@ -446,6 +446,8 @@ struct data_queue {
enum data_queue_qid qid;
spinlock_t lock;
unsigned long last_index;
unsigned long last_index_done;
unsigned int count;
unsigned short limit;
unsigned short threshold;
@ -598,6 +600,15 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
return rt2x00queue_available(queue) < queue->threshold;
}
/**
* rt2x00queue_timeout - Check if a timeout occured for this queue
* @queue: Queue to check.
*/
static inline int rt2x00queue_timeout(struct data_queue *queue)
{
return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
}
/**
* _rt2x00_desc_read - Read a word from the hardware descriptor.
* @desc: Base descriptor address

View File

@ -63,7 +63,8 @@ enum led_mode {
enum tsf_sync {
TSF_SYNC_NONE = 0,
TSF_SYNC_INFRA = 1,
TSF_SYNC_BEACON = 2,
TSF_SYNC_ADHOC = 2,
TSF_SYNC_AP_NONE = 3,
};
/*
@ -88,6 +89,8 @@ enum dev_state {
STATE_RADIO_RX_OFF_LINK,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
STATE_RADIO_IRQ_ON_ISR,
STATE_RADIO_IRQ_OFF_ISR,
};
/*

View File

@ -292,6 +292,56 @@ void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
{
struct queue_entry_priv_usb *entry_priv;
unsigned short threshold = queue->threshold;
WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
/*
* Temporarily disable the TX queue, this will force mac80211
* to use the other queues until this queue has been restored.
*
* Set the queue threshold to the queue limit. This prevents the
* queue from being enabled during the txdone handler.
*/
queue->threshold = queue->limit;
ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
/*
* Reset all currently uploaded TX frames.
*/
while (!rt2x00queue_empty(queue)) {
entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
usb_kill_urb(entry_priv->urb);
/*
* We need a short delay here to wait for
* the URB to be canceled and invoked the tx_done handler.
*/
udelay(200);
}
/*
* The queue has been reset, and mac80211 is allowed to use the
* queue again.
*/
queue->threshold = threshold;
ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
}
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
if (rt2x00queue_timeout(queue))
rt2x00usb_watchdog_reset_tx(queue);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
/*
* RX data handlers.
*/

View File

@ -399,6 +399,16 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
* @rt2x00dev: Pointer to &struct rt2x00_dev
*
* Check the health of the USB communication and determine
* if timeouts have occured. If this is the case, this function
* will reset all communication to restore functionality again.
*/
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev);
/*
* Device initialization handlers.
*/

View File

@ -1622,7 +1622,8 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int mask = (state == STATE_RADIO_IRQ_OFF);
int mask = (state == STATE_RADIO_IRQ_OFF) ||
(state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@ -1739,7 +1740,9 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt61pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
rt61pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@ -2147,27 +2150,11 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg_mcu;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg && !reg_mcu)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
u32 reg = rt2x00dev->irqvalue[0];
u32 reg_mcu = rt2x00dev->irqvalue[1];
/*
* Handle interrupts, walk through all bits
@ -2206,9 +2193,45 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
rt2x00lib_beacondone(rt2x00dev);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg_mcu;
u32 reg;
/*
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg && !reg_mcu)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/* Store irqvalues for use in the interrupt thread. */
rt2x00dev->irqvalue[0] = reg;
rt2x00dev->irqvalue[1] = reg_mcu;
/* Disable interrupts, will be enabled again in the interrupt thread. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
STATE_RADIO_IRQ_OFF_ISR);
return IRQ_WAKE_THREAD;
}
/*
* Device probe functions.
*/
@ -2690,6 +2713,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -2781,8 +2805,9 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
@ -2792,6 +2817,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.irq_handler = rt61pci_interrupt,
.irq_handler_thread = rt61pci_interrupt_thread,
.probe_hw = rt61pci_probe_hw,
.get_firmware_name = rt61pci_get_firmware_name,
.check_firmware = rt61pci_check_firmware,

View File

@ -1400,7 +1400,9 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt73usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@ -2135,6 +2137,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
__set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@ -2228,6 +2232,8 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
@ -2248,6 +2254,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.link_stats = rt73usb_link_stats,
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
.watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,

View File

@ -10,7 +10,7 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
wl1271_init.o wl1271_debugfs.o
wl1271_init.o wl1271_debugfs.o wl1271_scan.o
wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o

View File

@ -1417,5 +1417,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
MODULE_ALIAS("spi:wl1251");
MODULE_FIRMWARE(WL1251_FW_NAME);

View File

@ -345,3 +345,4 @@ module_exit(wl1251_spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
MODULE_ALIAS("spi:wl1251");

View File

@ -300,12 +300,10 @@ struct wl1271_rx_mem_pool_addr {
struct wl1271_scan {
struct cfg80211_scan_request *req;
bool *scanned_ch;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
u8 active;
u8 high_prio;
u8 probe_requests;
};
struct wl1271_if_operations {
@ -343,14 +341,14 @@ struct wl1271 {
#define WL1271_FLAG_JOINED (2)
#define WL1271_FLAG_GPIO_POWER (3)
#define WL1271_FLAG_TX_QUEUE_STOPPED (4)
#define WL1271_FLAG_SCANNING (5)
#define WL1271_FLAG_IN_ELP (6)
#define WL1271_FLAG_PSM (7)
#define WL1271_FLAG_PSM_REQUESTED (8)
#define WL1271_FLAG_IRQ_PENDING (9)
#define WL1271_FLAG_IRQ_RUNNING (10)
#define WL1271_FLAG_IDLE (11)
#define WL1271_FLAG_IDLE_REQUESTED (12)
#define WL1271_FLAG_IN_ELP (5)
#define WL1271_FLAG_PSM (6)
#define WL1271_FLAG_PSM_REQUESTED (7)
#define WL1271_FLAG_IRQ_PENDING (8)
#define WL1271_FLAG_IRQ_RUNNING (9)
#define WL1271_FLAG_IDLE (10)
#define WL1271_FLAG_IDLE_REQUESTED (11)
#define WL1271_FLAG_PSPOLL_FAILURE (12)
unsigned long flags;
struct wl1271_partition_set part;
@ -445,6 +443,10 @@ struct wl1271 {
struct completion *elp_compl;
struct delayed_work elp_work;
struct delayed_work pspoll_work;
/* counter for ps-poll delivery failures */
int ps_poll_failures;
/* retry counter for PSM entries */
u8 psm_entry_retry;

View File

@ -1075,8 +1075,7 @@ out:
return ret;
}
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
u8 version)
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
{
struct wl1271_acx_arp_filter *acx;
int ret;
@ -1089,17 +1088,11 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
goto out;
}
acx->version = version;
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;
if (enable == true) {
if (version == ACX_IPV4_VERSION)
memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE);
else if (version == ACX_IPV6_VERSION)
memcpy(acx->address, address, sizeof(acx->address));
else
wl1271_error("Invalid IP version");
}
if (enable == true)
memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
acx, sizeof(*acx));
@ -1266,3 +1259,29 @@ out:
kfree(acx);
return ret;
}
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
{
struct wl1271_acx_fw_tsf_information *tsf_info;
int ret;
tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
if (!tsf_info) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
tsf_info, sizeof(*tsf_info));
if (ret < 0) {
wl1271_warning("acx tsf info interrogate failed");
goto out;
}
*mactime = le32_to_cpu(tsf_info->current_tsf_low) |
((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32);
out:
kfree(tsf_info);
return ret;
}

View File

@ -993,6 +993,17 @@ struct wl1271_acx_rssi_snr_avg_weights {
u8 snr_data;
};
struct wl1271_acx_fw_tsf_information {
struct acx_header header;
__le32 current_tsf_high;
__le32 current_tsf_low;
__le32 last_bttt_high;
__le32 last_tbtt_low;
u8 last_dtim_count;
u8 padding[3];
} __packed;
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@ -1106,13 +1117,13 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
u8 version);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address);
int wl1271_acx_pm_config(struct wl1271 *wl);
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
s16 thold, u8 hyst);
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
#endif /* __WL1271_ACX_H__ */

View File

@ -414,7 +414,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PS_REPORT_EVENT_ID |
JOIN_EVENT_COMPLETE_ID |
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID;
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {

View File

@ -104,100 +104,6 @@ out:
return ret;
}
static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
{
struct wl1271_cmd_cal_channel_tune *cmd;
int ret = 0;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->test.id = TEST_CMD_CHANNEL_TUNE;
cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
/* set up any channel, 7 is in the middle of the range */
cmd->channel = 7;
ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
kfree(cmd);
return ret;
}
static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
{
struct wl1271_cmd_cal_update_ref_point *cmd;
int ret = 0;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
/* FIXME: still waiting for the correct values */
cmd->ref_power = 0;
cmd->ref_detector = 0;
cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
kfree(cmd);
return ret;
}
static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
{
struct wl1271_cmd_cal_p2g *cmd;
int ret = 0;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->test.id = TEST_CMD_P2G_CAL;
cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_P2G_CAL failed");
kfree(cmd);
return ret;
}
static int wl1271_cmd_cal(struct wl1271 *wl)
{
/*
* FIXME: we must make sure that we're not sleeping when calibration
* is done
*/
int ret;
wl1271_notice("performing tx calibration");
ret = wl1271_cmd_cal_channel_tune(wl);
if (ret < 0)
return ret;
ret = wl1271_cmd_cal_update_ref_point(wl);
if (ret < 0)
return ret;
ret = wl1271_cmd_cal_p2g(wl);
if (ret < 0)
return ret;
return ret;
}
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
@ -226,7 +132,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms_cmd *radio_parms;
struct conf_radio_parms *rparam = &wl->conf.init.radioparam;
struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
int ret;
if (!wl->nvs)
@ -242,7 +148,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
sizeof(struct wl1271_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2,
&wl->nvs->dyn_radio_params_2[rparam->fem].params,
&wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_2));
/* 5GHz parameters */
@ -250,7 +156,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
&wl->nvs->stat_radio_params_5,
sizeof(struct wl1271_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5,
&wl->nvs->dyn_radio_params_5[rparam->fem].params,
&wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
@ -295,20 +201,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
{
static bool do_cal = true;
struct wl1271_cmd_join *join;
int ret, i;
u8 *bssid;
/* FIXME: remove when we get calibration from the factory */
if (do_cal) {
ret = wl1271_cmd_cal(wl);
if (ret < 0)
wl1271_warning("couldn't calibrate");
else
do_cal = false;
}
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
ret = -ENOMEM;
@ -567,142 +463,6 @@ out:
return ret;
}
int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req, u8 active_scan,
u8 high_prio, u8 band, u8 probe_requests)
{
struct wl1271_cmd_trigger_scan_to *trigger = NULL;
struct wl1271_cmd_scan *params = NULL;
struct ieee80211_channel *channels;
u32 rate;
int i, j, n_ch, ret;
u16 scan_options = 0;
u8 ieee_band;
if (band == WL1271_SCAN_BAND_2_4_GHZ) {
ieee_band = IEEE80211_BAND_2GHZ;
rate = wl->conf.tx.basic_rate;
} else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
ieee_band = IEEE80211_BAND_2GHZ;
rate = wl->conf.tx.basic_rate;
} else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
ieee_band = IEEE80211_BAND_5GHZ;
rate = wl->conf.tx.basic_rate_5;
} else
return -EINVAL;
if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
return -EINVAL;
channels = wl->hw->wiphy->bands[ieee_band]->channels;
n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
return -EINVAL;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
params->params.rx_filter_options =
cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
if (!active_scan)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
if (high_prio)
scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
params->params.scan_options = cpu_to_le16(scan_options);
params->params.num_probe_requests = probe_requests;
params->params.tx_rate = cpu_to_le32(rate);
params->params.tid_trigger = 0;
params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
if (band == WL1271_SCAN_BAND_DUAL)
params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
else
params->params.band = band;
for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
params->channels[j].min_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
params->channels[j].max_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
memset(&params->channels[j].bssid_lsb, 0xff, 4);
memset(&params->channels[j].bssid_msb, 0xff, 2);
params->channels[j].early_termination = 0;
params->channels[j].tx_power_att =
WL1271_SCAN_CURRENT_TX_PWR;
params->channels[j].channel = channels[i].hw_value;
j++;
}
}
params->params.num_channels = j;
if (ssid_len && ssid) {
params->params.ssid_len = ssid_len;
memcpy(params->params.ssid, ssid, ssid_len);
}
ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
req->ie, req->ie_len, ieee_band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
}
trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
if (!trigger) {
ret = -ENOMEM;
goto out;
}
/* disable the timeout */
trigger->timeout = 0;
ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
sizeof(*trigger), 0);
if (ret < 0) {
wl1271_error("trigger scan to failed for hw scan");
goto out;
}
wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
set_bit(WL1271_FLAG_SCANNING, &wl->flags);
if (wl1271_11a_enabled()) {
wl->scan.state = band;
if (band == WL1271_SCAN_BAND_DUAL) {
wl->scan.active = active_scan;
wl->scan.high_prio = high_prio;
wl->scan.probe_requests = probe_requests;
if (ssid_len && ssid) {
wl->scan.ssid_len = ssid_len;
memcpy(wl->scan.ssid, ssid, ssid_len);
} else
wl->scan.ssid_len = 0;
wl->scan.req = req;
} else
wl->scan.req = NULL;
}
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
goto out;
}
out:
kfree(params);
kfree(trigger);
return ret;
}
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates)
{
@ -807,7 +567,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
goto out;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
skb->len, 0, wl->basic_rate);
skb->len, 0, wl->basic_rate_set);
out:
dev_kfree_skb(skb);

View File

@ -41,9 +41,6 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req, u8 active_scan,
u8 high_prio, u8 band, u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates);
int wl1271_cmd_build_null_data(struct wl1271 *wl);
@ -350,71 +347,6 @@ struct wl1271_cmd_set_keys {
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
} __packed;
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
#define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_BAND_DUAL 2
struct basic_scan_params {
__le32 rx_config_options;
__le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
/* Number of scan channels in the list (maximum 30) */
u8 num_channels;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 num_probe_requests;
/* Rate bit field for sending the probes */
__le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
/* in order to align */
u8 padding1[2];
u8 ssid[IW_ESSID_MAX_SIZE];
/* Band to scan */
u8 band;
u8 use_ssid_list;
u8 scan_tag;
u8 padding2;
} __packed;
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
__le32 min_duration;
__le32 max_duration;
__le32 bssid_lsb;
__le16 bssid_msb;
u8 early_termination;
u8 tx_power_att;
u8 channel;
/* FW internal use only! */
u8 dfs_candidate;
u8 activity_detected;
u8 pad;
} __packed;
struct wl1271_cmd_scan {
struct wl1271_cmd_header header;
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
} __packed;
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
__le32 timeout;
} __packed;
struct wl1271_cmd_test_header {
u8 id;
u8 padding[3];

View File

@ -873,6 +873,13 @@ struct conf_conn_settings {
*/
u8 ps_poll_threshold;
/*
* PS Poll failure recovery ACTIVE period length
*
* Range: u32 (ms)
*/
u32 ps_poll_recovery_period;
/*
* Configuration of signal average weights.
*/
@ -948,14 +955,6 @@ struct conf_radio_parms {
u8 fem;
};
struct conf_init_settings {
/*
* Configure radio parameters.
*/
struct conf_radio_parms radioparam;
};
struct conf_itrim_settings {
/* enable dco itrim */
u8 enable;
@ -1022,7 +1021,6 @@ struct conf_drv_settings {
struct conf_rx_settings rx;
struct conf_tx_settings tx;
struct conf_conn_settings conn;
struct conf_init_settings init;
struct conf_itrim_settings itrim;
struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger;

View File

@ -26,36 +26,64 @@
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
#include "wl1271_scan.h"
#include "wl12xx_80211.h"
static int wl1271_event_scan_complete(struct wl1271 *wl,
struct event_mailbox *mbox)
void wl1271_pspoll_work(struct work_struct *work)
{
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
struct delayed_work *dwork;
struct wl1271 *wl;
if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
/* 2.4 GHz band scanned, scan 5 GHz band, pretend
* to the wl1271_cmd_scan function that we are not
* scanning as it checks that.
*/
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
/* FIXME: ie missing! */
wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req,
wl->scan.active,
wl->scan.high_prio,
WL1271_SCAN_BAND_5_GHZ,
wl->scan.probe_requests);
} else {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
mutex_lock(&wl->mutex);
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
}
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, pspoll_work);
wl1271_debug(DEBUG_EVENT, "pspoll work");
mutex_lock(&wl->mutex);
if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
goto out;
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;
/*
* if we end up here, then we were in powersave when the pspoll
* delivery failure occurred, and no-one changed state since, so
* we should go back to powersave.
*/
wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
out:
mutex_unlock(&wl->mutex);
};
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
{
int delay = wl->conf.conn.ps_poll_recovery_period;
int ret;
wl->ps_poll_failures++;
if (wl->ps_poll_failures == 1)
wl1271_info("AP with dysfunctional ps-poll, "
"trying to work around it.");
/* force active mode receive data from the AP */
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
if (ret < 0)
return;
set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
msecs_to_jiffies(delay));
}
return 0;
/*
* If already in active mode, lets we should be getting data from
* the AP right away. If we enter PSM too fast after this, and data
* remains on the AP, we will get another event like this, and we'll
* go into active once more.
*/
}
static int wl1271_event_ps_report(struct wl1271 *wl,
@ -163,9 +191,19 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
ret = wl1271_event_scan_complete(wl, mbox);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
wl1271_scan_stm(wl);
}
/* disable dynamic PS when requested by the firmware */
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
wl->bss_type == BSS_TYPE_STA_BSS) {
if (mbox->soft_gemini_sense_info)
ieee80211_disable_dyn_ps(wl->vif);
else
ieee80211_enable_dyn_ps(wl->vif);
}
/*
@ -191,6 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
wl1271_event_pspoll_delivery_fail(wl);
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
if (wl->vif)

View File

@ -121,5 +121,6 @@ struct event_mailbox {
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work);
#endif

View File

@ -28,7 +28,6 @@
#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
#include <linux/inetdevice.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -45,6 +44,7 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
#include "wl1271_testmode.h"
#include "wl1271_scan.h"
#define WL1271_BOOT_RETRIES 3
@ -55,7 +55,7 @@ static struct conf_drv_settings default_conf = {
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
[CONF_SG_BT_LOAD_RATIO] = 50,
[CONF_SG_AUTO_PS_MODE] = 0,
[CONF_SG_AUTO_PS_MODE] = 1,
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
[CONF_SG_ANTENNA_CONFIGURATION] = 0,
@ -234,18 +234,14 @@ static struct conf_drv_settings default_conf = {
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
.ps_poll_threshold = 20,
.ps_poll_threshold = 10,
.ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 10,
.psm_entry_retries = 3,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
.init = {
.radioparam = {
.fem = 1,
}
},
.itrim = {
.enable = false,
.timeout = 50000,
@ -818,93 +814,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
void *arg)
{
struct net_device *dev;
struct wireless_dev *wdev;
struct wiphy *wiphy;
struct ieee80211_hw *hw;
struct wl1271 *wl;
struct wl1271 *wl_temp;
struct in_device *idev;
struct in_ifaddr *ifa = arg;
int ret = 0;
/* FIXME: this ugly function should probably be implemented in the
* mac80211, and here should only be a simple callback handling actual
* setting of the filters. Now we need to dig up references to
* various structures to gain access to what we need.
* Also, because of this, there is no "initial" setting of the filter
* in "op_start", because we don't want to dig up struct net_device
* there - the filter will be set upon first change of the interface
* IP address. */
dev = ifa->ifa_dev->dev;
wdev = dev->ieee80211_ptr;
if (wdev == NULL)
return NOTIFY_DONE;
wiphy = wdev->wiphy;
if (wiphy == NULL)
return NOTIFY_DONE;
hw = wiphy_priv(wiphy);
if (hw == NULL)
return NOTIFY_DONE;
/* Check that the interface is one supported by this driver. */
wl_temp = hw->priv;
list_for_each_entry(wl, &wl_list, list) {
if (wl == wl_temp)
break;
}
if (wl != wl_temp)
return NOTIFY_DONE;
/* Get the interface IP address for the device. "ifa" will become
NULL if:
- there is no IPV4 protocol address configured
- there are multiple (virtual) IPV4 addresses configured
When "ifa" is NULL, filtering will be disabled.
*/
ifa = NULL;
idev = dev->ip_ptr;
if (idev)
ifa = idev->ifa_list;
if (ifa && ifa->ifa_next)
ifa = NULL;
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF)
goto out;
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
if (ifa)
ret = wl1271_acx_arp_ip_filter(wl, true,
(u8 *)&ifa->ifa_address,
ACX_IPV4_VERSION);
else
ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
ACX_IPV4_VERSION);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return NOTIFY_OK;
}
static struct notifier_block wl1271_dev_notifier = {
.notifier_call = wl1271_dev_notify,
};
static int wl1271_op_start(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@ -1008,10 +917,8 @@ power_off:
out:
mutex_unlock(&wl->mutex);
if (!ret) {
if (!ret)
list_add(&wl->list, &wl_list);
register_inetaddr_notifier(&wl1271_dev_notifier);
}
return ret;
}
@ -1022,8 +929,6 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
int i;
unregister_inetaddr_notifier(&wl1271_dev_notifier);
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
@ -1033,10 +938,17 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
WARN_ON(wl->state != WL1271_STATE_ON);
if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
/* enable dyn ps just in case (if left on due to fw crash etc) */
if (wl->bss_type == BSS_TYPE_STA_BSS)
ieee80211_enable_dyn_ps(wl->vif);
if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, true);
mutex_lock(&wl->mutex);
wl->scan.state = WL1271_SCAN_STATE_IDLE;
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
}
wl->state = WL1271_STATE_OFF;
@ -1047,6 +959,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->pspoll_work);
mutex_lock(&wl->mutex);
@ -1352,6 +1265,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
wl1271_warning("idle mode change failed %d", ret);
}
/*
* if mac80211 changes the PSM mode, make sure the mode is not
* incorrectly changed after the pspoll failure active window.
*/
if (changed & IEEE80211_CONF_CHANGE_PS)
clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
if (conf->flags & IEEE80211_CONF_PS &&
!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
@ -1634,11 +1554,9 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out;
if (wl1271_11a_enabled())
ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1, 0, WL1271_SCAN_BAND_DUAL, 3);
ret = wl1271_scan(hw->priv, ssid, len, req);
else
ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
ret = wl1271_scan(hw->priv, ssid, len, req);
wl1271_ps_elp_sleep(wl);
@ -1811,6 +1729,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
wl->aid = bss_conf->aid;
set_assoc = true;
wl->ps_poll_failures = 0;
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
@ -1860,6 +1780,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
/* re-enable dynamic ps - just in case */
ieee80211_enable_dyn_ps(wl->vif);
/* revert back to minimum rates for the current band */
wl1271_set_band_rate(wl);
wl->basic_rate = wl1271_min_rate_get(wl);
@ -1908,6 +1831,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
if (changed & BSS_CHANGED_ARP_FILTER) {
__be32 addr = bss_conf->arp_addr_list[0];
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
ret = wl1271_acx_arp_ip_filter(wl, true, addr);
else
ret = wl1271_acx_arp_ip_filter(wl, false, addr);
if (ret < 0)
goto out_sleep;
}
if (do_join) {
ret = wl1271_join(wl, set_assoc);
if (ret < 0) {
@ -1966,6 +1902,32 @@ out:
return ret;
}
static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
u64 mactime = ULLONG_MAX;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
ret = wl1271_acx_tsf_info(wl, &mactime);
if (ret < 0)
goto out_sleep;
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return mactime;
}
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
@ -2195,6 +2157,7 @@ static const struct ieee80211_ops wl1271_ops = {
.bss_info_changed = wl1271_op_bss_info_changed,
.set_rts_threshold = wl1271_op_set_rts_threshold,
.conf_tx = wl1271_op_conf_tx,
.get_tsf = wl1271_op_get_tsf,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@ -2407,6 +2370,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
skb_queue_head_init(&wl->tx_queue);
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;

View File

@ -53,12 +53,6 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->band = wl->band;
status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
/*
* FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the
* timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we
* only need the mactime for monitor mode. For now the mactime is
* not valid, so RX_FLAG_TSFT should not be set
*/
status->signal = desc->rssi;
status->freq = ieee80211_channel_to_frequency(desc->channel);

View File

@ -0,0 +1,257 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2009-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/ieee80211.h>
#include "wl1271.h"
#include "wl1271_cmd.h"
#include "wl1271_scan.h"
#include "wl1271_acx.h"
static int wl1271_get_scan_channels(struct wl1271 *wl,
struct cfg80211_scan_request *req,
struct basic_scan_channel_params *channels,
enum ieee80211_band band, bool passive)
{
int i, j;
u32 flags;
for (i = 0, j = 0;
i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
i++) {
flags = req->channels[i]->flags;
if (!wl->scan.scanned_ch[i] &&
!(flags & IEEE80211_CHAN_DISABLED) &&
((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
(req->channels[i]->band == band)) {
wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
req->channels[i]->band,
req->channels[i]->center_freq);
wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
req->channels[i]->hw_value,
req->channels[i]->flags);
wl1271_debug(DEBUG_SCAN,
"max_antenna_gain %d, max_power %d",
req->channels[i]->max_antenna_gain,
req->channels[i]->max_power);
wl1271_debug(DEBUG_SCAN, "beacon_found %d",
req->channels[i]->beacon_found);
channels[j].min_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
channels[j].max_duration =
cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
channels[j].early_termination = 0;
channels[j].tx_power_att = req->channels[i]->max_power;
channels[j].channel = req->channels[i]->hw_value;
memset(&channels[j].bssid_lsb, 0xff, 4);
memset(&channels[j].bssid_msb, 0xff, 2);
/* Mark the channels we already used */
wl->scan.scanned_ch[i] = true;
j++;
}
}
return j;
}
#define WL1271_NOTHING_TO_SCAN 1
static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
bool passive, u32 basic_rate)
{
struct wl1271_cmd_scan *cmd;
struct wl1271_cmd_trigger_scan_to *trigger;
int ret;
u16 scan_options = 0;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
if (!cmd || !trigger) {
ret = -ENOMEM;
goto out;
}
/* We always use high priority scans */
scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
if(passive)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
cmd->channels,
band, passive);
if (cmd->params.n_ch == 0) {
ret = WL1271_NOTHING_TO_SCAN;
goto out;
}
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
cmd->params.rx_filter_options =
cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
if (band == IEEE80211_BAND_2GHZ)
cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
else
cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
if (wl->scan.ssid_len && wl->scan.ssid) {
cmd->params.ssid_len = wl->scan.ssid_len;
memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
}
ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req->ie, wl->scan.req->ie_len,
band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
}
/* disable the timeout */
trigger->timeout = 0;
ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
sizeof(*trigger), 0);
if (ret < 0) {
wl1271_error("trigger scan to failed for hw scan");
goto out;
}
wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
goto out;
}
out:
kfree(cmd);
kfree(trigger);
return ret;
}
void wl1271_scan_stm(struct wl1271 *wl)
{
int ret;
switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE:
break;
case WL1271_SCAN_STATE_2GHZ_ACTIVE:
ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
wl->conf.tx.basic_rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
wl1271_scan_stm(wl);
}
break;
case WL1271_SCAN_STATE_2GHZ_PASSIVE:
ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
wl->conf.tx.basic_rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
if (wl1271_11a_enabled())
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
else
wl->scan.state = WL1271_SCAN_STATE_DONE;
wl1271_scan_stm(wl);
}
break;
case WL1271_SCAN_STATE_5GHZ_ACTIVE:
ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
wl->conf.tx.basic_rate_5);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
wl1271_scan_stm(wl);
}
break;
case WL1271_SCAN_STATE_5GHZ_PASSIVE:
ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
wl->conf.tx.basic_rate_5);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_DONE;
wl1271_scan_stm(wl);
}
break;
case WL1271_SCAN_STATE_DONE:
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
mutex_lock(&wl->mutex);
kfree(wl->scan.scanned_ch);
wl->scan.scanned_ch = NULL;
wl->scan.state = WL1271_SCAN_STATE_IDLE;
break;
default:
wl1271_error("invalid scan state");
break;
}
}
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req)
{
if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
return -EBUSY;
wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
if (ssid_len && ssid) {
wl->scan.ssid_len = ssid_len;
memcpy(wl->scan.ssid, ssid, ssid_len);
} else {
wl->scan.ssid_len = 0;
}
wl->scan.req = req;
wl->scan.scanned_ch = kzalloc(req->n_channels *
sizeof(*wl->scan.scanned_ch),
GFP_KERNEL);
wl1271_scan_stm(wl);
return 0;
}

View File

@ -0,0 +1,109 @@
/*
* This file is part of wl1271
*
* Copyright (C) 2009-2010 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL1271_SCAN_H__
#define __WL1271_SCAN_H__
#include "wl1271.h"
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req);
int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
#define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_PROBE_REQS 3
enum {
WL1271_SCAN_STATE_IDLE,
WL1271_SCAN_STATE_2GHZ_ACTIVE,
WL1271_SCAN_STATE_2GHZ_PASSIVE,
WL1271_SCAN_STATE_5GHZ_ACTIVE,
WL1271_SCAN_STATE_5GHZ_PASSIVE,
WL1271_SCAN_STATE_DONE
};
struct basic_scan_params {
__le32 rx_config_options;
__le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
/* Number of scan channels in the list (maximum 30) */
u8 n_ch;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 n_probe_reqs;
/* Rate bit field for sending the probes */
__le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
/* in order to align */
u8 padding1[2];
u8 ssid[IW_ESSID_MAX_SIZE];
/* Band to scan */
u8 band;
u8 use_ssid_list;
u8 scan_tag;
u8 padding2;
} __packed;
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
__le32 min_duration;
__le32 max_duration;
__le32 bssid_lsb;
__le16 bssid_msb;
u8 early_termination;
u8 tx_power_att;
u8 channel;
/* FW internal use only! */
u8 dfs_candidate;
u8 activity_detected;
u8 pad;
} __packed;
struct wl1271_cmd_scan {
struct wl1271_cmd_header header;
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
} __packed;
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
__le32 timeout;
} __packed;
#endif /* __WL1271_SCAN_H__ */

View File

@ -461,3 +461,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME);
MODULE_ALIAS("spi:wl1271");

View File

@ -143,6 +143,11 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
/* reject WEP and TKIP keys if WEP failed to initialize */
if ((alg == ALG_WEP || alg == ALG_TKIP) &&
IS_ERR(sdata->local->wep_tx_tfm))
return -EINVAL;
key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
params->seq_len, params->seq);
if (!key)

View File

@ -637,11 +637,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_sta_info;
result = ieee80211_wep_init(local);
if (result < 0) {
if (result < 0)
printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
wiphy_name(local->hw.wiphy), result);
goto fail_wep;
}
rtnl_lock();
@ -694,7 +692,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
fail_rate:
rtnl_unlock();
ieee80211_wep_free(local);
fail_wep:
sta_info_stop(local);
fail_sta_info:
destroy_workqueue(local->workqueue);

View File

@ -240,6 +240,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
mg->max_prob_rate = index;
cur_prob = mr->probability;
cur_prob_tp = mr->cur_tp;
}
if (mr->cur_tp > cur_tp) {
@ -275,6 +276,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
minstrel_mcs_groups[group].streams == 1) {
mi->max_prob_rate = mg->max_prob_rate;
cur_prob = mr->cur_prob;
cur_prob_tp = mr->cur_tp;
}
mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
@ -441,8 +443,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
if (rate->attempts > 30 &&
MINSTREL_FRAC(rate->success, rate->attempts) <
if (rate2->attempts > 30 &&
MINSTREL_FRAC(rate2->success, rate2->attempts) <
MINSTREL_FRAC(20, 100))
minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);

View File

@ -202,9 +202,9 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);
* @payload_len is the length of payload (_not_ including IV/ICV length).
* @ta is the transmitter addresses.
*/
void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta)
int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta)
{
u8 rc4key[16];
struct tkip_ctx *ctx = &key->u.tkip.tx;
@ -216,7 +216,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
}
/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the

Some files were not shown because too many files have changed in this diff Show More