Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
fae88f7eed
@ -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/
|
||||
|
||||
|
@ -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
@ -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
@ -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",
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)"
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)},
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
========================
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 */
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
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,
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
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(®, BCN_TIME_CFG_TSF_TICKING, 1);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value);
|
||||
rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
|
||||
rt2800_register_read(rt2x00dev, offset, ®);
|
||||
|
||||
rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value);
|
||||
rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value);
|
||||
rt2x00_set_field32(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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, ®);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 1600);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0);
|
||||
rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®);
|
||||
|
||||
/*
|
||||
* Setup leadtime for pre tbtt interrupt to 6ms
|
||||
*/
|
||||
rt2800_register_read(rt2x00dev, INT_TIMER_CFG, ®);
|
||||
rt2x00_set_field32(®, 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);
|
||||
|
@ -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 */
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
|
||||
rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
|
||||
rt2x00_set_field32(®, 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, ®);
|
||||
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 */
|
||||
|
@ -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, ®);
|
||||
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, ®);
|
||||
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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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, ®_mcu);
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
||||
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, ®_mcu);
|
||||
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
|
||||
|
||||
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -345,3 +345,4 @@ module_exit(wl1251_spi_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
|
||||
MODULE_ALIAS("spi:wl1251");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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) {
|
||||
|
@ -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(¶ms->channels[j].bssid_lsb, 0xff, 4);
|
||||
memset(¶ms->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);
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
257
drivers/net/wireless/wl12xx/wl1271_scan.c
Normal file
257
drivers/net/wireless/wl12xx/wl1271_scan.c
Normal 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;
|
||||
}
|
109
drivers/net/wireless/wl12xx/wl1271_scan.h
Normal file
109
drivers/net/wireless/wl12xx/wl1271_scan.h
Normal 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__ */
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user